集羣規模node
總體集羣規模:python
索引日誌:正則表達式
健康提示apache
爲了防止誤刪除,設置參數json
action.destructive_requires_name=true
採用監護人制度,開發併發布本身的版本。緩存
CPUruby
內存服務器
磁盤 I/O網絡
網絡帶寬併發
Marvel | 自研 |
---|---|
易用 | 須要花時間開發 |
數據存入 ES | 與本身的系統集成 |
不少分析度量 | |
沒有集成 | 重複造輪子 |
成本高 | 免費 |
度量在多個地方都有暴露:
_cat API
包括了大多數度量,易讀
_stats API,_nodes API
涵蓋全部,JSON格式,易於解析
建立 dashboards
磁盤空間預警的閥值 =((100 - 6)/ 100)- 15%
磁盤空間預警的閥值 = 79%
GC
超線程
將日誌以 JSON 格式輸出並無帶來很大的好處,除非不使用 grok,kv 等。Logstash 仍是須要將字符串轉換成爲 ruby 的 hash
在寫插件時須要時刻記住 GC
很差的:1_000_000.times { "This is a string" }
user | |
---|---|
time | 0.130000 |
好用法:foo = 'This is a string'; 1_000_000.times { foo }
user | |
---|---|
time | 0.060000 |
Logstash 簡單配置,10m 行 apache 日誌,沒有過濾:
input { file { path => "/var/log/httpd/access.log" start_position => "beginning" } } output { stdout { codec => "dots" } }
Python 腳本將 Logstash 輸出到 statsd :
sudo pip install statsd #!/usr/bin/env python import statsd, sys c = statsd.StatsClient('localhost', 8125) while True: sys.stdin.read(1) c.incr('logstash.testing.throughput', rate=0.001)
爲何咱們不用 statsd 輸出插件?它會下降輸出的速度!
放在一塊兒
logstash -f logstash.conf | pv -W | python throughput.py 
增長一個簡單的 Grok
grok { match => [ "message", "%{ETSY_APACHE_ACCESS}" ] }
在只有一個 worker 時,性能降低 80%
增長 worker 的數量,吞吐量仍然降低了 33%:65k/s -> 42k/s
-w <num_cpu_cores>
加一個 kv 過濾器
kv { field_split => "&" source => "qs" target => "foo" }
吞吐量基本不變,有 10% 的降低(40k/s)
吞吐量變化較大主要由於 GC 的壓力
kv 很慢,如下是一個用來查詢字符串的 splitkv
插件
kvarray = text.split(@field_split).map { |afield| pairs = afield.split(@value_split) if pairs[0].nil? || !(pairs[0] =~ /^[0-9]/).nil? || pairs[1].nil? || (pairs[0].length < @min_key_length && !@preserve_keys.include?(pairs[0])) next end if !@trimkey.nil? # 2 if's are faster (0.26s) than gsub (0.33s) #pairs[0] = pairs[0].slice(1..-1) if pairs[0].start_with?(@trimkey) #pairs[0].chop! if pairs[0].end_with?(@trimkey) # BUT! in-place tr is 6% faster than 2 if's (0.52s vs 0.55s) pairs[0].tr!(@trimkey, '') if pairs[0].start_with?(@trimkey) end if !@trimval.nil? pairs[1].tr!(@trimval, '') if pairs[1].start_with?(@trimval) end pairs } kvarray.delete_if { |x| x == nil } return Hash[kvarray]
splitkv
以前的 CPU 佔用率是 100% ,以後的佔用率是 33% 。
當使用缺省的 500 flush_size 時,Logstash 集羣的峯值會達到 50% ,處理能力在每秒 ~40k 日誌行。將這個值改到 10k 時,同時增長 idle_flush_time 到 5s 。處理能力在每秒 ~150k 日誌行,同時 CPU 佔用會降低到 25% 。
Logstash 2.3 以前
…/vendor/…/lib/logstash/pipeline.rb SizedQueue.new(20) -> SizedQueue.new(500)
Logstash 2.3 以後
—pipeline-batch-size=500
最好在調優最後改變這個參數。管道的性能受輸出插件性能的影響。
發現管道的延遲
mutate { add_field => [ "index_time", "%{+YYYY-MM-dd HH:mm:ss Z}" ] }
logstash 服務器處理日誌行
mutate { add_field => [ "logstash_host", "<%= node[:fqdn] %>" ] }
對日誌行進行哈希,實現重放
hashid
插件能夠避免重複行
~10% 降低
describe package('logstash'), :if => os[:family] == 'redhat' do it { should be_installed } end describe command('chef-client') do its(:exit_status) { should eq 0 } end describe command('logstash -t -f ls.conf.test') do its(:exit_status) { should eq 0 } end describe command('logstash -f ls.conf.test') do its(:stdout) { should_not match(/parse_fail/) } end describe command('restart logstash') do its(:exit_status) { should eq 0 } end describe command('sleep 15') do its(:exit_status) { should eq 0 } end describe service('logstash'), :if => os[:family] == 'redhat' do it { should be_enabled } it { should be_running } end describe port(5555) do it { should be_listening } end
input { generator { lines => [ '<Apache access log>' ] count => 1 type => "access_log" } generator { lines => [ '<Application log>' ] count => 1 type => "app_log" } }
filter { if [type] == "access_log" { grok { match => [ "message", "%{APACHE_ACCESS}" ] tag_on_failure => [ "parse_fail_access_log" ] } } if [type] == "app_log" { grok { match => [ "message", "%{APACHE_INFO}" ] tag_on_failure => [ "parse_fail_app_log" ] } } }
output { stdout { codec => json_lines } }
更快的 CPU
CPU 核心數 > CPU 時鐘速度
更多內存
18Gb+ 防止頻繁 GC
對全部的東西進行性能評測
Logstash 輸出: 默認選項 + 4 workers
Elasticsearch: 默認選項 + 1 shard, no replicas
映射
默認映射會建立大量 .raw 字段
恢復的速度
更快的網絡 == 更短的恢復延遲
以 32Gb 堆爲例的分佈狀況:
部分字段使用 doc_values:
1.7G Aug 11 18:42 logstash-2015.08.07/7/index/_1i4v_Lucene410_0.dvd
全部字段使用 doc_values:
106G Aug 13 20:33 logstash-2015.08.12/38/index/_2a9p_Lucene410_0.dvd
不要盲目地爲全部字段開啓 doc_values
示例
total | request_uri | _size | owner | ip_address |
---|---|---|---|---|
117.1mb | 11.2mb | 28.4mb | 8.6mb | 4.3mb |
96.3mb | 7.7mb | 19.7mb | 9.1mb | 4.4mb |
93.7mb | 7mb | 18.4mb | 8.8mb | 4.1mb |
139.1mb | 11.2mb | 27.7mb | 13.5mb | 6.6mb |
96.8mb | 7.8mb | 19.1mb | 8.8mb | 4.4mb |
145.9mb | 11.5mb | 28.6mb | 13.4mb | 6.7mb |
95mb | 7mb | 18.9mb | 8.7mb | 5.3mb |
122mb | 11.8mb | 28.4mb | 8.9mb | 5.7mb |
97.7mb | 6.8mb | 19.2mb | 8.9mb | 4.8mb |
88.9mb | 7.6mb | 18.2mb | 8.4mb | 4.6mb |
96.5mb | 7.7mb | 18.3mb | 8.8mb | 4.7mb |
147.4mb | 11.6mb | 27.9mb | 13.2mb | 8.8mb |
146.7mb | 10mb | 28.7mb | 13.6mb | 7.2mb |
根據硬件配置優化 RAM
Haswell/Skylake Xeon CPUs 有 4 個內存通道
Elasticsearch 多個實例
爲每一個實例分配本身的名稱 node.name
CPU 密集型操做
寫壓力
爲何這麼慢?
[logstash-2016.06.15][0] stop throttling indexing: numMergesInFlight=4, maxNumMerges=5
第一步:將分片數從 1 提高到 5
第二步:禁用 merge throttling(ES < 2.0)
index.store.throttle.type: none
當 CPU 接近最大時,須要加入更多節點
在不一樣 Hosts 上運行 Elasticsearch 以及 Logstash
吞吐量有 50% 的提高:13k/s -> 19k/s
超線程能夠提高 20% 的性能
~15-30% 的性能提高。
# echo performance | tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor
磁盤 I/O
建議
更多的建議
好的 SSD 很是重要
廉價 SSD 會大大下降性能
不要使用多個數據路徑,使用 RAID 0
大量的 translog 寫磁盤操做會是瓶頸
若是有大量段合併,可是 CPU 和 磁盤 I/O 還有空閒:
能夠嘗試提高值
index.merge.scheduler.max_thread_count
下降間隔(Durability)
index.translog.durability: async
Translog fsync() 值爲 5s ,足夠
集羣的恢復會吃掉大量磁盤 I/O
須要在恢復先後調整相應的參數
indices.recovery.max_bytes_per_sec: 300mb cluster.routing.allocation.cluster_concurrent_rebalance: 24 cluster.routing.allocation.node_concurrent_recoveries: 2
任何的持續 I/O 等待都意味着存在一個次優狀態
消費級
企業級
大量讀
混合使用
大量寫
基準
下降間隔後,基本仍然維持在 ~20-25k,但更平滑
爲何提高很小?Merging
$ curl -s 'http://localhost:9200/_nodes/hot_threads?threads=10' | grep % 73.6% (367.8ms out of 500ms) 'elasticsearch[es][bulk][T#25]' 66.8% (334.1ms out of 500ms) 'elasticsearch[es][[logstash][1]: Lucene Merge Thread #139]' 66.3% (331.6ms out of 500ms) 'elasticsearch[es][[logstash][3]: Lucene Merge Thread #183]' 66.1% (330.7ms out of 500ms) 'elasticsearch[es][[logstash][1]: Lucene Merge Thread #140]' 66.1% (330.4ms out of 500ms) 'elasticsearch[es][[logstash][4]: Lucene Merge Thread #158]' 62.9% (314.7ms out of 500ms) 'elasticsearch[es][[logstash][3]: Lucene Merge Thread #189]' 62.4% (312.2ms out of 500ms) 'elasticsearch[es][[logstash][2]: Lucene Merge Thread #160]' 61.8% (309.2ms out of 500ms) 'elasticsearch[es][[logstash][1]: Lucene Merge Thread #115]' 57.6% (287.7ms out of 500ms) 'elasticsearch[es][[logstash][0]: Lucene Merge Thread #155]' 55.6% (277.9ms out of 500ms) 'elasticsearch[es][[logstash][2]: Lucene Merge Thread #161]'
分層存儲
爲何默認的配置 Merging 如此多?
$ curl 'http://localhost:9200/_template/logstash?pretty'
看到了嗎?
"string_fields" : { "mapping" : { "index" : "analyzed", // <--- see? "omit_norms" : true, "type" : "string", "fields" : { "raw" : { "ignore_above" : 256, // <--- see? "index" : "not_analyzed", // <--- see? "type" : "string" // <--- see? } } }, "match_mapping_type" : "string", "match" : "*" }
使用自定義映射
"string_fields" : { "mapping" : { "index" : "not_analyzed", "omit_norms" : true, "type" : "string" }, "match_mapping_type" : "string", "match" : "*" }
有那麼一點幫助
增長 bulk 線程池能夠控制索引的爆發
但同時也要注意,這會隱藏性能的問題
增長 worker 直到沒有明顯的性能提高爲止
num_cpu / 2
增長 flush_size 知道沒有明顯的性能提高爲止
10,000
索引協議
自定義映射模板
消息的複雜度也十分相關
加 20k 的新行與平均 1.5k 的索引速率
截斷
ruby { code => "if event['message'].length > 10240 then event['message'] = event['message'].slice!(0,10240) end" }
讓 Logstash 作更多的事情
按索引來調優分片
num_shards = (num_nodes - failed_node_limit) / (number_of_replicas + 1)
50 個節點,並容許最多 4 個節點失敗,replication 爲 1x:
num_shards = (50 - 4) / (1 + 1) = 23
若是分片大於 25Gb ,須要相應增長分片數
調優 indices.memory.index_buffer_size
index_buffer_size = num_active_shards * 500Mb
其中「active_shards」:指任何 5 分鐘內更新的分片
調試 refresh_interval
目標:將磁盤裏的緩衝儘量的移儲
例如:Samsung SM863 SSDs
DRAM buffer: 1Gb
Flush speed: 500Mb/sec
參考來源:
2016.6 ELK: Moose-ively scaling your log system