為什麼需要佇列(Queue)#

在大規模分散式系統中,佇列是有效管理請求的關鍵元件。

  • 在小型系統中,處理負載低、資料庫規模小,寫入操作的速度是可預測的
  • 但在複雜的大型系統中,寫入可能耗費不確定的長時間——資料可能需要寫入不同伺服器的不同位置或索引,或者系統正處於高負載狀態
  • 在這些情況下,要達到高效能高可用性,系統的各元件必須以非同步(Asynchronous) 的方式運作,而佇列就是實現此目標的常見手段

同步模式的問題#

假設一個系統中,每個用戶端都向遠端伺服器發送任務處理請求:

  1. 在小型系統中,伺服器能即時處理所有請求,運作正常
  2. 但當請求量超過伺服器的處理能力時,每個用戶端都必須等待其他請求完成後才能收到回應

這種同步行為會帶來嚴重問題:

  • 用戶端被迫等待,實際上沒有做任何工作
  • 即使增加伺服器並搭配負載均衡,也很難確保公平且均衡的工作分配
  • 若處理請求的伺服器不可用或發生故障,上游的用戶端也會跟著失敗

有效解決此問題的關鍵在於:在用戶端的請求與實際執行的工作之間建立一層抽象層(Abstraction)

佇列的工作原理#

處理佇列的運作方式非常直觀:

  • 所有進入的任務都被加入佇列
  • 任何有空閒容量的 Worker 都可以從佇列中取出任務來處理
  • 任務的範圍可以從簡單的資料庫寫入,到複雜的文件縮圖預覽生成

圖 6.1:處理佇列架構圖

佇列基於非同步通訊協定實作:

  • 用戶端提交任務後,不需要等待結果,只需收到請求已被正確接收的確認通知(Acknowledgment)
  • 該確認通知可作為後續查詢結果的參考
  • 佇列對單次請求的資料大小佇列中未處理請求的數量有隱含或明確的限制

容錯能力(Fault Tolerance)#

佇列也被用於提升系統的容錯能力,提供對服務中斷和故障的保護:

  • 可以建立一個高健壯性的佇列,自動重試因暫時性系統故障而失敗的請求
  • 使用佇列來保證服務品質(Quality of Service),優於讓用戶端直接面對間歇性的服務中斷——後者需要複雜且往往不一致的用戶端錯誤處理邏輯

佇列在大規模分散式系統中扮演關鍵角色。常見的開源佇列實作包括 RabbitMQZeroMQActiveMQBeanstalkD