??xml version="1.0" encoding="utf-8" standalone="yes"?>日韩中文字幕一区,一区二区三区色,69久久精品http://www.aygfsteel.com/yongboy/category/54842.html记录工作/学习(fn)的点Ҏ(gu)滴?/description>zh-cnMon, 01 Jun 2015 03:42:52 GMTMon, 01 Jun 2015 03:42:52 GMT60100万ƈ发连接服务器W记之Java Netty处理1Mq接?x)怎么?/title><link>http://www.aygfsteel.com/yongboy/archive/2013/05/13/399203.html</link><dc:creator>nieyong</dc:creator><author>nieyong</author><pubDate>Mon, 13 May 2013 03:16:00 GMT</pubDate><guid>http://www.aygfsteel.com/yongboy/archive/2013/05/13/399203.html</guid><wfw:comment>http://www.aygfsteel.com/yongboy/comments/399203.html</wfw:comment><comments>http://www.aygfsteel.com/yongboy/archive/2013/05/13/399203.html#Feedback</comments><slash:comments>9</slash:comments><wfw:commentRss>http://www.aygfsteel.com/yongboy/comments/commentRss/399203.html</wfw:commentRss><trackback:ping>http://www.aygfsteel.com/yongboy/services/trackbacks/399203.html</trackback:ping><description><![CDATA[<h2>前言</h2> <p>每一U该语言在某些极限情况下的表C般都不太一P那么我常用的Java语言Q在辑ֈ100万个q发q接情况下,?x)怎么样呢Q有些好奇,更有些期盹{?br />q次使用l常使用的顺手的<strong><a >netty</a></strong> NIO框架Qnetty-3.6.5.FinalQ,装的很好,接口很全面,像它现在的域名 <strong>netty.io</strong>Q专注于|络IO?br />整个q程没有什么技术含量,显分析q就更显得有些枯燥无聊,准备好,着头皮吧?/p> <h2>试服务器配|?/h2> <p>q行在VMWare Workstation 9中,64位Centos 6.2pȝQ分?4.9G内存左右Q?核?br />已安装有Java7版本Q?/p><pre><code>java version "1.7.0_21" Java(TM) SE Runtime Environment (build 1.7.0_21-b11) Java HotSpot(TM) 64-Bit Server VM (build 23.21-b01, mixed mode) </code></pre> <p>?etc/sysctl.conf中添加如下配|:(x)</p><pre><code>fs.file-max = 1048576 net.ipv4.ip_local_port_range = 1024 65535 net.ipv4.tcp_mem = 786432 2097152 3145728 net.ipv4.tcp_rmem = 4096 4096 16777216 net.ipv4.tcp_wmem = 4096 4096 16777216 net.ipv4.tcp_tw_reuse = 1 net.ipv4.tcp_tw_recycle = 1 </code></pre> <p>?etc/security/limits.conf中添加如下配|:(x)</p><pre><code> * soft nofile 1048576 * hard nofile 1048576 </code></pre> <h2>试?/h2> <p>试端无论是配置q是E序和以前一Pȝ前几博客就可以看到client5.c的源码,以及(qing)相关的配|信息等?/p> <h2>服务器程?/h2> <p>q次也是很简单呐Q没有业务功能,客户端HTTPhQ服务端输出chunked~码内容?</p> <h3>入口HttpChunkedServer.javaQ?/h3><script src="https://gist.github.com/yongboy/5558672.js"></script> <h3>唯一的自定义处理器HttpChunkedServerHandler.java:</h3><script src="https://gist.github.com/yongboy/5558675.js"></script> <h3>启动脚本start.sh</h3><script src="https://gist.github.com/yongboy/5558701.js"></script> <h2>辑ֈ100万ƈ发连接时的一些信?/h2> <p>每次服务器端辑ֈ一百万个ƈ发持久连接之后,然后x试端程序,断开所有的q接Q等到服务器端日志输出在U用户ؓ(f)0Ӟ再次重复以上步骤。在q反反复复的情况下,观察内存{信息的一些情c(din)以某次断开所有测试端Z后,当前pȝ占用为(讄?code>list_free_1</code>Q?</p><pre><code> total used free shared buffers cached Mem: 15189 7736 7453 0 18 120 -/+ buffers/cache: 7597 7592 Swap: 4095 948 3147 </code></pre> <p>通过top观察Q其q程相关信息</p><pre><code> PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 4925 root 20 0 8206m 4.3g 2776 S 0.3 28.8 50:18.66 java </code></pre> <p>在启动脚本start.sh中,我们讄堆内存ؓ(f)6G?/p> <p><strong>ps aux|grep java</strong>命o(h)获得信息Q?/p><pre><code> root 4925 38.0 28.8 8403444 4484764 ? Sl 15:26 50:18 java -server...HttpChunkedServer 8000 </code></pre> <p>RSS占用内存?484764K/1024K=4379M</p> <p>然后再次启动试端,在服务器接收?strong>online user 1023749</strong>Ӟ<code>ps aux|grep java</code>内容为:(x)</p><pre><code> root 4925 43.6 28.4 8403444 4422824 ? Sl 15:26 62:53 java -server... </code></pre> <p>查看当前|络信息l计</p><pre><code> ss -s Total: 1024050 (kernel 1024084) TCP: 1023769 (estab 1023754, closed 2, orphaned 0, synrecv 0, timewait 0/0), ports 12 Transport Total IP IPv6 * 1024084 - - RAW 0 0 0 UDP 7 6 1 TCP 1023767 12 1023755 INET 1023774 18 1023756 FRAG 0 0 0 </code></pre> <p>通过top查看一?/p><pre><code> top -p 4925 top - 17:51:30 up 3:02, 4 users, load average: 1.03, 1.80, 1.19 Tasks: 1 total, 0 running, 1 sleeping, 0 stopped, 0 zombie Cpu0 : 0.9%us, 2.6%sy, 0.0%ni, 52.9%id, 1.0%wa, 13.6%hi, 29.0%si, 0.0%st Cpu1 : 1.4%us, 4.5%sy, 0.0%ni, 80.1%id, 1.9%wa, 0.0%hi, 12.0%si, 0.0%st Cpu2 : 1.5%us, 4.4%sy, 0.0%ni, 80.5%id, 4.3%wa, 0.0%hi, 9.3%si, 0.0%st Cpu3 : 1.9%us, 4.4%sy, 0.0%ni, 84.4%id, 3.2%wa, 0.0%hi, 6.2%si, 0.0%st Mem: 15554336k total, 15268728k used, 285608k free, 3904k buffers Swap: 4194296k total, 1082592k used, 3111704k free, 37968k cached PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 4925 root 20 0 8206m 4.2g 2220 S 3.3 28.4 62:53.66 java </code></pre> <p>四核都被占用了,每一个核心不太^均。这是在虚拟Z得到l果Q可能真实服务器?x)更好一些?因ؓ(f)不是CPU密集型应用,CPU不是问题Q无d加关注?/p> <p>pȝ内存状况</p><pre><code> free -m total used free shared buffers cached Mem: 15189 14926 263 0 5 56 -/+ buffers/cache: 14864 324 Swap: 4095 1057 3038 </code></pre> <p>物理内存已经无法满要求了,占用?057M虚拟内存?/p> <p>查看一下堆内存情况</p><pre><code> jmap -heap 4925 Attaching to process ID 4925, please wait... Debugger attached successfully. Server compiler detected. JVM version is 23.21-b01 using parallel threads in the new generation. using thread-local object allocation. Concurrent Mark-Sweep GC Heap Configuration: MinHeapFreeRatio = 40 MaxHeapFreeRatio = 70 MaxHeapSize = 6442450944 (6144.0MB) NewSize = 629145600 (600.0MB) MaxNewSize = 629145600 (600.0MB) OldSize = 5439488 (5.1875MB) NewRatio = 2 SurvivorRatio = 1 PermSize = 52428800 (50.0MB) MaxPermSize = 52428800 (50.0MB) G1HeapRegionSize = 0 (0.0MB) Heap Usage: New Generation (Eden + 1 Survivor Space): capacity = 419430400 (400.0MB) used = 308798864 (294.49354553222656MB) free = 110631536 (105.50645446777344MB) 73.62338638305664% used Eden Space: capacity = 209715200 (200.0MB) used = 103375232 (98.5863037109375MB) free = 106339968 (101.4136962890625MB) 49.29315185546875% used From Space: capacity = 209715200 (200.0MB) used = 205423632 (195.90724182128906MB) free = 4291568 (4.0927581787109375MB) 97.95362091064453% used To Space: capacity = 209715200 (200.0MB) used = 0 (0.0MB) free = 209715200 (200.0MB) 0.0% used concurrent mark-sweep generation: capacity = 5813305344 (5544.0MB) used = 4213515472 (4018.321487426758MB) free = 1599789872 (1525.6785125732422MB) 72.48054631000646% used Perm Generation: capacity = 52428800 (50.0MB) used = 5505696 (5.250640869140625MB) free = 46923104 (44.749359130859375MB) 10.50128173828125% used 1439 interned Strings occupying 110936 bytes. </code></pre> <p>老生代占用内存ؓ(f)72%Q较为合理,毕竟pȝ已经处理100万个q接?/p> <p>再次断开所有测试端Q看看系l内存(free -mQ?/p><pre><code> total used free shared buffers cached Mem: 15189 7723 7466 0 13 120 -/+ buffers/cache: 7589 7599 Swap: 4095 950 3145 </code></pre> <p>Cؓ(f)<code>list_free_2</code>?/p> <p><code>list_free_1</code>?code>list_free_2</code>两次都释攑֐的内存比较结果,pȝ可用物理已经内存已经降到7589MQ先前可?597M物理内存?br />MQ我们的JAVA试E序在内存占用方面已l,最低需?589 + 950 = 8.6G内存为最低需求内存吧?/p> <h2>GC日志</h2> <p>我们在启动脚本处讄的一大串参数Q到底是否达到目标,q得从gc日志处获得具体效果,推荐使用<a >GCViewer</a>?/p> <p>GC事g概览Q?br /><a href="http://www.aygfsteel.com/images/blogjava_net/yongboy/Windows-Live-Writer/bf3eb5ad9dd9_9C7F/gc_eventdetails_2.png"><img title="gc_eventdetails" style="border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-top-width: 0px" alt="gc_eventdetails" src="http://www.aygfsteel.com/images/blogjava_net/yongboy/Windows-Live-Writer/bf3eb5ad9dd9_9C7F/gc_eventdetails_thumb.png" border="0" height="476" width="814" /></a></p> <p>其它:<br /><a href="http://www.aygfsteel.com/images/blogjava_net/yongboy/Windows-Live-Writer/bf3eb5ad9dd9_9C7F/gc_total_1_2.png"><img title="gc_total_1" style="border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-top-width: 0px" alt="gc_total_1" src="http://www.aygfsteel.com/images/blogjava_net/yongboy/Windows-Live-Writer/bf3eb5ad9dd9_9C7F/gc_total_1_thumb.png" border="0" height="367" width="364" /></a> <a href="http://www.aygfsteel.com/images/blogjava_net/yongboy/Windows-Live-Writer/bf3eb5ad9dd9_9C7F/gc_total_2_2.png"><img title="gc_total_2" style="border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-top-width: 0px" alt="gc_total_2" src="http://www.aygfsteel.com/images/blogjava_net/yongboy/Windows-Live-Writer/bf3eb5ad9dd9_9C7F/gc_total_2_thumb.png" border="0" height="367" width="363" /></a> <a href="http://www.aygfsteel.com/images/blogjava_net/yongboy/Windows-Live-Writer/bf3eb5ad9dd9_9C7F/gc_total_3_2.png"><img title="gc_total_3" style="border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; padding-top: 0px; padding-left: 0px; display: inline; padding-right: 0px; border-top-width: 0px" alt="gc_total_3" src="http://www.aygfsteel.com/images/blogjava_net/yongboy/Windows-Live-Writer/bf3eb5ad9dd9_9C7F/gc_total_3_thumb.png" border="0" height="368" width="367" /></a></p> <p>MQ?/p> <ul> <li>只进行了一ơFull GCQ代价太高,停顿?2U? </li><li>PartNew成ؓ(f)了停大PD整个pȝ停顿?1U之久,不可接受? </li><li>当前JVM调优喜忧参半Q还得l努力等 </li></ul> <h2>结</h2> <p>Java与与Erlang、C相比Q比较麻烦的事情Q需要在E序一开始就得准备好它的堆栈到底需要多大空_(d)换个说法是JVM启动参数讄堆内存大,讄合适的垃圾回收机制Q若以后E序需要更多内存,需停止E序Q编辑启动参敎ͼ然后再次启动。M一句话Q就是麻烦。单单JVM的调优,得持箋不断的根据检、信息、日志等q行适当微调?/p> <ul> <li>JVM需要提前指定堆大小Q相比Erlang/CQ这可能是个ȝ </li><li>GC(垃圾回收)Q相Ҏ(gu)ȝQ需要持l不断的Ҏ(gu)日志、JVM堆栈信息、运行时情况q行JVM参数微调 </li><li>讄一个最大连接目标,多次试辑ֈ峰Q然后释放所有连接,反复观察内存占用Q获得一个较为合适的pȝq行内存? </li><li>Eclipse Memory Analyzerl合jmap导出堆栈DUMP文gQ分析内存泄漏,q是很方便的 </li><li>想修改运行时内容Q或者称之ؓ(f)热加载,默认不可? </li><li>真实机器上会(x)有更好的反映 </li></ul> <p>吐槽一下:(x)<br />JAVA OSGIQ相Ҏ(gu)Erlang来说Q需要h转换思\Q不是那么原生的东西QL有些别扭Q社区或商业公司Ҏ(gu)的修修补补,不过是实C些面向对象所不具备的热加载的企业Ҏ(gu)?/p> <p>试源代码,<a href="http://www.aygfsteel.com/Files/yongboy/just_test.zip">下蝲just_test</a>?/p><img src ="http://www.aygfsteel.com/yongboy/aggbug/399203.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.aygfsteel.com/yongboy/" target="_blank">nieyong</a> 2013-05-13 11:16 <a href="http://www.aygfsteel.com/yongboy/archive/2013/05/13/399203.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>100万ƈ发连接服务器W记之Erlang完成1Mq发q接目标http://www.aygfsteel.com/yongboy/archive/2013/04/28/398558.htmlnieyongnieyongSun, 28 Apr 2013 09:17:00 GMThttp://www.aygfsteel.com/yongboy/archive/2013/04/28/398558.htmlhttp://www.aygfsteel.com/yongboy/comments/398558.htmlhttp://www.aygfsteel.com/yongboy/archive/2013/04/28/398558.html#Feedback1http://www.aygfsteel.com/yongboy/comments/commentRss/398558.htmlhttp://www.aygfsteel.com/yongboy/services/trackbacks/398558.html前言

