??xml version="1.0" encoding="utf-8" standalone="yes"?>
之前几天说过Q因为经?/span>iocp实现Q以下简U经典实玎ͼ多个ioU程l定在一?/span>iocp上,q样内部理?/span>iocp队列的处理,内部军_是不是需要线E切换,我上ơ修改的一个版本(以下U实?/span>2Q,用了多个ioU程Q每?/span>iocp队列仅绑定一?/span>ioU程Q一l用户共享一?/span>ioU程Q这和经典的多线E?/span>epoll模型的做法是很相似的Q这h?/span>ioU程是可以独立控制了Q但理论上这U做法没有发?/span>iocp自动理U程切换的优势,昨晚没事用这两种实现分别做了?/span>echoserver试了一下,q两套实C码仅40行左右不同,其他完全一P效果真的是差很多Q测试仅用一个进E模拟了4000个客L(fng)Q每U?/span>1个包Q先看实?/span>2的,cpu?/span>14%Q?/span>2?/span>ioU程Q?/span>1?/span>acceptU程Q?/span>1个主U程Q其他线E都没干z闲|?/span>
Cpu |
Memory |
Threads |
handles |
14 |
40088k |
8 |
4236 |
Cpu |
Memory |
Threads |
handles |
0 |
39244k |
7 |
4336 |
说实话,在测试之前我也没惛_有这么大的差距,l典实现是1.2w个连接连上来q是q样Q就是内存占用多一点:(x)
Cpu |
Memory |
Threads |
handles |
0 |
112068k |
7 |
12280 |
?fn)惯上L人喜Ƣ拿epoll?/span>iocp来对比,我到现在也没看到真正公^的对比,q是相对公q的也没见到Q因为在我看来,要对比硬件应该是一L(fng)Q?/span>os都应该是最新的Q最重要的是Q?/span>server端程序应该都是发挥了各自优势的,如果拿我q里的实?/span>2M?/span>iocp的水q_epollҎ(gu)Q势必造成?/span>epoll差很多的l果Q然而这昄是不正确的?/span>
epolll典多线E模式实际实现和实现2很相|理论上也有类似的U程切换问题Q不知道效率怎样?/span>
回调函数实在是用得太q泛Q回调函数又有多U实现方式,如:(x)
1?span style="font:7.0pt "Times New Roman""> 静态函?/span>
2?span style="font:7.0pt "Times New Roman""> 虚函?/span>
3?span style="font:7.0pt "Times New Roman""> 函数对象
4?span style="font:7.0pt "Times New Roman""> 传统c函数Q通过一?/span>void *传递对象地址Q内部强制{?/span>
5?span style="font:7.0pt "Times New Roman""> fastdelegate
6?span style="font:7.0pt "Times New Roman""> Tr1::function + bind
7?span style="font:7.0pt "Times New Roman""> Boost::Function + bind
基本上速度是按照由快到慢的序排列的,是
1 > 2 > 3 > 4 > 5 > 6 > 7
其实234速度很接q,有的时候函数对象效率更高一点,基本上越是高U的Ҏ(gu)使用h方便,但速度慢Q越是传l的Ҏ(gu)速度快Q呵呵,看来?/span>server端程序要l合考虑效率太新的东西还是要用啊,q是用传l的Ҏ(gu)比较靠谱一点,当然如果调用ơ数不多的地方,使用更方便的Ҏ(gu)q是好一些,毕竟我们要综合权衡,而不能死板恪守教条?/span>
之前设计了一套网l框Ӟ持箋改进了很多年Q用在很多目上,l合效率q行Q也很稳定,一直以来对q套东西信心满满QM为啥问题都好解决Q但最q就有个需求让我选择q是改了下这个框架?/span>
之前的框架是q样的,可以开一l?/span>N?/span>ioU程Q可以开一l?/span>N个同步线E(默认1个)Q可以开一l?/span>N个异步线E(默认1个)Q可以开一l?/span>N?/span>timerU程Q默?/span>1个)Q可以开一l?/span>N个异步线E(默认cpu个)Q每l可独立受控Q每l可支持自定义消息,可支?/span>timerQ一l?/span>N个如?/span>N大于1则无法直接给q组里面的特定线E发消息Q只能给一l发消息Q这个组里面?x)选择某个合适的U程处理q个消息Q这也是iocp高效和典型的用法了,但这也正是问题的l症所在?/span>
Linux下的多线E服务器更常见的做法跟这个不大相|一般都是将某些socket分配到某些线E?/span>epollQ分好之后就是固定的Q不再变化,?/span>Iocp?/span>socketl定Cl线E的做法不同Q由于某?/span>socket直接l定C某个U程Q所以有些问题就变得单了Q如同一个连接的在同一个线E内消息q行了同步,要跟ioU程l定U有化数据也单了Q而且每个U程可独立受控,所以很Ҏ(gu)实现一l?/span>io各自?/span>tlsQ线E局部存储)数据Q而我现在做的q套框架是q方面不好控了,其实也很难说q两U意义上的框架到底谁更优Q如用在web型应用上q种socket被一l?/span>ioU程理的模式很方便效率也高Q但我现在的需求需要某?/span>socket使用U程相关数据Q以避免数据之间的锁Q我用内存换旉Q由于在原来的框架上增逻辑难以实现可直接控?/span>ioU程的框架的Q所以花了一个晚上重新改写了一套框Ӟ在原?/span>iocpframe的基上派生了一l带2名称的类Q除替换cd之外只修改了几十行代码就做好了,ȝ来说q旉q是比较?yu)的。修改后ioU程一l,但独立受控,外部可对q组U程中的某一个直接发消息Q基本满了需求,现在要给每个ioU程l定U有数据q触发特定消息比之前单多了,而且l对无锁?/span>
׃原先?/span>appserver功能不断增多Q最q又增了两个功能Q需要不断从后端memcached中提取数据ƈq行计算Q由于提取数据量大且频繁Q导致效率很低,_测了一下,获取数据和格式化{操作花?/span>90%以上的时_(d)由此设想?/span>memcached改写或重写一个支?/span>memcached的服务器Q将计算功能?/span>memcached做到一P让获取数据的路径最短,也就最大限度减了数据传输和格式化{操作,是cM存储q程一样啦Q这部分可以考虑使用插g来实玎ͼ甚至可考虑使用脚本语言来实现?/span>
|上搜了一下,果然发现早有么干了,正所谓英雄所见啊Q呵c(din)具体方法倒很多,自定?/span>key命名Q根据特D?/span>key?/span>get?/span>set?/span>replace上做Ҏ(gu)操作Q或者根据命令中?/span>flag{做Ҏ(gu)处理Q或者扩?/span>stat命o(h){,都是可以的,我们暂时p虑修改Ҏ(gu)的键值做Ҏ(gu)处理?/span>
要做一个完备的既支?/span>ascii命o(h)又支?/span>binary命o(h)的兼?/span>memcachedq是有一点点ȝ的,我暂时也没有太多需求,所以就仅支持了ascii命o(h)Q其实也是考虑支持ascii的客L(fng)更多Q各U语a的支?/span>mc的客L(fng)C胜数Q但大多只支?/span>ascii命o(h)。由于我之前Z试服务器框架效率,做过一个支?/span>ascii命o(h)?/span>memcached兼容版本Q因此拿q来直接使用太方便了Q这个版本的实现其实很容易,如果有一个较好的框架代码的话基本上在一天之内可做完Q当然要做到很好可能需要多׃些时_(d)我现在做的也不是特好Q要完全取代memcached使用q是有些差距Q主要是一些过期机制等没完全实玎ͼ虽然速度上比标准mc版本q要快一点,呵呵Q因为暂时的是不需要这些过期机Ӟ所以也没打这个版本实玎ͼ其他功能基本上都有?/span>
以后准备这?/span>memcached解码部分作ؓ(f)一个单独的解析器,和支持其他协议一P换上q个解析那就支持mc协议了,q是很方便的Q以后有I是要做个支持binary协议的,以便可以更高效的解决问题?/span>
惛_server能支?/span>Memcached协议真是好啊Q客L(fng)基本只要用个libmemcached好了,多服务器分布Q容错,多䆾数据啥的都有现成的解x案,只要?/span>server做稳定了基?/span>ok了,对咱q种团队来说再合适不q了Q节省了很多开发维护成本啊Q现在内存这么便宜,部v几个点实在是?/span>easy的问题?/span>
最q要一些数据放到内存里面做很高的ƈ发操作,考虑了很多方案,
1?nbsp;单点使用map hash_map{自q理?/span>
2?nbsp;?/span>sqlite内存表?/span>
3?nbsp;?/span>fastdb内存数据库?/span>
4?nbsp;?/span>ExtremeDbQ?/span>TimesTen{?/span>
比较试了一?/span>123Q发现还是自己实现速度最快,?/span>fastdb模式?/span>3-5倍,fastdb模式?/span>sqlite内存表模式快10倍左叻I׃自己实现不具有典型通用性,多线E下讉K效率?x)下降,要管理多U程下各U更新查扄q是比较ȝ的,所以在1?/span>3Ҏ(gu)之间U结?/span>
Z使得决策更好一些,暂时q没做决定,ZC方等上面搜烦了一些论文来看,看来看去看得真来气啊Q虽焉叫内存数据库但各U实现的都有Q有?/span>gdbm来做的,有直?/span>map理的,?/span>hash理数据的,?/span>t?wi)管理的Q有数组队列理的,有的明显是个不大变的东西还弄个啥事务的Q靠Q刚刚居然还看到一鸟文《电(sh)|监控系l实时数据库的设计与实现》里面的试居然?/span>1000条,插入旉80毫秒Q真可笑啊,区区q么Ҏ(gu)据也好意思测Q还要花80毫秒Q还自以为很快,q个速度臛_可提?/span>1000倍以上啊Q这帮垃圾,写的啥鸟文章Q研I个屁啊?/span>
看完q十来篇论文Q俺的思A又回?/span>1999q_(d)当年我给别h优化q一个电(sh)信计费的软gQ看的论文里面有好几讲?sh)信计费的)Q当时有个朋友的朋友拿了个需求过来,7000万条记录Q原来计费单要花十几个时吧,我帮他改了下Q十来分钟就完了,朋友很满意,当时的做法很单,是弄了?/span>mmtableQ大体就是跟mapcM的东西吧Q那个时?/span>mapq没行hQ俺也不知道Q所以就自己弄了个内存表Q内部基本就是二分查找了Q那个时候我?/span>hash都不大熟(zhn),B?wi)之cȝ法刚接触也不会(x)用,p么个东西当时的电(sh)脑也只要花十来分钟,我估计就是那个老程序放在现在的普通台式机上要不了几秒钟就可算完。也不知道这么几千万条记录的需求怎么在这帮h眼里成了什么v量数据,对俺来说跟玩似的Q区区几千万嘛,不过是俺拿来试用的?/span>
d中做了个md5 hash反查的东西,数据都是几百亿到几万亿的Q后来的效果是一个文件可存万亿记录,一ơ查询^?/span>1.2?/span>IOQ即使全攑֜SATA盘上也十来毫U而已?/span>
区区几千万条记录咋就叫什么v量数据呢Qv量个毛啊Q内存都攑־下的叫什么v量,现在服务器动不动都是几十G内存Q区区千万根本算不上什么,查询定位都可到微妙了Q?/span>1U插入至千万条了,居然q看?/span>1000条插入的试Q真是不得不佩服国内q帮垃圾研究生的水^Q也不知道这U论文咋p通过审查Q只能得出结Z们的老师也都是猪?/span>
骂归骂自q问题q需要l努力,对咱目前的需求来说自q理数据,即一个线E都搞得定,因ؓ(f)不过区区几个表,几十万条记录而已Q不q这U?/span>10q前咱就?x)的技术还真是拿不出手Q怎么的也得做得更好一点,呵呵Ql研I吧Q多U程下内存数据库Q从概念上看的确是个很有吸引力的东西Q要是性能跟得上,其实在很多地方可以取代普通的数据l构用法了,可以大大减少~程隑ֺQ甚x在想如果有个支持事务的内存数据库Q之前设计的cadcY件的undo/redo都可以用事务来实玎ͼ完全可以抛弃先前设计的复杂结构,其实q种东西即不用内存数据库就是用个sqlite都完全能搞定Q唉Q往事不堪回首啊Q看来数据库斚w的确得多花功夫,特别是多U程和分布式模式下的内存数据库?/span>
最q给自己换了个老板Q忙了一D|_(d)所以有几个月没写博客,今后q是要争取多写啊Q呵c(din)?/span>
换来新地方,W一件大的事情就是修改后端架构和通信协议Q架构也设计得很普通,因ؓ(f)q边的业务不需要太q复杂的后端Q所以就单设计了一下,基本是参?/span>web的模型,W合我一贯的?/span>web学习(fn)的思想Q弄了个gate理入口Q相当于web下的webserverQ后端其他服务器挂在?/span>gate下,相当?/span>web模型下的appserverQ或?/span>fastcgi模型?/span>fastcgiq程Q?/span>gate上管理连接、合法性检、登录、加密、压~、缓存?/span>Gate和后端通信本来惛_?/span>fastcgi协议Q但看了之后觉得fastcgi协议q是复杂了,所以就设计了一个更单的协议Q?/span>gate和后?/span>server之间可传?/span>key:value型数据对Q?/span>value不局限于字符Ԍ可以是Q意数据,q样基本满了当前的需求,W一版放上去之后也运行良好,C天也基本持箋E_q行快一个月了,没出q什么事情。由于在gateq边~冲?/span>job理Q所以后?/span>server升很方便,随时可关闭更斎ͼgate?x)在H口旉内将未执行完成的d重新提交Q有此功能可攑ֿ大胆的升U后端,q个月这L(fng)工作做了几次Q在架构修改之前q样的事情几乎是不敢做的Q因Z旦升U所有用户全部断开q接Q而现在用户则基本无感觉?/span>Gate上的~存层ؓ(f)后端减少了一些压力,q个~存是按照请求的md5?/span>key做的QƈҎ(gu)协议配置时效Q有?/span>cache后端大多数服务可不设计缓存或降低~存设计的复杂度?/span>Gate上针Ҏ(gu)感数据统一做了加密处理Q主要是辛辛苦苦整理的数据不能轻易让竞争Ҏ(gu)H去了,呵呵?/span>Gate也做了压~,现在是针?/span>>=128长度的包q行压羃Q用了qlzQ压~效率还是很不错的,速度很快。目?/span>gate后端挂接的既?/span>win上的server也有linux上的serverQ这是一开始就q么规划的,现在看来当初的目的达CQ合发挥各自的优势Q有的项目在原有pȝ上跑得好好的Q没必要重新开发嘛?/span>
协议设计上本来我是计划二q制混合json格式Q以二进制ؓ(f)主,但尝试了一个协议之后发玎ͼq边的小伙子们对直接操纵内存普遍技术不q关Q他们大多是?/span>java开始的Q后来才学习(fn)cQ对字符串用得很熟练Q权衡之下采用了jsonZQ合二q制的方案,q样修改之后的协议和他们之前使用?/span>xmlcMQ就是更更紧凑一点,使用Ҏ(gu)上很cMQ从现在的效果看q行Q?/span>json格式Z的协议当然不能跟使用pb之类的相比,解析效率上大U单U程每秒解析20来万10?/span>obj的对象,速度上不太快但也不太慢,对付一U至多几万数据包的应用来说还是够的,因ؓ(f)现在cpu计算能力普遍q剩Q?/span>json的另个好处就是增删字D很方便Q各个版本之间不需要太考虑版本的问题,要是全用二进制格式就要麻烦很多了Q在使用压羃之后Q目前的json格式协议比之前的xml协议减少?/span>2/3的带宽用,M效果q是可以的。?/span>json调试也很方便Q我提供了一个工P写后端的q接用该工h?/span>json格式收发数据Q无需{?/span>client开发好了再d后端Q之后做client也很方便Q请求发q去之后q回来的是标准?/span>json格式数据Q同L(fng)解析Ҏ(gu)Q每个不同的应用按照不同的格式处理下即可,?/span>web{模块交互也很方便,q可是额外的好处了?/span>
MQ虽?/span>json格式存储效率和解析效率跟二进制方式还差半个量U到一个量U,但合理用还是可以的Q特别是?/span>xml相比优势很明显,权衡使用吧,当然q求极致效率可能q是?/span>pb之类的更合适一些,或者自p?/span>tlv格式?/span>