您好,登錄后才能下訂單哦!
本篇文章給大家分享的是有關Filebeat優化實踐的示例分析,小編覺得挺實用的,因此分享給大家學習,希望大家閱讀完這篇文章后可以有所收獲,話不多說,跟著小編一起來看看吧。
目前比較主流的日志采集系統有ELK(ES+Logstash+Kibana),EFK(ES+Fluentd+Kibana)等。由于Logstash出現較早,大多數日志文件搜集采用了Logstash。但由于Logstash是JRuby實現的,性能開銷較大,因此我們的日志搜集采用的Filebeat,然后發送到Logstash進行數據處理(例如:解析json,正則解析文件名稱等),最后由Logstash發送到Kafka或者ES。這種方式雖然減輕了每個節點的處理壓力,但部署Logstash的節點性能開銷依舊很大,而且經常出現Filebeat無法發送數據到Logstash的情況。
由于Logstash性能開銷較大,為了提高客戶端的日志采集性能,又減少數據傳輸環節和部署復雜度,并更充分地將 Go 語言的性能優勢利用于日志解析,于是決定在 Filebeat 上通過開發插件的方式,實現針對公司日志格式規范的解析,直接作為 Logstash 的替代品。
我們的平臺是基于Kubernetes的,因此我們需要解析每一條日志的source,從日志文件名稱中獲取Kubernetes資源名稱,以確定該條日志的發往Topic。解析文件名稱需要用到正則匹配,但由于正則性能開銷較大,如果每一條日志都用正則解析名稱將會帶來比較大的性能開銷,因此我們決定采用緩存來解決這一問題。即每個文件只解析一次名稱,存放到一個Map變量中,如果已經解析過的文件名稱則不再解析。這樣大大提高了Filebeat的吞吐量。
Filebeat配置文件如下,其中kubernetes_metadata是自己開發的Processor。
################### Filebeat Configuration Example ######################### ############################# Filebeat ###################################### filebeat: # List of prospectors to fetch data. prospectors: - paths: - /var/log/containers/* symlinks: true # tail_files: true encoding: plain input_type: log fields: type: k8s-log cluster: cluster1 hostname: k8s-node1 fields_under_root: true scan_frequency: 5s max_bytes: 1048576 # 1M # General filebeat configuration options registry_file: /data/usr/filebeat/kube-filebeat.registry ############################# Libbeat Config ################################## # Base config file used by all other beats for using libbeat features ############################# Processors ###################################### processors: - decode_json_fields: fields: ["message"] target: "" - drop_fields: fields: ["message", "beat", "input_type"] - kubernetes_metadata: # Default ############################# Output ########################################## # Configure what outputs to use when sending the data collected by the beat. # Multiple outputs may be used. output: file: path: "/data/usr/filebeat" filename: filebeat.log
測試環境:
性能測試工具使用https://github.com/urso/ljtest
火焰圖生成使用uber的go-torch https://github.com/uber/go-torch
CPU通過runtime.GOMAXPROCS(1)限制使用一個核
第一版性能數據如下:
平均速度 | 100萬條總時間 |
---|---|
11970 條/s | 83.5秒 |
生成的CPU火焰圖如下
從火焰圖中可以看出 CPU 時間占用最多的主要有兩塊。一塊是 Output 處理部分,寫文件。另一塊就比較奇怪了,是 common.MapStr.Clone() 方法,居然占了 34.3% 的 CPU 時間。其中Errorf 占據了21%的CPU時間。看下代碼:
func toMapStr(v interface{}) (MapStr, error) { switch v.(type) { case MapStr: return v.(MapStr), nil case map[string]interface{}: m := v.(map[string]interface{}) return MapStr(m), nil default: return nil, errors.Errorf("expected map but type is %T", v) } }
errors.Errorf生成error對象占據了大塊時間,把這一塊判斷邏輯放到MapStr.Clone()中就可以避免產生error,到此你是不是該有些思考?go的error雖然是很好的設計,但不能濫用,不能濫用,不能濫用!否則你可能會為此付出慘痛的代價。
優化后:
平均速度 | 100萬條總時間 |
---|---|
18687 條/s | 53.5秒 |
處理速度竟然提高了50%多,沒想到幾行代碼的優化,吞吐量竟然能提高這么多,驚不驚喜,意不意外。 再看下修改后的火焰圖
發現MapStr.Clone() 的性能消耗幾乎可以忽略不計了。
進一步優化:
我們的日志都是Docker產生的,使用 JSON 格式,而 Filebeat 使用 Go 自帶的 encoding/json 包是基于反射實現的,性能有一定問題。 既然我們的日志格式是固定的,解析出來的字段也是固定的,這時就可以基于固定的日志結構體做 JSON 的序列化,而不必用低效率的反射來實現。Go 有多個針對給定結構體做 JSON 序列化 / 反序列化的第三方包,這里使用的是 easyjson:https://github.com/mailru/easyjson。
由于解析的日志格式是固定的,所以提前定義好日志的結構體,然后使用easyjson解析。 處理速度性能提升到
平均速度 | 100萬條總時間 |
---|---|
20374 條/s | 49秒 |
但這樣修改后就會使decode_json_fields 這個processor只能處理特定的日志格式,適用范圍會有所降低。所以json解析這塊暫時沒有修改。
日志處理一直是系統運維中比較重要的環節,無論是傳統的運維方式還是基于Kubernetes(或者Mesos,Swarm等)的新型云平臺日志搜集都格外重要。無論選用哪種方式搜集日志,都有可能遇到性能瓶頸,但一小段代碼的改善就可能完全解決了你的問題,路漫漫其修遠兮,優化永無止境。
需要稍作說明的是:
Filebeat 開發是基于 5.5.1 版本,Go 版本是 1.8.3
測試中Filebeat使用runtime.GOMAXPROCS(1)限制只使用一個核
由于測試是在同一臺機器上使用相同數據進行的,將日志輸出到文件對測試結果影響不大。
以上就是Filebeat優化實踐的示例分析,小編相信有部分知識點可能是我們日常工作會見到或用到的。希望你能通過這篇文章學到更多知識。更多詳情敬請關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。