使用Erlang语言也写一个测试和前面大同异的测试,?00万个q发q接用户情况下,是惌察一下极显情况下的表现?br /> q个试使用了优U的Erlang界的明星框架cowboyQ加单易用的接口Q避免了我们对HTTP栈再ơ进行闭门造R?/p>

试Erlang服务?/h2>

q行在VMWare Workstation 9中,64位Centos 6.4pȝQ分?4.9G内存左右Q双?个线E,服务器安装Erlang/OTP R16BQ最新版本支持异步代码热加蝲Q很赞?/p>

下蝲安装

本系l已l提前安装JDKQ只需要安装Erlang好了?/p>

安装依赖


yum install build-essential m4
yum install openssl
yum install openssl-devel
yum install unixODBC
yum install unixODBC-devel
yum -y install openssl make gcc gcc-c++ kernel-devel m4 ncurses-devel openssl-devel
yum install xsltproc fop

源代码安?/p>

#wget https://elearning.erlang-solutions.com/binaries/sources/otp_src_R16B.tar.gz
#tar xvf otp_src_R16B.tar.gz
cd otp_src_R16B
./configure --prefix=/usr/local/erlang --enable-hipe --enable-threads --enable-smp-support --enable-kernel-poll
make
make install

d到环境变量中(/etc/profile)

