请教一个ACE Proactor服务器(IOCP)的架构设计问题

baojian88888 2006-10-25 11:14:17
工作中需要做一个服务器,要处理成千上万的连接,决定采用ACE的Proactor模型(即Windows下的IOCP)

服务器的业务是接受客户端的连接,简单交互后,收到一个数据包,对该数据包进行一些处理后,返回给客户端,断开。

数据包的处理可能会比较耗时,包括加解密运算,可能还要查询数据库等

用ACE Proactor时,现在有两种选择(方案):
  第一种:从ACE_Service_Handler派生一个类,在这个类中进行网络收发,并进行运算处理(在handle_read_stream中收到后处理)。也就是说所有的工作都在一个线程中完成,整个服务器基本只有这一个线程。
  第二种:从ACE_Service_Handler派生的类中只做网络收发,把收到的数据包放入一个队列,让另一个线程去循环处理,处理后的结果再通过网络发出去。也就是说基本是两个线程,再加一个队列。

第一种做法因为是单线程,基本不需要考虑任何线程同步的问题,实现会比较简单。
第二种做法可能结构会比较好,但实现上麻烦一些,需要考虑两个线程间的同步,并要在队列的数据包中保存一个连接句柄,用于处理完后的发送,还要考虑数据包处理完后它的所属连接可能已经关闭的问题。

我个人认为ACE的Proactor(即IOCP)本身是异步IO模型,它设计的目的就是为了减少多线程所带来的复杂性,避免CPU线程同步而造成的性能退化。个人认为两个线程一个队列的方法,对于效率的提高没有帮助。
因此我比较倾向于第一种方案,而有同事则认为应该用第二种方案。

请有相关ACE服务器设计经验的朋友谈谈看法,谢谢。
...全文
961 15 打赏 收藏 转发到动态 举报
写回复
用AI写文章
15 条回复
切换为时间正序
请发表友善的回复…
发表回复
herocloud 2006-11-17
  • 打赏
  • 举报
回复
FT,做过大连接数的绝不会用第一种方案。

一个工作线程可能有N种原因阻塞。

数据处理线程一般独立开,特别是数据处理时间较长时
LoveBugs 2006-11-17
  • 打赏
  • 举报
回复
第一种方案,多开几个等待线程应该可以了。
laolaoliu2002 2006-11-15
  • 打赏
  • 举报
回复
一般情况下应该数据处理和网络收发分开处理.
可以考虑数据的处理放在其它机器上进行,就是说数据库服务器是独立的.
firera 2006-11-15
  • 打赏
  • 举报
回复
有数据库查询的话,肯定要另外开线程做的
另外,如果数据处理时间太长,会导致网络这块性能低下,看看ace书,上面对数据处理时间和网络消息频率有限制。
trueadou 2006-10-27
  • 打赏
  • 举报
回复
学习~
rickerliang 2006-10-27
  • 打赏
  • 举报
回复
用第一种还是第二种要看看的是cpu bound还是io bound了
baojian88888 2006-10-26
  • 打赏
  • 举报
回复
>>DentistryDoctor
另外IOCP本身就可以指定超过一个线程来处理IO Request的。
-----
是可以开多个处理线程,最好是cpu个数或者乘以2吧。这可以认为还是第一种方案,因为没有队列,基本不需要线程同步。
baojian88888 2006-10-26
  • 打赏
  • 举报
回复
感谢楼上的回复
好像大多赞成第二种方案啊,第二种方案确实结构比较清晰,网络处理和数据处理分离

提出一些不同意见啊

我觉得把网络I/O用单独的线程来处理的话(即第二种方案),如果单个数据包处理的时间比较长,就会出现网络I/O很快,CPU处理较慢,即大量的任务会堆积在队列中等待处理。这样总的吞吐量其实是一样的。如楼上所说,IOCP异步模式下,可以认为CPU在网络I/O上是不花时间的,所以服务器CPU的全部时间都花在数据处理运算上。

