閱讀932 返回首頁    go 阿裏雲 go 技術社區[雲棲]


最佳實踐:如何基於消息服務MNS實現嚴格有序隊列

問題背景
阿裏消息服務提供的隊列(queue)主要特點是高可靠、高可用、高並發。每個隊列的數據都會被持久化三份到阿裏雲的飛天分布式平台;其中每個隊列至少有2台服務器向外提供服務;同時每台服務器都支持高並發訪問。這些分布式特性,也導致了消息服務隊列無法像傳統單機隊列那樣保證嚴格的消息FIFO特點,隻能做到基本有序。


我們的隊列如果同時有多個消息發送者(sender),由於並發和網絡延遲不一等問題,消息的嚴格順序本身就是失去了意義,因為在這種情況下,我們根本無法獲知消息在多個sender上的實際發送順序和消息到達服務器端的真實順序。同樣的,當有多個接收者並發接收消息時,其真正的處理順序也是不可獲知的。

因此,我們認為隻有一個發送者(一個進程,可以是多個線程), 一個接收者時,消息順序才有意義,也隻有在這種情況下我們能夠感知和記錄消息的真實發送順序和消息的真實接收順序。

解決方案
基於上述假設,同時為了滿足部分用戶對於消息消費順序性的要求,我們設計了下麵的方案,確保消息按照用戶發送順序被接收和消費。
主要步驟:
1.消息在發送端進行染色,加上SeqId(例如:#num#)
2.消息在接收端進行還原,並根據SeqId 排序後返回給上層,同時對於已經receive的消息會有後台線程保證消息不會被重複消費。
3.為了避免因為發送者fail,或者接收者fail,導致seqid 丟失。seqid 會被持久存儲到本地磁盤文件。
   當然也可以存儲到其他存儲或數據庫:例如OSS,OTS,RDS
240_1365541074971606_dcf0b3cd382d9d5.png
程序說明
附件提供了python版的方案實現(依賴MNS Python SDK)。其中,主要提供了OrderedQueueWrapper 類(oredered_queue.py文件),可以將普通的mns queue包裝成有序queue。
OrderedQueueWrapper  提供兩個方法:SendMessageInOrder()和ReceiveMessageInOrder()。send中對消息進行染色,receive還原消息,並且按順序返回給接收者。

另外,send_message_in_order.py和receive_message_in_order.py提供了發送者和接收者使用OrderedQueueWrapper的程序示例。
send_message_in_order.py:
    #init orderedQueue
    seqIdConfig = {"localFileName":"/tmp/mns_send_message_seq_id"}   # 指定持久化發送SeqId的磁盤文件。
    seqIdPS = LocalDiskStorage(seqIdConfig)
    orderedQueue = OrderedQueueWrapper(myQueue, sendSeqIdPersistStorage = seqIdPS)
    orderedQueue.SendMessageInOrder(message)

receive_message_in_order.py:
    #init orderedQueue
    seqIdConfig = {"localFileName":"/tmp/mns_receive_message_seq_id"} #指定持久化接收SeqId的磁盤文件
    seqIdPS = LocalDiskStorage(seqIdConfig)
    orderedQueue = OrderedQueueWrapper(myQueue, receiveSeqIdPersistStorage = seqIdPS)
    recv_msg = orderedQueue.ReceiveMessageInOrder(wait_seconds)


運行方法:
1.配置send_message_in_order.py 和receive_message_in_order.py 中下列配置
g_endpoint,g_accessKeyId,g_accessKeySecret,g_testQueueName 
2.運行send_message_in_order.py
3.運行receive_message_in_order.py (可以不用等步驟2程序運行完成)
發送程序會發送20條消息,接收程序會按順序消費20條消息
240_1365541074971606_9530b6f93c549f4.png


也可以運行oredered_queue.py (需配置endpoint 和AK)的測試case對比普通mns queue的區別:
運行命令:$python oredered_queue.py
非嚴格有序:(整體有序,部分相鄰消息無序,同時側麵證明MNS 的單個queue同時有多個服務器在提供服務)
240_1365541074971606_0a406a4c540529a.png



嚴格有序:
240_1365541074971606_4971ecb1f2f1a91.png

注意事項:
1.本帖主要目的是展示順序消息的解決方案,本帖中的代碼未經過嚴格測試,不建議不加測試直接用於生產環境。同時程序倉促完成,難免由瑕疵,歡迎回帖指正。
2.正常情況下,發送端和接收端的seqid應該和queue中的消息(染色)匹配,當出現刪除queue重新創建等操作時,請注意磁盤文件中的seqid 是否和queue中的真實情況相符,同時建議不要往染色的消息隊列裏發送非染色消息。
3.隊列的消息有效期設置過短或者每條消息的實際處理結果都有可能會對消息有序性造成影響,在您的程序中需要對這些情況所導致的的亂序現象進行處理。


示例程序下載:
zip.gif ordered_queue_wrapper.tar.gz (4 K) 

最後更新:2017-04-01 13:37:05

  上一篇:go 支付寶錢包客戶端技術架構
  下一篇:go 手機淘寶客戶端架構探索實踐