摘要:微服務各個組件的相關實踐會涉及到工具,本文將會介紹微服務日常開發的一些利器,這些工具幫助我們構建更加健壯的微服務系統,並幫助排查解決微服務系統中的問題與性能瓶頸等。
微服務各個組件的相關實踐會涉及到工具,本文將會介紹微服務日常開發的一些利器,這些工具幫助我們構建更加健壯的微服務系統,並幫助排查解決微服務系統中的問題與性能瓶頸等。
我們將重點介紹微服務架構中的日志收集方案 ELK(ELK 是 Elasticsearch、Logstash、Kibana 的簡稱),准確的說是 ELKB,即 ELK + Filebeat,其中 Filebeat 是用於轉發和集中日志數據的輕量級傳送工具。
為什么需要分布式日志系統
在以前的項目中,如果想要在生產環境需要通過日志定位業務服務的 bug 或者性能問題,則需要運維人員使用命令挨個服務實例去查詢日志文件,導致的結果是排查問題的效率非常低。
微服務架構下,服務多實例部署在不同的物理機上,各個微服務的日志被分散儲存不同的物理機。集群足夠大的話,使用上述傳統的方式查閱日志變得非常不合適。因此需要集中化管理分布式系統中的日志,其中有開源的組件如 syslog,用於將所有服務器上的日志收集匯總。
然而集中化日志文件之后,我們面臨的是對這些日志文件進行統計和檢索,哪些服務有報警和異常,這些需要有詳細的統計。所以在之前出現線上故障時,經常會看到開發和運維人員下載了服務的日志,基於 Linux 下的一些命令,如 grep、awk 和 wc 等,進行檢索和統計。這樣的方式效率低,工作量大,且對於要求更高的查詢、排序和統計等要求和龐大的機器數量依然使用這樣的方法難免有點力不從心。
ELKB 分布式日志系統
ELKB 是一個完整的分布式日志收集系統,很好地解決了上述提到的日志收集難,檢索和分析難的問題。ELKB 分別是指 Elasticsearch、Logstash、Kibana 和 Filebeat。elastic 提供的一整套組件可以看作為 MVC 模型,logstash 對應邏輯控制 controller 層,Elasticsearch 是一個數據模型 model 層,而 Kibana 則是視圖 view 層。logstash 和 Elasticsearch 基於 Java 編寫實現,Kibana 則使用的是 node.js 框架。
下面依次介紹這幾個組件的功能,以及在日志采集系統中的作用。
Elasticsearch 的安裝與使用
Elasticsearch 是實時全文搜索和分析引擎,提供搜集、分析、存儲數據三大功能;是一套開放 REST 和 JAVA API 等結構提供高效搜索功能,可擴展的分布式系統。它構建於 Apache Lucene 搜索引擎庫之上。
Elasticsearch可以用於搜索各種文檔。它提供可擴展的搜索,具有接近實時的搜索,並支持多租戶,能勝任上百個服務節點的擴展,並支持 PB 級別的結構化或者非結構化數據。
Elasticsearch是分布式的,這意味着索引可以被分成分片,每個分片可以有0個或多個副本。每個節點托管一個或多個分片,並充當協調器將操作委托給正確的分片。再平衡和路由是自動完成的。相關數據通常存儲在同一個索引中,該索引由一個或多個主分片和零個或多個復制分片組成。一旦創建了索引,就不能更改主分片的數量。
Elasticsearch 是一個實時的分布式搜索分析引擎,它被用作全文檢索、結構化搜索、分析以及這三個功能的組合,它是面向文檔 的,意味着它存儲整個對象或 文檔。Elasticsearch 不僅存儲文檔,而且 索引每個文檔的內容使之可以被檢索。在 Elasticsearch 中,你 對文檔進行索引、檢索、排序和過濾--而不是對行列數據。
為了方便,我們直接使用使用 docker 安裝 Elasticsearch:
$ docker run -d --name elasticsearch docker.elastic.co/elasticsearch/elasticsearch:5.4.0
需要注意的是,Elasticsearch 啟動之后需要進行簡單的設置,xpack.security.enabled 默認是開啟的,為了方便,取消登錄認證。我們登入到容器內部,執行如下的命令:
# 進入啟動好的容器 $ docker exec -it elasticsearch bash # 編輯配置文件 $ vim config/elasticsearch.yml cluster.name: "docker-cluster" network.host: 0.0.0.0 http.cors.enabled: true http.cors.allow-origin: "*" xpack.security.enabled: false # minimum_master_nodes need to be explicitly set when bound on a public IP # set to 1 to allow single node clusters # Details: https://github.com/elastic/elasticsearch/pull/17288 discovery.zen.minimum_master_nodes: 1
修改好配置文件之后,退出容器,重啟容器即可。我們為了后面使用時能夠保留配置,需要從該容器創建一個新的鏡像。首先獲取到該容器對應的 ContainerId。然后基於該容器提交成一個新的鏡像。
$ docker commit -a "add config" -m "dev" a404c6c174a2 es:latest sha256:5cb8c995ca819765323e76cccea8f55b423a6fa2eecd9c1048b2787818c1a994
這樣我們得到了一個新的鏡像 es:latest。我們運行新的鏡像:
docker run -d --name es -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" es:latest
通過訪問 Elasticsearch 提供的內置端點,我們檢查是否安裝成功。
[root@VM_1_14_centos ~]# curl 'http://localhost:9200/_nodes/http?pretty' { "_nodes" : { "total" : 1, "successful" : 1, "failed" : 0 }, "cluster_name" : "docker-cluster", "nodes" : { "8iH5v9C-Q9GA3aSupm4caw" : { "name" : "8iH5v9C", "transport_address" : "10.0.1.14:9300", "host" : "10.0.1.14", "ip" : "10.0.1.14", "version" : "5.4.0", "build_hash" : "780f8c4", "roles" : [ "master", "data", "ingest" ], "attributes" : { "ml.enabled" : "true" }, "http" : { "bound_address" : [ "[::]:9200" ], "publish_address" : "10.0.1.14:9200", "max_content_length_in_bytes" : 104857600 } } } }
可以看到,我們成功安裝了 Elasticsearch,Elasticsearch 作為日志數據信息的存儲源,為我們提供了高效的搜索性能。
我們另外還安裝了 Elasticsearch 的可視化工具:elasticsearch-head。安裝方法很簡答:
$ docker run -p 9100:9100 mobz/elasticsearch-head:5
elasticsearch-head 用於監控 Elasticsearch 狀態的客戶端插件,包括數據可視化、執行增刪改查操作等。
安裝之后的界面如下所示:
logstash 的安裝與使用
logstash 是一個數據分析軟件,主要目的是分析 log 日志。其使用的原理如下所示:
數據源首先將數據傳給 logstash,我們這里使用的是 Filebeat 傳輸日志數據。它主要的組成部分有 Input 數據輸入、Filter 數據源過濾和 Output 數據輸出三部分。
logstash 將數據進行過濾和格式化(轉成 JSON 格式),然后發送到 Elasticsearch 進行存儲,並建搜索的索引,Kibana 提供前端的頁面視圖,可以在頁面進行搜索,使得結果變成圖表可視化。
下面我們開始安裝使用 logstash。首先下載解壓 logstash:
# 下載 logstash $ wget https://artifacts.elastic.co/downloads/logstash/logstash-5.4.3.tar.gz # 解壓 logstash $ tar -zxvf logstash-5.4.3.tar.gz
下載速度可能比較慢,可以選擇國內的鏡像源。解壓成功之后,我們需要配置 logstash,主要就是我們所提到的輸入、輸出和過濾。
[root@VM_1_14_centos elk]# cat logstash-5.4.3/client.conf input { beats { port => 5044 codec => "json" } } output { elasticsearch { hosts => ["127.0.0.1:9200"] index => "logstash-app-error-%{+YYYY.MM.dd}" } stdout {codec => rubydebug} }
輸入支持文件、syslog、beats,我們在配置時只能選擇其中一種。這里我們配置了 filebeats 方式。
過濾則用於處理一些特定的行為來,處理匹配特定規則的事件流。常見的 filters 有 grok 解析無規則的文字並轉化為有結構的格式、 geoip 添加地理信息、drop 丟棄部分事件 和 mutate 修改文檔等。如下是一個 filter 使用的示例:
filter { #定義客戶端的 IP 是哪個字段 geoip { source => "clientIp" } }
輸出支持 Elasticsearch、file、graphite 和 statsd,默認情況下將過濾扣的數據輸出到 Elasticsearch,當我們不需要輸出到ES時需要特別聲明輸出的方式是哪一種,同時支持配置多個輸出源。
一個 event 可以在處理過程中經過多重輸出,但是一旦所有的 outputs 都執行結束,這個 event 也就完成生命周期。
我們在配置中,將日志信息輸出到 Elasticsearch。配置文件搞定之后,我們開始啟動 logstash:
$ bin/logstash -f client.conf Sending Logstash's logs to /elk/logstash-5.4.3/logs which is now configured via log4j2.properties [2020-10-30T14:12:26,056][INFO ][logstash.outputs.elasticsearch] Elasticsearch pool URLs updated {:changes=>{:removed=>[], :added=>[http://127.0.0.1:9200/]}} [2020-10-30T14:12:26,062][INFO ][logstash.outputs.elasticsearch] Running health check to see if an Elasticsearch connection is working {:healthcheck_url=>http://127.0.0.1:9200/, :path=>"/"} log4j:WARN No appenders could be found for logger (org.apache.http.client.protocol.RequestAuthCache). log4j:WARN Please initialize the log4j system properly. log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info. [2020-10-30T14:12:26,209][WARN ][logstash.outputs.elasticsearch] Restored connection to ES instance {:url=>#<URI::HTTP:0x1abac0 URL:http://127.0.0.1:9200/>}[2020-10-30T14:12:26,225][INFO ][logstash.outputs.elasticsearch] Using mapping template from {:path=>nil} [2020-10-30T14:12:26,288][INFO ][logstash.outputs.elasticsearch] Attempting to install template {:manage_template=>{"template"=>"logstash-*", "version"=>50001, "settings"=>{"index.refresh_interval"=>"5s"}, "mappings"=>{"_default_"=>{"_all"=>{"enabled"=>true, "norms"=>false}, "dynamic_templates"=>[{"message_field"=>{"path_match"=>"message", "match_mapping_type"=>"string", "mapping"=>{"type"=>"text", "norms"=>false}}}, {"string_fields"=>{"match"=>"*", "match_mapping_type"=>"string", "mapping"=>{"type"=>"text", "norms"=>false, "fields"=>{"keyword"=>{"type"=>"keyword"}}}}}], "properties"=>{"@timestamp"=>{"type"=>"date", "include_in_all"=>false}, "@version"=>{"type"=>"keyword", "include_in_all"=>false}, "geoip"=>{"dynamic"=>true, "properties"=>{"ip"=>{"type"=>"ip"}, "location"=>{"type"=>"geo_point"}, "latitude"=>{"type"=>"half_float"}, "longitude"=>{"type"=>"half_float"}}}}}}}} [2020-10-30T14:12:26,304][INFO ][logstash.outputs.elasticsearch] New Elasticsearch output {:class=>"LogStash::Outputs::ElasticSearch", :hosts=>[#<URI::Generic:0x2fec3fe6 URL://127.0.0.1:9200>]} [2020-10-30T14:12:26,312][INFO ][logstash.pipeline ] Starting pipeline {"id"=>"main", "pipeline.workers"=>4, "pipeline.batch.size"=>125, "pipeline.batch.delay"=>5, "pipeline.max_inflight"=>500} [2020-10-30T14:12:27,226][INFO ][logstash.inputs.beats ] Beats inputs: Starting input listener {:address=>"0.0.0.0:5044"} [2020-10-30T14:12:27,319][INFO ][logstash.pipeline ] Pipeline main started [2020-10-30T14:12:27,422][INFO ][logstash.agent ] Successfully started Logstash API endpoint {:port=>9600}
根據控制台輸出的日志,我們知道 logstash 已經正常啟動。
Kibana 的安裝與使用
Kibana 是一個基於 Web 的圖形界面,用於搜索、分析和可視化存儲在 Elasticsearch 指標中的日志數據。Kibana 調用 Elasticsearch 的接口返回的數據進行可視化。它利用 Elasticsearch 的 REST 接口來檢索數據,不僅允許用戶創建他們自己的數據的定制儀表板視圖,還允許他們以特殊的方式查詢和過濾數據。
Kibana 的安裝比較簡單,我們基於 docker 安裝即可:
docker run --name kibana -e ELASTICSEARCH_URL=http://127.0.0.1:9200 -p 5601:5601 -d kibana:5.6.9
我們在啟動命令中指定了 ELASTICSEARCH 的環境變量,就是本地的 127.0.0.1:9200。
Filebeat 的安裝與使用
Filebeat 用於轉發和集中日志數據的輕量級傳送工具。Filebeat 監視指定的日志文件或位置,收集日志事件,並將它們轉發到 Logstash、Kafka、Redis 等,或直接轉發到 Elasticsearch 進行索引。
下面我們開始安裝配置 Filebeat:
# 下載 filebeat $ wget https://artifacts.elastic.co/downloads/beats/filebeat/filebeat-5.4.3-linux-x86_64.tar.gz $ tar -zxvf filebeat-5.4.3-linux-x86_64.tar.gz $ mv filebeat-5.4.3-linux-x86_64 filebeat # 進入目錄 $ cd filebeat # 配置 filebeat $ vi filebeat/client.yml filebeat.prospectors: - input_type: log paths: - /var/log/*.log output.logstash: hosts: ["localhost:5044"]
在 filebeat 的配置中,input_type 支持從Log、Syslog、Stdin、Redis、UDP、Docker、TCP、NetFlow 輸入。上述配置了從 log 中讀取日志信息。並且配置了只輸入 /var/log/ 目錄下的日志文件。output 將 Filebeat 配置為使用 logstash,並且使用 logstash 對 Filebeat 收集的數據執行額外的處理。
配置好之后,我們啟動 Filebeat:
$ ./filebeat -e -c client.yml 2020/10/30 06:46:31.764391 beat.go:285: INFO Home path: [/elk/filebeat] Config path: [/elk/filebeat] Data path: [/elk/filebeat/data] Logs path: [/elk/filebeat/logs] 2020/10/30 06:46:31.764426 beat.go:186: INFO Setup Beat: filebeat; Version: 5.4.3 2020/10/30 06:46:31.764522 logstash.go:90: INFO Max Retries set to: 3 2020/10/30 06:46:31.764588 outputs.go:108: INFO Activated logstash as output plugin. 2020/10/30 06:46:31.764586 metrics.go:23: INFO Metrics logging every 30s 2020/10/30 06:46:31.764664 publish.go:295: INFO Publisher name: VM_1_14_centos 2020/10/30 06:46:31.765299 async.go:63: INFO Flush Interval set to: 1s 2020/10/30 06:46:31.765315 async.go:64: INFO Max Bulk Size set to: 2048 2020/10/30 06:46:31.765563 beat.go:221: INFO filebeat start running. 2020/10/30 06:46:31.765592 registrar.go:85: INFO Registry file set to: /elk/filebeat/data/registry 2020/10/30 06:46:31.765630 registrar.go:106: INFO Loading registrar data from /elk/filebeat/data/registry 2020/10/30 06:46:31.766100 registrar.go:123: INFO States Loaded from registrar: 6 2020/10/30 06:46:31.766136 crawler.go:38: INFO Loading Prospectors: 1 2020/10/30 06:46:31.766209 registrar.go:236: INFO Starting Registrar 2020/10/30 06:46:31.766256 sync.go:41: INFO Start sending events to output 2020/10/30 06:46:31.766291 prospector_log.go:65: INFO Prospector with previous states loaded: 0 2020/10/30 06:46:31.766390 prospector.go:124: INFO Starting prospector of type: log; id: 2536729917787673381 2020/10/30 06:46:31.766422 crawler.go:58: INFO Loading and starting Prospectors completed. Enabled prospectors: 1 2020/10/30 06:46:31.766430 spooler.go:63: INFO Starting spooler: spool_size: 2048; idle_timeout: 5s 2020/10/30 06:47:01.764888 metrics.go:34: INFO No non-zero metrics in the last 30s 2020/10/30 06:47:31.764929 metrics.go:34: INFO No non-zero metrics in the last 30s 2020/10/30 06:48:01.765134 metrics.go:34: INFO No non-zero metrics in the last 30s
啟動 Filebeat 時,它將啟動一個或多個輸入,這些輸入將在為日志數據指定的位置中查找。對於 Filebeat 所找到的每個日志,Filebeat 都會啟動收集器。每個收集器都讀取單個日志以獲取新內容,並將新日志數據發送到 libbeat,libbeat 將聚集事件,並將聚集的數據發送到為 Filebeat 配置的輸出。
ELKB 的使用實踐
安裝好 ELKB 組件之后,我們開始整合這些組件。首先看下 ELKB 收集日志的流程。
Filebeat 監聽應用的日志文件,隨后將數據發送給 logstash,logstash 則對數據進行過濾和格式化,如 JSON 格式化;之后 logstash 將處理好的日志數據發送給 Elasticsearch,Elasticsearch 存儲並建立搜索的索引;Kibana 提供可視化的視圖頁面。
我們運行所有的組件之后,首先看下 elasticsearch-head 中的索引變化:
可以看到多了一個 filebeat-2020.10.12 的索引,說明 ELKB 分布式日志收集框架搭建成功。訪問 http://localhost:9100,我們來具體看下索引的數據:
從上面兩幅截圖可以看到,/var/log/ 目錄下的 mysqld.log 文件中產生了新的日志數據,這些數據非常多,我們在生產環境需要根據實際的業務進行過濾,並處理相應的日志格式。
elasticsearch-head 是一個簡單的 Elasticsearch 客戶端,更加完整的統計和搜索需求,需要借助於 Kibana,Kibana 提升了 Elasticsearch 分析能力,能夠更加智能地分析數據,執行數學轉換並且根據要求對數據切割分塊。
訪問 http://localhost:5601,得到了上圖中的日志信息。Filebeat 監聽到了 mysql 日志,並在 Kibana 上展示。Kibana 能夠更好地處理海量數據,並據此創建柱形圖、折線圖、散點圖、直方圖、餅圖和地圖,這里就不一一展示了。
小結
本文主要介紹了分布式日志采集系統 ELKB。日志主要用來記錄離散的事件,包含程序執行到某一點或某一階段的詳細信息。ELKB 很好地解決了微服務架構下,服務實例眾多且分散,日志難以收集和分析的問題。限於篇幅,本課時只介紹了 ELKB 的安裝使用,Go 微服務中一般使用日志框架如 logrus、zap 等,按照一定的格式將日志輸出到指定的位置,讀者可以自行構建一個微服務進行實踐。
本文分享自華為雲社區《【華為雲專家原創】微服務架構中使用 ELK 進行日志采集以及統一處理》,原文作者: aoho 。