在運維 ES 集群的過程中,我們一般使用 node stats 接口獲取關(guān)鍵指標(biāo)掘猿, node-stats
API 可以通過如下命令執(zhí)行:
node-stats
API 可以通過如下命令執(zhí)行:
GET _nodes/stats
從輸出的頂部開始,我們看到集群名稱和我們的第一個節(jié)點:
{
"cluster_name": "elasticsearch_zach",
"nodes": {
"UNr6ZMf5Qk-YCPA_L18BOQ": {
"timestamp": 1408474151742,
"name": "Zach",
"transport_address": "inet[zacharys-air/192.168.1.131:9300]",
"host": "zacharys-air",
"ip": [
"inet[zacharys-air/192.168.1.131:9300]",
"NONE"
],
...
節(jié)點以哈希表列出急凰,key 為節(jié)點的UUID药蜻。 顯示有關(guān)節(jié)點網(wǎng)絡(luò)屬性的一些信息(如傳輸?shù)刂泛椭鳈C(jī))喳瓣。 當(dāng)節(jié)點沒有正確加入集群的時候乍炉,這些值對于調(diào)試發(fā)現(xiàn)問題非常有用:通常會看到使用了錯誤的端口绢片,或者該節(jié)點綁定到錯誤的IP地址/接口。
indices 信息塊
indices
信息塊列出該節(jié)點上所有 indices 的聚合信息:
"indices": {
"docs": {
"count": 6163666,
"deleted": 0
},
"store": {
"size_in_bytes": 2301398179,
"throttle_time_in_millis": 122850
},
返回結(jié)果可以分為 2 塊:
-
docs
表示存儲在該節(jié)點的 documents 數(shù)量岛琼,包括標(biāo)記刪除但是實際沒有從 segment 清除的底循。 -
store
表示磁盤占用空間大小,包括 primary 和 replica shards槐瑞。如果 throttle time 過大熙涤,可能表示磁盤限制過低。
"indexing": {
"index_total": 803441,
"index_time_in_millis": 367654,
"index_current": 99,
"delete_total": 0,
"delete_time_in_millis": 0,
"delete_current": 0
},
"get": {
"total": 6,
"time_in_millis": 2,
"exists_total": 5,
"exists_time_in_millis": 2,
"missing_total": 1,
"missing_time_in_millis": 0,
"current": 0
},
"search": {
"open_contexts": 0,
"query_total": 123,
"query_time_in_millis": 531,
"query_current": 0,
"fetch_total": 3,
"fetch_time_in_millis": 55,
"fetch_current": 0
},
"merges": {
"current": 0,
"current_docs": 0,
"current_size_in_bytes": 0,
"total": 1128,
"total_time_in_millis": 21338523,
"total_docs": 7241313,
"total_size_in_bytes": 5724869463
},
indexing
表示曾經(jīng)被索引過的 docs困檩。 這個值是單調(diào)遞增的祠挫,當(dāng) docs 被刪除時,它不會減少窗看。 還要注意茸歧,在內(nèi)部執(zhí)行索引操作的任何時候它都會增加,包括更新操作显沈。一起被列出的指標(biāo)還有 indexing 耗時,當(dāng)前被 indexing 的 docs 數(shù)量逢唤,以及類似的刪除操作對應(yīng)的統(tǒng)計指標(biāo)拉讯。get
get-by-ID 的統(tǒng)計信息,包括針對單個 doc 的GET
和HEAD
請求鳖藕。-
search
描述了活躍 search 數(shù)量 (open_contexts
)魔慷,總 query 的數(shù)量, 以及自節(jié)點啟動后 query 的累計耗時著恩。query_time_in_millis / query_total
的比率可以作為查詢效率的粗略指標(biāo)院尔。比例越大蜻展,每個查詢的時間越多,應(yīng)該考慮調(diào)優(yōu)邀摆。fetch 詳細(xì)統(tǒng)計的是查詢的后半段 (query-then-fetch 中的 fetch )纵顾。如果 fetch 的時間比 query 更多,這是慢盤或大查詢的指示符栋盹,或可能 search 請求涉及的分頁過大 (比如施逾,
size: 10000
). -
merges
包含有關(guān)Lucene segment 合并的信息。 包括當(dāng)前有效的 merge 數(shù)量例获,涉及的 doc 數(shù)量汉额,已 merge 的 segment 的累積大小以及 merge 所花費的時間。如果寫負(fù)載很高榨汤,則合并統(tǒng)計信息非常重要蠕搜,因為合并消耗大量的磁盤 I/O 和 CPU 資源。
注意:update 和 delete 也會帶來 merge 操作收壕,因為它們會導(dǎo)致片段碎片需要最終被合并妓灌。
"filter_cache": {
"memory_size_in_bytes": 48,
"evictions": 0
},
"fielddata": {
"memory_size_in_bytes": 0,
"evictions": 0
},
"segments": {
"count": 319,
"memory_in_bytes": 65812120
},
...
-
filter_cache
描述 cache filter 的內(nèi)存使用大小,filter 被淘汰的次數(shù)啼器。 大量的淘汰意味著需要增加 filter cache旬渠,或filter 沒有被正確緩存。然而端壳,淘汰是一個非常難以評估的指標(biāo)告丢。 filter 以 segment 為單元進(jìn)行緩存,這意味著淘汰一個 small segment 代價相對較小损谦。 如果是大量的 small segment 淘汰岖免,這意味著它們對查詢性能幾乎沒有影響。
field_data
描述了 field_data 使用的內(nèi)存照捡,它會被用作 聚合(aggregation)颅湘,排序(sorting)等,這塊內(nèi)存指標(biāo)也包括淘汰次數(shù)栗精。 和filter_cache
不一樣闯参,這里的淘汰次數(shù)必須為 0 或者逼近 0 才合理。 因為 field data 不是 cache悲立,所有任何淘汰都是代價昂貴且需要避免的鹿寨。如果發(fā)現(xiàn)這里有淘汰,就需要重新評估包括內(nèi)存薪夕、 field data 限制脚草、query。-
segments
描述的是該節(jié)點目前服務(wù)的 Lucene segment 的數(shù)量原献,非常重要馏慨。 大多數(shù) indices 應(yīng)該有大約 50-150 個 segment埂淮,即使是 TB 大小,包含十億級別 documents 的写隶。 大量的 segment 可以體現(xiàn)出合并的問題(例如倔撞,合并趕不上 segment 的創(chuàng)建)。 請注意樟澜,此統(tǒng)計信息是節(jié)點上所有 indices 的總和误窖。內(nèi)存統(tǒng)計信息讓我們了解 Lucene segment 本身使用的內(nèi)存量,包括 low-level 數(shù)據(jù)結(jié)構(gòu)秩贰,例如發(fā)布列表霹俺,字典和布隆過濾器。
OS 和 Process 信息塊
OS
和 Process
信息塊描述的指標(biāo)比較簡單通用毒费,無需詳細(xì)解釋丙唧。 OS
信息塊描述的是整個 OS
,而 Process
信息塊 展示的是 Elasticsearch JVM 進(jìn)程相關(guān)指標(biāo)觅玻。
這些都是非常有價值的指標(biāo)想际,但是我們通常都會在其他監(jiān)控平臺進(jìn)行采集和展示:
- CPU
- Load
- Memory usage
- Swap usage
- Open file descriptors
JVM 信息塊
jvm
信息塊包括一些 ElasticSearch JVM 進(jìn)程的重要指標(biāo)。更重要的是包含了 GC 相關(guān)的詳細(xì)指標(biāo)溪厘,這對觀察集群穩(wěn)定性非常必要胡本。
Garbage Collection Primer
在描述指標(biāo)之前,非常有必要插入下 GC 相關(guān)的知識和對 ES 本身的影響畸悬。如果您非常了解 JVM GC侧甫,可以直接跳過。
Java 是一種 garbage-collected 語言蹋宦,意味著開發(fā)者不需要關(guān)心內(nèi)存的分配和回收披粟。
當(dāng)內(nèi)存被分配至 JVM 進(jìn)程,會被分配到叫做 heap 的大 chunk冷冗。JVM 會把 heap 劃分為兩大塊守屉,根據(jù) generations:
-
Young (or Eden)
用于分配新建對象的空間。新生代的空間往往較小蒿辙,經(jīng)常是 100 MB–500 MB拇泛。新生代往往包含兩塊 survivor 空間。
-
Old
用于存儲老對象的空間思灌。這些對象預(yù)計會長期存在碰镜, 老生代通常比新生代大得多,而 ES 節(jié)點往往會有大于 30 GB 的老生代空間分配习瑰。
當(dāng)對象被實例化時,它被分配至新生代秽荤。 當(dāng)新生代空間滿時甜奄,會發(fā)生 YGC柠横。 仍然需要存在的對象會被移動到其中的一個 suvive 空間中,并且"dead"對象會在這個過程被移除课兄。 如果一個對象在若干個 YGC 中幸存下來牍氛,那么它就會晉升到老生代。
在老生代中也會發(fā)生類似的過程:當(dāng)空間變滿時烟阐,垃圾回收開始搬俊,"dead"對象被刪除。
然而蜒茄,GC 過程是有代價的唉擂。 不論是 YGC 還是 FGC 都有 "Stop-the-World" 的階段。 在此期間檀葛,JVM會直接停止執(zhí)行程序玩祟,以便跟蹤對象 graph 并收集 "dead" 對象。 在 "Stop-the-World" 階段任何事情都不會發(fā)生屿聋。 請求不得到服務(wù)空扎,ping 不受到響應(yīng),shards 不被重定位润讥。 對于 ES 來說转锈,世界確實停止了。
這對新生代來說不是什么大問題楚殿;其小尺寸意味著 GC 會被快速執(zhí)行撮慨。 但是老生代的問題還是比較大的,而這里如果存在緩慢的 GC 可能意味著1秒甚至150秒的暫停勒魔,這對服務(wù)器軟件是不可接受的甫煞。
JVM中的垃圾回收器是非常復(fù)雜的算法,并且可以很好地縮短停頓時間冠绢。 和 ES 在 GC 方面做了很深的優(yōu)化抚吠,通過智能地內(nèi)部重用對象,重用網(wǎng)絡(luò)緩沖區(qū)弟胀,并默認(rèn)啟用[docvalues]楷力。 但是最終,GC 頻率和持續(xù)時間仍是需要關(guān)注的指標(biāo)孵户,因為它是群集不穩(wěn)定性的首要原因萧朝。
經(jīng)常遇到長 GC 的集群將是一個負(fù)載較重的內(nèi)存不足的集群。 這些長時間的 GC 將使節(jié)點短暫地離開集群夏哭。 這種不穩(wěn)定性導(dǎo)致 shards 頻繁被 realocate检柬,因為 Elasticsearch 嘗試保持集群平衡和足夠可用的副本。 這反過來又增加了網(wǎng)絡(luò)流量和磁盤 I /O竖配,而同時集群也在嘗試維護(hù)正常的 indexing 和 query 負(fù)載何址。
總而言之里逆, 長時間的 GC 應(yīng)該被重視并盡可能的優(yōu)化。
因為 GC 對 ES 集群至關(guān)重要用爪,我們應(yīng)該密切關(guān)注 node-stats
API 的 GC 信息塊:
"jvm": {
"timestamp": 1408556438203,
"uptime_in_millis": 14457,
"mem": {
"heap_used_in_bytes": 457252160,
"heap_used_percent": 44,
"heap_committed_in_bytes": 1038876672,
"heap_max_in_bytes": 1038876672,
"non_heap_used_in_bytes": 38680680,
"non_heap_committed_in_bytes": 38993920,
-
jvm
信息塊首先展示了堆內(nèi)存的信息原押。我們可以看到堆內(nèi)存被使用的情況,內(nèi)存之余進(jìn)程分配的情況以及最大的可用堆內(nèi)存偎血。 理想情況下诸衔,heap_committed_in_bytes
需要和heap_max_in_bytes
相同。如果 committed size 較小颇玷,JVM 將必須在某些情況下 resize heap — 這是一個代價很大的過程笨农。如果數(shù)值不同,請參看 [heap-sizing] 進(jìn)行合理配置亚隙。heap_used_percent
是一個十分有用的指標(biāo)磁餐。Elasticsearch 默認(rèn)情況會在 75% 的水位線進(jìn)行 GC。 如果節(jié)點的堆內(nèi)存持續(xù) >= 75%阿弃,節(jié)點會處于 memory pressure诊霹。這意味著接下來可能會處發(fā)長時間的 GC。
如果節(jié)點的堆內(nèi)存長時間 >=85%渣淳,那就更嚴(yán)重脾还。水位線處于 90–95%會非常恐怖的觸發(fā) 10–30 秒的 GC入愧,甚至是 OOM鄙漏。
"pools": {
"young": {
"used_in_bytes": 138467752,
"max_in_bytes": 279183360,
"peak_used_in_bytes": 279183360,
"peak_max_in_bytes": 279183360
},
"survivor": {
"used_in_bytes": 34865152,
"max_in_bytes": 34865152,
"peak_used_in_bytes": 34865152,
"peak_max_in_bytes": 34865152
},
"old": {
"used_in_bytes": 283919256,
"max_in_bytes": 724828160,
"peak_used_in_bytes": 283919256,
"peak_max_in_bytes": 724828160
}
}
},
-
young
,survivor
棺蛛,以及old
信息塊將會給到不同空間的指標(biāo)怔蚌。但是并沒有上述指標(biāo)那么重要。
"gc": {
"collectors": {
"young": {
"collection_count": 13,
"collection_time_in_millis": 923
},
"old": {
"collection_count": 0,
"collection_time_in_millis": 0
}
}
}
-
gc
信息塊顯示了 YGC 和 FGC 的次數(shù)和累積時間旁赊。一般情況下我們可以忽略 YGC 的次數(shù):這個數(shù)字往往很大桦踊。相反的 FGC 次數(shù)應(yīng)該較小,并且有較小的
collection_time_in_millis
终畅。這些都是累積指標(biāo)籍胯,所以參考價值不是很大。 (比如离福,一個啟動很久的節(jié)點可能會有很大的值)杖狼。這就是為什么第三方監(jiān)控工具很重要的原因,GC 次數(shù) over time are 是非常有必要考慮的指標(biāo)妖爷。GC 持續(xù)時間也很重要蝶涩。比如,在進(jìn)行 indexing 的時候,會有觸發(fā)一系列的 GC子寓。 這些 GC 往往很快并且對節(jié)點的影響很邪堤簟:YGC 大概是 1-2 ms,F(xiàn)GC 大概是數(shù)百 ms斜友。
最好的官方建議是周期性的抓取 GC 次數(shù)和持續(xù)時間(或者用第三方監(jiān)控工具),并且關(guān)注頻繁的 GC垃它。我們也可以 enable slow-GC logging[logging]鲜屏。
Threadpool 信息塊
Elasticsearch 在內(nèi)部維護(hù)了線程池。這些線程池進(jìn)行協(xié)作完成工作国拇,在必要的時候傳遞工作洛史。一般情況下,無需對其進(jìn)行配置酱吝,但是某些情況下獲取他們的狀態(tài)去觀察集群的行為是有用的也殖。
ES 大概有一打線程池,具有相同的狀態(tài)信息輸出:
"index": {
"threads": 1,
"queue": 0,
"active": 0,
"rejected": 0,
"largest": 1,
"completed": 1
}
每一個線程池都列出了它們被配置的線程數(shù)(threads
)务热,其中正在處理工作的線程數(shù) (active
)忆嗜,和有多少工作單元在隊列中排隊 (queue
)。
如果隊列達(dá)到了極限崎岂,新的工作單元會被拒絕捆毫,我們會在 rejected
看到統(tǒng)計信息。這表示集群因為某些資源達(dá)到了瓶頸冲甘,因為隊列滿了意味著節(jié)點或者集群的處理速度趕不上工作單元的生成速度绩卤。
Bulk Rejections(批處理拒絕)
如果遇到了隊列拒絕,很大可能是因為 bulk indexing 請求造成的江醇。一旦閾值達(dá)到濒憋,隊列會迅速被填滿陶夜,新的 bulk 請求會被拒絕。隊列拒絕是一種集群友好的策略辐烂,避免被打爆。他告訴了運維同學(xué)集群的最大能力在哪里捂贿,絕對比把數(shù)據(jù)持續(xù)塞進(jìn)內(nèi)存隊列好的多纠修。增加隊列大小并不能帶來性能提升厂僧,而是隱藏了問題。如果集群只能處理 10K docs/s,不論隊列多大辰妙,那也只能處理那么多鹰祸。隊列會簡單的隱藏性能問題并且加重數(shù)據(jù)丟失的風(fēng)險。任何被塞進(jìn)隊列的都是被定義為未被處理的密浑。如果節(jié)點宕機(jī),這些請求都會被永久丟失街图。進(jìn)一步來說懒构,隊列也會吃掉大量的內(nèi)存所以不建議開太大。
所以在開發(fā)應(yīng)用的時候也需要優(yōu)雅的處理 queue rejected 導(dǎo)致的問題絮姆,當(dāng)接收到 bulk rejections 相關(guān)異常時,必須這么做:
- 停止核心線程 3-5 秒篙悯;
- 從bulk response 中解析出被拒絕的 actions前域,因為可能 bulk 操作中有大量 action 是成功的;
- 再次發(fā)送新的 bulk request移宅,去處理被拒絕的 actions椿疗;
- 如果再次遇到 rejected 重復(fù)第1步;
Rejections 并不是 error:他意味著你必須要再次重試浅乔;
我們需要關(guān)注如下的線程池信息:
-
indexing
普通 indexing requests 的線程池铝条;
-
bulk
Bulk requests, 區(qū)別于 nonbulk indexing 請求;
-
get
Get-by-ID 操作贤壁;
-
search
所有的 search 和 query 請求;
-
merging
Lucene merge 的請求埠忘;
FS 和 Network 信息塊
往下拉馒索,可以看到 node-stats
API 還附帶了這些輸出信息:free space名船,data directory paths,disk I/O stats 等等蜈块。如果你沒有在第三方監(jiān)控到渴邦,那么可以走這里獲取。
同樣的對于網(wǎng)絡(luò)信息塊,輸出如下:
"transport": {
"server_open": 13,
"rx_count": 11696,
"rx_size_in_bytes": 1525774,
"tx_count": 10282,
"tx_size_in_bytes": 1440101928
},
"http": {
"current_open": 4,
"total_opened": 23
},
-
transport
描述的是 transport address 相關(guān)基礎(chǔ)信息瓮床。這和集群內(nèi)部通信有關(guān)(9300端口)产镐。如果看到很多連接請不要擔(dān)心,因為 ES 在集群內(nèi)部維護(hù)了很多連接丑掺。 -
http
匯報的是外部通信端口信心 (often 9200)述雾。如果total_opened
非常大并且持續(xù)增長,這說明有 HTTP 客戶端沒有使用 keep-alive 連接唆缴。對于性能來說黍翎,keep-alive 模式很重要,因為構(gòu)建和銷毀 socket 的代價很大趟紊。
Circuit Breaker 信息塊
最后介紹下 Circuit Breaker 信息塊:fielddata circuit-breaker 相關(guān)統(tǒng)計指標(biāo):
"fielddata_breaker": {
"maximum_size_in_bytes": 623326003,
"maximum_size": "594.4mb",
"estimated_size_in_bytes": 0,
"estimated_size": "0b",
"overhead": 1.03,
"tripped": 0
}
這段信息告訴了我們 circuit-breaker 的大信鲈汀(例如,如果 query 嘗試使用更多內(nèi)存唧躲,circuit breaker 會在什么閾值跳閘,阻斷 query)饭入,還告訴了我們 circuit-breaker 阻斷的次數(shù)以及當(dāng)前配置的開銷肛真。 開銷用于彌補估計值的偏差,因為某些 query 比其他 query 更難估計乾忱。最重要的指標(biāo)是tripped
历极,如果該值很大或者持續(xù)增加,說明 query 需要被優(yōu)化或者需要更多內(nèi)存去支撐 query蹄葱。