说说ejabberd 离线消息的坑
使用过ejabberd的或许知道,也许踩过这个坑。那么就说说我们踩过的ejabberd的离线消息的坑吧。
ejabberd原生的离线消息的机制是,一般用户保存100条离线消息,管理员保存5000条离线消息。超过之后竟然没有删除老的离线消息的机制。😓 仅仅是报一个警告。
max_user_offline_messages: - 5000: admin - 100
<<"Your contact offline message queue is " "full. The message has been discarded.">>
ejabberd原生的群聊是没有离线消息的,只要用户不在线,这期间其他群成员在群里面的聊天,不在线的用户上线后收不到这些消息的。
完全跟现在的一些即时聊天软件不一样,太不好耍了,而且一些客户都是按照某信的要求来看待的,对比一下就会发现这些问题,然后就是一堆的需求。
按照现在的即时聊天软件,我们在原来的基础上实现了群聊离线消息的机制,还添加多客户端消息同步的机制,那么一条离线消息就咬保存好几份了,然后的条数限制远远不够了,即使调了离线消息的配置(由原来的100改为2000),在一个群里面疯狂的聊天,一下子就满了。
好吧,那么就添加删除的机制吧,只要用户的离线消息大于配置的条数,那么就删除超出配置的老的离线消息。
%% 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,模块就会奔溃。
“As far as I know dets can only handle 2GB files not 4GB, 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数据库,改表吧。
一路磕磕碰碰的,献给那些走在路上的人和那些即将走到路上的人。
——————————
一名企业社交平台(www.joywok.com)的远程办公程序员,微博:代码改变世界
本文版权归本博作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接,否则保留追究法律责任的权利。