`
wudixiaotie
  • 浏览: 139844 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

erlang mnesia 脏读性能测试

 
阅读更多

mnesia有2种方式脏读数据,一种是以Key的方式用dirty_read(Tab, Key),一种是以其他建立索引的字段读取dirty_index_read(Tab, OtherKey, Position).最开始以为这两个的速度是一样的,结果一侧是发现第一种是第二种的将近3倍。测试是用1千万的数据,10万的进程并发访问。

测试用的代码:

-module (tm).

-behaviour (gen_server).

% APIs
-export([start_link/0, find/1, find1/1, ct/0, ct1/0]).

% gen_server callbacks
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
          terminate/2, code_change/3]).

-record (test_mnesia, {userid, pid}).


start_link() ->
    gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
find(UserId) ->
    mnesia:dirty_read(test_mnesia, UserId).
find1(UserId) ->
    mnesia:dirty_index_read(test_mnesia, UserId, #test_mnesia.pid).
ct() ->
    tc:ct(tm, find, [<<"user_1@android">>], 100000).
ct1() ->
    tc:ct(tm, find1, [<<"user_1@android">>], 100000).
    
    
%% ===================================================================
%% gen_server callbacks
%% ===================================================================

init([]) ->
    mnesia:stop(),
    mnesia:delete_schema([node()]),
    mnesia:create_schema([node()]),
    mnesia:start(),
    {atomic,ok} = mnesia:create_table(test_mnesia, [{ram_copies, [node()]},
                                                    {attributes, record_info(fields, test_mnesia)}]),
    {atomic,ok} = mnesia:add_table_index(test_mnesia, pid),
    loop(10000000),
    {ok, []}.
handle_call(_Request, _From, State) ->
    {reply, nomatch, State}.
handle_cast(_Msg, State) ->
    {noreply, State}.
handle_info(_Info, State) ->
    {noreply, State}.
terminate(_Reason, _State) -> ok.
code_change(_OldVer, State, _Extra) -> {ok, State}.


%% ===================================================================
%% Internal functions
%% ===================================================================
loop(N) when N > 0 ->
    UserId = <<"user_", (integer_to_binary(N))/binary, "@android">>,
    mnesia:dirty_write(#test_mnesia{userid = UserId, pid = UserId}),
    loop(N - 1);
loop(0) ->
    ok.

tc的代码:

%% ===================================================================
%% Author xiaotie
%% 2015-07-30
%% 单进程循环测试:LoopTimes是循环次数
%% tc:t(Module, Function, ArgsList, LoopTimes).
%% 多进程并发测试:SpawnProcessesCount是并发的进程数
%% tc:ct(Module, Function, ArgsList, SpawnProcessesCount).
%% ===================================================================

-module (tc).

-export ([t/4, ct/4]).


tc(M, F, A) ->
    {Microsecond, _} = timer:tc (M, F, A),
    Microsecond.

distribution(List, Aver) ->
    distribution(List, Aver, 0, 0).
distribution([H|T], Aver, Greater, Less) ->
    case H > Aver of
        true ->
            distribution(T, Aver, Greater + 1, Less);
        false ->
            distribution(T, Aver, Greater, Less + 1)
    end;
distribution([], _Aver, Greater, Less) ->
    {Greater, Less}.

%% ===================================================================
%% test: one process test N times
%% ===================================================================

t(M, F, A, N) ->
    {Max, Min, Sum, Aver, Greater, Less} = loop ({M, F, A}, N),
    io:format ("=====================~n"),
    io:format ("execute [~p] times of {~p, ~p, ~p}:~n", [N, M, F, A]),
    io:format ("Maximum: ~p(μs)\t~p(s)~n", [Max, Max / 1000000]),
    io:format ("Minimum: ~p(μs)\t~p(s)~n", [Min, Min / 1000000]),
    io:format ("Sum: ~p(μs)\t~p(s)~n", [Sum, Sum / 1000000]),
    io:format ("Average: ~p(μs)\t~p(s)~n", [Aver, Aver / 1000000]),
    io:format ("Greater: ~p~nLess: ~p~n", [Greater, Less]),
    io:format ("=====================~n").


loop({M, F, A}, N) ->
    loop ({M, F, A}, N, 1, 0, 0, 0, []).

loop({M, F, A}, N, I, Max, Min, Sum, List) when N >= I ->
    Microsecond = tc (M, F, A),
    NewSum = Sum + Microsecond,
    if
        Max == 0 ->
            NewMax = NewMin = Microsecond;
        Max < Microsecond ->
            NewMax = Microsecond,
            NewMin = Min;
        Min > Microsecond ->
            NewMax = Max,
            NewMin = Microsecond;
        true ->
            NewMax = Max,
            NewMin = Min
    end,
    loop ({M, F, A}, N, I + 1, NewMax, NewMin, NewSum, [Microsecond|List]);
loop({_M, _F, _A}, N, _I, Max, Min, Sum, List) ->
    Aver = Sum / N,
    {Greater, Less} = distribution(List, Aver),
    {Max, Min, Sum, Aver, Greater, Less}.

%% ===================================================================
%% Concurrency test: N processes each test one time
%% ===================================================================

ct(M, F, A, N) ->
    {Max, Min, Sum, Aver, Greater, Less} = cloop ({M, F, A}, N),
    io:format ("=====================~n"),
    io:format ("spawn [~p] processes of {~p, ~p, ~p}:~n", [N, M, F, A]),
    io:format ("Maximum: ~p(μs)\t~p(s)~n", [Max, Max / 1000000]),
    io:format ("Minimum: ~p(μs)\t~p(s)~n", [Min, Min / 1000000]),
    io:format ("Sum: ~p(μs)\t~p(s)~n", [Sum, Sum / 1000000]),
    io:format ("Average: ~p(μs)\t~p(s)~n", [Aver, Aver / 1000000]),
    io:format ("Greater: ~p~nLess: ~p~n", [Greater, Less]),
    io:format ("=====================~n").


cloop({M, F, A}, N) ->
    CollectorPid = self(),
    ok = loop_spawn({M, F, A}, CollectorPid, N),
    collector(0, 0, 0, N, 1, []).


loop_spawn({M, F, A}, CollectorPid, N) when N > 0 ->
    spawn_link(fun() -> worker({M, F, A}, CollectorPid) end),
    loop_spawn({M, F, A}, CollectorPid, N - 1);
loop_spawn(_, _, 0) ->
    ok.

collector(Max, Min, Sum, N, I, List) when N >= I ->
    receive
        {result, Microsecond} ->
            NewSum = Sum + Microsecond,
            if
                Max == 0 ->
                    NewMax = NewMin = Microsecond;
                Max < Microsecond ->
                    NewMax = Microsecond,
                    NewMin = Min;
                Min > Microsecond ->
                    NewMax = Max,
                    NewMin = Microsecond;
                true ->
                    NewMax = Max,
                    NewMin = Min
            end,
            collector(NewMax, NewMin, NewSum, N, I + 1, [Microsecond|List])
    after
        10000 ->
            ok
    end;
collector(Max, Min, Sum, N, _, List) ->
    Aver = Sum / N,
    {Greater, Less} = distribution(List, Aver),
    {Max, Min, Sum, Aver, Greater, Less}.


worker({M, F, A}, CollectorPid) ->
    Microsecond = tc(M, F, A),
    CollectorPid ! {result, Microsecond}.

 

 

结果同时10万并发进程去访问find和find1,结果:

=====================
spawn [100000] processes of {tm, find, [<<"user_1@android">>]}:
Maximum: 1686(μs)       0.001686(s)
Minimum: 1(μs)  1.0e-6(s)
Sum: 237287(μs) 0.237287(s)
Average: 2.37287(μs)    2.3728699999999998e-6(s)
Greater: 28017
Less: 71983
=====================
ok
3> tm:ct1().
=====================
spawn [100000] processes of {tm, find1, [<<"user_1@android">>]}:
Maximum: 1862(μs)       0.001862(s)
Minimum: 4(μs)  4.0e-6(s)
Sum: 741330(μs) 0.74133(s)
Average: 7.4133(μs)     7.4133e-6(s)
Greater: 29711
Less: 70289
=====================

 测了几次 基本dirty_read在2微秒左右,dirty_index_read在7微秒左右。性能在3倍左右。

 

总结:

经过测试,我们用mnesia想快速读取数据的时候尽量把总查的字段作为Key。

2
3
分享到:
评论

相关推荐

    erlang_otp_win64_25.0

    此外,Erlang OTP的Mnesia数据库系统支持分布式数据存储和事务处理,非常适合构建容错性强的系统。 总的来说,Erlang OTP 25.0 for Windows 64位是一个强大的开发工具,对于那些需要构建高可用、高性能、分布式应用...

    erlang23.2版windows64位.zip

    5. **函数式编程**:Erlang是函数式的,强调无副作用的纯函数,以及数据不可变性,这有助于编写简洁、易于理解和测试的代码。 6. **模式匹配**:Erlang的模式匹配机制使得解构复杂数据结构和条件分支变得简单。 7....

    Mnesia用户手册

    **Mnesia用户手册** ...总之,Mnesia是Erlang生态系统中不可或缺的一部分,为构建高可用、高性能的分布式系统提供了坚实的基础。理解并掌握Mnesia的使用,将极大地提升Erlang开发者的设计和实现能力。

    erlang中文基础教程

    1. **函数式编程**:Erlang采用函数式编程范式,强调不可变数据和纯函数,这使得代码更易于理解和测试。 2. **并发性**:Erlang中的进程是轻量级的,创建和销毁几乎无开销,且进程间通过消息传递通信,降低了共享...

    inside Erlang VM3

    - **商用产品的验证**:Erlang已经被众多商业产品采用,并经过了长时间的实际测试。 #### 高级网络程序要素与ERTS实现 - **CPU管理**:ERTS支持多核CPU,每个核心有一个调度器,实现负载均衡。每个调度器有自己的...

    tsung+erlang包

    Tsung 是一个开源的多协议负载和性能测试工具,它可以模拟大量用户并发访问服务器,从而评估系统的负载能力和稳定性。Tsung 的设计目标是提供一个灵活、可扩展的解决方案,能够测试各种网络服务,如 HTTP、FTP、TCP...

    Erlang高级应用和原理

    Erlang的分布式数据库Mnesia则提供了一种实时性较强、支持水平分割和数据冗余的解决方案,特别适合读多写少的场景。 Mnesia数据库在Erlang生态系统中扮演着重要角色,它可以避免传统数据库的实时性问题和IPC通讯...

    erlang源码包

    - **Mnesia数据库**:Mnesia是Erlang自带的分布式数据库,设计用于处理大量并发事务。 尽管5.10.3是一个较老的版本,但这些基础特性都是Erlang的核心价值,也是后来版本持续发展的基础。如果你正在使用这个版本,...

    erlang学习资料

    9. **Erlang虚拟机(BEAM)**:了解BEAM虚拟机的工作原理,包括垃圾回收、内存管理和调度策略,可以帮助优化Erlang程序的性能。 10. **实战经验**:理论学习之余,通过实际项目或练习来应用所学知识,是加深理解的...

    erlang高级原理和应用PPT

    7. **标准库与第三方库**:Erlang的标准库介绍,如ETS(Erlang Term Storage)和Mnesia数据库,以及常用的第三方库如 Cowboy(Web服务器)和Rebar3(构建工具)。 8. **实战案例**:可能包含一些实际项目或案例研究...

    mnesia_pg:Postgres后端通过mnesia_ext到Mnesia

    “mnesia_pg:Postgres后端通过mnesia_ext到Mnesia” 这个标题揭示了一个项目,它的目标是将PostgreSQL数据库作为Erlang的Mnesia分布式数据库系统的一个后端。Mnesia_ext是Mnesia的一个扩展,它允许添加自定义的数据...

    Erlang-OTP-API 离线查询英文全手册

    8. **性能和监控**:通过`observer`工具和其他监控模块,开发者可以深入了解系统的运行状态,优化性能,检测瓶颈。 9. **错误日志和调试**:`error_logger`模块用于记录系统错误和警告,而`dbg`模块提供了调试工具...

    erlang_otp_win64_20.2

    安装完成后,可以通过命令行界面(如cmd或PowerShell)来启动Erlang shell,执行Erlang代码,或者使用rebar3等工具进行项目构建和测试。对于开发者来说,理解Erlang OTP的这些核心概念和特性是构建高效、可靠并发...

    Erlang otp_win64_21和22版本 exe

    - **Mnesia数据库**:Erlang内置的分布式数据库,支持事务处理和实时查询,适用于高并发场景。 3. **Erlang OTP 21.3与22的区别** - **性能提升**:新版本通常会包含优化,提高运行速度和内存效率。 - **语言...

    Erlang-game-server开发实践.zip

    Erlang是一种功能强大的并行计算和分布式系统编程语言,以其在高并发、容错性和实时性方面的出色性能,被广泛应用于构建大规模、高可用性的游戏服务器。 ### 1. Erlang简介 Erlang是由Ericsson公司于1986年开发的,...

    Erlang.and.OTP.实战

    2. **模块(Modules)**:如ETS(Erlang Term Storage)和Mnesia,提供了内存数据库和分布式数据库解决方案。 3. **应用程序框架**: OTP提供了一套标准的应用程序结构和管理机制,便于构建和管理复杂系统。 4. **...

    awesome-erlang:精选的Erlang库,资源和闪亮内容的精选列表

    - ** Rebar3**:Erlang的构建工具,用于编译、测试和打包Erlang项目。 2. **学习资源**: - ** 官方文档**:Erlang/OTP的官方文档提供了全面的语言特性和库的介绍,是学习的基础。 - ** Learn You Some Erlang**...

    Erlang_Practice:学习如何在Erlang中编码

    3. **模式匹配**:Erlang的模式匹配允许在函数定义中直接对参数进行解构和比较,使得代码更加简洁和可读。 4. **错误处理与容错**:Erlang采用“let it crash”哲学,鼓励程序在遇到错误时崩溃,然后由监督树自动...

    erlang_server:卡牌游戏《萌兽堂》完整服务器erlang原始码

    5. **数据持久化**:为了保存玩家的游戏进度和卡牌信息,服务器可能使用Erlang的Mnesia数据库,这是一个分布式事务型数据库,适合处理高并发读写操作。 6. **网络通信**:服务器需要处理客户端的请求,这通常通过...

Global site tag (gtag.js) - Google Analytics