問題
DB Test 的搜尋引擎 lab(MySQL → Logstash JDBC → Elasticsearch)從建立起就沒跑通過,make demo 卻一直顯示成功。修的過程中發現,這條管線出事時幾乎不會報錯,而是資料靜默不見或被汙染。
修法
七個坑與解法:
| # | 坑 | 症狀 | 解法 |
|---|---|---|---|
| 1 | 官方 image(logstash:8.12.0)不含 MySQL JDBC driver | Logstash 啟動即 FATAL(file not readable) | 自建 image,從 Maven Central 下載固定版本並驗 sha256 |
| 2 | ADD --chmod=644 會套到 ADD 自動建立的目錄 | 目錄變成 drw-r-Sr--,沒有 x,jar 照樣讀不到 | 先 RUN mkdir -m 755 -p 再 ADD |
| 3 | 對 JDBC 欄位用 date filter | 每筆 _dateparsefailure 塞進 tags;tags 變陣列後 split 不作用,"a,b" 整串存進去 | 拿掉 date filter:JDBC 讀 DATETIME 已經是時間型別。tags 是 Logstash 保留欄位,業務欄位最好別叫這個名字 |
| 4 | strict mapping 拒收新欄位 | ES 回 400 strict_dynamic_mapping_exception,Logstash 只記 WARN(Could not index event)就丟、不重試;補上 mapping 後只有被重新 UPDATE 的那筆回來(1/13) | 先改 mapping(連 template 一起改),再讓那些列的 updated_at 前進觸發重送 |
| 5 | 條件式比對布林或數字 | if [is_deleted] == true 讓 pipeline 啟動即 ConfigurationError(沒有 true 字面值);SQL CAST(is_deleted AS UNSIGNED) 後 rubydebug 顯示 is_deleted => 1,== 1 仍不成立 | 不在 Logstash 做型別比對:SQL 直接產出 IF(is_deleted = 1, 'delete', 'index') AS sync_action,搬進 @metadata 給 output 的 action 用。實測刪除 13→12、還原 12→13、0 筆拒收 |
| 6 | 改了 pipeline 檔、docker compose up -d | compose 設定沒變就不重建,Logstash 不重載,跑的還是舊版 | 改完 pipeline 一律 docker compose restart logstash |
| 7 | 容器重建 | last_run_metadata_path 在容器裡,進度遺失,整表 12 筆重送 | 進度路徑掛 volume。document_id 固定的話,重送不會重複 |
第 5 個坑裡,CAST 之後 == 1 為什麼不成立,我沒有查 Logstash 原始碼。我的推測是 CAST 出來的值在 Logstash 裡是 Java BigInteger,跟條件式裡的字面值型別不同,所以比對失敗(推測,未查證)。
還有兩個設計面的選擇:
- 增量條件用
>=而不是>:同一毫秒更新的列用>會永遠漏掉。>=會讓邊界那筆重送,但document_id固定,等於覆寫。 - 輪詢抓不到 DELETE:要嘛改成軟刪除(上面第 5 點),要嘛改用 CDC 讀 binlog。
為什麼這樣解
這條管線的共同特性是失敗被設計成不中斷。filter 失敗只加 tag,output 遇到 400 只記 WARN,條件不成立就走 else。好處是一筆壞資料不會卡住整條管線,代價是沒有驗證就不知道丟了什麼。
所以解法的重點不在個別修補,而是補上 make verify。它逐段比對結果:
- MySQL 與 ES 的筆數
tags裡沒有失敗標記- 增量新增、修改在 30 秒內到 ES
- demo 查詢的第一筆是預期的文章
反向驗證也做了:停掉 Logstash、清空搜尋索引,兩種情況都必須 exit 1。
怎麼預防再次發生
- 任何「資料從 A 同步到 B」的管線,驗收一律比對兩邊的結果(筆數+抽樣內容),不看「指令有沒有回 0」。
curl -sf只看 HTTP 狀態,查到 0 筆照樣成功。 - 新增 filter 前先想:它失敗時會往哪裡寫標記?會不會撞到業務欄位?
- Logstash 的 WARN 要當成錯誤看待;正式環境開 dead letter queue,讓被拒收的資料有地方去。
相關主題
- 「
make demo顯示成功但查到 0 筆」是假綠燈的典型形態:指令成功不等於結果正確 - 除錯過程中還踩到 zsh 沒有
PIPESTATUS(zsh 用的是pipestatus)