所以我觉得在服务器性能、数据吞吐率等指标上,两种方案应该是一样的,第一种不会比第二种低。

楼上acejoy说第二种方案“可以避免数据处理占用了I/O处理的时间”,应该是指单线程中CPU的计算会阻碍对网络I/O的及时响应吧,确实会阻碍,不过我觉得即使不阻碍,CPU也来不及处理不断到来的数据包,CPU的计算能力是一定的。也许有人会说这样可以把数据放在队列中可以缓存起来,弹性更好,可以在瞬间接受大量的连接,但是我觉得这个弹性可以通过ACE_Asynch_Acceptor的open函数的backlog参数(内部是通过多次的AcceptEx来实现的)来解决。两种方法都提供了对连接的缓存,一种是自己把数据先收下来缓存在内存中,另一种是靠操作系统本身提供的机制来缓存。

第一种方案的缺点应该在结构上,不便于以后可能把数据计算任务交给另外一台计算机来处理(即分布式的处理)

不同意见欢迎讨论
ifeelhappy 2006-10-26
  • 打赏
  • 举报
回复
应该要用第二种。
你都说到了,你的数据包处理比较耗时,
我对完成端口应该开多少工作者线程的理解在你这个例子中就是,
你处理数据包需要的时间/网络收发的时间=(你要建立的工作者线程数目-1)/主线程数目(就是1)=你要建立的工作者线程数目-1。

比如说你的服务器不需要进行任何处理,那么就直接开一个主线程就够了,如果处理数据包时间片基本和处理连接时间相同,只要开两个工作者线程就可以了,这两个线程可以跑同样的线程函数,这样的话,你的服务器可以一直不断的接受连接,两个线程函数轮流值班执行数据包处理,就是说任何时候到来的连接,都可以找到相应的处理线程处理。
如果你的数据包处理过程明显比较耗时,就应该考虑多开几个,因为你的主线程每接受一个连接的话,可能因为开的线程数不够不能即时找到相应的处理线程,这样,CPU使用效率明显下降。
注意,上面说的这些都不包括I/O操作,I/O处理时间片是不用考虑的,因为它根本不用你的程序来处理
DentistryDoctor 2006-10-25
  • 打赏
  • 举报
回复
这个要看对接卍收到的数据的数据是否会影响网络的性能了。如果每次处理的时间都很短,就没必要增加一个缓冲,还要同步了。如果对数据的处理需要时间的,增加一个或几个线程来处理这个也不错。

另外IOCP本身就可以指定超过一个线程来处理IO Request的。
wawaku 2006-10-25
  • 打赏
  • 举报
回复
我觉得主要看你的服务器的工作量,如果没有太多客户端同时要求处理数据.单线程就可以.

需求决定设计.
wangk 2006-10-25
  • 打赏
  • 举报
回复
我觉得要考虑服务端的构架,要看服务的瓶颈在哪里。如果是在数据处理的话,可以采用分布式计算的服务构架就采用第二种方案比较好。
我看你的说法:数据包的处理可能会比较耗时,包括加解密运算,可能还要查询数据库
最好还是用第二方案,并且把数据库服务器独立出去。
lzd 2006-10-25
  • 打赏
  • 举报
回复
我都是用第二种的。。比较清晰。。
helldream2002 2006-10-25
  • 打赏
  • 举报
回复
up
acejoy 2006-10-25
  • 打赏
  • 举报
回复
一般选择第二种,因为可以避免数据处理占用了I/O处理的时间。

──────────────────────
国内专业的ACE网络编程、开发论坛开通:
www.acejoy.com
www.acedevelop.com
涉及ACE使用和开发,中间件、服务器端软件的设计,P2P技术,
socket网络编程、应用开发等内容。
欢迎加入,大家一起交流、学习成长!

18,356

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 网络编程
c++c语言开发语言 技术论坛(原bbs)
社区管理员
  • 网络编程
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