2015-10-28 87 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,卡桑德拉等