export ERL_HOME=/usr/local/erlang export PATH=$ERL_HOME/bin:$PATH

保存生效

source /etc/profile

试q程创徏

q里拯《ErlangE序设计》一书提供的processes.erl源码Q稍作修攏V?

创徏一百万个进E,看看大概p多少旉?/p>

[yongboy@base erlang]$ erl +P 10240000
Erlang R16B (erts-5.10.1) [source] [64-bit] [smp:4:4] [async-threads:10] [hipe] [kernel-poll:false]
Eshell V5.10.1 (abort with ^G)
1> processes:max(200000).
Maxmium allowed process is 16777216 Process spawn time=1.1 (2.68) microseconds ok
2> processes:max(200000).
Maxmium allowed process is 16777216 Process spawn time=1.7 (2.33) microseconds ok
3> processes:max(200000).
Maxmium allowed process is 16777216 Process spawn time=1.55 (2.12) microseconds ok
4> processes:max(1000000).
Maxmium allowed process is 16777216 Process spawn time=2.97 (3.967) microseconds ok
5> processes:max(1000000).
Maxmium allowed process is 16777216 Process spawn time=2.4 (2.729) microseconds ok
6> processes:max(1000000).
Maxmium allowed process is 16777216 Process spawn time=2.19 (2.735) microseconds ok
7> processes:max(10000000).
Maxmium allowed process is 16777216 Process spawn time=3.328 (4.2777) microseconds ok
8> processes:max(10000000).
Maxmium allowed process is 16777216 Process spawn time=3.144 (3.1361) microseconds ok
9> processes:max(10000000).
Maxmium allowed process is 16777216 Process spawn time=3.394 (3.2051) microseconds ok

恩,创徏1000万个q程Q每一个进E花?.4微秒(μs)的CPU旉Q相当于4.3微秒(μs)的消耗时?亦即消耗的真实旉),在一定量的区间内Q其值变化,可以看做是一个常量?/p>

初始化小问题

Cowboy初始化需要事?/h3>

我们做的单程序,使用了非常受Ƣ迎的cowboy框架Q其启动函数:

cowboy:start_http(my_http_listener, 100,
[{port, 8000}],
[{env, [{dispatch, Dispatch}]}]
),

Cowboy默认支持1024个连接,服务器端输出Q?/p>

online user 1122 online user 1123 

