erlang mnesia 脏写的性能瓶颈和解决办法
来源:互联网 发布:mac用office 编辑:程序博客网 时间:2024/06/09 19:51
mnesia脏写的话和脏读最大的区别是要同步数据,假如一个项目有3个节点A,B,C。在A节点脏写一个数据,这个操作需要2步,1,对本地节点的mnesia写入数据。2,对B,C两个节点发消息,告诉他们要脏写一个数据,然后等待他们回应,B,C两个节点全部返回确认消息后整个操作才算完成。
做了一下测试:
1.当单独一个节点时,并发100000个进程去脏写mnesia,平均每次的耗时是18微秒左右。
2.但是2个节点的话,并发100000个进程去脏写mnesia,平均每次的耗时是54微秒左右。
3.而3个节点的话,并发100000个进程去脏写mnesia,平均每次的耗时是82微秒左右。
也就是说同步这个操作就是脏读的瓶颈所在了,随着节点的增加,同步耗费的时间越高。
那么怎么解决这个问题呢?首先要明白mnesia的dirty_write的运行过程,才能找到解决办法。那么其他节点收到同步的信息后怎么处理的呢?
当A节点的dirty_write被调用后,会对包括自己在内的所有节点发送一个{From, {sync_dirty, Tid, Commit, Tab}}消息,然后mnesia_tm的进程收到后判断需要操作的表是否在被用,如果是blocked的话,则把操作放入一个dirty_queue里面存储在自己的state中。当mnesia_tm处理完一个请求后,就会给From发送一个确认消息。当A收到所有节点发回的确认后,dirty_write操作完成。
现在能改动的就是尽量减少blocked的情况出现,最好就是所有的同步请求都能及时处理然后回发确认。所以我们要分表,分表的越多,遇到同表锁住的情况越少。
分表后做了个测试:
1.还是3个节点,并且分3张表,并发100000个进程去脏写mnesia,平均每次的耗时是54微秒左右。
2.还是3个节点,并且分4张表,并发100000个进程去脏写mnesia,平均每次的耗时是28微秒左右。
由此看出,性能有较大的提升,证明分表是个不错的解决方案。
下面是测试的代码:
Erlang代码 收藏代码
-module (test_mnesia_split).
-export ([start/0, dw/0, tdw/0, stop/0, dw1/0, tdw1/0]).
-record (test_mnesia, {userid, pid}).
-record (test_mnesia1, {userid, pid}).
-record (test_mnesia2, {userid, pid}).
-record (test_mnesia3, {userid, pid}).
//娱乐世界http://www.sj523.com/xtgg/
start() ->
NodeList = node_list(),
rpc_call(mnesia, stop, [], stopped),
mnesia:delete_schema(NodeList),
mnesia:create_schema(NodeList),
rpc_call(mnesia, start, [], ok),
{atomic,ok} = mnesia:create_table(test_mnesia, [{ram_copies, NodeList},
{attributes, record_info(fields, test_mnesia)}]),
{atomic,ok} = mnesia:create_table(test_mnesia1, [{ram_copies, NodeList},
{attributes, record_info(fields, test_mnesia1)}]),
{atomic,ok} = mnesia:create_table(test_mnesia2, [{ram_copies, NodeList},
{attributes, record_info(fields, test_mnesia2)}]),
{atomic,ok} = mnesia:create_table(test_mnesia3, [{ram_copies, NodeList},
{attributes, record_info(fields, test_mnesia3)}]),
{atomic,ok} = mnesia:add_table_index(test_mnesia, pid),
rpc_call(mnesia, stop, [], stopped).
stop() ->
NodeList = node_list(),
rpc_call(mnesia, stop, [], stopped),
mnesia:delete_schema(NodeList).
dw() ->
<<A:32, B:32, C:32>> = crypto:strong_rand_bytes(12),
random:seed (A, B, C),
Random = random:uniform(3),
UserId = <<"user_1@android">>,
mnesia:dirty_write(#test_mnesia{userid = UserId, pid = UserId}).
tdw() ->
tc:ct(?MODULE, dw, [], 100000).
dw1() ->
<<A:32, B:32, C:32>> = crypto:strong_rand_bytes(12),
random:seed (A, B, C),
Random = random:uniform(3),
UserId = <<"user_1@android">>,
case Random of
1 ->
mnesia:dirty_write(#test_mnesia1{userid = UserId, pid = UserId});
2 ->
mnesia:dirty_write(#test_mnesia2{userid = UserId, pid = UserId});
3 ->
mnesia:dirty_write(#test_mnesia3{userid = UserId, pid = UserId});
_ ->
mnesia:dirty_write(#test_mnesia{userid = UserId, pid = UserId})
end.
tdw1() ->
tc:ct(?MODULE, dw1, [], 100000).
%% ===================================================================
%% Internal functions
%% ===================================================================
node_list() ->
[node() | nodes()].
rpc_call(Module, Function, Args, Result) ->
rpc_call(node_list(), Module, Function, Args, Result).
rpc_call([H|T], Module, Function, Args, Result) ->
Result = rpc:call(H, Module, Function, Args),
rpc_call(T, Module, Function, Args, Result);
rpc_call([], _, _, _, _) ->
ok.
做了一下测试:
1.当单独一个节点时,并发100000个进程去脏写mnesia,平均每次的耗时是18微秒左右。
2.但是2个节点的话,并发100000个进程去脏写mnesia,平均每次的耗时是54微秒左右。
3.而3个节点的话,并发100000个进程去脏写mnesia,平均每次的耗时是82微秒左右。
也就是说同步这个操作就是脏读的瓶颈所在了,随着节点的增加,同步耗费的时间越高。
那么怎么解决这个问题呢?首先要明白mnesia的dirty_write的运行过程,才能找到解决办法。那么其他节点收到同步的信息后怎么处理的呢?
当A节点的dirty_write被调用后,会对包括自己在内的所有节点发送一个{From, {sync_dirty, Tid, Commit, Tab}}消息,然后mnesia_tm的进程收到后判断需要操作的表是否在被用,如果是blocked的话,则把操作放入一个dirty_queue里面存储在自己的state中。当mnesia_tm处理完一个请求后,就会给From发送一个确认消息。当A收到所有节点发回的确认后,dirty_write操作完成。
现在能改动的就是尽量减少blocked的情况出现,最好就是所有的同步请求都能及时处理然后回发确认。所以我们要分表,分表的越多,遇到同表锁住的情况越少。
分表后做了个测试:
1.还是3个节点,并且分3张表,并发100000个进程去脏写mnesia,平均每次的耗时是54微秒左右。
2.还是3个节点,并且分4张表,并发100000个进程去脏写mnesia,平均每次的耗时是28微秒左右。
由此看出,性能有较大的提升,证明分表是个不错的解决方案。
下面是测试的代码:
Erlang代码 收藏代码
-module (test_mnesia_split).
-export ([start/0, dw/0, tdw/0, stop/0, dw1/0, tdw1/0]).
-record (test_mnesia, {userid, pid}).
-record (test_mnesia1, {userid, pid}).
-record (test_mnesia2, {userid, pid}).
-record (test_mnesia3, {userid, pid}).
//娱乐世界http://www.sj523.com/xtgg/
start() ->
NodeList = node_list(),
rpc_call(mnesia, stop, [], stopped),
mnesia:delete_schema(NodeList),
mnesia:create_schema(NodeList),
rpc_call(mnesia, start, [], ok),
{atomic,ok} = mnesia:create_table(test_mnesia, [{ram_copies, NodeList},
{attributes, record_info(fields, test_mnesia)}]),
{atomic,ok} = mnesia:create_table(test_mnesia1, [{ram_copies, NodeList},
{attributes, record_info(fields, test_mnesia1)}]),
{atomic,ok} = mnesia:create_table(test_mnesia2, [{ram_copies, NodeList},
{attributes, record_info(fields, test_mnesia2)}]),
{atomic,ok} = mnesia:create_table(test_mnesia3, [{ram_copies, NodeList},
{attributes, record_info(fields, test_mnesia3)}]),
{atomic,ok} = mnesia:add_table_index(test_mnesia, pid),
rpc_call(mnesia, stop, [], stopped).
stop() ->
NodeList = node_list(),
rpc_call(mnesia, stop, [], stopped),
mnesia:delete_schema(NodeList).
dw() ->
<<A:32, B:32, C:32>> = crypto:strong_rand_bytes(12),
random:seed (A, B, C),
Random = random:uniform(3),
UserId = <<"user_1@android">>,
mnesia:dirty_write(#test_mnesia{userid = UserId, pid = UserId}).
tdw() ->
tc:ct(?MODULE, dw, [], 100000).
dw1() ->
<<A:32, B:32, C:32>> = crypto:strong_rand_bytes(12),
random:seed (A, B, C),
Random = random:uniform(3),
UserId = <<"user_1@android">>,
case Random of
1 ->
mnesia:dirty_write(#test_mnesia1{userid = UserId, pid = UserId});
2 ->
mnesia:dirty_write(#test_mnesia2{userid = UserId, pid = UserId});
3 ->
mnesia:dirty_write(#test_mnesia3{userid = UserId, pid = UserId});
_ ->
mnesia:dirty_write(#test_mnesia{userid = UserId, pid = UserId})
end.
tdw1() ->
tc:ct(?MODULE, dw1, [], 100000).
%% ===================================================================
%% Internal functions
%% ===================================================================
node_list() ->
[node() | nodes()].
rpc_call(Module, Function, Args, Result) ->
rpc_call(node_list(), Module, Function, Args, Result).
rpc_call([H|T], Module, Function, Args, Result) ->
Result = rpc:call(H, Module, Function, Args),
rpc_call(T, Module, Function, Args, Result);
rpc_call([], _, _, _, _) ->
ok.
0 0
- erlang mnesia 脏写的性能瓶颈和解决办法
- Erlang Mnesia数据库的备份和还原
- mnesia的脏写和事物写的测试
- erlang的mnesia总结
- erlang的mnesia
- 最近研究Erlang的mnesia
- erlang mnesia表的遍历
- erlang mnesia
- erlang mnesia
- erlang中mnesia的动态加载
- [Erlang]Mnesia的备份与还原
- erlang 中 mnesia 的使用实例
- [Erlang]Mnesia分布式应用
- [Erlang]Mnesia常用技巧
- Erlang数据库Mnesia操作
- erlang mnesia 分布式应用
- erlang mnesia 遍历
- Erlang 之 Mnesia error
- POJ 1218 THE DRUNK JAILER
- struts2 学习之 redirectAction初步认识
- AndroidStudio启动时发生The environment variable JAVA_HOMExxxdoes not point to a valid jvm installation的错误
- 删除AX的表
- 平衡二叉树实现的实例
- erlang mnesia 脏写的性能瓶颈和解决办法
- 华为OJ(计算日期到天数转换)
- 阿里校招 数据分析师 笔试题
- 设计模式之桥接
- java学习记录笔记--继承,super,Object类
- java 字节流和字符流的区别 转载
- Android编译系统环境初始化过程分析3
- C++中的智能指针
- Eclipse打开-报错:发现了以元素 ‘d:skin’ 开头的无效内容。此处不应含有子元素(解决方法)