說說ejabberd離線消息踩過的坑

使用過ejabberd的或許知道,也許踩過這個坑。那麼就說說咱們踩過的ejabberd的離線消息的坑吧。數據庫

ejabberd原生的離線消息的機制是,通常用戶保存100條離線消息,管理員保存5000條離線消息。超過以後居然沒有刪除老的離線消息的機制。😓 僅僅是報一個警告。app

1測試

2spa

3code

max_user_offline_messages:router

    - 5000: adminxml

    - 100排序

1教程

2ci

<<"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(USMsgsCountMaxOfflineMsgs, 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 MaxOfflineMsgsRsort),

    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) endMsgs)

    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 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數據庫,改表吧。

 

一路磕磕碰碰的,獻給那些走在路上的人和那些即將走到路上的人。

相關文章
相關標籤/搜索