rabbitmq——集群启动问题

问题现象: java

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

问题缘由: code

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

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}对应的值。 rem

若是对应的Table未加载,即为nowhere,而且Timeout设置为infinity,那么程序就会出现死等。 get

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

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