ibrowse可用性测试
程序员文章站
2024-01-12 18:15:10
...
之前发帖抱怨过erlang inet http client的性能很糟糕并且有严重bug
litaocheng同学曾建议使用ibrowse,正好目前有项目需要一个http client,
遂下载查看源码学习之(erlang周边项目基本可以放弃只看doc就可以使用的想法)
ibrowse启动首先会读取priv下的配置文件,默认为ibrowse.conf
格式:
{dest, Hostname, Portnumber, MaxSessions, MaxPipelineSize, Options}.
程序是通过file:consult()这个读取的,所以应该知道什么格式了
其实程序中会保存这个配置到一个ets表,
基本就是一个key/value结构,每个host+port都会有上面3项配置,稍候解释上面参数
ibrowse的进程模型基本是这样:
每个host+port都有唯一一个 gen_server进程进行管理,就是ibrowse_lb.erl这个
然后每个ibrowse_lb进程负责对该host+port的请求进行,连接管理工作,
具体的连接请求处理等由ibrowse_http_client.erl进行处理,
也就是说一个ibrowse_http_client就是对应一个物理tcp connection,然后由ibrowse_lb来进行连接管理
ibrowse_lb会根据我们配置的 每个host+port对应的maxsession来决定是否创建新的连接,也就是决定是否启动一个
新的ibrowse_http_client实例,
如果maxsession已经达到最大值,这是ibrowse_lb会根据maxpipline来把请求发给某个ibrowse_http_client实例进行排队处理
当然,选择是根据哪个实例的请求排队量最小,这个也是用一个order_set的ets表保存的特殊数据结构
大部分client基本都是这个原理,好看看测试效果如何,先贴下测试代码
运行结果:
基本发现开大量进程(10000)进行测试,这时调高默认的max_session(默认10)反而降低了性能
这个基本根据应用场景可以自己进行调整到合适的值
结论:这东西比inet好太多了,inet开几百个进程测试自己就crash了,而ibrowse开一万进程每个进程
抓取10次页面,平均每个花掉1s左右时间,应该是可以接受的,适当调优参数应该还可以提高
ps: 我的测试页面在单个进程,单个请求花费的时间在1ms内,是一个静态页
另外提一下,这个ibrowse在读取完配置文件后,其他进程在获取配置文件时并不是发消息的哦,
而是直接从public 的ets表里取的,这个在erlang大会上,yufeng老大特别提到,是不是体现了
小消息大计算的思想呢,接收消息端运算的成本如果远远小于消息发送的成本,那么就不要发消息
litaocheng同学曾建议使用ibrowse,正好目前有项目需要一个http client,
遂下载查看源码学习之(erlang周边项目基本可以放弃只看doc就可以使用的想法)
ibrowse启动首先会读取priv下的配置文件,默认为ibrowse.conf
格式:
{dest, Hostname, Portnumber, MaxSessions, MaxPipelineSize, Options}.
程序是通过file:consult()这个读取的,所以应该知道什么格式了
其实程序中会保存这个配置到一个ets表,
{{max_sessions, Host, Port}, MaxSess}, {{max_pipeline_size, Host, Port}, MaxPipe}, {{options, Host, Port}, Options},
基本就是一个key/value结构,每个host+port都会有上面3项配置,稍候解释上面参数
ibrowse的进程模型基本是这样:
每个host+port都有唯一一个 gen_server进程进行管理,就是ibrowse_lb.erl这个
然后每个ibrowse_lb进程负责对该host+port的请求进行,连接管理工作,
具体的连接请求处理等由ibrowse_http_client.erl进行处理,
也就是说一个ibrowse_http_client就是对应一个物理tcp connection,然后由ibrowse_lb来进行连接管理
ibrowse_lb会根据我们配置的 每个host+port对应的maxsession来决定是否创建新的连接,也就是决定是否启动一个
新的ibrowse_http_client实例,
如果maxsession已经达到最大值,这是ibrowse_lb会根据maxpipline来把请求发给某个ibrowse_http_client实例进行排队处理
当然,选择是根据哪个实例的请求排队量最小,这个也是用一个order_set的ets表保存的特殊数据结构
大部分client基本都是这个原理,好看看测试效果如何,先贴下测试代码
-module(ib_test). %% %% Include files %% %% %% Exported Functions %% -export([start/2,dotest/3]). %% %% API Functions %% start(Processes,Loops)-> ibrowse:start(), ets:new(ib,[named_table,set]), [spawn(?MODULE,dotest,[self(),X,Loops])||X<-lists:seq(1,Processes)], recv(Processes,Loops), ets:delete(ib). recv(Processes,Loops)-> receive {fin,ProcessNum,Elapse}-> ets:insert(ib,{ProcessNum,Elapse}), case ets:info(ib,size) of Processes-> %%got all the resp print_result(Processes,Loops); _-> recv(Processes,Loops) end; Err-> io:format("recv unknowen msg~n"), recv(Processes,Loops) end. print_result(Processes,Loops)-> io:format("=================ibrowse http client performance report=============~n"), TotalElapse= lists:foldr( fun({ProcessNum,Elapse},Acc)-> io:format("process #~p send ~p request spent ~p ms~n",[ProcessNum,Loops,Elapse]), Acc + Elapse end, 0, ets:tab2list(ib) ), AvgElapse=TotalElapse div Processes, io:format("total spent=~p ms,avg spent=~p ms~n",[TotalElapse,AvgElapse]), io:format("=====================================================================~n"). dotest(From,ProcessNum,Loops)-> Start=timestamp_in_millinsec(), [ibrowse:send_req("http://xxx.xxx.xxx.xxx/refresh",[],get)||X<-lists:seq(1,Loops)], Elapse=timestamp_in_millinsec()-Start, From!{fin,ProcessNum,Elapse}. timestamp_in_millinsec()-> {MegaSec,Sec,MicoSec}=erlang:now(), MegaSec * 1000000000+Sec*1000+MicoSec div 1000.
运行结果:
ib_test:start(10,1000). =================ibrowse http client performance report============= process #5 send 1000 request spent 2947 ms process #3 send 1000 request spent 2946 ms process #2 send 1000 request spent 2946 ms process #8 send 1000 request spent 2947 ms process #10 send 1000 request spent 2945 ms process #9 send 1000 request spent 2947 ms process #1 send 1000 request spent 2947 ms process #4 send 1000 request spent 2946 ms process #6 send 1000 request spent 2948 ms process #7 send 1000 request spent 2946 ms total spent=29465 ms,avg spent=2946 ms ===================================================================== ib_test:start(10000,10). =================ibrowse http client performance report============= ... ... process #20 send 10 request spent 954 ms process #1418 send 10 request spent 1173 ms process #5189 send 10 request spent 1165 ms process #5859 send 10 request spent 1207 ms process #9278 send 10 request spent 1173 ms process #9826 send 10 request spent 1187 ms total spent=11491457 ms,avg spent=1149 ms =====================================================================
基本发现开大量进程(10000)进行测试,这时调高默认的max_session(默认10)反而降低了性能
这个基本根据应用场景可以自己进行调整到合适的值
结论:这东西比inet好太多了,inet开几百个进程测试自己就crash了,而ibrowse开一万进程每个进程
抓取10次页面,平均每个花掉1s左右时间,应该是可以接受的,适当调优参数应该还可以提高
ps: 我的测试页面在单个进程,单个请求花费的时间在1ms内,是一个静态页
另外提一下,这个ibrowse在读取完配置文件后,其他进程在获取配置文件时并不是发消息的哦,
而是直接从public 的ets表里取的,这个在erlang大会上,yufeng老大特别提到,是不是体现了
小消息大计算的思想呢,接收消息端运算的成本如果远远小于消息发送的成本,那么就不要发消息
上一篇: mochiweb 学习笔记1
下一篇: 设计模式之Facade(门面)