高性能服务器的基石:从并发模子到状态机
本文整合了Linux服务器开发的核心规范、五种经典并发模式(Reactor、Proactor、半同步/半异步、向导者/跟随者)以及有限状态机,并重点扩展了主从Reactor模式的详细解说。读完本文,你将把握操持高性能、高并发、可维护服务端步伐的理论底子与工程实践。弁言
写一个能跑的TCP服务器很轻易,写一个能支持高并发、低延长、稳固运行的生产级服务器却很难。很多开发者在学习了Socket API之后,下一个狐疑每每是:我该怎么构造我的代码?用什么线程模子?怎么处理处罚协议分析?
这些题目的答案,就藏在本文要讲的几个核心模式中:
[*]Reactor模式:高性能网络编程的究竟标准,Nginx、Redis、Netty都在用
[*]Proactor模式:异步I/O的极致表现,Windows IOCP的经典搭档
[*]半同步/半异步模式:分身I/O处理处罚与业务盘算的实用架构
[*]向导者/跟随者模式:无锁操持的并发模子,得当CPU麋集型场景
[*]有限状态机:协议分析的通用解法,让复杂协议变得可控
同时,我们还会梳理Linux服务器开发中的通用规范——从保卫进程、信号处理处罚到日记体系,这些“工程细节”每每决定了服务可否在生产情况中稳固运行。
Linux服务器开发通用规范
在讨论模式之前,先明白一个底线:一个生产级服务器,必须服从以下底子规范。
保卫进程化(Daemonize)
长期运行的服务应当以保卫进程情势运行,脱离终端控制,制止因终端关闭而退出。
void daemonize() {
if (fork() != 0) exit(0);// 父进程退出
setsid(); // 创建新会话
if (fork() != 0) exit(0);// 再次fork,确保不是会话首进程
chdir("/"); // 切换到根目录
umask(0); // 重置文件掩码
// 关闭标准输入输出错误
close(STDIN_FILENO);
close(STDOUT_FILENO);
close(STDERR_FILENO);
open("/dev/null", O_RDWR); // 重定向到/dev/null
dup2(0, 1);
dup2(0, 2);
}留意:当代Linux体系可用daemon(1, 0)简化,但明白底层原理有助于排查题目。
进程/线程定名
设置进程名、线程名,便于运维监控和故障定位。
#include <sys/prctl.h>
void set_thread_name(const std::string& name) {
prctl(PR_SET_NAME, name.c_str(), 0, 0, 0);
}1.3 信号处理处罚
优雅退出、忽略SIGPIPE(防止写已关闭的毗连导致进程瓦解)、处理处罚SIGCHLD采取子进程。
void setup_signals() {
signal(SIGPIPE, SIG_IGN); // 忽略SIGPIPE
struct sigaction sa;
sa.sa_handler = sig_handler;
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
sigaction(SIGTERM, &sa, nullptr);
sigaction(SIGINT, &sa, nullptr);
}设置文件与下令行参数
使用getopt_long或成熟的设置库(如libconfig、yaml-cpp),支持默认值和热重载。
日记体系
异步日记、分级日记(DEBUG/INFO/WARN/ERROR)、支持滚动输出。绝对不能在生产情况使用printf或cout无缓冲输出。
资源限定
通过setrlimit调解文件形貌符上限、核心文件巨细等。
struct rlimit rl;
rl.rlim_cur = rl.rlim_max = 65535;
setrlimit(RLIMIT_NOFILE, &rl);模块化与设置热加载
生产级服务器通常支持动态加载设置(如修改日记级别后发送SIGHUP信号),制止重启。
从同步壅闭模子到Reactor模式
最简单的服务器就是每毗连一线程(或每哀求一线程)的同步壅闭模子:
主线程accept → 创建新线程 → 线程内recv(阻塞) → 处理 → send → 关闭这个模子在毗连数少时简单有用,但毗连数到达数千时,线程数爆炸、上下文切换开销巨大、内存占用过高,根本不可行。
Reactor模式应运而生:它使用事故驱动架构,用少量的线程处理处罚海量毗连。
Reactor的核心构成
组件职责句柄集(Handle)文件形貌符聚集(socket fd)事故分发器(Event Demultiplexer)select/poll/epoll,期待事故停当事故处理处罚器(Event Handler)界说回调接口(handle_read/handle_write等)反应器(Reactor)注册/注销事故,循环调用事故分发器,根据事故范例调用对应的处理处罚器Reactor的工作流程
1. 初始化Reactor,注册监听socket的读事件
2. 进入事件循环:
- 调用epoll_wait等待事件
- 遍历就绪事件:
如果是监听socket读事件 → accept新连接 → 注册新连接的读事件
如果是客户端socket读事件 → 读数据 → 解码 → 业务处理 → 编码 → 注册写事件
如果是客户端socket写事件 → 写数据 → 若写完且需要关闭,则关闭连接Reactor的三种变体
变体形貌代表单Reactor单线程Redis 6.0前使用的模子,事故处理处罚和业务逻辑都在一个线程Redis单Reactor多线程Reactor线程负责I/O,业务逻辑交给线程池早期的Netty 3.x多Reactor多线程(主从Reactor)主Reactor负责accept,从Reactor负责读写,业务线程池负责盘算Nginx、Netty 4.x、Memcached以下分别睁开。
单Reactor单线程
工作流程:一个线程完玉成部工作:accept、read、decode、compute、encode、write。
长处:实现简单,无锁竞争。
缺点:无法使用多核;盘算逻辑会壅闭I/O。
实用场景:Redis这种内存操纵极快、险些没有壅闭的场景。
单Reactor多线程
工作流程:Reactor线程负责I/O(读、写)和协议解码/编码,将业务逻辑(如查询数据库)提交给线程池处理处罚。处理处罚完成后,将相应放回Reactor的发送队列,触发写事故。
长处:充实使用多核,I/O与盘算分离。
缺点:Reactor线程仍大概成为瓶颈(全部I/O事故都在一个线程处理处罚);队列大概产生竞争。
实用场景:中等并发、业务盘算较重的服务。
主从Reactor模式(Multi-Reactor / Master-Slave Reactor)
这是Reactor模式最成熟、应用最广的变体,我们将重点睁开。
主从Reactor模式(Master-Slave Reactor)
为什么必要主从Reactor?
单Reactor模式下,一个Reactor线程既必要处理处罚监听socket的accept事故,又必要处理处罚全部已毗连socket的I/O事故。在高并发场景下(如瞬时大量毗连哀求),accept事故的处理处罚大概会壅闭Reactor对其他已毗连socket的事故相应,造成延长抖动。
主从Reactor的核心头脑:将毗连创建与毗连上的I/O分离到差别的Reactor线程中。
[*]主Reactor(Master Reactor):仅负责监听listen fd,处理处罚accept事故,将新毗连分发给从Reactor。
[*]从Reactor(Slave Reactor):负责已毗连socket的I/O读写,每个从Reactor独立运行在一个线程中,多个从Reactor构成线程池。
[*]业务线程池(可选):对于耗时业务逻辑,可交由专门的工作线程处理处罚,从Reactor仅负责I/O和协议编解码。
架构图
┌─────────────────────────────────────────┐
│ 主Reactor(单线程) │
│- epoll_wait(listen_fd) │
│- accept() 获取新连接 │
│- 轮询选择一个从Reactor |
└───────────────┬─────────────────────────┘
│ 分发给从Reactor
┌─────────────────────┼─────────────────────┐
▼ ▼ ▼
┌──────────────────────────┐ ┌──────────────────────────┐ ┌──────────────────────────┐
│ 从Reactor 1(线程) │ │ 从Reactor 2(线程) │ │ 从Reactor N(线程) │
│- epoll_wait(client_fds)│ │- epoll_wait(client_fds)│ │- epoll_wait(client_fds)│
│- 读数据 → 解码 │ │- 读数据 → 解码 │ │- 读数据 → 解码 │
│- 编码 → 写数据 │ │- 编码 → 写数据 │ │- 编码 → 写数据 │
└────────────┬─────────────┘ └────────────┬─────────────┘ └────────────┬─────────────┘
│ 可选 │ │
▼ ▼ ▼
┌─────────────────────────────────────────────────────────────────┐
│ 业务线程池(可选) │
│- 处理耗时业务逻辑(数据库查询、复杂计算) │
│- 处理完成后将响应交给对应的从Reactor写回 │
└─────────────────────────────────────────────────────────────────┘工作流程
[*]主Reactor初始化:创建listen fd,将其注册到主Reactor的epoll中,只关注EPOLLIN事故。
[*]事故循环:
[*]主Reactor调用epoll_wait,当listen fd可读时,调用accept获取新毗连的client fd。
[*]主Reactor通过某种负载均衡战略(如轮询、最小负载)选择一个从Reactor,将client fd注册到该从Reactor的epoll中(关注EPOLLIN | EPOLLET等)。
[*]从Reactor处理处罚I/O:
[*]从Reactor在本身的线程中调用epoll_wait,当client fd有数据可读时,读取数据、解码、天生相应(或交给业务线程池)。
[*]当必要写回数据时,注册EPOLLOUT事故,待可写时发送数据。
[*]毗连关闭:从Reactor负责关闭client fd,并从本身的epoll中移除。
负载均衡战略
主Reactor将新毗连分配给从Reactor时,常用的战略有:
[*]轮询(Round-Robin):简单匀称,但未思量各从Reactor当前负载。
[*]最少毗连(Least Connections):记载每个从Reactor当前处理处罚的毗连数,分配给最空闲的。必要原子操纵维护计数。
[*]哈希(Hash):根据客户端IP或端口哈希到固定从Reactor,有利于当地缓存掷中。
Nginx采取的是轮询 + 可设置权重的方式;Netty默认使用轮询,也支持自界说EventExecutorChooser。
代码框架表现
class MasterReactor {
public:
void run() {
while (running_) {
int nfds = epoll_wait(epfd_, events_, MAX_EVENTS, -1);
for (int i = 0; i < nfds; ++i) {
if (events_.data.fd == listen_fd_) {
handle_accept();
}
}
}
}
private:
void handle_accept() {
int client_fd = accept(listen_fd_, ...);
set_nonblocking(client_fd);
// 选择一个从Reactor(轮询)
SlaveReactor* slave = reactors_;
slave->register_fd(client_fd);
}
std::vector<SlaveReactor*> reactors_;
};
class SlaveReactor {
public:
void run() {
while (running_) {
int nfds = epoll_wait(epfd_, events_, MAX_EVENTS, -1);
for (auto& ev : events_) {
if (ev.events & EPOLLIN) {
handle_read(ev.data.fd);
} else if (ev.events & EPOLLOUT) {
handle_write(ev.data.fd);
}
}
}
}
void register_fd(int fd) {
// 注意:需要通过eventfd或消息队列跨线程通信,让从Reactor在自己的线程中执行epoll_ctl
// 简化示例:假设从Reactor提供了线程安全的注册队列,在run()中消费
pending_fds_.push(fd);
notify_fd();// 写eventfd唤醒epoll_wait
}
private:
int epfd_;
std::unordered_map<int, Connection> fds_;
ThreadSafeQueue<int> pending_fds_;
};范例应用案例
[*]Nginx:工作进程(Worker Process)模式下,每个worker进程内部实际上是单Reactor(每个worker独立监听同一端口,通过SO_REUSEPORT实现负载均衡),但团体架构是多个worker进程,每个worker内部的Reactor负责accept和I/O,可视为多进程主从Reactor。
[*]Netty 4.x:EventLoopGroup分为bossGroup(主Reactor)和workerGroup(从Reactor),范例的Java主从Reactor实现。
[*]Memcached:使用多线程模子,主线程负责accept,将毗连分配给工作线程,工作线程内部使用libevent举行I/O事故处理处罚。
上风与范围
上风分析高并发毗连创建主Reactor专注于accept,不会因I/O处理处罚延长而壅闭新毗连接入可扩展性从Reactor数目可根据CPU核心数调解,充实使用多核隔离性单个从Reactor的非常(如慢客户端)不会影响其他从Reactor上的毗连符合常见硬件特性当代网卡多队列、RSS(Receive Side Scaling)可以将差别毗连的分发到差别CPU,主从Reactor天然适配范围分析实现复杂度较高必要管理多个Reactor线程、负载均衡战略、跨线程注册fd资源开销每个从Reactor必要独立的epoll fd和线程栈惊群风险若多个从Reactor共享同一监听fd(不是主从模式),会有惊群;主从模式已制止与单Reactor多线程的对比
[*]单Reactor多线程:一个线程处理处罚全部I/O事故(包罗accept),业务盘算交给线程池。缺点:I/O负载重时,accept大概被延长;同时,单Reactor线程大概成为瓶颈。
[*]主从Reactor:将I/O分散到多个线程,accept独立,制止了单点瓶颈。
选型发起:对于中小型服务器(几千毗连),单Reactor多线程富足;对于大型网关(百万毗连)或对建连延长敏感的服务,保举主从Reactor。
简单代码示例
点击检察代码class Reactor {
public:
void run() {
while (running_) {
int nfds = epoll_wait(epfd_, events_, MAX_EVENTS, -1);
for (int i = 0; i < nfds; ++i) {
if (events_.data.fd == listen_fd_) {
handle_accept();
} else if (events_.events & EPOLLIN) {
handle_read(events_.data.fd);
} else if (events_.events & EPOLLOUT) {
handle_write(events_.data.fd);
} else if (events_.events & EPOLLERR) {
handle_error(events_.data.fd);
}
}
}
}
private:
int epfd_;
struct epoll_event events_;
};Proactor模式:异步I/O的集大成者
Reactor模式本质是同步非壅闭——它告诉我们何时可以读/写,但实际的读写操纵照旧由应用步伐调用read/write完成,这个过程依然是同步的(数据从内核拷贝到用户缓冲区时,线程会期待)。
而Proactor模式基于真正的异步I/O(Windows上的IOCP,Linux上的io_uring),应用步伐发起读写哀求后立即返回,内核完成数据拷贝后通过回调或事故关照应用步伐。
Proactor的核心构成
组件职责异步操纵处理处罚器实验异步操纵(如aio_read、io_uring_prep_read)完成事故队列存储已完成操纵的结果Proactor循环获取完成事故,调用对应的完成处理处罚器完成处理处罚器处理处罚读写完成后的业务逻辑3.2 Proactor vs Reactor
维度ReactorProactorI/O范例同步非壅闭异步数据拷贝应用步伐自动调用read/write,拷贝时壅闭内核自动完成拷贝,完成后关照编程复杂度相对较低较高(回调嵌套、状态管理)吞吐量精良理论上更高(制止用户态到场拷贝)Linux支持epoll成熟稳固io_uring正在崛起,但生态不如epoll为什么Linux下Reactor照旧主流?
Linux的异步I/O(AIO)长期存在缺陷(仅支持O_DIRECT,对平常文件有限定)。io_uring固然强大,但遍及必要时间。因此,现在绝大多数Linux高性能服务器(Nginx、Redis、Memcached)都采取Reactor模式,共同非壅闭I/O + 多路复用,已经能发挥硬件极致性能。
发起:新项目可关注io_uring,但生产情况优先选择Reactor。
半同步/半异步模式(Half-Sync/Half-Async)
Reactor模式办理了I/O麋集型题目,但业务逻辑中如果有耗时操纵(数据库查询、复杂盘算),仍然会壅闭Reactor线程,导致其他毗连被饿死。
半同步/半异步模式的核心头脑:将I/O处理处罚与业务处理处罚分离到差别线程中。
架构
[同步层] [队列层] [异步层]
↓ ↓ ↓
Reactor线程 请求队列 业务线程池
(处理I/O) → (解耦) → (处理请求)
[*]同步层:Reactor线程处理处罚I/O事故,读取哀求、分析协议,然后将封装好的使命放入队列
[*]队列层:线程安全的哀求队列(如std::queue + 互斥锁,或无锁队列)
[*]异步层:业务线程池从队列中取出使命,实验盘算,天生相应,然后通过同步层写回
代码框架
点击检察代码class HalfSyncHalfAsyncServer {
public:
void start() {
// 启动业务线程池
for (int i = 0; i < worker_count_; ++i) {
workers_.emplace_back(&HalfSyncHalfAsyncServer::worker_loop, this);
}
// 启动Reactor主循环
reactor_loop();
}
private:
void reactor_loop() {
while (running_) {
epoll_wait(...);
// 读到一个完整请求后,封装成Task,放入队列
task_queue_.push(std::move(task));
// 通知业务线程有任务(条件变量或eventfd)
}
}
void worker_loop() {
while (running_) {
Task task = task_queue_.pop();
Response resp = process(task);
// 将响应写回客户端(可放入另一个队列由Reactor写回)
write_back(resp);
}
}
std::vector<std::thread> workers_;
ThreadSafeQueue<Task> task_queue_;
};优缺点
长处缺点I/O和盘算分离,互不壅闭队列大概成为瓶颈充实使用多核CPU增长线程同步开销易于明白,实现简单队列中使命的次序大概被改变(非FIFO要求不严酷的场景无影响)向导者/跟随者模式(Leader/Follower)
向导者/跟随者模式是一个无锁并发模子,得当CPU麋集型、事故处理处罚时间短的场景。
核心头脑
线程池中的线程分为向导者和跟随者:
[*]向导者:唯一期待事故发生的线程。事故到来时,向导者负责处理处罚该事故,并指定一个新向导者
[*]跟随者:别的线程,不期待事故,而是在停当队列中休眠,期待被选为向导者
事故处理处罚完成后,当火线程会重新成为跟随者,期待下一轮提升。
工作流程
初始状态:线程1为领导者(在epoll_wait上等待)
事件到来 → 线程1醒来,同时指定线程2为新领导者
线程1处理事件(处理过程中,线程2在等待新事件)
处理完成 → 线程1进入追随者队列,等待下次被选为领导者与半同步/半异步的对比
维度向导者/跟随者半同步/半异步线程模子单层(全部线程雷同脚色)双层(I/O线程+工作线程)数据通报事故直接派发到线程,无队列必要哀求队列同步开销无队列锁,仅有向导者推选的轻量锁队列必要锁或CAS实用场景事故处理处罚时间短、CPU麋集事故处理处罚时间长、I/O混淆范例应用
[*]ACE框架中的Leader/Follower实现
[*]某些高性能RPC框架的底层I/O线程模子
留意:Linux下使用epoll时,多线程同时epoll_wait同一个epoll fd是线程安全的,但惊群题目依然存在(多个线程被同一个事故叫醒)。当代内核支持EPOLLEXCLUSIVE标志办理惊群,向导者/跟随者模式可使用此特性。
有限状态机(FSM):协议分析的灵魂
如果说前面的模式办理了服务器架构题目,那么有限状态机办理的是协议分析题目。
HTTP、Redis协议、WebSocket等险些全部应用层协议,都必要一个分析器。而分析器的天然实现方式就是状态机——由于协议界说了状态之间的转换规则。
为什么协议分析必要状态机?
由于数据是流式到达的。好比HTTP哀求大概分两次收到:
第一次recv: "GET /index.html HTTP/1.1\r\nHost: www"
第二次recv: ".com\r\n\r\n"用状态机,我们可以:
[*]在ParseState::RequestLine状态下分析哀求行,碰到\r\n后切换到ParseState::Headers
[*]在ParseState::Headers下逐行分析头部,碰到空行后切换到ParseState::Body
[*]每次进入状态时,从前次停止的地方继续分析
6.2 状态机在HTTP分析中的简化示例
enum class ParseState {
METHOD, // 解析方法
URL, // 解析URL
VERSION,// 解析版本
HEADER_KEY, // 解析头部key
HEADER_VALUE, // 解析头部value
BODY, // 解析body
DONE
};
ParseState state_ = ParseState::METHOD;
int parse(char c) {
switch (state_) {
case ParseState::METHOD:
if (c == ' ') state_ = ParseState::URL;
else method_.push_back(c);
break;
case ParseState::URL:
if (c == ' ') state_ = ParseState::VERSION;
else url_.push_back(c);
break;
// ... 省略其他状态
}
return 0;
}但要留意:上面的逐字符分析服从较低,工业级分析器通常按行处理处罚(如HTTP哀求行、头部行)。但不管按行照旧按字符,本质都是状态机——每行分析完成切换状态。
状态机的扩展:支持子状态
对于复杂协议(如分块传输编码),必要在主状态内部嵌套子状态:
enum class ChunkState { SIZE, DATA, TRAILER };
ChunkState chunk_state_ = ChunkState::SIZE;
size_t current_chunk_size_ = 0;
// 在主状态ParseState::BODY内部,根据Transfer-Encoding判断走chunked逻辑这种分层状态机操持,既保持了代码清晰,又能处理处罚复杂的协议逻辑。
状态机的性能考量
[*]无回溯:每个字节最多处理处罚一次,时间复杂度O(n)
[*]无递归:状态转移用循环+switch实现,不会爆栈
[*]可预制状态表:对于复杂协议,可用状态转移表(二维数组)替换switch-case,进步可维护性(但大概断送一点性能)
各模式对比与选型发起
模式核心办理的题目线程模子范例场景代表作品单Reactor单线程简单I/O复用单线程低并发、逻辑简单Redis单Reactor多线程I/O与盘算分离单I/O线程+业务线程池中等并发、业务盘算重早期Netty主从Reactor高并发建连+高吞吐I/O主Reactor+从Reactor池+业务线程池网关、Web服务器、署理Nginx、Netty 4.xProactor异步I/O极致性能异步操纵+完成回调文件服务器、数据库Windows IOCP、io_uring半同步/半异步I/O与盘算分离分层(I/O线程+盘算线程池)业务服务器、RPC框架大多数自研框架向导者/跟随者无锁事故派发单层脚色切换CPU麋集型、事故处理处罚短ACE框架有限状态机协议分析无任何协议分析器HTTP分析器选型发起
[*]通用HTTP/TCP服务器:主从Reactor + 半同步/半异步(从Reactor负责I/O和编解码,业务线程池负责盘算)
[*]极致性能网关:主从Reactor + 向导者/跟随者(镌汰锁竞争)
[*]文件服务器:Proactor + io_uring(发挥异步I/O上风)
[*]协议分析模块:有限状态机 + 缓冲区管理(任何服务器都逃不掉)
工程实践避坑清单
通用避坑
[*]不要在Reactor线程中做壅闭操纵:数据库查询、文件I/O、复杂盘算都会壅闭事故循环,导致延长飙升。务必交给工作线程。
[*]准确处理处罚部分读写:write大概只写入部分数据,必要维护写缓冲区,下次EPOLLOUT时继续发送。
[*]防止边沿触发模式下的数据饥饿:边沿触发要求读到EAGAIN为止,否则大概遗漏数据。
[*]状态秘密处理处罚“必要更多数据”的情况:当一行不完备时,返回OPEN状态,生存当前分析位置,下次继续。
[*]暂时对象的生命周期管理:在异步回调中,确保捕捉的对象有用(用shared_ptr或包管对象存活时间)。
[*]制止每个毗连都创建线程:线程数宏大于CPU核心数时,调理开销会吞噬性能。用线程池。
[*]留意惊群效应:多线程epoll_wait同一fd时,使用EPOLLEXCLUSIVE(内核4.5+)或采取单Reactor模式。
[*]保卫进程化的日记处理处罚:保卫进程没有控制台,必须将日记输出到syslog或文件。
主从Reactor专用避坑
[*]跨线程注册fd:从Reactor的epoll只能在运行该Reactor的线程内修改(epoll_ctl并非线程安全)。主Reactor分发新毗连时,必要通过事故关照(如使用eventfd或socket pair)让目的从Reactor在本身线程中实验添加操纵,而不是直接调用epoll_ctl。
[*]负载均衡导致的热门题目:如果采取简单的轮询,但某些从Reactor处理处罚的毗连大量发送数据,大概导致该Reactor负载不均。可以思量动态调解战略或引入毗连数/流量统计。
[*]从Reactor数目设置:通常设置为CPU核心数,由于每个从Reactor线程会占用一个CPU核心。但若业务逻辑较重且使用独立线程池,可以恰当镌汰从Reactor数目(如CPU核心数的一半),将更多CPU留给盘算。
[*]惊群效应再次提示:使用主从Reactor模式时,只有主Reactor监听listen fd,从Reactor不监听,因此不会出现accept惊群。但仍然大概出现多个毗连同时停当时,多个从Reactor被叫醒的稍微惊群(epoll本身会制止,但边沿触发下需留意)。
结语
从同步壅闭到Reactor,再到主从Reactor、Proactor、半同步/半异步、向导者/跟随者,以及支持协议分析的有限状态机——这些模式不是要你背下来应付口试,而是让你在面临实际题目时,能有一套“工具箱”。
[*]当你的服务器撑不住万级毗连时,Reactor会帮你
[*]当你的业务逻辑壅闭I/O时,半同步/半异步会帮你
[*]当你的协议分析变得一团乱麻时,状态时机帮你
[*]当你的建连延长成为瓶颈时,主从Reactor会帮你
后续的文章中,我们还会深入Reactor的详细实现(epoll vs kqueue)、io_uring的实践、以及怎样将这些模式组合成一个完备的服务器框架。欢迎一连关注。
下一篇预告:《从零实现一个高性能HTTP分析器:状态机、协议细节与工程实践》。
免责声明:如果侵犯了您的权益,请联系站长及时删除侵权内容,谢谢合作!qidao123.com:ToB企服之家,中国第一个企服评测及软件市场,开放入驻,技术点评得现金.
页:
[1]