案發現場:永遠跑不完的最後 1%
你是否遇過這種情況?
Cluster 發生波動(例如重啟節點),大部分 Index 很快就變綠了,唯獨幾個 APM 或 Log 類的 Index,進度條卡在 99.x%。
你下指令檢查:
GET _cat/recovery?v&active_only=true&h=index,time,stage,bytes_percent,translog_ops_percent,speed
發現那個「釘子戶」的狀態是:
- Stage:
translog - Translog Ops: 還有 1700 萬筆 (17,481,622)
- Speed: 很慢,而且總數不減反增。
為什麼會這樣?
Elasticsearch 的副寫本復原 (Peer Recovery) 分為兩階段:
- Phase 1 (File Copy): 複製硬碟裡的 Segment Files。這很快,因為是循序 I/O。
- Phase 2 (Translog Replay): 重放記憶體中還沒落盤的操作。這就是卡住的地方。
當你的 Index 是「熱資料 (Hot Data)」時,新的資料正瘋狂寫入 (Ingest)。 如果 「寫入新資料的速度」 > 「Translog 重放的速度」,那復原工作就像是在跑跑步機——你跑得很累,但永遠在原地踏步。
第一招:外科手術 (Force Flush)
這是最溫和且通常有效的解法。 原理:強制執行 Flush,把記憶體裡的 Translog 寫成硬碟上的 Segment File。這樣 Phase 2 要重放的操作數就會瞬間歸零(或大幅減少)。
指令:
# 針對卡住的特定 Index 執行 Flush
POST /.ds-traces-apm-default-2026.02.03-005374/_flush?wait_if_ongoing=true
SRE 觀點: 這招通常能瞬間把千萬級別的 Ops 降到零頭,讓進度條直接衝破 100%。
第二招:核選項 (Replica Reset)
如果 Flush 之後,Translog 還是累積太快(例如每秒寫入幾萬筆),那就只能用這招「砍掉重練」。 原理:將副本數設為 0(刪除副本),再設回 1(重新建立)。這會強制觸發 Phase 1 (File Copy),直接複製檔案比重放 Log 快得多。
步驟:
# 1. 歸零副本 (中斷慢速的 Translog 復原)
PUT /.ds-metrics-xxxxxx_2026-02-03-2026.02.03-000001/_settings
{
"index": {
"number_of_replicas": 0
}
}
# 2. 強制落盤 (確保 Primary 端資料都變成檔案,這步很重要!)
POST /.ds-metrics-xxxxx_2026-02-03-2026.02.03-000001/_flush
# 3. 重啟副本 (啟動高速檔案複製)
PUT /.ds-metrics-xxxxx_2026-02-03-2026.02.03-000001/_settings
{
"index": {
"number_of_replicas": 1
}
}
第三招:加大頻寬 (Traffic Shaping)
預設的復原限速(通常是 40MB/s)對於現代 10G/25G 網路來說太保守了。我們可以暫時調大限制,讓資料像洪水一樣灌過去。
指令:
PUT /_cluster/settings
{
"transient": {
# 針對 10Gbps 網路,開到 200mb-500mb 都是安全的
"indices.recovery.max_bytes_per_sec": "200mb",
# 允許單節點同時並行處理的數量 (預設是 2)
"cluster.routing.allocation.node_concurrent_recoveries": 8,
"cluster.routing.allocation.node_initial_primaries_recoveries": 8
}
}
⚠️ 恢復設定: 復原完成後,記得改回 null (預設值),以免影響正常服務的效能。
PUT /_cluster/settings
{
"transient": {
"indices.recovery.max_bytes_per_sec": null,
"cluster.routing.allocation.node_concurrent_recoveries": null,
"cluster.routing.allocation.node_initial_primaries_recoveries": null
}
}
第四招:危險操作 (Async Translog)
警告:這招會犧牲資料安全性 (Data Durability)。 原理:預設 ES 每一個 Request 都會 fsync 到硬碟 (request)。改成 async 後,會先寫在記憶體,每隔一段時間才落盤。這能大幅提升寫入和復原速度。
適用場景: 你確定這段時間「掉一點資料沒關係」,只求趕快恢復綠燈。
指令:
PUT /_all/_settings
{
"index": {
"translog.durability": "async",
"translog.flush_threshold_size": "1gb" # 減少 Flush 頻率
}
}
⚠️ 恢復設定: 務必在變綠燈後立刻改回來!
PUT /_all/_settings
{
"index": {
"translog.durability": "request", # 改回預設值
"translog.flush_threshold_size": "512mb"
}
}
SRE 總結
面對「釘子戶 Index」的處理 SOP:
- 觀察: 用
_cat/recovery確認是不是卡在translog階段。 - 輕解: 對該 Index 執行
_flush。 - 重解: 調整 Cluster 頻寬 (
max_bytes_per_sec)。 - 根除: 歸零副本 -> Flush -> 重開副本。
記住,99% 不是終點,只是因為你跑得還不夠快。