【游戏】服务器性能测试(六) 简单压测工具之高并发网络篇
目录
一、前言
对网络游戏服务器进行性能压测时,压测工具一般是模拟大量客户端连接服务器进行协议接口请求并发来压测服务器,因此就需要具有高并发的网络模块支持。本篇主要介绍我所了解的网络相关的知识。
二、阻塞BIO,非阻塞NIO,异步AIO
1. 阻塞I/O模型+同步IO 简称BIO
当调用一个IO函数例如下面的recv函数,程序会进入阻塞,等待数据准备好,如果数据没有准备好将一直阻塞在recv处,直到有数据从系统内核拷贝到用户空间(即同步IO),然后IO函数返回读取的数据。还有recvfrom、send、sendto、accept、connect也是同理。
# python 代码 sock = socket.socket() sock.connect(address) sock.recv(1024)
如果创建多个socket后,对每一个socket做轮询recv,其中一个socket没有数据进入阻塞,同时会导致其他的socket也被阻塞,无法读取数据如下代码展示。
# python 代码 for sock in socklist: sock.recv(1024) # 一旦某个socket没有数据,整个循环就阻塞了
2. 非阻塞I/O模型+同步IO 简称NIO
通过对socket进行设置为非阻塞模式,当调用IO函数时,如果数据未准备好时程序不是进入睡眠阻塞,而是立即返回一个错误码。这样就可以知道这个socket是否有数据可以读取。
sock = socket.socket() sock.connect(address) sock.setblocking(False) # 设置为非阻塞模式 sock.recv(1024)
将socket设置为非阻塞模式,在没有数据的时候会立即返回,但拷贝数据依然是同步完成的,即需要等数据从内核拷贝到用户空间后才返回。相对于阻塞模式其优点比较明显,但是代码编写会稍微复杂一点,需要理解不同的返回错误码的具体意思。
for sock in socklist: try: # 有数据时需要等待数据拷贝完成,没有数据则立即返回 sock.recv(1024) except: #这里需要处理不同的异常 pass
3. I/O多路复用+同步IO
使用select、poll、epoll可同时对多个socket的I/O操作进行监听,只返回已准备就绪的socket,通过调用已准备就绪的IO操作就可以做到不阻塞整个程序。这里监听的socket可以是阻塞模式,也可以是非阻塞模式的,用非阻塞模式的会更好一些。
r_socks, w_socks, e_socks = select.select(socklist,[],[]) for sock in r_socks: sock.recv(1024) # 进行相关的io函数操作
select会遍历整个socket列表,从中找到准备就绪的socket对象,如果socket列表很大的话,遍历本身就会产生很大的开销。select可以在windows和Linux系统中使用,poll和epoll则只能在Linux系统中使用。poll和select的机制差不多,epoll则是改进的poll。
4. 异步IO 简称AIO
异步IO就是在调用IO函数后会立即返回,但不会立即得到结果,而真正的函数结果需要通过状态、通知和回调来通知调用者进行操作。windows下提供了IOCP异步IO技术,但在Linux系统下却没有这种技术。因此到目前为止大量的网络库都是采用的IO多路复用+非阻塞模式编写的。
三、总结
1. IOCP完成端口
IO完成端口是Wnidows系统提供的最复杂的内核对象,是一种解决并发IO请求的最佳模型,是用来实现高容量网路服务器的最佳方法。此技术仅在windows系统中才可以使用。如果是选择开发windows下的网络程序,可以考虑用IOCP来实现高并发的网络模块。如果是使用Java开发语言,可以用AIO模块,在windows下采用的是IOCP实现,但在Linux则是用epoll模拟的。
2. IO多路复用
IO多路复用在windows和Linux下都可以使用,可以使用都支持的select,但它的时间复杂度是O(n),而且有最大连接数限制。poll与select类似,但没有最大连接数限制,仅Linux下可以使用。epoll是Linux内核为处理大批量文件描述符而作了改进的poll,是Linux下多路复用IO接口select/poll的增强版本,它能显著提高程序在大量并发连接中只有少量活跃的情况下的系统CPU利用率,时间复杂度可以降至O(1)。
因此从目前来看,BIO不适合做高并发,NIO是比较通用的解决方案,AIO目前只有windows系统支持,因此可以根据具体需求进行选择。
欢迎微信搜索"游戏测试开发"关注一起沟通交流。