Chinaunix首页 | 论坛 | 博客
  • 博客访问: 26393
  • 博文数量: 5
  • 博客积分: 90
  • 博客等级: 民兵
  • 技术积分: 45
  • 用 户 组: 普通用户
  • 注册时间: 2010-08-30 10:57
文章分类

全部博文(5)

文章存档

2011年(5)

我的朋友
最近访客

分类: 云计算

2011-06-09 00:09:09

很多同行一提起网络服务程序,好像就必须多进程多线程,必须领导者/跟随者,必须线程池worker模式,必须这个锁那个同步,好像缺少这些就是很没水平的设计一样。本人一碰到这样的论调,通常私下即会将此人归为没见识一类――无论这人供职什么知名企业,身处多么高位,做了多少年系统设计,都一个鸟样。

    网络服务程序,一般有如下要求:

    1.稳定性:长期运行不用重启也能正常服务。

    2.能支持大并发,过万连接。

    3.新建连接速度,认证/服务反应时间。

    4.如果是引擎级别的库,还需要支持协议易扩展,模块可装卸等

    5.配置动态更新,易调试等其它要求

    多进程多线程的模式确实能解决上述问题,但通常写得复杂无比五万行C++算少了。通常一人先很有成就感地去搭底层框架,再要一堆人很爽快地去“补”功能,再要另一大堆人坚毅地去测试,然后要一小堆技术骨干痛苦着去改BUG,没个小半年的周期根本下不来。最后还必须推迟研发周期,还有部分人顶不住压力离职,有些项目直接就没有结果,无疾而终了。可是,必须这么复杂?

    提到这时估计就有人很不爽了,不说废话。转一转思路,单进程作为服务程序的核心,也不是不能解决这些问题的,而且经本人实践,似乎还有点满足要求过头了。一条条说说:

    稳定性方面,主要面临俩大问题:一是踩堆或栈内存,二是内存碎片;这两点其实什么架构都会面临,解决办法也大同小异,第一点手段用工具或自己写malloc/free,调试时动态采点打日志;第二点手段用全局级内存池,只管8K以下的分配,固定大小的块,挑着分配就行,这池用C写应该不会超过300行。

    大并发支持方面,首先是网络模型要支持大并发,linux下就用epollwin下就用iocp,其次是所有的连接都要做成非阻塞,包括acceptconnect,再次是要设计一个循环缓冲,方便读数据和写数据,写数据再支持缓冲链的形式,这样封装成库也不会超过500行(不含循环缓冲)。

    新建连接速度就不用提了,把那个listenbacklog设大点,然后从接到新连接开始,到挂新连接到epoll里这段时间不要堵塞操作,不要大量循环,尽量少的系统调用例如malloc之类的,它的速度自然会很可观。

    至于可扩展,学着apache写几个支持钩子函数链的宏,再在创建/销毁连接,连接成功/失败,读到/写出数据,定时器回调/重读配置等点调用函数链,再写个模块支持的实现,就OK了,代码量加起来都不应超500行。

    动态更新支持,其实每次epoll出来检查一下是否有新信号标志设置,有就调用对应的函数链,根本无需要上锁,最多就是读配置时所有服务都会略堵一下,但基本不会受影响,总比上锁好多了。

    可调试?直接在上述框架里加个支持telnet的连接侦听类型,做按输入来输出调试信息,简单得很,核心功能代码量不会超过200行。可以放心读写功能模块里的信息,反正又没有多线程的互斥同步问题。

    这样大体上看来,单进程的框架基本上还是能做到大并发、高性能、易扩展的,而且由于精简内耗,代码量极少,代表着维护工作量大大降低。只是具体实现时也会碰到很多与非单进程下不同的问题需要解决,这里略提一些本人碰到的:

    定时器:定时器就学linux内核里的jiff,在epoll出来后马上设这个值,这就不用多线程。

    外设IO,或其它没法用epolliocp整合处理的业务,例如radius/ldap等外部认证,则单独开一个内部UDP pair,或者用atomic类型,或者直接自己做两个unsigned long的变量,做成主动对象的形式,多开个进程或线程,这边通知要处理,那边回信说完成了,又因为双边通信都是单一生产者单一消费者,用两个之前提到的循环缓冲来存储通信内容或内容的指针,就可避开限制。

    数据库操作:如果数据量少,直接全读到内存里缓存吧,如果多,就用主动对象。

    SMP:有时觉得SMP挺浪费的,很多设计说是多进程多线程能利用它提高性能,却由于对OS调度不熟悉,基本上没真利用上,给16个核和给一个核是一般效果。在单进程模式里也没利用上SMP的优势,但其实总体来讲,单进程模型免除了大部分的内耗,对网络传输层提供极薄的一层抽象封装,它本身是极高效的,只要在实现上层功能时小心处理,通常这种架构它的CPU占用很低的,其它核就留给其它服务器程序吧,或者留给其它堵塞式的业务。

    另外公布一下本人的实践数据,引擎代码在4000行纯C左右,在1G内存,1.7G赛扬D上跑TCP代理,在网络IO达到75Mbps,连接数达到1500时,CPU也不超过%35,内存也不超过300M,这其中还包括了OS和业务模块占的内存。

    其实看看lighttpd的实现,它也是支持单进程的,也很高效,这就已经能说明问题了。

    补充一句废话,C++实在不是个好语言,特别是在服务程序设计方面,它常把人带进错误思路,也没见到过几个用C++写的比较稳定的开源网络服务程序,一上压力测试就挺不住,有点软蛋了!

阅读(2033) | 评论(0) | 转发(0) |
0

上一篇:sed & awk语法总结

下一篇:没有了

给主人留下些什么吧!~~