天天看點

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

問題背景:

阿裡雲消息服務提供的隊列(queue)主要特點是高可靠、高可用、高并發。每個隊列的資料都會被持久化三份到阿裡雲的飛天分布式平台;其中每個隊列至少有2台伺服器向外提供服務;同時每台伺服器都支援高并發通路。這些分布式特性,也導緻了消息服務隊列無法像傳統單機隊列那樣保證嚴格的消息fifo特點,隻能做到基本有序。

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

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

解決方案:

基于上述假設,同時為了滿足部分使用者對于消息消費順序性的要求,我們設計了下面的方案,確定消息按照使用者發送順序被接收和消費。

主要步驟:

1.消息在發送端進行染色,加上seqid(例如:#num#)

2.消息在接收端進行還原,并根據seqid 排序後傳回給上層,同時對于已經receive的消息會有背景線程保證消息不會被重複消費。

3.為了避免因為發送者fail,或者接收者fail,導緻seqid 丢失。seqid 會被持久存儲到本地磁盤檔案。

   當然也可以存儲到其他存儲或資料庫:例如oss,ots,rds

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

程式說明:

附件提供了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:

    seqidconfig = {"localfilename":"/tmp/mns_receive_message_seq_id"} #指定持久化接收seqid的磁盤檔案

    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條消息

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

也可以運作oredered_queue.py (需配置endpoint 和ak)的測試case對比普通mns queue的差別:

運作指令:$python oredered_queue.py

非嚴格有序:(整體有序,部分相鄰消息無序,同時側面證明mns 的單個queue同時有多個伺服器在提供服務)

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

嚴格有序:

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

注意事項:

1.本帖主要目的是展示順序消息的解決方案,本帖中的代碼未經過嚴格測試,不建議不加測試直接用于生産環境。同時程式倉促完成,難免由瑕疵,歡迎回帖指正。

2.正常情況下,發送端和接收端的seqid應該和queue中的消息(染色)比對,當出現删除queue重新建立等操作時,請注意磁盤檔案中的seqid 是否和queue中的真實情況相符,同時建議不要往染色的消息隊列裡發送非染色消息。

3.隊列的消息有效期設定過短或者每條消息的實際處理結果都有可能會對消息有序性造成影響,在您的程式中需要對這些情況所導緻的的亂序現象進行處理。

示例程式下載下傳:

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

 ordered_queue_wrapper.tar.gz (4 k)