停滞于此Q后l的q接只能排队{候了?/p>

q里讄支持无限个连接好了?/p>

{max_connections, infinity}

话说QCowboy为Erlang世界的明星品,l对值得一试!

Erlang默认创徏q程限制

Erlang在我的机器上默认允许创徏的线E也是有限的Q?/p>

erlang:system_info(process_limit).
262144

?6万个Q不够用。在启动脚本(start.sh)处添加允许创建的最大线E支持:(x)

#!/bin/sh
erl +K true +P 10240000 -sname testserver -pa ebin -pa deps/*/ebin -s htmlfilesimple\
-eval "io:format(\"Server start with port 8000 Success!~n\")."

脚本启动后现在在erl shell中测试一下:(x)

erlang:system_info(process_limit).
16777216

数量完全够用了?/p>

开启erlang的epoll属?/h3>
+K true | false 是否开启kernel pollQ就是epollQ?

不开启,试q程中,在内存完好情况下Q经怼(x)有连接失败情c(din)?/p>

使用cowboy_req:compact降低内存占用

一旦你从request对象中获取到_的信息,以后不再获取光加属性时Q调?strong>compact/1函数可去除无用属性,起到节省内存作用?
E序里面调用如下Q?/p>

init(_Any, Req, State) -> NowCount = count_server:welcome(),
io:format("online user ~p :))~n", [NowCount]),
output_first(Req),
Req2 = cowboy_req:compact(Req),
{loop, Req2, State, hibernate}.

在本例中_测压羃内存效果不明显,因ؓ(f) Q测试端输出的HTTP头部压根没有几个?/p>

Cowboy无法处理没有header的HTTPh

q里需要牢讎ͼ也不能算是BUGQ前面的client2.c源码Q就未曾讄HTTP Header元数据,需要做些简单修改,修改之后的测试端E序文g名ؓ(f)client5.c, 可以到这?下蝲client.c?/p>

Cowboy处理长连?/h2>

Cowboy很脓(chung)心的提供?code>cowboy_loop_handler behaviour。在init/3函数中,可以q入休眠状态,节省内存Q消息到达时Q被唤醒Q值得一赞! 其定义如下:(x) 注意hibernate?strong>timeout参数Q按照实际需求返回即可?/p>

htmlfile_handlerC代码如下Q?

100万ƈ发连接达?/h2>

试q程跌跌撞撞的,虽然q中间因为内存问题抛q的异常Q但也达?00Wq接的数?/p>

online user 1022324 :))
online user 1022325 :))
online user 1022326 :))
online user 1022327 :))
online user 1022328 :))
online user 1022329 :))
online user 1022330 :))
online user 1022331 :))
online user 1022332 :))
online user 1022333 :))
online user 1022334 :))
online user 1022335 :))
online user 1022336 :))
online user 1022337 :))
online user 1022338 :))

可以看到状态信?

一下:(x) 14987952K = 14636M
14987952/1022338 = 14.7K/Connection

未启动时的内存情况:(x)

 total used free shared buffers cached
Mem: 14806 245 14561 0 12 60
-/+ buffers/cache: 172 14634
Swap: 3999 0 3999

启动后的内存占用情况Q?/p>

 total used free shared buffers cached
Mem: 14806 435 14370 0 12 60
-/+ buffers/cache: 363 14443
Swap: 3999 0 3999

用户量达?022338数量后的内存一览:(x)

 total used free shared buffers cached
Mem: 14806 14641 165 0 1 5
-/+ buffers/cache: 14634 172
Swap: 3999 1068 2931

可以看到Q当前内存不够用了,需要虚拟内存配合了?/p>

查看一下当前进E的内存占用

ps -o rss= -p `pgrep -f 'sname testserver'`
4869520

q样v来,pȝ为每一个进E持?4869520/1022338 = 4.8K 内存? q个值只是计物理内存,实际上连虚拟内存都占用了Q估计在4.8K-6.8K之间吧?/p>

和C语言相比Q内存占用相当大Q我虚拟机器分配?5G内存Q也仅仅处理辑ֈ100万的q接Q已l接q极限时Q会(x)发现陆陆l箋的有q接p|?/p>

不得不说的代码热加蝲

q行时系l的代码热加载功能,在这个实例中Q通过vi修改了htmlfile_handler.erl文gQ主要修改内容如下:(x)

io:format("online user ~p :))~n", [NowCount]),
......
io:format("offline user ~p :(( ~n", [NowCount]).

执行makeQ编?/p>

[root@base htmlfilesimple]# make
==> ranch (get-deps)
==> cowboy (get-deps)
==> htmlfilesimple (get-deps)
==> ranch (compile)
==> cowboy (compile)
==> htmlfilesimple (compile)
src/htmlfile_handler.erl:5: Warning: record status is unused
src/htmlfile_handler.erl:29: Warning: variable 'Reason' is unused
Compiled src/htmlfile_handler.erl

很好Q非常智能的rebarQ自动只~译?strong>htmlfile_handler.erl一个文Ӟ然后通知Erlang的运行环境进行代码热替换吧?/p>

(testserver@base)4> code:load_file(htmlfile_handler). 

查看日志输出控制収ͼ可以看到已经生效Q同时也保存着到状态数据等?/p>

非常利于q行时调试,即不伤害在线状态数据,又能x修改Q赞Q但生环境下,一般都是版本切换,OTP的版本切换,试或马上修改bugӞ着实有些复杂?/p>

和C相比Q处理相同的事情Q?00万ƈ发连接)Q及(qing)其简单,但Erlang?x)需要更多的内存Q廉L(fng)内存可以满Q只是我的搭建在Vmware中的虚拟机器已经辑ֈ了它所要求的极限?
完整的源代码Q可点击q里下蝲?/p>

nieyong 2013-04-28 17:17 发表评论
]]>
100万ƈ发连接服务器W记?Mq发q接目标达成http://www.aygfsteel.com/yongboy/archive/2013/04/11/397677.htmlnieyongnieyongThu, 11 Apr 2013 01:01:00 GMThttp://www.aygfsteel.com/yongboy/archive/2013/04/11/397677.htmlhttp://www.aygfsteel.com/yongboy/comments/397677.htmlhttp://www.aygfsteel.com/yongboy/archive/2013/04/11/397677.html#Feedback8http://www.aygfsteel.com/yongboy/comments/commentRss/397677.htmlhttp://www.aygfsteel.com/yongboy/services/trackbacks/397677.htmlW四个遇到的问题Qtcp_mem

在服务端Q连接达C定数量,诸如50WӞ有些隐藏很深的问题,׃断的抛出来? 通过查看dmesg命o(h)查看Q发现大?strong>TCP: too many of orphaned sockets错误Q也很正常,下面C需要调整tcp socket参数的时候了?/p>

W一个需要调整的是tcp_rmemQ即TCPd~冲区,单位为字节,查看默认?/p>

cat /proc/sys/net/ipv4/tcp_rmem
4096 87380 4161536

默认gؓ(f)87380 byte ≈ 86KQ最ؓ(f)4096 byte=4KQ最大gؓ(f)4064K?/p>

W二个需要调整的是tcp_wmemQ发送缓冲区Q单位是字节Q默认?/p>

cat /proc/sys/net/ipv4/tcp_wmem
4096 16384 4161536

解释同上

W三个需要调整的tcp_memQ调整TCP的内存大,其单位是,1늭?096字节。系l默认|(x)

cat /proc/sys/net/ipv4/tcp_mem
932448 1243264 1864896

tcp_mem(3个INTEGER变量)Qlow, pressure, high

  • lowQ当TCP使用了低于该值的内存面数时QTCP不会(x)考虑释放内存?/li>
  • pressureQ当TCP使用了超q该值的内存面数量ӞTCP试图E_其内存用,q入pressure模式Q当内存消耗低于low值时则退出pressure状态?/li>
  • highQ允许所有tcp sockets用于排队~冲数据报的面量,当内存占用超q此|pȝ拒绝分配socketQ后台日志输?#8220;TCP: too many of orphaned sockets”?/li>

一般情况下q些值是在系l启动时Ҏ(gu)pȝ内存数量计算得到的? Ҏ(gu)当前tcp_mem最大内存页面数?864896Q当内存?1864896*4)/1024K=7284.75MӞpȝ无法ؓ(f)新的socketq接分配内存Q即TCPq接被拒绝?/p>

实际试环境中,据观察大概在99万个q接左右的时?零头不算)Q进E被杀死,触发out of socket memory错误Qdmesg命o(h)查看获得Q。每一个连接大致占?.5K内存Q下面给方式)Q大致可的此时内存占用情况Q?90000 * 7.5 / 1024K = 7251M)?/p>

q样和tcp_mem最大页面值数量比较吻合,因此此g需要修攏V?/p>

三个TCP调整语句?

echo "net.ipv4.tcp_mem = 786432 2097152 3145728">> /etc/sysctl.conf
echo "net.ipv4.tcp_rmem = 4096 4096 16777216">> /etc/sysctl.conf
echo "net.ipv4.tcp_wmem = 4096 4096 16777216">> /etc/sysctl.conf

备注Q?Z节省内存Q设|tcp诅R写~冲区都?K大小Q?code>tcp_mem三个值分别ؓ(f)3G 8G 16GQ?code>tcp_rmem?code>tcp_wmem最大g?6G?/p>

目标达成

l过若干ơ的试Q最l达到目标,1024000个持久连接?024000数字是怎么得来的呢Q两台物理机器各自发?4000个请求,两个配置?G左右的centos试端机?l定7个桥接或NATq接)各自发出640007 = 448000。也是 1024000 = (64000) + (64000) + (640007) + (64000*7), ׃用了16个网卡(物理|卡+虚拟|卡Q?
l端输出

......
online user 1023990
online user 1023991
online user 1023992
online user 1023993
online user 1023994
online user 1023995
online user 1023996
online user 1023997
online user 1023998
online user 1023999
online user 1024000

在线用户目标辑ֈ1024000个!

服务器状态信?/h2>

服务启动时内存占用:(x)

                 total       used       free     shared    buffers     cached
    Mem:         10442        271      10171          0         22         78
    -/+ buffers/cache:        171      10271
    Swap:         8127          0       8127

pȝ辑ֈ1024000个连接后的内存情况(执行三次 free -m 命o(h)Q获取三ơ结果)Q?/p>

                 total       used       free     shared    buffers     cached
    Mem:         10442       7781       2661          0         22         78
    -/+ buffers/cache:       7680       2762
    Swap:         8127          0       8127

                 total       used       free     shared    buffers     cached
    Mem:         10442       7793       2649          0         22         78
    -/+ buffers/cache:       7692       2750
    Swap:         8127          0       8127

                 total       used       free     shared    buffers     cached
    Mem:         10442       7804       2638          0         22         79
    -/+ buffers/cache:       7702       2740
    Swap:         8127          0       8127

q三ơ内存用分别是7680,7692,7702Q这ơ不取^均|取一个中{偏上的|定ؓ(f)7701M。那么程序接?024000个连接,共消耗了 7701M-171M = 7530M内存Q?7530M*1024K / 1024000 = 7.53KQ?每一个连接消耗内存在?.5K左右Q这和在q接辑ֈ512000时所计算较ؓ(f)d?
虚拟行Centos内存占用Q不太稳定,但一般相差不大,以上数|仅供参考?/p>

执行top -p 某刻输出信息Q?/serverpid>

    top - 17:23:17 up 18 min,  4 users,  load average: 0.33, 0.12, 0.11
    Tasks:   1 total,   1 running,   0 sleeping,   0 stopped,   0 zombie
    Cpu(s):  0.2%us,  6.3%sy,  0.0%ni, 80.2%id,  0.0%wa,  4.5%hi,  8.8%si,  0.0%st
    Mem:  10693580k total,  6479980k used,  4213600k free,    22916k buffers
    Swap:  8323056k total,        0k used,  8323056k free,    80360k cached

      PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND                      
     2924 yongboy   20   0 82776  74m  508 R 51.3  0.7   3:53.95 server 

执行vmstateQ?/p>

vmstat
procs -----------memory---------- ---swap-- -----io---- --system-- -----cpu-----
 r b swpd free buff cache si so bi bo in cs us sy id wa st
 0 0 0 2725572 23008 80360 0 0 21 2 1012 894 0 9 89 2 0 

获取当前socketq接状态统计信息:(x)

cat /proc/net/sockstat
sockets: used 1024380
TCP: inuse 1024009 orphan 0 tw 0 alloc 1024014 mem 2
UDP: inuse 11 mem 1
UDPLITE: inuse 0
RAW: inuse 0
FRAG: inuse 0 memory 0

获取当前pȝ打开的文件句柄:(x)

sysctl -a | grep file
fs.file-nr = 1025216 0 1048576
fs.file-max = 1048576

此时McM于下面查询操作都是一个慢Q等待若q时间还不见得执行完毕?/p>

netstat -nat|grep -i "8000"|grep ESTABLISHED|wc -l 
netstat -n | grep -i "8000" | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}'

以上两个命o(h)在二三十分钟q去了,q未执行完毕Q只好停止?/p>

本次从头到尾的测试,所需要有的linuxpȝ需要调整的参数也就是那么几个,汇M下:(x)

    echo "* - nofile 1048576" >> /etc/security/limits.conf

    echo "fs.file-max = 1048576" >> /etc/sysctl.conf
    echo "net.ipv4.ip_local_port_range = 1024 65535" >> /etc/sysctl.conf

    echo "net.ipv4.tcp_mem = 786432 2097152 3145728" >> /etc/sysctl.conf
    echo "net.ipv4.tcp_rmem = 4096 4096 16777216" >> /etc/sysctl.conf
    echo "net.ipv4.tcp_wmem = 4096 4096 16777216" >> /etc/sysctl.conf

其它没有调整的参敎ͼ仅仅因ؓ(f)它们暂时Ҏ(gu)ơ测试没有带来什么媄响,实际环境中需要结合需要调整类gSO_KEEPALIVE、tcpmax_orphans{大量参数?br />

本文代表一ơ实践,不之处Q欢q批评指正?/p>

nieyong 2013-04-11 09:01 发表评论
]]>
100万ƈ发连接服务器W记之测试端qAhttp://www.aygfsteel.com/yongboy/archive/2013/04/10/397631.htmlnieyongnieyongWed, 10 Apr 2013 03:07:00 GMThttp://www.aygfsteel.com/yongboy/archive/2013/04/10/397631.htmlhttp://www.aygfsteel.com/yongboy/comments/397631.htmlhttp://www.aygfsteel.com/yongboy/archive/2013/04/10/397631.html#Feedback2http://www.aygfsteel.com/yongboy/comments/commentRss/397631.htmlhttp://www.aygfsteel.com/yongboy/services/trackbacks/397631.html重新~写试端程?/h2>

试端程序需要增加绑定本机IP和本地端口的功能Q以可能的向外发出更多的tcph。需要对client1.c重构Q增加参C递? 下面是client2.c的代?

若不指定端口Q系l会(x)随机挑选没有用到的端口,可以节省些心力?/p>

~译Q?/p>

gcc -o client2 client2.c -levent

参数解释

  • -h 要连接的服务器IP地址
  • -p 要连接的服务器端?/li>
  • -m 本机IP地址需要绑定的随机端口数量
  • -o 本机所有可用的IP地址列表Q注意所有IP地址都应该可?/li>

q行Q?/p>

./client2 -h 192.168.190.230 -p 8000 -m 64000 -o 192.168.190.134,192.168.190.143,192.168.190.144,192.168.190.145,192.168.190.146,192.168.190.147,192.168.190.148,192.168.190.149,192.168.190.150,192.168.190.151

太长了,每次执行都要_脓(chung)q去Q直接放在一个client2.sh文g中,执行很单方便多了?/p>

#!/bin/sh
./client2 -h 192.168.190.230 -p 8000 -m 64000 -o 192.168.190.134,192.168.190.143,192.168.190.144,192.168.190.145,192.168.190.146,192.168.190.147,192.168.190.148,192.168.190.149,192.168.190.150,192.168.190.151

保存Q赋值可q行:

chmod +x client2.sh

启动试Q?/p>

sh client2.sh

W三个遇到的问题Qfs.file-max的问?/h2>

试端程序client2.c在发出的数量大于某个|大概?0万时Q是Q通过dmesg命o(h)查看?x)得到大量警告信息?x)

[warn] socket: Too many open files in system

此时Q就需要检?strong>/proc/sys/fs/file-max参数了?

查看一下系l对fs.file-max的说?/p>

 /proc/sys/fs/file-max
This file defines a system-wide limit on the number of open files for all processes. (See also setrlimit(2), which can be used by a process to set the per-process limit,
RLIMIT_NOFILE, on the number of files it may open.) If you get lots of error messages about running out of file handles, try increasing this value:
echo 100000 > /proc/sys/fs/file-max
The kernel constant NR_OPEN imposes an upper limit on the value that may be placed in file-max.
If you increase /proc/sys/fs/file-max, be sure to increase /proc/sys/fs/inode-max to 3-4 times the new value of /proc/sys/fs/file-max, or you will run out of inodes.

file-max表示pȝ所有进E最多允许同时打开所有的文g句柄敎ͼpȝU硬限制。Linuxpȝ在启动时Ҏ(gu)pȝg资源状况计算出来的最佳的最大同时打开文g数限Ӟ如果没有Ҏ(gu)需要,不用修改Q除非打开的文件句柄数过此倹{?/p>

在ؓ(f)试机分?G内存Ӟ对应的fs.file-maxgؓ(f)386562Q很昄打开的文件句柄很受限Q?8万个左右? 很显Ӟ无论是测试端q是服务端,都应该将此D大些Q一定要大于{于/etc/security/limits.conf送所讄的soft nofile和soft nofile倹{?
注意ulimit -nQ仅仅设|当前shell以及(qing)由它启动的进E的资源限制?/p>

备注Q以上参敎ͼh包含和被包含的关pR?

当前?x)话修改Q可以这么做Q?/p>

echo 1048576 > /proc/sys/fs/file-max

但系l重启后消失?/p>

怹修改Q要d?/etc/sysctl.conf 文g中:(x)

fs.file-max = 1048576

保存q之生效:(x)

sysctl -p

再测Q就不会(x)出现此问题了?

一?G内存机器试机,分配7个网卡,可以做到不占用虚拟内存,对外发出64000 * 7 = 448000个对外持久请求。要完成100万的持久q接Q还得再惛_法?/p>

最l测试端l成如下Q?/p>

  • 两台物理机器各自一个网卡,每个发出64000个请?/li>
  • 两个6G左右的centos试端机?l定7个桥接或NATq接)各自发出64000*7 = 448000h
  • ׃用了16个网卡(物理|卡+虚拟|卡Q?/li>
  • 1M ≈ 1024K ≈ 1024000 = (64000) + (64000) + (64000*7) + (64000*7)
  • p费16G内存Q?6个网?物理+虚拟)Q四台测试机

备注Q?
下面p完成1M持久q接的目标,但在服务端还?x)遇到最后一个问题?/p>

nieyong 2013-04-10 11:07 发表评论
]]>100万ƈ发连接服务器W记之处理端口数量受限问?/title><link>http://www.aygfsteel.com/yongboy/archive/2013/04/09/397594.html</link><dc:creator>nieyong</dc:creator><author>nieyong</author><pubDate>Tue, 09 Apr 2013 09:26:00 GMT</pubDate><guid>http://www.aygfsteel.com/yongboy/archive/2013/04/09/397594.html</guid><wfw:comment>http://www.aygfsteel.com/yongboy/comments/397594.html</wfw:comment><comments>http://www.aygfsteel.com/yongboy/archive/2013/04/09/397594.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.aygfsteel.com/yongboy/comments/commentRss/397594.html</wfw:commentRss><trackback:ping>http://www.aygfsteel.com/yongboy/services/trackbacks/397594.html</trackback:ping><description><![CDATA[<h2>W二个遇到的问题Q端口数量受?/h2> <p>一般来_(d)单独对外提供h的服务不用考虑端口数量问题Q监听某一个端口即可。但是向提供代理服务器,׃得不考虑端口数量受限问题了。当前的1Mq发q接试Q也需要在客户端突?万可用端口的限制?/p> <h2>单机端口上限?5536</h2> <p>端口?6q制Q那??6ơ方gؓ(f)65536Q在linuxpȝ里面Q?024以下端口都是񔽎理员用P如rootQ才可以使用Q普通用户只能用大?024的端口倹{?<br /> pȝ提供了默认的端口范围Q?/p> <blockquote> <p>cat /proc/sys/net/ipv4/ip_<em>local_</em>port_range <br /> 32768 61000</p> </blockquote> <p>大概也就是共61000-32768=28232个端口可以用,单个IP对外只能发?8232个TCPh?<br /> 以管理员w䆾Q把端口的范围区间增到最大:(x)</p> <blockquote> <p>echo "1024 65535"> /proc/sys/net/ipv4/ip_<em>local_</em>port_range</p> </blockquote> <p>现在?4511个端口可? <br /> 以上做法只是临时Q系l下ơ重启,?x)还原? 更ؓ(f)E_的做法是修改<strong>/etc/sysctl.conf</strong>文gQ增加一行内?/p> <blockquote> <p>net.ipv4.ip_<em>local_</em>port_range= 1024 65535</p> </blockquote> <p>保存Q然后之生效:(x)</p> <blockquote> <p>sysctl -p </p> </blockquote> <p>现在可以使用的端口达?4510个(假设pȝ所有运行的服务器是没有占用大于1024的端口的Q较为纯净的centospȝ可以做到Q,要想辑ֈ50万请求,q得再想办法?/p> <h2>增加IP地址</h2> <p>一般假设本机网卡名UCؓ(f) eth0Q那么手动再d几个虚拟的IPQ?/p> <blockquote> <p>ifconfig eth0:1 192.168.190.151 <br /> ifconfig eth0:2 192.168.190.152 ......</p> </blockquote> <p>或者偷懒一些:(x)</p> <blockquote> <p>for i in `seq 1 9`; do ifconfig eth0:$i 192.168.190.15$i up ; done</p> </blockquote> <p>q些虚拟的IP地址Q一旦重启,或?<strong>service network restart</strong> ׃(x)丢失?</p> <p>Z模拟较ؓ(f)真实环境Q在试端,手动再次d9个vmware虚拟机网卡,每一个网卡固定一个IP地址Q这L(fng)Lơ重启都要重新设|的ȝ?/p> <blockquote> <p>192.168.190.134 <br /> 192.168.190.143<br /> 192.168.190.144<br /> 192.168.190.145<br /> 192.168.190.146<br /> 192.168.190.147<br /> 192.168.190.148<br /> 192.168.190.149<br /> 192.168.190.150<br /> 192.168.190.151</p> </blockquote> <p>在server服务器端Q手动添加桥接网卡和NAT方式|卡</p> <pre><code>192.168.190.230 192.168.190.240 10.95.20.250 </code></pre> <p>要求试端和服务器端彼此双方都是可以ping通?/p> <h2>|络四元l?|络五元l?/h2> <p>四元l是指的?/p> <blockquote> <p>{源IP地址Q源端口Q目的IP地址Q目的端口}</p> </blockquote> <p>五元l指的是Q多了协议)</p> <blockquote> <p>{源IP地址Q目的IP地址Q协议号Q源端口Q目的端口}</p> </blockquote> <div>在《UNIX|络~程?Q套接字联网APIQ第3版)》一书中Q是q样解释Q?/div> <blockquote>一个TCPq接的套接字?socket pari)是一个定义该q接的两个端点的四元l,x地IP地址、本地TCP端口受外地IP地址、外地TCP端口受套接字对唯一标识一个网l上的每个TCPq接?<br /> <br /> ...... <br /> <br /> 标识每个端点的两个|IP地址和端口号Q通常UCؓ(f)一个套接字?/blockquote> <p> 以下以四元组为准。在试端四元组可以q样认ؓ(f)Q?/p> <blockquote> <p>{本机IP地址Q本机端口,目的IP地址Q目的端口}</p> </blockquote> <p>h的IP地址和目的端口基本上是固定的Q不?x)变化,那么只能从本机IP地址和本机端口上考虑Q端口的范围一旦指定了Q那么增加IP地址Q可以增加对外发出的h数量。假讄l可以用的端口范围已经如上所设,那么可以使用的大致端口ؓ(f)64000个,pȝd?0个IP地址Q那么可以对外发出的数量?64000 * 10 = 640000Q数量很可观?/p> <h2>只有{源IP地址Q源端口}定对外TCPh数量</h2> <p>l测试,四元l里面,只有<strong>{源IP地址Q源端口}</strong>才能够确定对外发求的数量Q跟<strong>{目的IP地址Q目的端口}</strong>无关?</p> <h2>试环境</h2> <p>在server端,q且启动./server两次Q分别绑?000端口?000端口</p> <pre><code>./server -p 8000 ./server -p 9000 </code></pre> <h2>本机IP、端口绑定测试程?/h2> <p>q里写一个简单的试l定本机IP地址和指定端口的客户端测试程序? <script src="https://gist.github.com/yongboy/5343986.js"></script></p> <p>可以看到l(f)ibevent-*/include/event2/http.h内置了对l定本地IP地址的支持:(x)</p> <pre><code>/** sets the ip address from which http connections are made */ void evhttp_connection_set_local_address(struct evhttp_connection *evcon, const char *address); </code></pre> <p>不用担心端口Q系l自动自动随机挑选,除非需要特别指定:(x)</p> <pre><code>/** sets the local port from which http connections are made */ void evhttp_connection_set_local_port(struct evhttp_connection *evcon, ev_uint16_t port); </code></pre> <p>~译</p> <pre><code>gcc -o client3 client3.c -levent </code></pre> <p>client3q行参数?/p> <ul> <li>-h q程LIP地址</li> <li>-p q程L端口</li> <li>-c 本机指定的IP地址(必须可用)</li> <li>-o 本机指定的端?必须可用)</li> </ul> <p>试用例Q本机指定同L(fng)IP地址和端口,但远E主机和IP不一? <br /> 在一个测试端打开一个终端窗?Q切换到 client3对应位置</p> <pre><code>./client3 -h 192.168.190.230 -p 8000 -c 192.168.190.148 -o 4000 </code></pre> <p>输出?/p> <pre><code>remote host is 192.168.190.230 remote port is 8000 local ip is 192.168.190.148 local port is 4000 >Chunks: 1 Bytes: 505 </code></pre> <p>再打开一个测试端l端H口2Q执行:(x)</p> <pre><code>./client3 -h 192.168.190.240 -p 9000 -c 192.168.190.148 -o 4000 </code></pre> <p>H口2E序Q无法执行,自动退出?<br /> 接着在窗?l端l箋输入Q?/p> <pre><code>./client3 -h 192.168.190.230 -p 8000 -c 192.168.190.148 -o 4001 </code></pre> <p>注意Q和H口1相比Q仅仅改变了端口号ؓ(f)4001。但执行l果Q和端口1输出一模一P在等待接收数据,没有自动退出?/p> <p>剩下的,无论怎么l合Q怎么折腾Q?strong>只要一对{本机IP,本机端口}被占?也就意味着对应一个具体的文g句柄</strong>Q那么其它程序将不能够再ơ用?/p> <h2>Java怎么l定本地IP地址Q?/h2> <p>javal定很单,但有些限Ӟ不够灉|Q单U从源码中看不出来,api doc可以告诉我们一些事情? 打开JDK<em>API</em>1_6<em>zh</em>CN.CHMQ查看InetSocketAddresscȝ构造函数说明:(x)</p> <blockquote> <p>public InetSocketAddress(InetAddress addr, int port) <br /> Ҏ(gu) IP 地址和端口号创徏套接字地址?有效端口g?0 ?65535 之间。端口号 zero 允许pȝ?bind 操作中挑选暂时的端口?</p> <p>null 地址分配通配W?地址?</p> <p>参数Q?<br /> addr - IP 地址 <br /> port - 端口?<br /> 抛出Q?<br /> IllegalArgumentException - 如果 port 参数出有效端口值的指定范围?/p> <hr /> <p>public InetSocketAddress(String hostname, int port) <br /> Ҏ(gu)L名和端口号创建套接字地址?<br /> 试主机名解析?InetAddress。如果尝试失败,则将地址标记为未解析?</p> <p>如果存在安全理器,则将L名用作参数调用其 checkConnect Ҏ(gu)Q以查解析它的权限。这可能?x)导?SecurityException 异常?</p> <p>有效端口g?0 ?65535 之间。端口号 zero 允许pȝ?bind 操作中挑选暂时的端口?</p> <p>参数Q? hostname - L?<br /> port - 端口?<br /> 抛出Q?<br /> IllegalArgumentException - 如果 port 参数出有效端口值的范围Q或者主机名参数?null?<br /> SecurityException - 如果存在安全理器,但拒l解析主机名的权限?<br /> 另请参见Q?<br /> isUnresolved()</p> </blockquote> <p>InetSocketAddress的两个构造函数都支持Q看情况使用。注意int port传递gؓ(f)0Q即可做到系l随机挑选端口。追t一下源代码Q发现最l调?/p> <pre><code>private native void socketBind(InetAddress address, int port) throws IOException; </code></pre> <p>如何查看socketBind的原始C代码Q我׃清楚了,(zhn)若知晓Q希望指教一下? 构造一个InetSocketAddress对象Q?/p> <pre><code>SocketAddress localSocketAddr = new InetSocketAddress("192.168.190.143", 0); </code></pre> <p>然后传递给需要位|即可。诸如用nettyq接到某个服务器上,在connect时指定远方地址Q以?qing)本机地址</p> <blockquote> <p>ChannelFuture connect(SocketAddress remoteAddress, SocketAddress localAddress) Attempts a new connection with the specified remoteAddress and the specified localAddress.</p> </blockquote> <p>Netty 客户端连接API见:(x) <ahref="http: docs.jboss.="" org="" netty="" 3.="" 2="" api="" jboss="" bootstrap="" clientbootstrap.html"=""><a http:></p> <h2>Linux支持l定本机IP、端口原?/h2> <p>说是原理Q有些牵强,因ؓ(f)linux C提供了如何绑定函敎ͼ框架或者高U语a再怎么装Q在linuxq_下面Q需要这么调用:(x)</p> <pre><code>struct sockaddr_in clnt_addr; .... clnt_addr.sin_family = AF_INET; clnt_addr.sin_addr.s_addr = INADDR_ANY; //l定本机IP地址 clnt_addr.sin_port = htons(33333); //l定本机端口 if (bind(sockfd, (struct sockaddr *) &clnt_addr, sizeof(clnt_addr)) < 0) error("ERROR on binding"); if (connect(sockfd,(struct sockaddr *) &serv_addr,sizeof(serv_addr)) < 0) error("ERROR connecting"); ....... </code></pre> <p>构造一个clnt_addrl构体,本地IP或者端口赋|在connect之前Q先bindQ就q么单?/p> <p>更完整例子,可以参?<a >http://stackoverflow.com/questions/4852256/need-a-complete-snippet-example-of-binding-tcp-client-socket</a></p> <p> </p> <div>有关端口的更详细解释Q请参考《UNIX|络~程?Q套接字联网APIQ第3版)?.9?端口号部分?/div> <p> </p> <p>有关端口的问题,到此为止Q下一,回到试?/p><img src ="http://www.aygfsteel.com/yongboy/aggbug/397594.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.aygfsteel.com/yongboy/" target="_blank">nieyong</a> 2013-04-09 17:26 <a href="http://www.aygfsteel.com/yongboy/archive/2013/04/09/397594.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>100万ƈ发连接服务器W记之准备篇http://www.aygfsteel.com/yongboy/archive/2013/04/09/397559.htmlnieyongnieyongTue, 09 Apr 2013 01:50:00 GMThttp://www.aygfsteel.com/yongboy/archive/2013/04/09/397559.htmlhttp://www.aygfsteel.com/yongboy/comments/397559.htmlhttp://www.aygfsteel.com/yongboy/archive/2013/04/09/397559.html#Feedback1http://www.aygfsteel.com/yongboy/comments/commentRss/397559.htmlhttp://www.aygfsteel.com/yongboy/services/trackbacks/397559.html前言

