- 浏览: 111339 次
- 性别:
- 来自: 北京
最新评论
-
yxnyxnyxnyxnyxn:
正需要这个 太感谢了
Memcached源码分析(线程模型) -
laier903:
请问这句的作用是?如何理解呢?if(events & ...
简单封装一下epoll -
aquester:
从实践来看,惊群对性能基本没有影响。
测试Lighttpd accept的惊群现象 -
anranran:
Event event = handler.pollEvent ...
Leader Follower线程模型简单实现 -
anranran:
好文,代码不全,可否补全
Leader Follower线程模型简单实现
之前发帖抱怨过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老大特别提到,是不是体现了
小消息大计算的思想呢,接收消息端运算的成本如果远远小于消息发送的成本,那么就不要发消息
好的,我回头再测试下
老大你终于又回来了
呵呵 最近写东西少了...
好的,我回头再测试下
老大你终于又回来了
老大说好,那一定是不错的,我回头看一下,另外可以试验下刚刚发布的R13B03那个
恩,cookie那个不太清楚呀,其实我们就是http作为erlang与外部通信的接口,因为外部程序基本都是java的,这样改动量最小
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老大特别提到,是不是体现了
小消息大计算的思想呢,接收消息端运算的成本如果远远小于消息发送的成本,那么就不要发消息
评论
8 楼
mryufeng
2010-03-09
bachmozart 写道
mryufeng 写道
httpc的那个bug已经修复 你回头再做下性能测试 比较下...
好的,我回头再测试下
老大你终于又回来了
呵呵 最近写东西少了...
7 楼
bachmozart
2010-03-09
mryufeng 写道
httpc的那个bug已经修复 你回头再做下性能测试 比较下...
好的,我回头再测试下
老大你终于又回来了
6 楼
mryufeng
2010-03-09
httpc的那个bug已经修复 你回头再做下性能测试 比较下...
5 楼
bachmozart
2009-11-27
mryufeng 写道
我是觉得 httpc挺好的 只是大家挖掘不够而已。。。。
老大说好,那一定是不错的,我回头看一下,另外可以试验下刚刚发布的R13B03那个
4 楼
mryufeng
2009-11-27
我是觉得 httpc挺好的 只是大家挖掘不够而已。。。。
3 楼
bachmozart
2009-11-26
mryufeng 写道
ibrowser对Cookie的保存做到好吗? http_client虽然不是非常快 但是特性还是很足的 而且otp官方对inets的库 最近改动很大, 俺是不建议用第三方的。
恩,cookie那个不太清楚呀,其实我们就是http作为erlang与外部通信的接口,因为外部程序基本都是java的,这样改动量最小
2 楼
mryufeng
2009-11-25
ibrowser对Cookie的保存做到好吗? http_client虽然不是非常快 但是特性还是很足的 而且otp官方对inets的库 最近改动很大, 俺是不建议用第三方的。
1 楼
bachmozart
2009-11-23
使用中发现另外一个问题,貌似有这种情况发生
大并发条件下,对同一个host+port的请求有可能在对应一个ibrowse_http_client进程里排队等待处理,也就是mailbox里的消息排队处理,
这时假如某次请求服务器端关闭了该条tcp连接,那么client端erlang的tcp driver会通过注册在系统上的事件获知连接关闭事件,然后给client端erlang进程发消息,这条消息本身也可能在进程mailbox里排队,还未处理,所以我的请求仍然可能发消息到这个进程,结果这些请求都会直接返回错误,ibrowse对这种情况是直接返回错误滴
为了印证这种情况,修改了测试代码如下:
测试5000并发结果(我修改了max_sessions配置为100):
可以看到,其中有一小半是不成功的,这个ibrowse是返回一个错误的,我没打出来而已
默认的5个max_sessions大约只能处理200左右的并发量
结论:在增大默认max_sessions的情况下ibrowse还是能处理一定的较大并发量的,如果并发量很大,
最好在程序里对请求结果做下判断
另外不建议把max_pipeline设置的太大,大量请求都会在进程里排队处理,遇到连接关闭就比较麻烦
大并发条件下,对同一个host+port的请求有可能在对应一个ibrowse_http_client进程里排队等待处理,也就是mailbox里的消息排队处理,
这时假如某次请求服务器端关闭了该条tcp连接,那么client端erlang的tcp driver会通过注册在系统上的事件获知连接关闭事件,然后给client端erlang进程发消息,这条消息本身也可能在进程mailbox里排队,还未处理,所以我的请求仍然可能发消息到这个进程,结果这些请求都会直接返回错误,ibrowse对这种情况是直接返回错误滴
为了印证这种情况,修改了测试代码如下:
-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,SuccessNum,Elapse}-> ets:insert(ib,{ProcessNum,SuccessNum,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,TotalSucc}= lists:foldr( fun({ProcessNum,SuccessNum,Elapse},{ElapseAcc,SuccAcc})-> io:format("process #~p send ~p request,SuccessNum=~p,spent ~p ms~n",[ProcessNum,Loops,SuccessNum,Elapse]), {ElapseAcc + Elapse,SuccAcc+SuccessNum} end, {0,0}, ets:tab2list(ib) ), AvgElapsePerProc=TotalElapse div Processes, AvgElapsePerReq=AvgElapsePerProc div Loops, TotalReq=Processes * Loops, io:format("------------------~n"), io:format("avg spent per process=~p ms~n",[AvgElapsePerProc]), io:format("avg spent per req=~p ms~n",[AvgElapsePerReq]), io:format("total req num=~p,success req num=~p~n",[TotalReq,TotalSucc]), io:format("=====================================================================~n"). dotest(From,ProcessNum,Loops)-> Start=timestamp_in_millinsec(), SuccessNum= lists:foldl( fun(X,Acc)-> Resp=ibrowse:send_req("http://xxx.xxx.xxx.xxx/refresh",[],get), case Resp of {ok,"200",_Headers,"none-none"}-> Acc+1; _-> Acc end end, 0, lists:seq(1,Loops) ), Elapse=timestamp_in_millinsec()-Start, From!{fin,ProcessNum,SuccessNum,Elapse}. timestamp_in_millinsec()-> {MegaSec,Sec,MicoSec}=erlang:now(), MegaSec * 1000000000+Sec*1000+MicoSec div 1000.
测试5000并发结果(我修改了max_sessions配置为100):
ib_test:start(5000,1). ==================================================================== ... process #3584 send 1 request,SuccessNum=1,spent 117 ms process #3330 send 1 request,SuccessNum=1,spent 140 ms process #4121 send 1 request,SuccessNum=1,spent 132 ms process #4798 send 1 request,SuccessNum=1,spent 108 ms ------------------ avg spent per process=91 ms avg spent per req=91 ms total req num=5000,success req num=3863 =====================================================================
可以看到,其中有一小半是不成功的,这个ibrowse是返回一个错误的,我没打出来而已
默认的5个max_sessions大约只能处理200左右的并发量
结论:在增大默认max_sessions的情况下ibrowse还是能处理一定的较大并发量的,如果并发量很大,
最好在程序里对请求结果做下判断
另外不建议把max_pipeline设置的太大,大量请求都会在进程里排队处理,遇到连接关闭就比较麻烦
发表评论
-
hibernate your gen_fsm process
2009-12-14 11:37 2864关于erlang进程hibernate的好处,去过这次erla ... -
修改gen_fsm源码构建更强壮的有限状态机
2009-12-09 14:34 2432关于erlang提供的gen_fsm有限状态机模型,可以说是很 ... -
解释下erlang与flash通信细节
2009-11-26 17:06 2708今天花了大半天时间给前端flash同学解释TCP相关的原理和细 ... -
tsung源码学习之xmerl
2009-10-25 14:10 2057开始规模研究tsung的源代码,代码不多,看起来应该不会太费力 ... -
gen_tcp async accept大致流程
2009-10-07 14:33 5897erlang 调用 gen_tcp:accept时是会阻塞的, ... -
看gen_tcp driver源码学写erlang driver
2009-10-06 16:09 3050erlang 与外部通信有2种 ... -
erlang 网游服务器端socket设计问题
2009-09-24 12:03 3657准备用erlang做网游的服务器端,遇到一个通信层设计的问题 ... -
gen_server源码杂记
2009-09-17 16:12 1999调用gen_server启动的方法 ... -
mochiweb,comet,web2.0实时feed方式靠谱不
2009-09-12 13:51 0自从facebook刮起的一阵mochiweb comet方式 ... -
inets 的http client在大量请求调用时有错误
2009-07-21 11:33 2394试了下inets的http client,调用http:req ... -
mochiweb 学习笔记2
2009-06-11 17:44 2261启动创建好的skeleton时,skel.erl调用appli ... -
mochiweb 学习笔记1
2009-06-10 19:36 2803不知为什么,我看书的 ... -
erlang轻松实现memcached binary协议
2009-06-04 13:05 3345简单实现了下memcached binary protocol ... -
programming erlang - Distributed 那章的实验
2009-03-25 11:56 1510试了下programming erlang distribut ...
相关推荐
这种开放的开发模式通常会导致软件的快速迭代和适应性增强。 在iBrowse X的案例中,用户可能会期待以下特性: 1. **隐私保护**:作为一个独立的浏览器,iBrowse X可能会有独特的隐私保护措施,如内置广告拦截器、...
然后尝试iBROWSE iBROWSE使您可以更轻松地搜索浏览历史记录。您的浏览行为将以日历热图的形式显示,显示您在哪几天访问了哪些网站。输入搜索词后,包含该词的日期或时间会突出显示,并且可以选择以查看找到的项目。...
- **erlang**:Erlang是一种面向并发的、函数式编程语言,常用于构建高可用性、分布式系统,尤其适合处理大量并发连接和实时性需求。 - **HTTPErlang**:可能是指Erlang中的HTTP相关库或工具,强调了这个客户端是用...
设置在您的mix.exs添加RestClient和ibrowse作为依赖mix.exs : defp deps do [ {:rest_client, "~> 0.0.1"}, {:ibrowse, github: "cmullaparthi/ibrowse", tag: "v4.1.2"} ]end 在您的mix.exs添加RestClient作为应用...
这个仓库包含了项目的源代码、测试、文档等资源,如果你想要深入理解 Maxwell 的工作原理或者对其进行扩展,这是一个很好的起点。你可以查看项目的 README 文件,了解如何安装和使用 Maxwell,也可以查阅源码来学习...
验证码 用于Elixir应用程序的简单显示/验证代码。 将Exrecaptcha与CMS等很容易。 安装 在您的mix.exs中设置为dep,并确保它与您的应用... { :ibrowse , github: " cmullaparthi/ibrowse " , tag: " v4.1.0 " }, { :ex
- **Middleware**: 中间件是软件架构中的一个概念,用于处理请求和响应,提供一种插入额外功能的方式,而不会影响核心代码的简洁性。 - **JSON**: JavaScript Object Notation,是一种轻量级的数据交换格式,易于人...
- **IBrowse**: 浏览服务器地址空间的能力。 ##### 4.5 服务器地址空间及配置 OPC服务器维护一个地址空间(Address Space),其中包含了所有的对象和它们的属性。这些对象可以通过特定的路径来访问。 ##### 4.6 时间...
当前带有用于HTTPoison , HTTPotion , Hackney和IBrowse 。 JSON解析器是可配置的,但默认为Poison如果存在)。 可以在上找到文档。 还很早。 欢迎反馈! 用法示例 defmodule MyApp . APIClient do import ...
对于稳定性和长期支持的需求,开发者可能需要考虑使用更成熟的HTTP库,如ibrowse或httpc。但在研究、学习或特定项目中,gen_http是一个极具价值的工具,可以帮助开发者深入理解HTTP协议和Erlang的并发编程模型。
HTTPoison使用hackney而不是ibrowse来执行HTTP请求。 我喜欢哈克尼 :thumbs_up: 使用hackney,我们仅使用二进制文件而不是字符串列表。安装首先,将HTTPoison添加到您的mix.exs依赖项中: def deps do [{ :...
语言:English (United States) 保存和阅读谷歌驱动器上的Chrome历史... - 在goolge驱动器上读取已保存的历史记录(来自ibrowse的ui)。 - 每个月只有1个PC备份。 在其他PC上使用自定义文件名。 在不需要的PC上注销。
在您的Google云端硬盘上保存并读取Chrome历史...-在Goolge Drive(iBROWSE的UI)上读取已保存的历史记录。 -每月仅备份1台PC。 在其他PC上使用自定义文件名。 在不需要的PC上注销。 支持语言:English (United States)
Gtk WebCore / Hana / HotJava / Hv3 Build / IBM WebExplorer / IBrowse / iCab / Iceape / IceBrowser v6 / IceWeasel / IEMobile / iNet Browser / Internet Explorer / Internet Explorer Spartan / ...
httpotion :(不推荐使用)Elixir的HTTP客户端(请使用Tesla)
6. **发送请求**:构建完请求后,使用Erlang的HTTP客户端库(如`httpc`或第三方库如`ibrowse`)向百度云推送服务器发送POST请求,携带所有必要的参数,包括APIkey、channelId、消息内容等。 7. **错误处理与反馈**...