erlang mnesia 节点同步数据

来源:互联网 发布:淘宝客域名备案 编辑:程序博客网 时间:2024/05/23 17:23
Mnesia的机制稍微有些奇怪, 今天一天都比较闲,于是测试study了下, 看看是如果动作. 

目标: 
  逐渐新增N个Mnesia节点,并确保数据在这些节点上保持同步. 

过程如下: 
1. Mnesia的分布式可以从一个节点开始, 然后慢慢新增. 
2. 新增加一个节点的时候, 首先要确保新节点上已经调用过mnesia:start() 
3. 在每个已知存活的节点上调用(可以用rpc:call)mnesia:change_config(extra_db_nodes, [NewNode]),这样可以通知每个节点, 有一个新的节点要加入进来了 
4. 改变NewNode上的schema表的存储方式: mnesia:change_table_copy_type(schema, NewNode, disc_copies) 
5. 重启动NewNode的Mnesia,并稍微等待一段时间.(这大概是由于远程新节点的schema改变后,不能及时反应的缘故,可能不是必要的) 
6. 向NewNode追加TableList : mensia:add_table_copy(Table, NewNode, disc_copies), 这里可能会调用多次,有多少用户表,就调用多少次 
---- Over All ---- 

上面的6步可以确保依次增加新的节点并确保数据同步. 
对应的代码如下: 
Erlang代码  收藏代码
  1. addNode(NewNode) ->  
  2.     io:format("New Node = ~p~n", [NewNode]),  
  3.     RunningNodeList = mnesia:system_info(running_db_nodes),  
  4.     io:format("-----------Adding Extra Node---------~n"),  
  5.     addExtraNode(RunningNodeList, NewNode),  
  6.     io:format("-----------Chang schema -> disc_copies---------~n"),  
  7.     Rtn = mnesia:change_table_copy_type(schema, NewNode, disc_copies),  
  8.     io:format("Rtn=~p~n", [Rtn]),  
  9.     io:format("-----------Reboot Remote Node Mnesia---------~n"),  
  10.     rpc:call(NewNode, mnesia, stop, []),  
  11.     timer:sleep(1000),  
  12.     rpc:call(NewNode, mnesia, start, []),  
  13.     timer:sleep(1000),  
  14.     io:format("-----------Adding Table List---------~n"),  
  15.     addTableList(?TableList, NewNode),  
  16.     io:format("-----------Over All---------~n").  
  17.   
  18. addExtraNode([], _NewNode) ->  
  19.     null;  
  20. addExtraNode(_RunningNodeList = [Node | T], NewNode) ->  
  21.     Rtn = rpc:call(Node, mnesia, change_config, [extra_db_nodes, [NewNode]]),  
  22.     io:format("Node = ~p, Rtn=~p~n", [Node, Rtn]),  
  23.     addExtraNode(T, NewNode).  
  24.   
  25. addTableList([], _NewNode) ->  
  26.     null;  
  27. addTableList(_TableList = [Table | T], NewNode) ->  
  28.     Rtn = mnesia:add_table_copy(Table, NewNode, disc_copies),  
  29.     io:format("Table = ~p, Rtn = ~p~n", [Table, Rtn]),  
  30.     addTableList(T, NewNode).  




额外的, 可能会有这种情况, 一个A节点可能已经断开了,然后一个新的B节点被追加了进来, 这个时候如果A节点在上线,可能检测不到B节点其实是于自己保持同步的,这样有可能造成数据不同步, 解决该问题的方法即调用net_adm:ping(Node) :即每一个新节点上线后,即mnesia:start()以后, 立即查找与自己相连接的节点(mnesia:system_info(db_nodes)),然后用net_adm:ping()去ping下每一个连接的node,告诉自己上来了,这样即可解决刚才的问题. 

对应的代码如下: 
Erlang代码  收藏代码
  1. -module(ping).  
  2. -compile(export_all).  
  3.   
  4. ping() ->  
  5.     case whereis(ping) of  
  6.         undefined ->  
  7.             null;  
  8.         OldPid ->  
  9.             OldPid ! {exit},  
  10.             unregister(ping)  
  11.     end,  
  12.     PingID = spawn(?MODULE, pingMain, []),  
  13.     register(ping, PingID),  
  14.     PingID.  
  15.   
  16. pingMain() ->  
  17.     AllNodeList = mnesia:system_info(db_nodes),  
  18.     pingList(AllNodeList),  
  19.     NodeListCount = length(AllNodeList),  
  20.     receiveMsg(00, NodeListCount).  
  21.   
  22. receiveMsg(PingOK, PingFailed, NodeListCount) ->  
  23.     receive  
  24.         {ping, Result} ->  
  25.             case Result of  
  26.                 true ->  
  27.                     NewPingOK = PingOK + 1,  
  28.                     NewPingFailed = PingFailed;  
  29.                 false ->  
  30.                     NewPingOK = PingOK,  
  31.                     NewPingFailed = PingFailed  + 1  
  32.             end,  
  33.             case (NewPingOK + NewPingFailed < NodeListCount) of  
  34.                 true ->  
  35.                     receiveMsg(NewPingOK, NewPingFailed, NodeListCount);  
  36.                 false ->  
  37.                     io:format("-------Ping Over---------~n"),  
  38.                     io:format("Ping OK = ~p~n", [NewPingOK]),  
  39.                     io:format("Ping Failed = ~p~n", [NewPingFailed])  
  40.             end;  
  41.         {exit} ->  
  42.             io:format("Receive to exit~n");  
  43.         _Any ->  
  44.             receiveMsg(PingOK, PingFailed, NodeListCount)  
  45.     after 30000 ->  
  46.         io:format("Error : Time out~n")  
  47.     end.  
  48.   
  49. pingList([])  ->  
  50.     null;  
  51. pingList(_NodeList = [Node | T]) ->  
  52.     spawn(?MODULE, pingOne, [Node]),  
  53.     pingList(T).  
  54.           
  55. pingOne(Node) ->  
  56.     Rtn = net_adm:ping(Node),  
  57.     PingID = whereis(ping),  
  58.     case Rtn of  
  59.         pong ->  
  60.             PingID ! {ping, true};  
  61.         pang ->  
  62.             PingID ! {ping, false}  
  63.     end.  

原创粉丝点击