rabbitmq——集群启动问题

原创
2015/01/14 14:55
阅读数 978

问题现象:

mnesia集群中的节点全部停止,然后再次启动,偶然出现所有节点都在一直等待数据同步的现象。

问题原因:

翻看相关源码后发现问题:

mnesia_contorller.erl
%% 选择可以进行数据加载的 table
initial_safe_loads() ->
    case val({schema, storage_type}) of
        ram_copies ->
            %% 如果表为仅在内存中存储, 可以直接加载
            %% 因此停止前记录的 down 掉的节点设置为 []
            Downs = [],
            Tabs = val({schema, local_tables}) -- [schema],
            LastC = fun(T) -> last_consistent_replica(T, Downs) end,
            lists:zf(LastC, Tabs);
        disc_copies ->
            %% 如果表为 磁盘存储, 需要判断停止前集群节点的存活状态
            Downs = mnesia_recover:get_mnesia_downs(),
            Tabs = val({schema, local_tables}) -- [schema],
            LastC = fun(T) -> last_consistent_replica(T, Downs) end,
            lists:zf(LastC, Tabs)
    end.

last_consistent_replica(Tab, Downs) ->
    %% 查找表结构信息
    Cs = val({Tab, cstruct}),
    %% 查找该表所有复制的节点信息
    Copies = mnesia_lib:copy_holders(Cs),
    ...
    %% 查找可以用来复制的远端节点
    %% 注意 是远端节点 表示除去了节点本身
    %% 另外 集群中先于本节点停止的节点需排除
    BetterCopies0 = mnesia_lib:remote_copy_holders(Cs) -- Downs,
    ...
    if
        %% 该表仅在本节点进行拷贝复制
        Copies == [node()] ->
            {true, {Tab, local_only}};
        ...
        %% 不是集群中最后一个停止的节点
        %% 为防止可能的数据不一致 需从远端记载数据
        BetterCopies /= [], Masters /= [node()] ->
            false;
        %% 
        true ->
            {true, {Tab, initial}}
    end.

这么一来,不是集群中最后一个停止的节点先启动时,对于disc存储类型的表,都不会进行加载。并且在mneia_gvar会记录{{Tab, where_to_read}, nowhere}。

调用mnesia:wait_for_tables(Tabs, Timeout)后最终会在mnesia_gvar中查找{Tab, where_to_read}对应的值。

如果对应的Table未加载,即为nowhere,并且Timeout设置为infinity,那么程序就会出现死等。

如果Timeout设置为具体的值,那么超时仍未完成加载的话,需要业务根据实际需求进行特殊处理。通常是抛出异常让程序无法正常启动。

注:ejabberd采用的死等的方式,rabbitmq则是采用超时抛出异常停止运行。

展开阅读全文
加载中
点击引领话题📣 发布并加入讨论🔥
0 评论
0 收藏
0
分享
返回顶部
顶部