前言:
服务端通常需要支持高并发业务访问,如何设计优秀的服务端网络IO工作线程/进程模型对业务的高并发访问需求起着至关重要的核心作用。
本文总结了了不同场景下的多种网络IO线程/进程模型,并给出了各种模型的优缺点及其性能优化方法,非常适合服务端开发、中间件开发、数据库开发等开发人员借鉴。
1. 线程模型一. 单线程网络IO复用模型
说明:
1. 所有网络IO事件(accept事件、读事件、写事件)注册到epoll事件集
2. 主循环中通过epoll_wait一次性获取内核态收集到的epoll事件信息,然后轮询执行各个事件对应的回调。
3. 事件注册、epoll_wait事件获取、事件回调执行全部由一个线程处理
1.1一个完整请求组成
一个完整的请求处理过程主要包含以下几个部分:
步骤1:通过epoll_wait一次性获取网络IO事件
步骤2:读取数据及协议解析
步骤3:解析成功后进行业务逻辑处理,然后应答客户端
1.2 该网络线程模型缺陷
1. 所有工作都由一个线程执行,包括epoll事件获取、事件处理(数据读写)、只要任一一个请求的事件回调处理阻塞,其他请求都会阻塞。例如redis的hash结构,如果filed过多,假设一个hash key包含数百万filed,则该Hash key过期的时候,整个redis阻塞。
2. 单线程工作模型,CPU会成为瓶颈,如果QPS过高,整个CPU负载会达到100%,时延抖动厉害。
1.3 典型案例
- redis缓存
- 推特缓存中间件twemproxy
1.4 主循环工作流程
while (1) {
//epoll_wait等待网络事件,如果有网络事件则返回,或者超时范围
size_t numevents= epoll_wait();
//遍历前面epoll获取到的网络事件,执行对应事件回调
for (j = 0; j < numevents; j++) {
if(读事件) {
//读数据
readData()
//解析
parseData()
//读事件处理、读到数据后的业务逻辑处理
requestDeal()
} else if(写事件) {
//写事件处理,写数据逻辑处理
writeEentDeal()
} else {
//异常事件处理
errorDeal()
}
}
}
说明:后续多线程/进程模型中,每个线程/进程的主流程和该while()流程一致。
1.5 redis源码分析及异步网络IO复用精简版demo
由于之前工作需要&