一、elk 實用知識點總結
1、編碼轉換問題(主要就是中文亂碼)
(1)input 中的codec => plain (將UTF-8 的編碼的文本編碼,轉為gbk)
codec => plain {
charset =>"gbk"
}
(2)在filebeat中實現編碼的轉換(推薦)
- type: log
tags: ["test01_info"]
enabled: true
paths:
- /data/logs/test/**
encoding: gbk
2、刪除多余字段
logstash filter 中刪除多余字段(另一種是在grok解析時,不解析該字段)
filter {
grok {
match => {
"message"=>"\[?%{TIMESTAMP_ISO8601:time}\]? \[?%{LOGLEVEL:level}\]? \[%{JAVACLASS:class}\] - \[ %{JAVALOGMESSAGE:kp} \] >>>%{JAVALOGMESSAGE}>>>>%{JAVALOGMESSAGE:message}"
remove_field => "class"
}
}
}
3、grok 處理日志
(1)日志示例:
2019-12-27 09:47:31,201 INFO [com.sunline.netty.utils.HttpHandlerUtils] - [ 6f0f6c0dbb6b4a44b3966a92f76861c2 ] >>> url:/api/ef, result:>>>>{"errorMsg":"成功","result":{"data":[{"assetId":"02318.HK","currentAmount":"6","stockCode":"2318",{"assetId":"01385.HK","lotSize":2000,"moneyType":"2","secSType":60}]}}
.......
(2)logstash grok處理
filter {
grok {
match => {
"message"=>"\[?%{TIMESTAMP_ISO8601:time}\]? \[?%{LOGLEVEL:level}\]? \[%{JAVACLASS:class}\] - \[ %{JAVALOGMESSAGE:kp} \] >>>%{JAVALOGMESSAGE}>>>>%{JAVALOGMESSAGE:message}"
}
}
}
4、multiline處理多行日志
(1)在filebeat中使用multiline 插件多行處理(推薦)
① 介紹multiline
pattern:正則匹配從哪行合並
negate:true/false,匹配到pattern 部分開始合並,還是不配到的合並
match:after/before(需自己理解)
after:匹配到pattern 部分后合並,注意:這種情況最后一行日志不會被匹配處理
before:匹配到pattern 部分前合並(推薦)
② after為例
- type: log
tags: ["test_info"]
enabled: true
paths:
- /data/logs/test/**
encoding: gbk
exclude_files: ['\.gz','\.zip']
multiline.pattern: '^\[?[0-9]{4}-[0-9]{2}-[0-9]{2}'
multiline.negate: true
multiline.match: after
close_inactive: 1h
tail_files: true
(2)在logstash input中使用multiline 插件(沒有filebeat 時推薦)
① 介紹multiline
pattern:正則匹配從哪行合並
negate:true/false,匹配到pattern 部分開始合並,還是不配到的合並
what:previous/next(需自己理解)
previous:相當於filebeat 的after
next:相當於filebeat 的before
② 用法
input {
file {
path => ["/data/logs/test/**"]
start_position =>"beginning"
codec => multiline {
pattern =>"^\[?[0-9]{4}-[0-9]{2}-[0-9]{2}"
negate => true
what =>"previous"
}
}
}
5、logstash filter中的date使用
(1)date 介紹
就是將匹配日志中時間的key 替換為@timestamp 的時間,因為@timestamp 的時間是日志送到logstash 的時間,並不是日志中真正的時間,而是采集日志的時間。
(2)date 使用
date {
match => ["time", "yyyy-MM-dd HH:mm:ss,SSS"]
remove_field => "time"
}
注:
match => ["timestamp" ,"dd/MMM/YYYY H : m: s Z"
匹配這個字段,字段的格式為:日日/月月月/年年年年 時/分/秒 時區
也可以寫為:match => ["timestamp","ISO8601"](推薦)
6、對多類日志分類處理(重點)
① 在filebeat 的配置中添加type 分類
- type: log_test01
tags: ["test01_info"]
enabled: true
paths:
- /data/logs/test01/**
encoding: gbk
exclude_files: ['\.gz','\.zip']
multiline.pattern: '^\[?[0-9]{4}-[0-9]{2}-[0-9]{2}'
multiline.negate: true
multiline.match: after
close_inactive: 1h
tail_files: true
- type: log_test02
tags: ["test02_info"]
enabled: true
paths:
- /data/logs/test02/**
encoding: gbk
exclude_files: ['\.gz','\.zip']
multiline.pattern: '^\[?[0-9]{4}-[0-9]{2}-[0-9]{2}'
multiline.negate: true
multiline.match: after
close_inactive: 1h
tail_files: true
② 在logstash filter中使用if,可進行對不同類進行不同處理
filter {
grok {
match => ["message", "\[?%{TIMESTAMP_ISO8601:timestamp}\]? \[?%{LOGLEVEL:level}\]? \[%{JAVACLASS:class}\] - %{JAVALOGMESSAGE}"]
}
if "test01" in [tags] {
grok {
match => ["message", "\[?%{TIMESTAMP_ISO8601:time}\]? \[?%{LOGLEVEL:level}\]? \[%{JAVACLASS:class}\] - \[ %{JAVALOGMESSAGE:kp} \] >>>%{JAVALOGMESSAGE}>>>>%{JAVALOGMESSAGE:grm_re} ip:%{JAVALOGMESSAGE:result.ipAddress} r%{JAVALOGMESSAGE}:%{JAVALOGMESSAGE:request
_time}."]
}
}
}
③ 在logstash output中使用if
output{
if "test01_info" in [tags] {
elasticsearch {
hosts => ["node01:9200","node02:9200","node03:9200"]
index => "test01_message-%{+YYYY.MM.dd}"
}
}
}
二、對elk 整體性能的優化
1、性能分析
(1)服務器硬件Linux:1cpu 4GRAM
假設每條日志250 Byte
(2)分析
① ogstash-Linux:1cpu 4GRAM
每秒500條日志,去掉ruby每秒660條日志,去掉grok后每秒1000條數據;
② filebeat-Linux:1cpu 4GRAM
每秒2500-3500條數據;每天每台機器可處理:24h*60min*60sec*3000*250Byte=64,800,000,000Bytes,約64G;
③ 瓶頸在logstash 從redis中取數據存入ES,開啟一個logstash,每秒約處理6000條數據;開啟兩個logstash,每秒約處理10000條數據(cpu已基本跑滿);
④ logstash的啟動過程占用大量系統資源,因為腳本中要檢查java、ruby以及其他環境變量,啟動后資源占用會恢復到正常狀態。
2、關於收集日志的選擇:logstash/filter
(1)沒有原則要求使用filebeat或logstash,兩者作為shipper的功能是一樣的,區別在於:
① logstash由於集成了眾多插件,如grok,ruby,所以相比beat是重量級的;
② logstash啟動后占用資源更多,如果硬件資源足夠則無需考慮二者差異;
③ logstash基於JVM,支持跨平台;而beat使用golang編寫,AIX不支持;
④ AIX 64bit平台上需要安裝jdk(jre)1.7 32bit,64bit的不支持;
⑤ filebeat可以直接輸入到ES,但是系統中存在logstash直接輸入到ES的情況,這將造成不同的索引類型造成檢索復雜,最好統一輸入到els 的源。
(2)總結]
logstash/filter 總之各有千秋,但是,我推薦選擇:在每個需要收集的日志服務器上配置filebeat,因為輕量級,用於收集日志;再統一輸出給logstash,做對日志的處理;最后統一由logstash 輸出給els。
3、logstash的優化相關配置
(1)可以優化的參數,可根據自己的硬件進行優化配置
① pipeline 線程數,官方建議是等於CPU內核數
默認配置 ---> pipeline.workers: 2
可優化為 ---> pipeline.workers: CPU內核數(或幾倍cpu內核數)
② 實際output 時的線程數
默認配置 ---> pipeline.output.workers:1
可優化為 ---> pipeline.output.workers: 不超過pipeline 線程數
③ 每次發送的事件
默認配置 ---> pipeline.batch.size: 125
可優化為 ---> pipeline.batch.size: 1000
④ 發送延時
默認配置 ---> pipeline.batch.delay: 5
可優化為 ---> pipeline.batch.size: 10
(2)總結]
通過設置-w參數指定pipeline worker數量,也可直接修改配置文件logstash.yml。這會提高filter和output的線程數,如果需要的話,將其設置為cpu核心數的幾倍是安全的,線程在I/O上是空閑的。
默認每個輸出在一個pipeline worker線程上活動,可以在輸出output 中設置workers設置,不要將該值設置大於pipeline worker數。
還可以設置輸出的batch_size數,例如ES輸出與batch size一致。
filter設置multiline后,pipline worker會自動將為1,如果使用filebeat,建議在beat中就使用multiline,如果使用logstash作為shipper,建議在input 中設置multiline,不要在filter中設置multiline。
(3)Logstash中的JVM配置文件
Logstash是一個基於Java開發的程序,需要運行在JVM中,可以通過配置jvm.options來針對JVM進行設定。比如內存的最大最小、垃圾清理機制等等。JVM的內存分配不能太大不能太小,太大會拖慢操作系統。太小導致無法啟動。默認如下:
-Xms256m #最小使用內
-Xmx1g #最大使用內存
(4)logstas中的grok
grok是logstash的filter插件中的功能,用來對日志數據進行正則匹配實現各個字段的切割,增加錨點可以有效提升性能,比如:^、$等,使用合適的類型去分割字段,盡量避免使用DATA,經過對logstash的優化,可以做到logstash單點導入速度有2000/s 提升到 18000/s。
(5) Logstash持久化到磁盤
當發生異常情況,比如logstash重啟,有可能發生數據丟失,可以選擇logstash持久化到磁盤,修改之前重啟logstash數據丟失,修改之后重啟logstash數據不丟失。以下是具體操作:
在config/logstash.yml中進行配置以下內容
queue.type: persisted
path.queue: /data/logstash/data/queue #隊列存儲路徑;如果隊列類型為persisted,則生效
queue.page_capacity: 250mb #隊列為持久化,單個隊列大小
queue.max_events: 0 #當啟用持久化隊列時,隊列中未讀事件的最大數量,0為不限制
queue.max_bytes: 1024mb #隊列最大容量
queue.checkpoint.acks: 1024 #在啟用持久隊列時強制執行檢查點的最大數量,0為不限制
queue.checkpoint.writes: 1024 #在啟用持久隊列時強制執行檢查點之前的最大數量的寫入事件,0為不限制
queue.checkpoint.interval: 1000 #當啟用持久隊列時,在頭頁面上強制一個檢查點的時間間隔
修改完后,重啟logstash即可
4、引入Redis 的相關問題
(1)filebeat可以直接輸入到logstash(indexer),但logstash沒有存儲功能,如果需要重啟需要先停所有連入的beat,再停logstash,造成運維麻煩;另外如果logstash發生異常則會丟失數據;引入Redis作為數據緩沖池,當logstash異常停止后可以從Redis的客戶端看到數據緩存在Redis中;
(2)Redis可以使用list(最長支持4,294,967,295條)或發布訂閱存儲模式;
(3)redis 做elk 緩沖隊列的優化:
#bind 0.0.0.0 #不要監聽本地端口
requirepass **** #加密碼,為了安全運行
#只做隊列,沒必要持久存儲,關閉所有持久化功能
save "" #禁用快照
appendonly no #關閉RDB
#把內存的淘汰策略關掉,把內存空間最大
maxmemory 0 #maxmemory為0的時候表示我們對Redis的內存使用沒有限制
5、elasticsearch節點優化配置
(1)服務器硬件配置,OS 參數
(a) /etc/sysctl.conf 配置
vim /etc/sysctl.conf
#ES 推薦將此參數設置為1,大幅降低 swap 分區的大小,強制最大程度的使用內存,注意,這里不要設置為0, 這會很可能會造成 OOM
vm.swappiness =1
#定義了每個端口最大的監聽隊列的長度
net.core.somaxconn =65535
#限制一個進程可以擁有的VMA(虛擬內存區域)的數量。虛擬內存區域是一個連續的虛擬地址空間區域。當VMA 的數量超過這個值,OOM
vm.max_map_count=655360
#設置 Linux 內核分配的文件句柄的最大數量
fs.file-max =518144
sysctl -p 加載
(b)limits.conf 配置
vim /etc/security/limits.conf
* soft nofile 65536
* hard nofile 131072
* soft nproc 2048
* hard nproc 4096
(2)elasticsearch 中的JVM配置文件
-Xms2g
-Xmx2g
① 將最小堆大小(Xms)和最大堆大小(Xmx)設置為彼此相等
② Elasticsearch可用的堆越多,可用於緩存的內存就越多。但請注意,太多的堆可能會使您長時間垃圾收集暫停
③ 設置Xmx為不超過物理RAM的50%,以確保有足夠的物理內存留給內核文件系統緩存
④ 不要設置Xmx為JVM用於壓縮對象指針的臨界值以上;確切的截止值有所不同,但接近32 GB。不要超過32G,如果空間大,多跑幾個實例,不要讓一個實例太大內存
(3)elasticsearch 配置文件優化參數
vim elasticsearch.yml
action.destructive_requires_name: true #禁止使用all或者*
transport.tcp.compress: true #傳輸壓縮
indices.fielddata.cache.size: 40% #聚合操作
indices.memory.index_buffer_size: 30% # 內存 默認為整個堆空間的10%
indices.memory.min_index_buffer_size: 1024mb #默認48mb
thread_pool.bulk.size: 2 # 寫入的線程數
thread_pool.bulk.queue_size: 1000 # 寫入線程隊列大小
bootstrap.memory_lock: true #禁用交換分區
(4)集群的優化
① ES是分布式存儲,當設置同樣的cluster.name后會自動發現並加入集群;
② 集群會自動選舉一個master,當master宕機后重新選舉;
③ 為防止"腦裂",集群中個數最好為奇數個
④ 為有效管理節點,可關閉廣播 discovery.zen.ping.multicast.enabled: false,並設置單播節點組
discovery.zen.ping.unicast.hosts: ["ip1", "ip2", "ip3"]
(5)通過curl請求命令進行優化
curl -XPUT 'localhost:9200/_template/elasticsearch' -H "Content-Type: application/json" -d '
{
"order": 6,
"template": "*",
"settings": {
"number_of_replicas" : 0,
"number_of_shards" : 6,
"refresh_interval": "30s",
"index.translog.durability": "async",
"index.translog.sync_interval": "60s"
}
}'
備注
template #匹配的Index分片名稱
number_of_replicas #副本數為0,需要查詢性能高可以設置為1
number_of_shards #分片數為6, 副本為1時可以設置成5
refresh_interval #索引刷新間隔,默認1s
index.translog.durability #同步,默認request
index.translog.sync_interval #刷新時間,默認1s
6、性能的檢查
(1)檢查輸入和輸出的性能
Logstash和其連接的服務運行速度一致,它可以和輸入、輸出的速度一樣快。
(2)檢查系統參數
① CPU
[注意CPU是否過載。在Linux/Unix系統中可以使用top -H查看進程參數以及總計;如果CPU使用過高,直接跳到檢查JVM堆的章節並檢查Logstash worker設置。
② Memory
注意Logstash是運行在Java虛擬機中的,所以它只會用到你分配給它的最大內存;檢查其他應用使用大量內存的情況,這將造成Logstash使用硬盤swap,這種情況會在應用占用內存超出物理內存范圍時。
③ I/O 監控磁盤I/O檢查磁盤飽和度
使用Logstash plugin(例如使用文件輸出)磁盤會發生飽和。當發生大量錯誤,Logstash生成大量錯誤日志時磁盤也會發生飽和;在Linux中,可使用iostat,dstat或者其他命令監控磁盤I/O。
④ 監控網絡I/O
當使用大量網絡操作的input、output時,會導致網絡飽和;在Linux中可使用dstat或iftop監控網絡情況。
(3)檢查JVM heap
heap設置太小會導致CPU使用率過高,這是因為JVM的垃圾回收機制導致的。一個快速檢查該設置的方法是將heap設置為兩倍大小然后檢測性能改進。不要將heap設置超過物理內存大小,保留至少1G內存給操作系統和其他進程。你可以使用類似jmap命令行或VisualVM更加精確的計算。
7、索引效率優化
索引優化主要是在 Elasticsearch 插入層面優化,如果瓶頸不在這塊,而是在產生數據部分,比如 DB 或者 Hadoop 上,那么優化方向就需要改變下。同時,Elasticsearch 本身索引速度其實還是蠻快的,具體數據,我們可以參考官方的 benchmark 數據。
(1)批量提交
當有大量數據提交的時候,建議采用批量提交。比如在做 ELK 過程中 ,Logstash indexer 提交數據到 Elasticsearch 中 ,batch size 就可以作為一個優化功能點。但是優化 size 大小需要根據文檔大小和服務器性能而定。
像 Logstash 中提交文檔大小超過 20MB ,Logstash 會請一個批量請求切分為多個批量請求。如果在提交過程中,遇到 EsRejectedExecutionException 異常的話,則說明集群的索引性能已經達到極限了。這種情況,要么提高服務器集群的資源,要么根據業務規則,減少數據收集速度,比如只收集 Warn、Error 級別以上的日志。
(2)優化硬件
優化硬件設備一直是最快速有效的手段。
① 在經濟壓力能承受的范圍下, 盡量使用固態硬盤 SSD。SSD 相對於機器硬盤,無論隨機寫還是順序寫,都較大的提升。
② 磁盤備份采用 RAID0。因為 Elasticsearch 在自身層面通過副本,已經提供了備份的功能,所以不需要利用磁盤的備份功能,同時如果使用磁盤備份功能的話,對寫入速度有較大的影響。
(3)增加 Refresh 時間間隔
為了提高索引性能,Elasticsearch 在寫入數據時候,采用延遲寫入的策略,即數據先寫到內存中,當超過默認 1 秒 (index.refresh_interval)會進行一次寫入操作,就是將內存中 segment 數據刷新到操作系統中,此時我們才能將數據搜索出來,所以這就是為什么 Elasticsearch 提供的是近實時搜索功能,而不是實時搜索功能。
當然像我們的內部系統對數據延遲要求不高的話,我們可以通過延長 refresh 時間間隔,可以有效的減少 segment 合並壓力,提供索引速度。在做全鏈路跟蹤的過程中,我們就將 index.refresh_interval 設置為 30s,減少 refresh 次數。
同時,在進行全量索引時,可以將 refresh 次數臨時關閉,即 index.refresh_interval 設置為 -1,數據導入成功后再打開到正常模式,比如 30s。
(4)減少副本數量
Elasticsearch 默認副本數量為 3 個,雖然這樣會提高集群的可用性,增加搜索的並發數,但是同時也會影響寫入索引的效率。
在索引過程中,需要把更新的文檔發到副本節點上,等副本節點生效后在進行返回結束。使用 Elasticsearch 做業務搜索的時候,建議副本數目還是設置為 3 個,但是像內部 ELK 日志系統、分布式跟蹤系統中,完全可以將副本數目設置為 1 個。