2012年4月22日星期日
2012年4月7日星期六
大量短连接的Server中的惊群问题
最近继续完善自己的多进程非阻塞网络服务框架arch,对于所谓的惊群(Thundering herd)的问题,查看了在这个问题上nginx源码以及其它一些非开源代码,公司内部代码中的处理方式,有以下的思考:
惊群问题(Thundering herd problem),wiki上的解释简单说是“大量处理进程/CPU阻塞在一个调用上,由于某个触发条件导致都被唤醒,但只有一个进程能继续处理,其它均失败”。惊群现象会浪费较多的CPU。这种现象可以出现在很多场景中,以下讨论的具体场景为处理大量短连接的Server中的惊群。
这种场景以Web Server为典型,一般有多个进程/线程同时监听80端口(poll非阻塞IO方式),则当有一个客户端连接上来时,所有的等待者均被唤醒,继而都调用accept处理,但只有一个能成功,其它均失败。
目前较多的实现是基本不考虑惊群问题,如检查的第一个公司内部实现代码,lighthttpd。Redis因为是单进程单线程的实现,故没有考虑此问题。
Nginx是用进程锁的方式解决该问题,即确保在某一个时刻,只有一个进程监听端口处理接收的连接;后续通过比较复杂的手段在多个进程间切换监听工作达到负载均衡的效果,仍然用到进程锁。
Nginx的实现对于我来说过复杂了。我在arch中用了一个较为简单方式解决这个问题。
arch是一个多进程的框架实现,故这里先讨论多进程模型下的一种较简单的解决方法:
1. 一个主控进程(Manager)监听指定端口,将FD加入到非阻塞IO集合中,用类poll方式监听(select/poll/epoll)
2. 启动N(N=CPU个数)个工作IO进程(Worker),建立Worker和Manager之间的通信连接(Linux下只能用UnixDomainSocket, 某些Unix可用Stream管道)
3. 以上是进程初始化时的工作,当一个连接发生时,Manager接受此链接,马上将该连接的文件描述符发送到一个Worker进程(同时关闭文件描述符),马上返回到自己的等待状态等待处理下一个连接;(这里的选择Worker进程即是复杂均衡的判断逻辑,一般来说轮询选择就可以达到较好的平衡状态)
4. Worker进程接收到文件描述符后,加入到自己的非阻塞IO集合,读取数据处理业务逻辑
同Nginx的实现一样,arch也避免了惊群现象,不同之处在于arch用到了进程间文件描述符传送,避免了复杂的锁实现;而Nginx用了进程锁,避免了文件描述符传送的系统调用;后续会比较一下两者性能区别。
多线程模型下较为简单,只需要采用类似Nginx的锁方式,结合arch的manager+worker模型:
1. 启动Manager线程,监听定端口,将其加入到非阻塞IO集合中,用类poll方式监听(select/poll/epoll)
2. 启动N(N=CPU个数)个工作IO线程(Worker)
3. 当一个连接发生时,Manager接受此链接,马上将该连接的文件描述符交给一个Worker线程马上返回到自己的等待状态处理下一个连接;(这里的选择Worker进程即是复杂均衡的判断逻辑,一般来说轮询选择就可以达到较好的平衡状态)
4. Worker线程接收到文件描述符后,加入到自己的非阻塞IO集合,读取数据处理业务逻辑。
不过,对于编写C/C++的Server程序来说,多线程应当是尽量避免的。这倒是题外话了。
2012年2月4日星期六
《古今笑》一则
读《古今笑》,谬误部第五中开篇第一则颇为有趣,说的是乡下人经常以讹传讹,将寺庙,神像之原名附会为一些可笑的名称。如谐音“杜拾遗”变为“杜十姨”,“伍子胥”称为“伍髭须”;“文宣王”因为年代久远只余一“王”以及“宣”字中的“一”字,故被附近的和尚附会为“一字王佛”。及乡下人认为“伍髭须”没有老婆,而将“杜十姨”移到“伍髭须”相配,更是令人绝倒。
另外从这则里也得到一个典故:吴王夫差在伍子胥被迫自杀后,以鸱夷盛伍子胥尸沉之江中,故称伍子胥为“鸱夷子”。《史记·越王勾践世家》也记载范蠡”变姓名,自谓 鴟夷子皮”,可能与伍子胥有一些关系。
2012年1月20日星期五
Snova的C4在几个免费PaaS平台上的部署(Openshift, CloundFoundry, Heroku, Jelastic)
C4主要是从snova-heroku部分移植,修复了一些bug,性能大大增强,实用性大为增强,不再只是玩具试验性质的东东了。
Openshift
- 注册帐号
到这个链接注册https://openshift.redhat.com
- 安装工具
安装命令行工具rhc,安装依赖ruby以及gem, https://openshift.redhat.com/app/express#quickstart
注意, gem安装rhc可能被防火墙中断,可能需要设置代理,代理可以用snova设置,如
gem install --http-proxy http://127.0.0.1:48100 rhc
- 部署
将snova-c4-server-[version].war 放到一个创建的空目录下,然后在命令行下进入该目录,逐个执行下面的命令:
rhc-create-domain -n <domainName> -l <yourId> -p <yourPassword> 创建主域名, 部署新应用是这一步可不执行
rhc-create-app -a <appName> -t jbossas-7.0 -p <yourPassword> 创建app
cd <appName> 进入上一步创建的目录
mv ../snova-c4-server-[version].war <appName>/deployments/ROOT.war
git rm -r src pom.xml
git commit –m “delete”
git push 以上三步重新部署同一个app时可不执行
git init
git add .
git commit –m “deploy”
git push
CloundFoundry
- 注册帐号
注册, https://my.cloudfoundry.com/signup, 注意,注册不是马上成功,似乎是第二天才会收到注册成功的邮件
- 安装工具
安装命令行工具vmc,安装依赖ruby以及gem,和openshift的工具rhc安装过程类似
http://start.cloudfoundry.com/tools/vmc/installing-vmc.html
- 部署
将snova-c4-server-[version].war放到任意的空目录下,然后在命令行下进入该目录,逐个执行下面的命令
vmc target api.cloudfoundry.com
vmc login
vmc push <appname> —— 此处appname为任意名称,为域名一部分,此命令执行后有后面的交互,参照下面的输入Y/N
Would you like to deploy from the current directory? [Yn]: Y
Application Deployed URL [<appname>.cloudfoundry.com]: <回车>
Detected a Java Web Application, is this correct? [Yn]: Y
Memory Reservation (64M, 128M, 256M, 512M, 1G, 2G) [512M]: <回车>
Creating Application: OK
Would you like to bind any services to 'snova4'? [yN]: n
Uploading Application:
Checking for available resources: OK
Processing resources: OK
Packing application: OK
Uploading (843K): OK
Push Status: OK
Staging Application: OK
Starting Application: OK
Heroku
参考snova中heroku的wiki即可
Jelastic
- 注册帐号
- 部署
完全图形化的操作,无需安装工具,按照说明将war上传并deploy到ROOT下即可
http://jelastic.com/docs/upload-deploy-application
后记:
这几个所谓的PaaS平台中,粗略观察下,纯以平台IO性能而言,似乎Openshift较差,CloundFoundry最好,已接近或超过AppEngine;部署上,Jelastic部署最为简单,完全界面上操作,其它几个则相对复杂,需要安装各种复杂的命令行工具部署,简直到了”非程序员不能为也的地步”了。
2012年1月9日星期一
字符串匹配算法
今日,研究了一天的字符串匹配算法,小有所得。主要是从这个链接学习, http://www-igm.univ-mlv.fr/~lecroq/string/
理论上,这里算法都比glibc中strstr的算法复杂度小,但在实际场景中,特别是和目前的开发的产品中关键字匹配场景下,无论是Boyer-Moore还是Knuth-Morris-Pratt等这些经典的算法实现都比strstr慢得多,而strstr的默认算法仅是一种高度优化过的Brute Force实现(Linux下C的测试结果证明如此,java下根据默认string.IndexOf算法看来,可能另有差别,需要进一步证明)。
目前得到一点结论是,这些经典的算法中都有预处理阶段,而Brute Force实现并无此阶段,当是预处理阶段耗时较多造成的差别。
(从200字节中查找20字节字符串1000000次, strstr:0ms, 其它最优的实现是250ms+)
2012年1月7日星期六
关于《郭嘉传》的一事
维基上关于林彪的条目中有一段说1966年9月,毛让林读《三国志》中的《郭嘉传》和《宋书》中的《范晔传》。
重读《郭嘉传》,契合当时环境下最重要的就是是曹操在郭嘉死时对大臣们说的一段话,就是毛对林的暗示,以太祖自喻,以郭嘉喻林。(林也是较为年轻,亦是多病之身)
毛这里借曹操之口告诉林值的以天下事相托,不过另外半句从《范晔传》中传达的信息却是险恶万分,这里暂且不谈。
”及薨,临其丧,哀甚,谓荀攸等曰:「诸君年皆孤辈也,唯奉孝最少.天下事竟,欲以後事属之,而中年夭折,命也夫!」“ ——《郭嘉传》