🎯 什麼情境該想到我

當你「想讓兩個獨立系統交換資料,但不想讓它們彼此直接相依,能接受不是即時、批次同步就好」的時候(例如一方每晚匯出一份檔案,另一方隔天匯入)。

⚙️ 怎麼用(步驟 / 公式)

意圖:讓每個應用程式各自產生與消費檔案,藉由共享檔案來交換資料,彼此不需知道對方的技術細節。

做法 / 結構要點:

  • 產生方把資料匯出成一個雙方講好格式的檔案(欄位、編碼、檔名慣例)。
  • 消費方在約定的位置與時間讀取並匯入該檔案。
  • 需明確約定:檔案格式、命名、放置位置、產生頻率,以及「檔案何時算寫完可讀」。

★ 今天的檔案傳輸長什麼樣(2003 → 2026)

EIP 書裡今天的實作
FTP/共享目錄 + 固定檔名★ 物件儲存(S3/GCS/R2)+ 事件通知(S3 Event → SQS/Lambda)
CSV/固定寬度文字★ Parquet/Avro(欄式、自帶 schema、可壓縮)
cron 每晚跑一次Airflow/Dagster/Step Functions 排程;或事件觸發
「檔案寫完了」靠時間猜★ 寫入 _SUCCESS 標記檔,或寫到 temp 名再 rename

★ 這個模式完全沒有過時。 它今天的名字叫「資料湖」「批次 ETL」「S3 落地區」——
大量資料的搬運,批次檔案至今仍然比逐筆訊息便宜一到兩個數量級。

★★ 最重要的一個陷阱:怎麼知道「檔案寫完了」

// ❌ 消費端直接去讀 —— 可能讀到寫了一半的檔案
if _, err := os.Stat("/inbox/orders.csv"); err == nil { process(…) }

三種正確做法:

// ① ★ 寫到暫時名稱,完成後 rename(同一檔案系統上 rename 是原子的)
tmp := dst + ".tmp"
writeAll(tmp); os.Rename(tmp, dst)          // ★ 消費端只會看到完整的檔案
 
// ② ★ 額外寫一個標記檔(Hadoop/Spark 的慣例)
writeAll("/inbox/2026-09-25/data.parquet")
writeAll("/inbox/2026-09-25/_SUCCESS")      // ★ 消費端只認有 _SUCCESS 的目錄
 
// ③ ★ 物件儲存本身就是原子的
//    S3 的 PutObject 沒有「寫一半可見」的狀態 —— 物件要嘛完整存在,要嘛不存在
//    多段上傳(multipart)也是在 CompleteMultipartUpload 那一刻才可見

⚠️ os.Rename 只有在「同一個檔案系統」上是原子的。 跨掛載點會退化成 copy + delete,
中間狀態是可見的——這是 NFS 共享目錄最常出事的地方。

★ 冪等與重複處理:檔案傳輸沒有「訊息 ID」

// ★ 用「檔名 + ETag/大小 + 已處理表」自己做去重
type processed struct{ Key, ETag string }   // ★ 唯一索引在 (Key, ETag)
// → 同一個檔案被重放(例如上游重跑)時,ETag 相同就跳過;ETag 不同代表內容真的變了

★ 移動檔案到 done/ 目錄是最常見的做法,但它不是交易性的:
process(f) 成功、move(f) 失敗 → 下次重跑會再處理一次。
→ 所以還是要冪等(見 冪等接收者)。

★ 什麼時候選檔案傳輸而不是訊息

選檔案選訊息
★ 資料量大(GB 級以上)——逐筆訊息的 per-message overhead 會壓垮 broker資料量小、筆數多
★ 延遲容忍高(小時/天級)需要秒級以下
★ 需要重跑整批(回填、對帳)只關心增量
兩邊技術棧差異極大(大型主機、第三方廠商)兩邊都是你的服務
★ 需要人看得懂的中間產物(稽核、爭議處理)—

★ 判準:這是「資料同步」還是「事件通知」? 同步 → 檔案;通知 → 訊息。
兩者常常並存:檔案落地 → 發一則「檔案已就緒」的訊息(見 寄物單)。

🧪 我實際套用的紀錄

  • (待填)

⚠️ 注意 / 什麼時候不適用

  • 即時性差:資料只在檔案產生後才更新,通常是批次、有延遲。

  • 缺乏交易與一致性保證,兩邊可能短暫看到不同步的資料。

  • 格式一旦要改,雙方要一起協調;不適合需要即時互動或高頻交換的場景。

  • ★★ 「檔案寫完了嗎」是這個模式的頭號 bug 來源。用 rename、_SUCCESS 標記檔,或物件儲存的原子語義。

  • ★ os.Rename 只在同一檔案系統上原子。跨 NFS 掛載點會退化成 copy + delete。

  • ★ 沒有訊息 ID,去重要自己做(檔名 + ETag + 已處理表)。「移到 done/ 目錄」不是交易性的。

  • ★ 檔案格式就是契約,而且沒有版本協商。CSV 多一欄可能讓下游整個錯位。用 Parquet/Avro 之類自帶 schema 的格式(見 工具-資料編碼與演進)。

  • CSV 的地雷很多:BOM、換行在引號內、時區、千分位、Excel 把長數字變科學記號。這些每一個都造成過真實事故。

  • ★ 延遲是小時/天級。需要即時就不要用這個模式。

  • 檔案堆積要監控:inbox/ 累積代表消費端掛了,而它不會自己告警。

  • 重跑要能安全重跑。回填是檔案傳輸最大的優勢,但前提是處理端冪等。

🔗 相關工具