2015-10-28 47 views
0

我正在編寫一個ejabberd模塊,用戶控制何時將消息發送給接收者而不是立即發送(如提前發送的生日祝福)。這是通過添加自定義XML元素的消息節像下面Mnesia數據庫設計用於存儲將來需要發送的消息

<message xmlns="jabber:client" from="[email protected]" to="[email protected]/32375806281445450055240436" type="chat"> 
    <schedule xmlns="ank" year="2015" month="10" day="19" hour="22" minute="36" second="13"/> 
    <body>hi</body> 
</message> 

現在這些計劃的消息,必須存儲在Mnesia數據庫和發送給收件人當時間到達完成。

方法1: 一種方法是創建一個表爲每個用戶,當收到消息,存儲消息到用戶表,並設置一個計時器來處理 消息,並刪除時像下面的做示例代碼

timer:apply_after(SecondsDelay, ?MODULE, post_message_delete, [TableName, RecordUniqueKeyHash, From, To, Packet]). 

post_message_delete方法將發送該消息的定時器超時使用路由方法顯示在以下和刪除Mnesia數據庫記錄後,當被調用。

ejabberd_router:route(From, To, Packet) 

由於mnesia中表的數量限制,爲每個用戶創建表是不可行的。

方法2: 另一種方法是所有的用戶的消息存儲在一個單獨的表,並作爲消息到達並且一旦處理消息刪除它設置爲每一個消息中的計時器(與上述相同)。

使用mnesia數據庫的整個想法是在ejabberd服務器崩潰的情況下可靠地處理消息。

爲了達到這個目的,我們在每條消息的記錄中使用一個pid字段。每個消息記錄都有一個pid字段,其中包含正在處理此消息的進程的pid。最初,它是未定義的(當消息到達filter_packet掛鉤時),但在生成消息處理方法後,它將更新mnesia數據庫中的記錄中的pid。

因此,如果服務器在模塊啓動方法重新啓動時崩潰,則所有消息都會迭代並檢查pid是否處於活動狀態(is_process_alive),如果沒有活動,則會在消息中產生處理方法,處理消息並刪除一次。

缺點 這種方法的缺點是,即使消息必須在未來(下個月或明年)仍然是一個進程正在運行此消息遠交付並有運行的儘可能多的進程有儘可能多的消息。

方法3:

要在來到方法二的缺點,掃描數據庫每隔一小時,並積累有下一個小時,僅投放和處理它的消息。

這種方法的缺點是數據庫每小時掃描一次可能會影響性能。

方法4:

要在來到方法3的性能,我們可以爲每一個YEAR_MONTH表和產卵只對當前月表的消息處理函數。

什麼其他方法最適合使用mnesia數據庫的這種用例?

+0

我相信這個問題可能是基於堆棧溢出的一種觀點,但可以在http://programmers.stackexchange.com中找到,因爲他們的幫助中心指出[「軟件架構和設計」](http://programmers.stackexchange .com/help/on-topic)在那裏。這個問題實際上並不是erlang特有的。 – Lol4t0

+0

@ Lol4t0指其他網站時,它往往是有幫助的那點(http://meta.stackexchange.com/tags/cross-posting/info) – gnat

+0

@gnat [交叉張貼是令人難以接受的],嘿嘿!但這仍然不意味着問題不會移到正確的地方!如果你有重複的_wrong place_職位應該被刪除。 – Lol4t0

回答

1

即使這是一個老問題,但它有一天可能成爲別人的問題。

我認爲mnesia是這種數據存儲用例的錯誤選擇。 Redis 2.8.0版具有密鑰空間事件通知功能,當執行某些操作時,包括密鑰過期命令由EXPIREEXPIREAT和其他變體。此信息可以通過PUBSUB功能達到您的代碼。請參閱Redis Keyspace Notifications 關於如何開始。

生成一個唯一的密鑰(K)可能爲UUID爲每個生日消息。 將消息(整個XML)存儲在給定生成的K下發送。

商店作爲被叫K鍵下一個值該消息鍵:計時器使用SET命令與TTL設置爲現在和以秒爲生日時間戳OR之間的時間差使用EXPIREAT將消息到期時間設置爲生日本身的Unix時間戳。當TTL到期時,pubsub客戶端會收到有關密鑰信息過期的事件通知K:計時器。提取K並使用它獲取消息。發送消息並在之後刪除。

問題需要考慮:

1:多個發佈 - 訂閱的客戶可能會通知同期滿事件的。這可能會導致同一消息被多次發送。實施某種鎖定來防止這種情況發生。

2: Redis PUBSUB是一個消防和遺忘的消息傳遞構造。因此,如果客戶宕機再次出現,則可能在此時段內錯過了事件通知。確保可靠性的一種方式是將密鑰K存儲在K:定時器,K:定時器:1,K:定時器:2,K:定時器:3,......的不同密鑰變體中,增加TTL偏移量(1,2,3之間的分鐘),以針對可用客戶端可用的最差時間窗口。

3: Redis的是在存儲器中。存儲大量的大量消息將花費你的RAM。解決這個的一種方法是僅存儲消息密鑰ķ在redis的和消息(XML)使用相同的密鑰存儲,ķ,在任何磁盤基鍵值存儲像了Riak,卡桑德拉等