试一个非常简单服务器如何辑ֈ100万(1M=1024Kq接Q的q发q接Qƈ且这些连接一旦连接上服务器,׃?x)断开Q一直连着?
环境受限Q没有服务器Q刚开始都是在自己的DELLW记本上试Q凭?6G内存Q和优秀的vmware workstation虚拟机配合,另外q得外借别拟机使用Q最l还得搭上两?G内存的台式机Q安装centosQ,最l才完成1Mq发q接d?

  • 试E序也很陋,一个C语言所写服务器E序Q没有Q何业务存在,收到h后发送一些头部,不断开q接
  • 试端程序也是用C语言所写,发送请求,然后{待接收数据Q仅此而已
  • 服务器端/试端内存都受限(8G不够使用)Q要惛_?024K的目标,需要放弃一些东西,诸如业务不是那么完整
  • 一台分?0G内存Centos服务器,两台分配6G内存Centos试端,两台2G内存Centos试?/li>
  • 假如热心的?zhn)可以提供丰富的服务器资源Q那再好不q了?/li>
  • 理论?00万的q发q接QIO密集型)Q加上业务,40G-50G的内存大概能够保?/li>

说明

以前也做q类似的工作Q量不大Q没记录下来Q一些压力测试和调优Q随着旉逝,早已忘记。这ơ是从零开始,基本上所有过E都?x)记录,一步一步,每一步都?x)遇到问题,q且l出相关解决问题的方法,最l完成目标?
Z方便Q服务器端程序和客户端测试程序,都是使用C语言Q不用像JAVA一样需要预先指定内存,感觉ȝ。用较为原始的语言来写Q可以避免不必要的调优工作。这中间Q可能会(x)I插Java代码的思考方式?/p>

