文 | Mr-Bruce 作為系列文章的第四篇,本文將重點探討數(shù)據(jù)采集層中的ELK日志系統(tǒng)。 日志,指的是后臺服務中產(chǎn)生的log信息,通常會輸入到不同的文件中,比如Django服務下,一般會有nginx日志和uWSGI日志。這些日志分散地存儲在不同的機器上,取決于服務的部署情況了。 如果我們依次登錄每臺機器去查閱日志,顯然非常繁瑣,效率也很低,而且也沒法進行統(tǒng)計和檢索。因此,我們需要對日志進行集中化管理,將所有機器上的日志信息收集、匯總到一起。完整的日志數(shù)據(jù)具有非常重要的作用:
ELK是一套開源的集中式日志數(shù)據(jù)管理的解決方案,由Elasticsearch、Logstash和Kibana三個系統(tǒng)組成。 最初我們建設ELK日志系統(tǒng)的目的是做數(shù)據(jù)分析,記得第一個需求是期望利用nginx的日志,從API請求的參數(shù)中挖掘出用戶的位置分布信息。 后來該系統(tǒng)在追蹤惡意刷量、優(yōu)化耗時服務等方面都發(fā)揮了重要作用,而且隨著對Elasticsearch的認知加深,我們將其應用到了其他方面的數(shù)據(jù)存儲和分析中。 本文的重點是結合自身實踐來介紹如何使用ELK系統(tǒng)、使用中的問題以及如何解決,文中涉及的ELK版本是:Elasticsearch 2.3、Logstash 2.3、Kibana 4。 ELK整體方案ELK中的三個系統(tǒng)分別扮演不同的角色,組成了一個整體的解決方案。Logstash是一個ETL工具,負責從每臺機器抓取日志數(shù)據(jù),對數(shù)據(jù)進行格式轉換和處理后,輸出到Elasticsearch中存儲。 Elasticsearch是一個分布式搜索引擎和分析引擎,用于數(shù)據(jù)存儲,可提供實時的數(shù)據(jù)查詢。Kibana是一個數(shù)據(jù)可視化服務,根據(jù)用戶的操作從Elasticsearch中查詢數(shù)據(jù),形成相應的分析結果,以圖表的形式展現(xiàn)給用戶。 ELK的安裝很簡單,可以按照“下載->修改配置文件->啟動”方法分別部署三個系統(tǒng),也可以使用docker來快速部署。具體的安裝方法這里不詳細介紹,我們來看一個常見的部署方案,如下圖所示,部署思路是: 第一,在每臺生成日志文件的機器上,部署Logstash,作為Shipper的角色,負責從日志文件中提取數(shù)據(jù),但是不做任何處理,直接將數(shù)據(jù)輸出到Redis隊列(list)中; 第二,需要一臺機器部署Logstash,作為Indexer的角色,負責從Redis中取出數(shù)據(jù),對數(shù)據(jù)進行格式化和相關處理后,輸出到Elasticsearch中存儲; 第三,部署Elasticsearch集群,當然取決于你的數(shù)據(jù)量了,數(shù)據(jù)量小的話可以使用單臺服務,如果做集群的話,最好是有3個以上節(jié)點,同時還需要部署相關的監(jiān)控插件; 第四,部署Kibana服務,提供Web服務。 在前期部署階段,主要工作是Logstash節(jié)點和Elasticsearch集群的部署,而在后期使用階段,主要工作就是Elasticsearch集群的監(jiān)控和使用Kibana來檢索、分析日志數(shù)據(jù)了,當然也可以直接編寫程序來消費Elasticsearch中的數(shù)據(jù)。 在上面的部署方案中,我們將Logstash分為Shipper和Indexer兩種角色來完成不同的工作,中間通過Redis做數(shù)據(jù)管道,為什么要這樣做?為什么不是直接在每臺機器上使用Logstash提取數(shù)據(jù)、處理、存入Elasticsearch? 首先,采用這樣的架構部署,有三點優(yōu)勢: 第一,降低對日志所在機器的影響,這些機器上一般都部署著反向代理或應用服務,本身負載就很重了,所以盡可能的在這些機器上少做事; 第二,如果有很多臺機器需要做日志收集,那么讓每臺機器都向Elasticsearch持續(xù)寫入數(shù)據(jù),必然會對Elasticsearch造成壓力,因此需要對數(shù)據(jù)進行緩沖,同時,這樣的緩沖也可以一定程度的保護數(shù)據(jù)不丟失; 第三,將日志數(shù)據(jù)的格式化與處理放到Indexer中統(tǒng)一做,可以在一處修改代碼、部署,避免需要到多臺機器上去修改配置。 其次,我們需要做的是將數(shù)據(jù)放入一個消息隊列中進行緩沖,所以Redis只是其中一個選擇,也可以是RabbitMQ、Kafka等等,在實際生產(chǎn)中,Redis與Kafka用的比較多。 由于Redis集群一般都是通過key來做分片,無法對list類型做集群,在數(shù)據(jù)量大的時候必然不合適了,而Kafka天生就是分布式的消息隊列系統(tǒng)。 Logstash在官方文檔中,Deploying and Scaling Logstash一文詳細介紹了各種Logstash的部署架構,下圖是與我們上述方案相吻合的架構。 Logstash由input、filter和output三部分組成,input負責從數(shù)據(jù)源提取數(shù)據(jù),filter負責解析、處理數(shù)據(jù),output負責輸出數(shù)據(jù),每部分都有提供豐富的插件。 Logstash的設計思路也非常值得借鑒,以插件的形式來組織功能,通過配置文件來描述需要插件做什么。我們以nginx日志為例,來看看如何使用一些常用插件。 1. 配置nginx日志格式 首先需要將nginx日志格式規(guī)范化,便于做解析處理。在nginx.conf文件中設置: 2. nginx日志–>>Logstash–>>消息隊列 這部分是Logstash Shipper的工作,涉及input和output兩種插件。input部分,由于需要提取的是日志文件,一般使用file插件,該插件常用的幾個參數(shù)是:
output部分,將數(shù)據(jù)輸出到消息隊列,以redis為例,需要指定redis server和list key名稱。另外,在測試階段,可以使用stdout來查看輸出信息。 3. 消息隊列–>>Logstash–>>Elasticsearch 這部分是Logstash Indexer的工作,涉及input、filter和output三種插件。在input部分,我們通過redis插件將數(shù)據(jù)從消息隊列中取出來。在output部分,我們通過elasticsearch插件將數(shù)據(jù)寫入Elasticsearch。 這里,我們重點關注filter部分,下面列舉幾個常用的插件,實際使用中根據(jù)自身需求從官方文檔中查找適合自己業(yè)務的插件并使用即可,當然也可以編寫自己的插件。 grok,是Logstash最重要的一個插件,用于將非結構化的文本數(shù)據(jù)轉化為結構化的數(shù)據(jù)。 grok內部使用正則語法對文本數(shù)據(jù)進行匹配,為了降低使用復雜度,其提供了一組pattern,我們可以直接調用pattern而不需要自己寫正則表達式,參考源碼grok-patterns。 grok解析文本的語法格式是%{SYNTAX:SEMANTIC},SYNTAX是pattern名稱,SEMANTIC是需要生成的字段名稱,使用工具Grok Debugger可以對解析語法進行調試。 例如,在下面的配置中,我們先使用grok對輸入的原始nginx日志信息(默認以message作為字段名)進行解析,并添加新的字段request_path_with_verb(該字段的值是verb和request_path的組合),然后對request_path字段做進一步解析。 kv,用于將某個字段的值進行分解,類似于編程語言中的字符串Split。在下面的配置中,我們將request_args字段值按照“&”進行分解,分解后的字段名稱以“request_args_”作為前綴,并且丟棄重復的字段。 geoip,用于根據(jù)IP信息生成地理位置信息,默認使用自帶的一份GeoLiteCity database,也可以自己更換為最新的數(shù)據(jù)庫,但是需要數(shù)據(jù)格式需要遵循Maxmind的格式(參考GeoLite),似乎目前只能支持legacy database,數(shù)據(jù)類型必須是.dat。 下載GeoLiteCity.dat.gz后解壓, 并將文件路徑配置到source中即可。 translate,用于檢測某字段的值是否符合條件,如果符合條件則將其翻譯成新的值,寫入一個新的字段,匹配pattern可以通過YAML文件來配置。例如,在下面的配置中,我們對request_api字段翻譯成更加易懂的文字描述。 ElasticsearchElasticsearch承載了數(shù)據(jù)存儲和查詢的功能,其基礎概念和使用方法可以參考另一篇博文Elasticsearch使用總結,這里主要介紹些實際生產(chǎn)中的問題和方法: 關于集群配置,重點關注三個參數(shù): 第一,discovery.zen.ping.unicast.hosts,Elasticsearch默認使用Zen Discovery來做節(jié)點發(fā)現(xiàn)機制,推薦使用unicast來做通信方式,在該配置項中列舉出Master節(jié)點。 第二,discovery.zen.minimum_master_nodes,該參數(shù)表示集群中可工作的具有Master節(jié)點資格的最小數(shù)量,默認值是1。為了提高集群的可用性,避免腦裂現(xiàn)象(所謂腦裂,就是同一個集群中的不同節(jié)點,對集群的狀態(tài)有不一致的理解。),官方推薦設置為(N/2) 1,其中N是具有Master資格的節(jié)點的數(shù)量。 第三,discovery.zen.ping_timeout,表示節(jié)點在發(fā)現(xiàn)過程中的等待時間,默認值是3秒,可以根據(jù)自身網(wǎng)絡環(huán)境進行調整,一定程度上提供可用性。 關于集群節(jié)點: 第一,節(jié)點類型包括:候選Master節(jié)點、數(shù)據(jù)節(jié)點和Client節(jié)點。通過設置兩個配置項node.master和node.data為true或false,來決定將一個節(jié)點分配為什么類型的節(jié)點。 第二,盡量將候選Master節(jié)點和Data節(jié)點分離開,通常Data節(jié)點負載較重,需要考慮單獨部署。 關于內存,Elasticsearch默認設置的內存是1GB,對于任何一個業(yè)務部署來說,這個都太小了。通過指定ES_HEAP_SIZE環(huán)境變量,可以修改其堆內存大小,服務進程在啟動時候會讀取這個變量,并相應的設置堆的大小。 建議設置系統(tǒng)內存的一半給Elasticsearch,但是不要超過32GB。參考官方文檔。 關于硬盤空間,Elasticsearch默認將數(shù)據(jù)存儲在/var/lib/elasticsearch路徑下,隨著數(shù)據(jù)的增長,一定會出現(xiàn)硬盤空間不夠用的情形,此時就需要給機器掛載新的硬盤,并將Elasticsearch的路徑配置到新硬盤的路徑下。 通過“path.data”配置項來進行設置,比如“path.data: /data1,/var/lib/elasticsearch,/data”。需要注意的是,同一分片下的數(shù)據(jù)只能寫入到一個路徑下,因此還是需要合理的規(guī)劃和監(jiān)控硬盤的使用。 關于Index的劃分和分片的個數(shù),這個需要根據(jù)數(shù)據(jù)量來做權衡了,Index可以按時間劃分,比如每月一個或者每天一個,在Logstash輸出時進行配置,shard的數(shù)量也需要做好控制。 關于監(jiān)控,筆者使用過head和marvel兩個監(jiān)控插件,head免費,功能相對有限,marvel現(xiàn)在需要收費了。另外,不要在數(shù)據(jù)節(jié)點開啟監(jiān)控插件。 KibanaKibana提供的是數(shù)據(jù)查詢和顯示的Web服務,有豐富的圖表樣板,能滿足大部分的數(shù)據(jù)可視化需求,這也是很多人選擇ELK的主要原因之一。UI的操作沒有什么特別需要介紹的,經(jīng)常使用就會熟練,這里主要介紹經(jīng)常遇到的三個問題。 1. 查詢語法 在Kibana的Discover頁面中,可以輸入一個查詢條件來查詢所需的數(shù)據(jù)。查詢條件的寫法使用的是Elasticsearch的Query String語法,而不是Query DSL,參考官方文檔query-string-syntax,這里列舉其中部分常用的:
2. 錯誤“Discover: Request Timeout after 30000ms” 這個錯誤經(jīng)常發(fā)生在要查詢的數(shù)據(jù)量比較大的情況下,此時Elasticsearch需要較長時間才能返回,導致Kibana發(fā)生Timeout報錯。 解決這個問題的方法,就是在Kibana的配置文件中修改elasticsearch.requestTimeout一項的值,然后重啟Kibana服務即可,注意單位是ms。 3. 疑惑“字符串被分解了” |
|
來自: 昵稱39796580 > 《技術文摘》