Riger (stranger)
06-03-13 11:02
|
UDP并发服务器设计讨论一:一台主机、一个CPU,实现单位时间内最大并发数
|
| |
讨论:“一台主机、一个CPU”,用UDP实现单位时间内最大并发数的接入服务器的方案。设计方案不考虑特定OS系统。
为了简化讨论,我们简化该服务器的流程:接收UDP包---->处理数据包。流程就两步,且假设接收
UDP包的时间Tr和处理数据包的时间Tp的关系为:Tp = K*Tr。
设计方案一:一个线程处理整个流程。
设计方案二:一个接收线程+一个缓冲队列+一个处理线程。
设计方案三:N个接收线程+一个缓冲队列+一个处理线程,其中N > 1。
设计方案四:N个接收线程+N个缓冲队列+一个处理线程,其中N,M > 1,N和M可以相等。
为更有利于讨论,我们再假设Tp = K*Tr中的K相当大,也就说,相对Tp,Tr可忽略不计(现实应用中大部分情况也是这样的^-^)。
在K足够大的情况下,可以肯定,方案一并发性能是最差的。
方案二实现起来最直观,要作数据写入队列和从队列读出数据时的同步,由于我们关心的写入性能,所以不用Multi Read Single Write锁进行同步。这里在要注意的是,从队列读出数据后就要解锁。
方案三多了一些接收线程,但所有的接收线程和处理线程在写数据到缓冲队列列时都要作同步。
方案四是一个接收线程对应一个缓冲队列,接收线程之间不须要同步(通过TSS),但每一个接收线程还须要和处理线程同步。(有没有方法做到当两个读写线程同时访问公共资源的时候,不须要作同步?^-^)。
我在这方面的经验不多,就两年前做过一个即时通信的接入服务器。当时做这个系统的时候,领导们催得紧,选择方案三,也经得起压力测试。
但我现在想想,在一个CPU的情况下,方案二的性能比方案三的性能来得更高一些。方案四相对于方案二,可能可以支持更多的并发数,但性能会下降。为什么会得出这样的结论呢?因为方案四中的接收线程间不须要同步!可以肯定的是在多CPU的情况下,方案四是首选。
我现在不从事这方面的工作了,没有那么多机器做测试,所以没有办法做这几个方案的比较测试,得出实验结果。希望兄弟们说出自己的观点;有条件的请给出测试数据。
文章选项:
|
teawater (Carpal Tunnel)
06-03-13 11:18
|
Re: UDP并发服务器设计讨论一:一台主机、一个CPU,实现单位时间内最大并发数
[re: Riger] |
| |
最大信息的问题好像以前讨论过 你可以到精华找找
-------------------- 没有一种感觉比的上回家睡觉
文章选项:
|
lonelyflyer (addict)
06-03-13 12:56
|
|
LZ要平台无关的,epoll,aio,完成端口那些都不能用了,那篇是专注 Linux的
不过那是自废武功了!
另外,觉得方案三多余了,方案四的复杂度不比它多多少,小心选择数据结构还可以省掉读写互斥
文章选项:
|
Riger (stranger)
06-03-13 15:20
|
|
谢谢二楼提醒。
LZ要平台无关的,epoll,aio,完成端口那些都不能用了
--------------------------------------------
我的意思是暂时不考虑在何种平台OS上实现,而不是平台无关,不好意思,没有说清楚。
不过,我个人认为接收UDP数据包的话,用epoll/aio/iocp对处理并发数的提高没有影响,反而带了设计上的负面影响。
另外,觉得方案三多余了,方案四的复杂度不比它多多少,小心选择数据结构还可以省掉读写互斥
----------------------------------------------
在方案四中,接收线程之间是不须要同步;但接收线程和处理线程有不须要同步的可能吗?能否给出不须要同步的实现方法?
在多CPU中,方案四是首选,但在一个CPU中,就不一定了。最好有条件的兄弟在不同的参数下,给出测试结果。我目前不从事这方面开发,没有这个条件测试。
文章选项:
|
lonelyflyer (addict)
06-03-13 15:39
|
Re: UDP并发服务器设计讨论一:一台主机、一个CPU,实现单位时间内最大并发数
[re: Riger] |
| |
epoll 是对select遍历套接字的优化,在套接字一千以上的优化效果卓著
aio可以最大化利用OS和硬件(CPU,网卡)提供的并行能力,因为同一时刻一个线程只能执行一个I/O操作(摘自APG)
这些都跟是不是UDP没什么关系
完成端口是Windows的东西,不管它
对于队列,都有一个头、尾指针,入队修改头指针,出队修改尾指针,各改各的,不需要互斥
文章选项:
|
ddd (old hand)
06-03-13 17:25
|
Re: UDP并发服务器设计讨论一:一台主机、一个CPU,实现单位时间内最大并发数
[re: Riger] |
| |
问一下,N个连接线程是什么意思?是不是对应不同的udp端口的意思?那么为什么没有N个处理线程的方案呢?这样不就不用同步了吧,如果每个端口都要处理M个主机的连接,那就N*M个线程?
-------------------- I solemnly swear that I am up to no good
文章选项:
|
Riger (stranger)
06-03-13 17:33
|
|
epoll 是对select遍历套接字的优化,在连接数一千以上的优化效果卓著
-----------------
UDP没有连接概念,在一个通信套接口处理连接请求。不过对TCP的连接处理肯定有用了。
aio可以最大化利用OS和硬件(CPU,网卡)提供的并行能力,因为同一时刻一个线程只能执行一个I/O操作(摘自APG)
-----------------------------
这个不理解,请多指教啊。
对于队列,都有一个头、尾指针,入队修改头指针,出队修改尾指针,各改各的,不需要互斥
-----------------------------------------
如果队列里只有一个或0个节点元素,会有问题的吧?
文章选项:
|
lonelyflyer (addict)
06-03-13 17:52
|
Re: UDP并发服务器设计讨论一:一台主机、一个CPU,实现单位时间内最大并发数
[re: Riger] |
| |
基本上,我没耐心了,留给大家看吧
第三问可以说一下:不是很严格的正确,而是工程上可以用的。只要你的入队(也就是接收)线程不用判断队列的size(一般没这个必要),就不会有问题;因为接受线程在没互斥时读到的size只有可能偏小,不会大,这样出队操作就不会造成队列头指针溢出。简而言之,处理线程被唤醒时,队列必然不空,不空就不会出问题。
文章选项:
|
Riger (stranger)
06-03-14 09:06
|
|
另外,对一个队列的读写一定要作同步处理的,就按照你的说法去做的话, 运行结果完全是不可预测的.
文章选项:
|
ddd (old hand)
06-03-14 09:46
|
|
》》处理线程被唤醒时,队列必然不空
用什么方法保证处理线程被唤醒时,队列必然不空?
-------------------- I solemnly swear that I am up to no good
文章选项:
|