大家好!小弟最近在学习erlang,熟悉代码做了一个消息转发的server,但是在测试性能的时候遇到一个问题,请教各位,是哪里的问题,谢谢!
我开发的消息转发server的功能:
Aclient Bclient都连入Server,都并加入一个组C,Aclient向C组发一条消息,Server负责将消息发给C组内除了A外的其他Client,也就是B。开发没用OTP这些高级东西。SOCKET使用二进制,{active true},{packet 2}.
消息Server的设计:
有一个独立的进程负责监听client连入,当有新的client连入会为client申请独立的进程(client_recv process)负责接受这个client发来的消息,有一个独立的进程(group_manager process)维护分组和组的client成员列表,每个组(group process)有一个独立进程负责向组内的client转发消息。
当Aclient连入server,就会为A启动(client_recv process)负责接受A发来的消息并通过进程通信告诉给group_manager来建立一个组group。Bclient连入操作和A一样,都会加入同一个组。
当A发消息给SERVER要求把消息给组的其他成员时,client_recv通过进程通讯将消息给group进程,group进程便利组的成员列表将消息转发。
在测试性能时遇到的问题:
测试的时候A向SERVER发送100W的消息,用了8秒就发完了,并自动退出了,消息内容都一样,在内网做的测试。
而SERVER通过tcpdump监听,确实也是在8秒把所有消息都收完了,不在有来自A的消息进入,但是SERVER向B转发消息用了很长时间,超过10分钟,最后我结束进程了。
在程序内做了打印来判断程序的运行流程,发现SERVER一直执行从client_recv接受A的消息并给group来转发。
请问是我设计的有问题造成消息转发很慢吗?还是由于进程间通讯造成的?有什么办法可以调优?
(以下只节选该作者出问题的代码,注意循环后面的那个ok原子)
72.group(Client)->%%负责组的消息群发的进程
73. ?DEBUG("group \r\n",[]),
74. receive
75. {join,Socket,ClientName,CPid} ->
76. ?DEBUG("group ClientName ~s\r\n",[ClientName]),
77. ?DEBUG("group Client set ~w\r\n",[Client]),
78. case lists:keysearch(ClientName,#client.name,Client) of
79. false->
80. ?DEBUG("group new client\r\n",[]),
81. ClientNew = #client{name=ClientName,pid=CPid,socket=Socket},
82. ClientTmp = [ClientNew|Client],
83. group(ClientTmp);
84. {value,SingleClient}->
85. ?DEBUG("group client is set ~s\r\n",[SingleClient#client.name]),
86. group(Client)
87. end;
88. {send,ClientName,Msg}->
89. ?DEBUG("group recv client send ~s\r\n",[Msg]),
90. lists:foreach(fun(T)->send(ClientName,T,Msg) end,Client),
91. group(Client)
92. end,
93. ok.
以下是高手的招数
1.你的send不是很高效,gen_tcp:send是会阻塞的,如果客户很慢,缓冲区已满就会阻塞,把TCP_OPTIONS加上{delay_send, true}测试一下有没有提高。
2.既然瓶颈在CPU上,还是使用fprof分析一下吧,测试可以减少到100-1000次
最容易出现的问题是receive匹配顺序,或者是没有匹配到,建议加一个任意匹配检查一下是否有没有匹配的消息
3.建议把receive里面加上_Any匹配一下,打印输出或者是exit都可以,没有匹配的消息对性能影响特别大,特别是你这里大量消息的情况。
4.感谢qiezi的帮忙!
代码的group下去掉一个无用ok,在server和client增加了tcp属性的设置{nodelay, false}, {delay_send, true},100W的数据在本地单机跑大概用40秒,迅驰1.7 1.5G内存的笔记本上。比以前快多了,谢谢qiezi一直在帮助,学到以前没了解的东西。
在我测试用的服务器上依然出现SERVER端CPU占用99%导致发消息慢的情况。感觉可能是服务器设置或erlang安装造成的问题,因为即使把代码放到同一机器走127.0.0.1的时候一样会出现cpu占满的情况的。
我在安装erlang的时候记得提示 没有java odbc libgd好像没别的库少了,各位还有别的办法吗?谢谢!
5.1. 你最初的代码没有设置client socket的options,不知后来有没有改过。
2. 安装erlang时有没有enable-kernel-poll? 运行server时有没有加 +K true选项? kernel poll对提高性能作用很大。
6.使用+K true了
我发现是我安装的时候没有disable smp,我的服务器是单核的。
执行shell的时候 -smp disable后 cpu运转还是99%但是运行速度已经升上来了,100w的数据 A服务器发SERVER SERVER转发B服务器 A服务器发送完用5秒,B服务器收完用11秒,消息内容长度1bytes,78bytes发8秒,收21秒。
可是CPU占用依然高,总是瞬间99%,这个问题各位有办法解决吗?
cpu占用到99%这应该算不正常吧?
7.CPU占用率高是肯定的。楼主能否说下目前的tcp选项?erlang邮件列表中建议你使用{active,once} 代替{active,true},您有试过吗?