問題現象: 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則是採用超時拋出異常中止運行。 源碼