epoll 仅作为高效i/o事件分发引擎,协同冲突解决需结合上层文档分片、热文档专用事件池、读写操作分流、et模式原子读取及冲突熔断机制实现极速分流。

epoll 本身不解决协同冲突,它只负责高效地监听和分发网络事件。在分布式协作文档系统中实现“协同操作冲突的极速分流”,关键在于把 epoll 作为底层 I/O 调度引擎,配合上层的冲突检测与路由策略,让真正有冲突风险的操作(比如多人同时编辑同一段落)被快速识别、隔离、排队或重定向,而非让所有请求无差别堆积在单个处理线程里。
用 epoll 做连接与事件的“高速入口闸机”
协作文档系统通常面对海量长连接(WebSocket 或自定义 TCP 连接),每个连接代表一个客户端的实时编辑会话。epoll 的优势在于:一个主线程可稳定支撑数万并发连接,且只对就绪连接做响应,避免轮询开销。
- 为每个新接入的客户端连接调用 epoll_ctl(EPOLL_CTL_ADD) 注册 EPOLLIN 事件,附带该连接的 session ID 和文档 ID(存入
epoll_data_t.fd或ptr) - 调用 epoll_wait 获取就绪连接时,立即从
events[i].data.ptr提取出文档标识,不等解析完整报文就完成初步路由判断 - 对高频更新的热门文档(如首页、会议纪要),可提前将其关联的连接 fd 归入独立 epoll 实例(即“热文档专用事件池”),实现物理级分流
把冲突判定逻辑下沉到事件分发前
真正的“极速分流”发生在数据还没进入业务逻辑层之前。不能等收到完整 OT(Operational Transformation)或 CRDT 操作后再比对——那已经晚了。
- 在
epoll_wait返回后、read()读取数据前,先检查该连接所属文档的当前锁状态或版本号缓存(例如 Redis 中的 doc:xxx:version) - 若检测到该文档正被其他写操作占用(如存在未提交的变更队列),立即将该事件标记为 “deferred”,并投递到异步冲突队列(如 ring buffer 或无锁 MPSC 队列),跳过同步处理路径
- 对只读操作(如光标位置同步、只读预览)直接放行;对写操作按文档哈希分片,绑定到固定工作线程,避免跨线程锁竞争
结合 ET 模式与非阻塞 socket 做原子化读取
协同场景下,一次编辑操作可能拆成多个小包到达。若用 LT 模式 + 阻塞 socket,容易因一次 read 不完整导致事件反复触发、线程卡住。
- 务必使用 EPOLLET(边缘触发)+ non-blocking socket,确保每次
epoll_wait返回后,用循环read把当前缓冲区数据一次性收完,直到返回EAGAIN - 这样能保证单次事件对应一个完整语义操作(如一个 JSON 格式的 OT 变更包),为后续冲突比对提供干净输入
- 搭配
SO_RCVBUF调优,防止小包粘连或拆包,减少应用层解析负担
分流不是靠 epoll 单独完成,而是分层协作
epoll 是第一道轻量级过滤器,真正的冲突决策由上层模块完成,但必须设计成低延迟、无锁、内存局部性好的结构:
- 文档维度分片:按文档 ID 哈希到 N 个工作组,每组独占一个 epoll 实例 + 一个处理线程 + 一份本地操作日志缓存
-
操作类型分流:用不同事件掩码区分(如自定义
EPOLLDOC_WRITE用 bit 组合),让 epoll_wait 返回时即可分类投递 - 冲突熔断机制:对某文档连续出现 3 次以上冲突,自动升级为“强一致性模式”,将后续所有操作强制串行化,并通知客户端降级为只读提示











