欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

IOCP不可忽视的细节

程序员文章站 2024-01-30 12:15:04
...
IOCP构架之所以公认高效,核心就在于异步IO。在网上纷纷为之膜拜之余,很少看到对稳定性或性能优化的观点。仔细想想,任何技术都有有利的一面,自然也有有弊的一面,这才符合辩证法思想。
我把自己在编写IOCP构架时重点处理的几个地方交代一下,如果你想认真写好一个稳定的IOCP服务端,建议重新规划以下几个细节。

1)不要修改套接字默认的收发缓冲区大小,即8192字节=8K=2分页。

2)总所周知,x86页面置换最少需要1分页,所以不管IOCP的重叠IO涉及多少字节,OS至少需要加锁/解锁1分页,在使用异步WSARecv/WSASend时,只要重叠缓冲区WSABuf的长度大于0,那么在投递异步操作时,系统至少会锁定1分页的非页面内存,而系统的非页面缓冲池是有大小限制的,如果你的IOCP消耗了太多非分页内存。轻则同服务器其他网络进程无法使用网络,重则可能会导致系统蓝屏或其他崩溃。而对于你的IOCP服务端通讯,常见的现象是客户端无法与服务端进行连接,或者收发包时出现10055

3)正是由于情况2的出现可能性,所以在投递WSARecv/WSASend时,绝对不要贪图简单,直接进行投递,正确的做法应该为每个套接字建立至少2个缓冲队列,一收一发。

4)对于同一个客户端套接字,在同一时间最好只有一个WSARecv/WSASend,如果你想提高IOCP网络吞吐量,可能会在同一个套接字上同时投递多个WSARecv/WSASend,那么你将会面临下面几个情况必须处理:

a)IO线程之间的WSARecv/WSASend操作频繁加锁/解锁,因为你无法保证线程1在GQCS时,线程2不会对相同套接字GQCS。

b)收发出现乱序,仔细想一下,正是因为你对同一套接字同时投递多个WSARecv/WSASend导致的,有你忙的了。

c)短时间内大量WSARecv/WSASend异步操作消耗太多非分页内存,也许在你下次投递收发操作时,OS会毫不留情给你一个10055错误。

5)现在你应该明白服务端的稳定是一个前提,需要比高吞吐量更要优先考虑,那么对于情况4建议的缓冲队列,绝对应该是你首先需要考虑的。

6)合理限制客户端套接字的流量(包速),即你需要规划完整合理的Qos,否则一旦恶意连接试图以大流量正常业务包攻击你的IOCP时,你会发现你的IOCP构架是多么脆弱。

7)为了减少情况6的出现,建议你在客户端/服务端通讯时增加压缩(加密)/解压缩(解密)功能,最好加入时间戳或GUID校验,避免出现同样的业务收发相同的包,最终导致攻击者只需要截取一个正常业务包,就能干出情况6的事情。

也许你会觉得如此实现太影响IOCP吞吐量,确实如此,收/发缓冲队列、Qos、加密解密都会降低IO吞吐量。希望你在决定之前,先衡量一下你未来的IOCP服务端菊花是否够紧,否则有一天你会高呼:OMG,是谁又把我那可怜而又脆弱的IOCP爆菊了?