问题现象: 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则是采用超时抛出异常中止运行。 源码