说说ejabberd 离线消息的坑

使用过ejabberd的或许知道,也许踩过这个坑。那么就说说我们踩过的ejabberd的离线消息的坑吧。

 

ejabberd原生的离线消息的机制是,一般用户保存100条离线消息,管理员保存5000条离线消息。超过之后竟然没有删除老的离线消息的机制。


1
2
3
max_user_offline_messages:
     - 5000: admin
     - 100

 

1
2
<< "Your contact offline message queue is "
"full. The message has been discarded." >>

  

ejabberd原生的群聊是没有离线消息的,只要用户不在线,这期间其他群成员在群里面的聊天,不在线的用户上线后收不到这些消息的。

完全跟现在的一些即时聊天软件不一样,太不好耍了,而且一些客户都是按照某信的要求来看待的,对比一下就会发现这些问题,然后就是一堆的需求。

 

按照现在的即时聊天软件,我们在原来的基础上实现了群聊离线消息的机制,还添加多客户端消息同步的机制,那么一条离线消息就咬保存好几份了,然后的条数限制远远不够了,即使调了离线消息的配置(由原来的100改为2000),在一个群里面疯狂的聊天,一下子就满了。

好吧,那么就添加删除的机制吧,只要用户的离线消息大于配置的条数,那么就删除超出配置的老的离线消息。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
%% Warn senders that their messages have been discarded:
% discard_warn_sender(Msgs) ->
%     lists:foreach(fun (#offline_msg{from = From, to = To,
%                   packet = Packet}) ->
%             ErrText = <<"Your contact offline message queue is "
%                     "full. The message has been discarded.">>,
%             Lang = xml:get_tag_attr_s(<<"xml:lang">>, Packet),
%             Err = jlib:make_error_reply(Packet,
%                             ?ERRT_RESOURCE_CONSTRAINT(Lang,
%                                       ErrText)),
%             ejabberd_router:route(To, From, Err)
%         end,
%         Msgs).
discard_warn_sender( US Msgs Count MaxOfflineMsgs , mnesia) ->
     ?INFO_MSG ( "Begin to discard offline msgs at time:~s" , [ erlang:timestamp ()]),
     R =  mnesia:select (offline_msg,[{#offline_msg{us =  US , _= '_' },[],[ '$_' ]}]),
     Rsort  lists:sort ( fun (A, B) -> A#offline_msg.timestamp < B#offline_msg.timestamp  end ,R),
     {M, _} =  lists:split ( Count  MaxOfflineMsgs Rsort ),
     F =  fun () ->
         lists:foreach ( fun (X) ->
             mnesia:delete_object (X)
         end ,M),
         if  Count  MaxOfflineMsgs  >= ( ?OFFLINE_TABLE_LOCK_THRESHOLD ) ->
                   mnesia:write_lock_table (offline_msg);
             true -> ok
         end ,
         lists:foreach ( fun  (N) ->  mnesia:write (N)  end Msgs )
     end ,
     mnesia:transaction (F),
     ?INFO_MSG ( "Discard offline msgs:~w" , [M]),
     ?INFO_MSG ( "End to discard offline msgs at time:~s" , [ erlang:timestamp ()]);

改造了一些源代码,思路就是先查询到所有的离线消息,排序删除老的离线消息。(本来不熟悉erlang的,业务需求硬着头皮改的。大家轻喷)

 

然后呢,又有效率问题。只要用户离线消息满了,就会一直循环这个删除动作,不停的查询所有的离线消息,删掉超出的部分。

既然这样,那就不限制离线消息的条数了。注释掉这个方法,测试一下静观其变吧。

 

好吧,即使这样还是有问题。mnsia的offline_msg表只要超过2G,模块就会奔溃。

1
As  far as I know dets can only handle 2 GB  files  not  4 GB , which will be the limit for disc_copies.  There  is an experimental 64-bit dets which can handle much larger files but no one has used it in production yet. –  Happi 

查到一些资料,Mnesia 单表的存储容量(Dets)目前只能处理2G。由于现在我们是 disc_only_copies,即现在离线消息占用的应该是磁盘。目前 Offline Mod 崩溃都是离线消息存储到达 2G 的时候,所以推测是触到 Mnesia 单表处理上线了。

这个就真的没有办法,那就只能将离线消息保存到MySQL中了,原生的本来就支持ODBC。

 

按照一些教程配置吧,很快就好了。主要是在mod_offline模块添加db_type:odbc就行。

额,又有小问题,emoji问题,那就又搜教程配置MySQL数据库,改表吧。

 

一路磕磕碰碰的,献给那些走在路上的人和那些即将走到路上的人。


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值