1. 引言:并发不是并行,但并发是永恒的
C10K问题(10K并发连接)由Dan Kegel在1999年提出,由Libevent和kqueue解决;C10M问题(1000万并发连接)由Robert Graham在2013年提出,依赖于内核旁路(Kernel Bypass)和用户态协议栈。高并发架构的本质是如何让单台服务器处理尽可能多的同时请求——O(1)事件通知是其核心。
2. Reactor模式:事件驱动的核心
2.1 Reactor的事件循环
Reactor模式由Douglas C. Schmidt在1995年提出——Reactor将I/O事件多路复用与事件处理分离,由Initiation Dispatcher负责多路分发,Synchronous Event Demultiplexer等待事件(epoll_wait/kevent/IOCP),Handle为每个连接的注册项,Event Handler注册回调函数。
2.2 三种多路复用模型对比
select() O(n)FD遍历限制1024FD_SETSIZE;poll() O(n)无硬上限但遍历全部;epoll O(1) 事件推送;kqueue O(1) BSD实现统一事件系统更灵活;IOCP async I/O完成端口在Windows上有更接近完成语义的性能优势。io_uring是Linux 5.1引入的最新方案——通过共享内存环形缓冲区避免系统调用本身。
3. 现代异步运行时设计
3.1 Work-Stealing调度器
Tokio、Go runtime、.NET ThreadPool的Work-Stealing机制:每个Worker维护本地任务队列,空闲时从其他Worker"窃取"任务分配,最大限度减少全局锁竞争,保证CPU利用率接近100%。Tokio的Multi-Threaded Runtime默认线程绑定物理核心。
3.2 协作式与抢占式调度
协程的协作式调度依赖Yield移交控制权;Go通过System Monitor线程抢占超过10ms执行的Goroutine;Rust async-std和Tokio使用非阻塞Future树实现极少量的系统线程,但同一Worker上的任务长时间不Yield会饿死其他任务。
4. Netty:Java高并发的事实标准
BossGroup接收Accept,WorkerGroup处理I/O——Netty将接受与处理分离达到高并发;ByteBuf的Direct Buffer +Reference Counting降低了GC压力;ChannelPipeline + ChannelHandler模式将TLS、HTTP、业务逻辑解耦为可组合的流水线。
5. Redis:单线程高并发的极致
Redis选择单线程模型的原因是内存操作足够快,多线程切换的价值不如独立I/O线程的价值。Redis 6.0引入的多线程只用于网络I/O读写,命令执行仍然单线程——这一精准的定位带来了40%+的吞吐提升。
6. 异步运行时选型指南
Tokio生态最完善但FFI绑定复杂;async-std API更友好但生态较小;smol极简适合嵌入式;monoio是字节跳动基于io_uring的Thread-per-Core方案,最大化本地存储性能。
7. 结语
高并发架构是"以正确的方式等待"的艺术——从epoll事件推送到io_uring的零系统调用,从阻塞I/O到异步/等待的演进,每一次范式升级都证明了人类对"充分利用每一纳秒"这一目标的永恒追求。

发表评论 取消回复