可能需要懂点LinuxQCQJavaQ假如?zhn)有更好的做法Q或者徏议,L(fng)接告知,谢谢?/p>

Linuxpȝ

试端和服务器端都选用较ؓ(f)熟?zhn)?4位Centos 6.4Q?2位系l最多支?G内存Q太受限。IO密集型应用,对CPU要求不是很高。另外服务器保安装上gccQ那可以开工了?
所有端pȝ一旦安装完之后Q默认不做Q何设|?/p>

服务器端E序

服务器端E序依赖libev框架Q需要提前编译,然后存放到相应位|。下面是具体服务器端代码Q?

~译

gcc server.c -o server ../include/libev.a -lm

q行

./server -p 8000

在源码中默认指定?000端口Q可以通过-pq行指定新的端口? 开启了8000端口q行监听hQhttp协议处理cM于htmlfile chunked块编码传输?/p>

试服务器端E序

试E序使用libevent框架Q因其用简单,提供丰富易用接口Q但需要提前下载,手动安装Q?/p>

wget https://github.com/downloads/libevent/libevent/libevent-2.0.21-stable.tar.gz
tar xvf libevent-2.0.21-stable.tar.gz
cd libevent-2.0.21-stable
./configure --prefix=/usr
make
make install

注意make和make install需要root用户?/p>

