HUAN 讙 · 開發者

ADR-0007:工作佇列用 PostgreSQL,不引入 Redis

狀態

已採用

背景

FFmpeg 轉檔必須離開 Fastify 的行程,因此需要一個工作佇列。業界的預設答案通常是 Redis 加上 BullMQ 之類的函式庫。

決策

工作佇列就是 PostgreSQL 的一張表,用 SELECT ... FOR UPDATE SKIP LOCKED 取件。

這個 MVP 不引入 Redis。

理由

FOR UPDATE SKIP LOCKED 就是為這件事設計的。 它是 PostgreSQL 內建的佇列原語:取件的交易鎖住那一列,其他工作者直接跳過去拿下一件。不需要輪詢衝突,也不需要分散式鎖。

工作量級完全不需要 Redis。 這是數位看板系統,不是影片平台。一天可能有幾十次上傳,尖峰也就是幾百件工作。PostgreSQL 在這個量級下連暖身都算不上。

少一個要維運的東西。 加上 Redis 就要多一個容器、多一組健康檢查、多一份備份策略、多一個會壞掉的地方。而且 Redis 預設不持久化——工作佇列放在會遺失的儲存裡,需要額外的設計才能保證不掉件。

交易一致性是免費的。 「建立素材紀錄」與「排入轉檔工作」在同一個交易裡完成。用 Redis 就是跨兩個系統的寫入,必須自己處理其中一邊失敗的情況。

Server 只需要一個外部相依。 這對想自架的客戶是很實際的差別。

後果

  • 取件是輪詢的(預設每 2 秒),不是即時推播。對於本來就要跑好幾分鐘的轉檔工作,兩秒的延遲毫無意義。
  • 工作表會成長,需要定期清理已完成的紀錄。
  • 高頻率的短工作會在資料庫上產生可觀的負載。如果未來出現那種工作型態,這個決定就該重新評估。

何時該重新評估

  • 工作量進入每秒數百件的等級。
  • 出現需要毫秒級延遲的工作型態。
  • 資料庫的佇列查詢在監控上開始成為熱點。

在那之前,多一個中介軟體只會增加維運負擔,換不到任何實際的好處。

替代方案

Redis 加 BullMQ:功能完整,但引入了一個新的有狀態元件,而且需要額外設計才能保證不掉件。

RabbitMQ / Kafka:這個規模下完全是過度設計。

在 Fastify 裡直接跑:轉檔期間 API 完全沒有回應,而且無法獨立擴充轉檔能力。