ELK實時日誌分析平臺環境部署--完整記錄(ElasticSearch+Logstash+Kibana )
在日常運維工作中,對於系統和業務日誌的處理尤為重要。今天,在這裡分享一下自己部署的ELK(+Redis)-開源實時日誌分析平臺的記錄過程(僅依據本人的實際操作為例說明,如有誤述,敬請指出)~
================概念介紹================
日誌主要包括系統日誌、應用程式日誌和安全日誌。系統運維和開發人員可以通過日誌瞭解伺服器軟硬體資訊、檢查配置過程中的錯誤及錯誤發生的原因。經常分析日誌可以瞭解伺服器的負荷,效能安全性,從而及時採取措施糾正錯誤。
通常,日誌被分散在儲存不同的裝置上。如果你管理數十上百臺伺服器,你還在使用依次登入每臺機器的傳統方法查閱日誌。這樣是不是感覺很繁瑣和效率低下。當務之急我們使用集中化的日誌管理,例如:開源的syslog,將所有伺服器上的日誌收集彙總。
集中化管理日誌後,日誌的統計和檢索又成為一件比較麻煩的事情,一般我們使用grep、awk和wc等Linux命令能實現檢索和統計,但是對於要求更高的查詢、排序和統計等要求和龐大的機器數量依然使用這樣的方法難免有點力不從心。
通過我們需要對日誌進行集中化管理,將所有機器上的日誌資訊收集、彙總到一起。完整的日誌資料具有非常重要的作用:
1)資訊查詢。通過檢索日誌資訊,定位相應的bug,找出解決方案。
2)服務診斷。通過對日誌資訊進行統計、分析,瞭解伺服器的負荷和服務執行狀態,找出耗時請求進行優化等等。
3)資料分析。如果是格式化的log,可以做進一步的資料分析,統計、聚合出有意義的資訊,比如根據請求中的商品id,找出TOP10使用者感興趣商品。
開源實時日誌分析ELK平臺能夠完美的解決我們上述的問題,ELK由ElasticSearch、Logstash和Kiabana三個開源工具組成:
1)ElasticSearch是一個基於Lucene的開源分散式搜尋伺服器。它的特點有:分散式,零配置,自動發現,索引自動分片,索引副本機制,restful風格介面,多資料來源,自動搜尋負載等。它提供了一個分散式多使用者能力的全文搜尋引擎,基於RESTful web介面。Elasticsearch是用Java開發的,並作為Apache許可條款下的開放原始碼釋出,是第二流行的企業搜尋引擎。設計用於雲端計算中,能夠達到實時搜尋,穩定,可靠,快速,安裝使用方便。
在elasticsearch中,所有節點的資料是均等的。
2)Logstash
3)Kibana 是一個基於瀏覽器頁面的Elasticsearch前端展示工具,也是一個開源和免費的工具,Kibana可以為 Logstash 和 ElasticSearch 提供的日誌分析友好的 Web 介面,可以幫助您彙總、分析和搜尋重要資料日誌。
為什麼要用到ELK?
一般我們需要進行日誌分析場景是:直接在日誌檔案中 grep、awk 就可以獲得自己想要的資訊。但在規模較大的場景中,此方法效率低下,面臨問題包括日誌量太大如何歸檔、文字搜尋太慢怎麼辦、如何多維度查詢。需要集中化的日誌管理,所有伺服器上的日誌收集彙總。常見解決思路是建立集中式日誌收集系統,將所有節點上的日誌統一收集,管理,訪問。
一般大型系統是一個分散式部署的架構,不同的服務模組部署在不同的伺服器上,問題出現時,大部分情況需要根據問題暴露的關鍵資訊,定位到具體的伺服器和服務模組,構建一套集中式日誌系統,可以提高定位問題的效率。
一般大型系統是一個分散式部署的架構,不同的服務模組部署在不同的伺服器上,問題出現時,大部分情況需要根據問題暴露的關鍵資訊,定位到具體的伺服器和服務模組,構建一套集中式日誌系統,可以提高定位問題的效率。
一個完整的集中式日誌系統,需要包含以下幾個主要特點:
1)收集-能夠採集多種來源的日誌資料
2)傳輸-能夠穩定的把日誌資料傳輸到中央系統
3)儲存-如何儲存日誌資料
4)分析-可以支援 UI 分析
5)警告-能夠提供錯誤報告,監控機制
ELK提供了一整套解決方案,並且都是開源軟體,之間互相配合使用,完美銜接,高效的滿足了很多場合的應用。目前主流的一種日誌系統。
ELK工作原理展示圖:
如上圖:Logstash收集AppServer產生的Log,並存放到ElasticSearch叢集中,而Kibana則從ES叢集中查詢資料生成圖表,再返回給Browser。
Logstash工作原理:
Logstash事件處理有三個階段:inputs → filters → outputs。是一個接收,處理,轉發日誌的工具。支援系統日誌,webserver日誌,錯誤日誌,應用日誌,總之包括所有可以丟擲來的日誌型別。
Input:輸入資料到logstash。
一些常用的輸入為:
file:從檔案系統的檔案中讀取,類似於tial -f命令
syslog:在514埠上監聽系統日誌訊息,並根據RFC3164標準進行解析
redis:從redis service中讀取
beats:從filebeat中讀取
Filters:資料中間處理,對資料進行操作。
一些常用的過濾器為:
grok:解析任意文字資料,Grok 是 Logstash 最重要的外掛。它的主要作用就是將文字格式的字串,轉換成為具體的結構化的資料,配合正則表示式使用。內建120多個解析語法。
mutate:對欄位進行轉換。例如對欄位進行刪除、替換、修改、重新命名等。
drop:丟棄一部分events不進行處理。
clone:拷貝 event,這個過程中也可以新增或移除欄位。
geoip:新增地理資訊(為前臺kibana圖形化展示使用)
Outputs:outputs是logstash處理管道的最末端元件。一個event可以在處理過程中經過多重輸出,但是一旦所有的outputs都執行結束,這個event也就完成生命週期。
一些常見的outputs為:
elasticsearch:可以高效的儲存資料,並且能夠方便和簡單的進行查詢。
file:將event資料儲存到檔案中。
graphite:將event資料傳送到圖形化元件中,一個很流行的開源儲存圖形化展示的元件。
Codecs:codecs 是基於資料流的過濾器,它可以作為input,output的一部分配置。Codecs可以幫助你輕鬆的分割傳送過來已經被序列化的資料。
一些常見的codecs:
json:使用json格式對資料進行編碼/解碼。
multiline:將匯多個事件中資料彙總為一個單一的行。比如:java異常資訊和堆疊資訊。
======================ELK整體方案=======================
ELK中的三個系統分別扮演不同的角色,組成了一個整體的解決方案。Logstash是一個ETL工具,負責從每臺機器抓取日誌資料,對資料進行格式轉換和處理後,輸出到Elasticsearch中儲存。Elasticsearch是一個分散式搜尋引擎和分析引擎,用於資料儲存,可提供實時的資料查詢。Kibana是一個數據視覺化服務,根據使用者的操作從Elasticsearch中查詢資料,形成相應的分析結果,以圖表的形式展現給使用者。
ELK的安裝很簡單,可以按照"下載->修改配置檔案->啟動"方法分別部署三個系統,也可以使用docker來快速部署。具體的安裝方法這裡不詳細介紹,下面來看一個常見的部署方案,如下圖所示,部署思路是:
1)在每臺生成日誌檔案的機器上,部署Logstash,作為Shipper的角色,負責從日誌檔案中提取資料,但是不做任何處理,直接將資料輸出到Redis佇列(list)中;
2)需要一臺機器部署Logstash,作為Indexer的角色,負責從Redis中取出資料,對資料進行格式化和相關處理後,輸出到Elasticsearch中儲存;
3)部署Elasticsearch叢集,當然取決於你的資料量了,資料量小的話可以使用單臺服務,如果做叢集的話,最好是有3個以上節點,同時還需要部署相關的監控外掛;
4)部署Kibana服務,提供Web服務。
在前期部署階段,主要工作是Logstash節點和Elasticsearch叢集的部署,而在後期使用階段,主要工作就是Elasticsearch叢集的監控和使用Kibana來檢索、分析日誌資料了,當然也可以直接編寫程式來消費Elasticsearch中的資料。
在上面的部署方案中,我們將Logstash分為Shipper和Indexer兩種角色來完成不同的工作,中間通過Redis做資料管道,為什麼要這樣做?為什麼不是直接在每臺機器上使用Logstash提取資料、處理、存入Elasticsearch?
首先,採用這樣的架構部署,有三點優勢:第一,降低對日誌所在機器的影響,這些機器上一般都部署著反向代理或應用服務,本身負載就很重了,所以儘可能的在這些機器上少做事;第二,如果有很多臺機器需要做日誌收集,那麼讓每臺機器都向Elasticsearch持續寫入資料,必然會對Elasticsearch造成壓力,因此需要對資料進行緩衝,同時,這樣的緩衝也可以一定程度的保護資料不丟失;第三,將日誌資料的格式化與處理放到Indexer中統一做,可以在一處修改程式碼、部署,避免需要到多臺機器上去修改配置。
其次,我們需要做的是將資料放入一個訊息佇列中進行緩衝,所以Redis只是其中一個選擇,也可以是RabbitMQ、Kafka等等,在實際生產中,Redis與Kafka用的比較多。由於Redis叢集一般都是通過key來做分片,無法對list型別做叢集,在資料量大的時候必然不合適了,而Kafka天生就是分散式的訊息佇列系統。
1)配置nginx日誌格式
首先需要將nginx日誌格式規範化,便於做解析處理。在nginx.conf檔案中設定:
12 | log_format main '$remote_addr "$time_iso8601" "$request" $status $body_bytes_sent "$http_user_agent" "$http_referer" "$http_x_forwarded_for" "$request_time" "$upstream_response_time" "$http_cookie" "$http_Authorization" "$http_token"' ; access_log /var/log/nginx/example .access.log main; |
2)nginx日誌–>>Logstash–>>訊息佇列
這部分是Logstash Shipper的工作,涉及input和output兩種外掛。input部分,由於需要提取的是日誌檔案,一般使用file外掛,該外掛常用的幾個引數是:
path:指定日誌檔案路徑。
type:指定一個名稱,設定type後,可以在後面的filter和output中對不同的type做不同的處理,適用於需要消費多個日誌檔案的場景。
start_position:指定起始讀取位置,“beginning”表示從檔案頭開始,“end”表示從檔案尾開始(類似tail -f)。
sincedb_path:與Logstash的一個坑有關。通常Logstash會記錄每個檔案已經被讀取到的位置,儲存在sincedb中,如果Logstash重啟,那麼對於同一個檔案,會繼續從上次記錄的位置開始讀取。如果想重新從頭讀取檔案,需要刪除sincedb檔案,sincedb_path則是指定了該檔案的路徑。為了方便,我們可以根據需要將其設定為“/dev/null”,即不儲存位置資訊。
123456789 | input { file { type => "example_nginx_access" path => [ "/var/log/nginx/example.access.log" ] start_position => "beginning" sincedb_path => "/dev/null" } } |
output部分,將資料輸出到訊息佇列,以redis為例,需要指定redis server和list key名稱。另外,在測試階段,可以使用stdout來檢視輸出資訊。
123456789101112 | # 輸出到redis output { if [ type ] == "example_nginx_access" { redis { host => "127.0.0.1" port => "6379" data_type => "list" key => "logstash:example_nginx_access" } # stdout {codec => rubydebug} } } |
3)訊息佇列–>>Logstash–>>Elasticsearch
這部分是Logstash Indexer的工作,涉及input、filter和output三種外掛。在input部分,我們通過redis外掛將資料從訊息佇列中取出來。在output部分,我們通過elasticsearch外掛將資料寫入Elasticsearch。
12345678910111213141516 | # 從redis輸入資料 input { redis { host => "127.0.0.1" port => "6379" data_type => "list" key => "logstash:example_nginx_access" } } output { elasticsearch { index => "logstash-example-nginx-%{+YYYY.MM}" hosts => [ "127.0.0.1:9200" ] } } |
這裡,需要重點關注filter部分,下面列舉幾個常用的外掛,實際使用中根據自身需求從官方文件中查詢適合自己業務的外掛並使用即可,當然也可以編寫自己的外掛。
grok:是Logstash最重要的一個外掛,用於將非結構化的文字資料轉化為結構化的資料。grok內部使用正則語法對文字資料進行匹配,為了降低使用複雜度,其提供了一組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:用於根據IP資訊生成地理位置資訊,預設使用自帶的一份GeoLiteCity database,也可以自己更換為最新的資料庫,但是需要資料格式需要遵循Maxmind的格式(參考GeoLite),似乎目前只能支援legacy database,資料型別必須是.dat。下載GeoLiteCity.dat.gz後解壓, 並將檔案路徑配置到source中即可。
translate:用於檢測某欄位的值是否符合條件,如果符合條件則將其翻譯成新的值,寫入一個新的欄位,匹配pattern可以通過YAML檔案來配置。例如,在下面的配置中,我們對request_api欄位翻譯成更加易懂的文字描述。
1234567891011121314151617181920212223242526272829303132 | filter { grok { match => {
|