试端程?/h3>

client1.c 源码Q?/p>

备注Q这部分代码参考了A Million-user Comet Application with Mochiweb, Part 3 Q根据需要有所修改?/p>

~译

gcc -o client1 client1.c -levent

q行

./client1

可能?4位系l会(x)遇到找不?strong>libevent-2.0.so.5情况Q需要徏立一个Yq接

ln -s /usr/lib/libevent-2.0.so.5 /lib64/libevent-2.0.so.5

卛_自动q接IP地址?92.168.190.133:8000的服务器端应用?

W一个遇到的问题Q文件句柄受?/h2>

试端程序输?/strong>

看看试端程序client1输出的错误信息:(x)

Chunks: 798 Bytes: 402990 Closed: 0
Req: 192.168.190.133 -/test/900
Req: 192.168.190.133 -/test/1000
Chunks: 998 Bytes: 503990 Closed: 0
[warn] socket: Too many open files
[warn] socket: Too many open files
[warn] socket: Too many open files

服务器端E序输出

服务器端最后一条日志ؓ(f)

online user 1018

两边都遇C文g句柄打开的情c(din)?
在服务器端查看已l连接,q且端口号ؓ(f)8000的所有连接数量:(x)

netstat -nat|grep -i "8000"|wc -l 
1019

