基於Dynomite的分散式延遲佇列
最近看了Dyno-queues分散式延遲佇列的原始碼,發現了一些不錯的技巧,而本文是對Dyno-queues架構精華的總結。
本文是根據 https://medium.com/netflix-techblog/distributed-delay-queues-based-on-dynomite-6b31eca37fbc 翻譯而來,如果有不準之處請大家多包含。
在Netflix的平臺上執行著許多的業務流程,這些流程的任務是通過非同步編排進行驅動,現在我們要實現一個分散式延遲佇列,這個延遲佇列具有如下特點:
- 分散式
- 不用外部的鎖機制
- 高併發
- 至少一次語義交付
- 不遵循嚴格的FIFO
- 延遲佇列(訊息在將來某個時間之前不會從佇列中取出)
- 優先順序
一、使用Dynomite和Redis構建佇列
Dynomite是一種通用的實現,可以與許多不同的key-value儲存引擎一起使用。目前它提供了對Redis序列化協議(RESP)和Memcached寫協議的支援。我們選擇Dynomite,是因為其具有效能,多資料中心複製和高可用性的特點。此外,Dynomite提供分片和可插拔的資料儲存引擎,允許我們在資料需求增加垂直和水平擴充套件。
1、為什麼選擇Redis?
我們選擇Redis作為構建佇列的儲存引擎:
- Redis架構通過提供構建佇列所需的資料結構很好地支援了佇列設計,同時Redis的效能也非常優秀,具備低延遲的特性
- Dynomite在Redis之上提供了高可用性、對等複製以及一致性等特性,用於構建分散式叢集佇列。
一個佇列被儲存為Redis的有序集合(ZADD和ZRANGE等操作),Redis使用分數對有序集合中的成員進行排序,當往佇列中儲存資料時,根據優先順序和超時時間計算分數。
2、使用Redis實現資料的push和pop
對於每個佇列,維護三組Redis資料結構:
- 包含佇列元素和分數的有序集合
- 包含訊息內容的Hash集合,其中key為訊息ID。
- 包含客戶端已經消費但尚未確認的訊息有序集合,Un-ack集合。
PUSH
- 根據訊息超時(延遲佇列)和優先順序計算得分
- 新增到佇列的有序集合
- 將Message物件到Hash集合中,key是messageId。
POP
- 計算當前時間為最大分數。
- 獲取分數在0和最大分數之間的訊息。
- 將messageID新增到unack集合中,並從佇列的有序集中刪除這個messageID。
- 如果上一步成功,則根據messageID從Redis集合中檢索訊息。
ACK
- 從unack集合中刪除messageID。
- 從Message有效集合中刪除messageID。
客戶端未進行確認的訊息,會被再度推回到佇列中(這是一個定時任務負責檢測)。
3、可用分割槽和機架意識
我們的佇列是在Dynomite的JAVA客戶端Dyno之上建立的,Dyno為持久連線提供連線池,並且可以配置為拓撲感知,此外,Dyno為應用程式提供特定的本地機架(在AWS中,機架是一個區域,例如 us-east-1a、us-east-1b等),us-east-1a的客戶端將連線到相同區域的Dynomite/Redis節點,除非該節點不可用,在這種情況下該客戶端將進行故障轉移。這個屬性被用於通過區域劃分佇列。
分片
佇列根據可用區域進行分片,將資料推送到佇列時,通過輪訓機制確定分片,這種機制可以確保所有分片的資料是平衡的,每個分片都代表Redis中的有序集合,有序集中的key是queueName和AVAILABILITY _ZONE的組合。
避免全域性鎖
- 每個節點(上圖中的N1…Nn)與可用性區域具有關聯性,並且與該區域中的redis伺服器進行通訊。
- Dynomite / Redis節點一次只能提供一個請求,Dynomite可以允許數千個併發連線,但是請求是由Redis中的單個執行緒處理,這確保了當發出兩個併發呼叫從佇列輪詢元素時,是由Redis伺服器順序執行,從而避免任何本地或分散式鎖。
- 在發生故障轉移的情況下,確保沒有兩個客戶端連線從佇列中獲取相同的訊息。
處理Un-ACK的訊息
後臺程式監視UNACK集合中的訊息,這些訊息在給定時間內未被客戶端確認(每個佇列可配置)。這些訊息將移回到佇列中。
Dyno-queues分散式延遲佇列的github地址是:
https://github.com/Netflix/dyno-queues
相關文章
- 實現簡單延遲佇列和分散式延遲佇列佇列分散式
- 靈感來襲,基於Redis的分散式延遲佇列(續)Redis分散式佇列
- Dyno-queues 分散式延遲佇列 之 輔助功能分散式佇列
- 基於rabbitmq延遲外掛實現分散式延遲任務MQ分散式
- Dyno-queues 分散式延遲佇列 之 生產消費分散式佇列
- Dyno-queues 分散式延遲佇列 之 基本功能分散式佇列
- redis 延遲佇列Redis佇列
- Laravel 延遲佇列Laravel佇列
- Delayer 基於 Redis 的延遲訊息佇列中介軟體Redis佇列
- 基於訊息佇列(RabbitMQ)實現延遲任務佇列MQ
- hyperf redis延遲佇列Redis佇列
- 延遲阻塞佇列 DelayQueue佇列
- 百行程式碼實現基於Redis的可靠延遲佇列行程Redis佇列
- [Redis]延遲訊息佇列Redis佇列
- RabbitMQ實現延遲佇列MQ佇列
- RabbitMQ實戰《延遲佇列》MQ佇列
- RabbitMQ 實現延遲佇列MQ佇列
- Golang 實現 RabbitMQ 的延遲佇列GolangMQ佇列
- Spring Boot(十四)RabbitMQ延遲佇列Spring BootMQ佇列
- 基於Redis的簡易延時佇列Redis佇列
- 基於asyncio和redis的Python分散式任務佇列RedisPython分散式佇列
- 使用RabbitMq原生實現延遲佇列MQ佇列
- RabbitMQ、RocketMQ、Kafka延遲佇列實現MQKafka佇列
- 如何用RabbitMQ實現延遲佇列MQ佇列
- php+redis實現延遲佇列PHPRedis佇列
- 高可用延遲佇列設計與實現佇列
- 你知道Redis可以實現延遲佇列嗎?Redis佇列
- Delayed Message 外掛實現 RabbitMQ 延遲佇列MQ佇列
- 基於promise的阻塞式佇列設計Promise佇列
- 【RabbitMQ】一文帶你搞定RabbitMQ延遲佇列MQ佇列
- RabbitMQ 學習筆記 -- 12 死信佇列 DLX + TTL 方式實現延遲佇列MQ筆記佇列
- 基於訊息佇列 RocketMQ 的大型分散式應用上雲最佳實踐佇列MQ分散式
- 使用Chronicle Queue建立低延遲的TB級別的佇列 - DZone佇列
- Laravel 在事件監聽中實現佇列的方法以及指定加入的佇列名稱和佇列延遲時間Laravel事件佇列
- rabbitMQ 延遲佇列外掛強制呼叫ReturnCallback裡returnedMessage方法MQ佇列
- 你真的知道怎麼實現一個延遲佇列嗎?佇列
- Kafka 延時佇列&重試佇列Kafka佇列
- 訊息佇列-一篇讀懂rabbitmq(生命週期,confirm模式,延遲佇列,叢集)佇列MQ模式