摘要:微服務各個元件的相關實踐會涉及到工具,本文将會介紹微服務日常開發的一些利器,這些工具幫助我們建構更加健壯的微服務系統,并幫助排查解決微服務系統中的問題與性能瓶頸等。
微服務各個元件的相關實踐會涉及到工具,本文将會介紹微服務日常開發的一些利器,這些工具幫助我們建構更加健壯的微服務系統,并幫助排查解決微服務系統中的問題與性能瓶頸等。

我們将重點介紹微服務架構中的日志收集方案 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 。
點選關注,第一時間了解華為雲新鮮技術~