但与服务器端输出数量对不上,增加所有已l徏立连接的选项Q?/p>

netstat -nat|grep -i "8000"|grep ESTABLISHED|wc -l 
1018

那么剩下的一条数据到底是什么呢Q?/p>

netstat -nat|grep -i "8000"|grep -v ESTABLISHED
tcp 0 0 0.0.0.0:8000 0.0.0.0:* LISTEN 

也就是server.c监听的端口,数量上对的上?

在测试服务器端,查看试q程打开的文件句柄数?/p>

lsof -n|grep client1|wc -l
1032

再次执行

ulimit -n
1024

也是是client1应用E序共打开?em>1032个文件句柄,而不?em>1024Qؓ(f)什么?
把当前进E所有打开的文件句柄保存到文g中,慢慢研究 lsof -n|grep client1 > testconnfinfo.txt

导出的文件可以参考:(x) https://gist.github.com/yongboy/5260773
除了W一行,我特意添加上供友善阅ȝ头部列定义,也就?032行信息,但是需要注意头部:(x)


COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
client1 3088 yongboy cwd DIR 253,0 4096 800747 /home/yongboy/workspace/c_socket.io_server/test
client1 3088 yongboy rtd DIR 253,0 4096 2 /test_conn
client1 3088 yongboy txt REG 253,0 9697 799991 /home/yongboy/workspace/c_socket.io_server/test/test_conn_1
client1 3088 yongboy mem REG 253,0 156872 50404 /lib64/ld-2.12.so
client1 3088 yongboy mem REG 253,0 1922152 78887 /lib64/libc-2.12.so
client1 3088 yongboy mem REG 253,0 145720 76555 /lib64/libpthread-2.12.so
client1 3088 yongboy mem REG 253,0 47064 69491 /lib64/librt-2.12.so
client1 3088 yongboy mem REG 253,0 968730 26292 /usr/lib/libevent-2.0.so.5.1.9
client1 3088 yongboy 0u CHR 136,2 0t0 5 /dev/pts/2
client1 3088 yongboy 1u CHR 136,2 0t0 5 /dev/pts/2
client1 3088 yongboy 2u CHR 136,2 0t0 5 /dev/pts/2
client1 3088 yongboy 3u REG 0,9 0 4032 anon_inode
client1 3088 yongboy 4u unix 0xffff88007c82f3c0 0t0 79883 socket
client1 3088 yongboy 5u unix 0xffff880037c34380 0t0 79884 socket
client1 3088 yongboy 6u IPv4 79885 0t0 TCP 192.168.190.134:58693->192.168.190.133:irdmi (ESTABLISHED)
client1 3088 yongboy 7u IPv4 79889 0t0 TCP 192.168.190.134:58694->192.168.190.133:irdmi (ESTABLISHED)
client1 3088 yongboy 8u IPv4 79891 0t0 TCP 192.168.190.134:58695->192.168.190.133:irdmi (ESTABLISHED)
client1 3088 yongboy 9u IPv4 79893 0t0 TCP 192.168.190.134:58696->192.168.190.133:irdmi (ESTABLISHED)

可以看到文g句柄是从0u开始,0u上面?个(5个mem + 3个启动)q程Q?032 - 8 = 1024个文件句柄,q样和pȝ限制的值吻合了?

root用户~辑/etc/security/limits.conf文gdQ?/p>

* soft nofile 1048576
* hard nofile 1048576
  • soft是一个警告|而hard则是一个真正意义的阀|过׃(x)报错?/li>
  • soft 指的是当前系l生效的讄倹{hard 表明pȝ中所能设定的最大?/li>
  • nofile - 打开文g的最大数?/li>
  • 星号表示针对所有用P若仅针对某个用户dIDQ请替换星号

注意Q?
1024K x 1024 = 1048576K = 1MQ?百万多一炏V?/strong>

备注Q测试端和服务器端都需要作此设|,保存退出,然后reboot卛_生效?

W一个问题,p样克服了。再ơ运?/client1试E序Q就不会(x)出现受打开文g句柄的限制。但大概在测试端打开对外28200个端口时Q会(x)出现E序异常Q直接退出?/p>

D错?/p>

q个也是E序没有处理端口不够用的异常Q但可以通过增加端口q行解决?

备注Q? 但测试端单机最多只能打开6万多个连接,是一个问题,如何克服Q下一解x问题Qƈ且还?x)遇到文件句柄的受限问题?/p>

nieyong 2013-04-09 09:50 发表评论
]]> վ֩ģ壺 Զ| Ͱ| | | | ʩ| | ƽ| ¡| ɽ| °Ͷ| | | | | ݳ| Ұ| | | | | Ʊ| | | | | | Ǹ| | | | ̶| Դ| ʤ| | ֦| | ȳ| ¤| | |