The Samo Log

Elasticsearch 復原卡在 99%?對付 Translog「釘子戶」的四種殺手鐧

案發現場:永遠跑不完的最後 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) 分為兩階段:

  1. Phase 1 (File Copy): 複製硬碟裡的 Segment Files。這很快,因為是循序 I/O。
  2. 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:

  1. 觀察: 用 _cat/recovery 確認是不是卡在 translog 階段。
  2. 輕解: 對該 Index 執行 _flush
  3. 重解: 調整 Cluster 頻寬 (max_bytes_per_sec)。
  4. 根除: 歸零副本 -> Flush -> 重開副本。

記住,99% 不是終點,只是因為你跑得還不夠快。

寫作日曆

Mon Wed Fri
Less
More

也看看我的其他文章

載入留言中...