每核心工作线程模型#
1. 概览#
每核心工作线程模型为 CPU 核心(或等效硬件切片)分配一个专用的工作线程执行上下文。每个工作线程托管一个独立的运行时、调度循环和它所拥有的分区的本地状态。该模型以粗粒度多处理和锁为代价,换取每个工作线程的隔离和每个工作线程内部的合作式事件驱动并发,以实现低延迟、高吞吐量的操作。
2. 动机#
减少同步开销:通过将大多数状态和执行保持在工作线程本地,该设计最小化了跨线程锁定和原子争用。
可预测延迟:每核心亲和性减少了上下文切换抖动,并改善了热数据和代码路径的缓存利用率。
可扩展并发:许多轻量级异步任务可以在工作线程内部合作运行,而无需为每个任务生成操作系统线程。
操作隔离:故障或过载可以被限制在工作线程内,并通过排空/重启或分区迁移来处理。
3. 每个工作线程模型#
亲和性:工作线程通常被固定到 CPU 核心(或逻辑核心),并运行单线程事件循环或 io_uring 支持的后端运行时。
工作线程内部的运行时组件:
事件循环 / 异步执行器:合作式调度任务(异步函数、系统调用、定时器)。
本地任务队列:高优先级和后台队列,将延迟敏感的工作与日常维护分开。
分区本地状态:分配给此工作线程的分区的存储和缓存(按 (table_id, partition_id) 键控的物理关系)。
网络端点:每个工作线程的 TCP 监听器(当启用 tcp_multi_port 时)或共享 acceptor 与交接。
并发模型:使用 async/await 原语(或转换后的等价物)的合作式多任务。任务在 I/O 或等待远程 RPC 结果时让出,允许其他任务在不进行操作系统线程切换的情况下取得进展。
实现说明:
在工作线程内部使用 io_uring 或高效的异步运行时(Tokio),以低开销实现高 I/O 并发。
工作线程分配和管理固定资源(线程本地缓存、预注册缓冲区)以减少运行时分配成本。
6. 工作线程间通信#
消息传递:工作线程通过定义良好的消息通道或内部消息总线上的 RPC 进行通信,而不是通过共享内存锁进行协调和远程分区访问。
远程分区 RPC:当工作线程收到它不拥有的分区的请求时,它通过内部 RPC 通道将请求转发给拥有者工作线程。请求者异步等待响应。
背压和流量控制:发送方必须处理背压(有界队列),并在目标工作线程过载时应用重试或熔断逻辑。
有序与无序消息:重要操作(例如,提交阶段消息)可能需要排序保证;消息层在需要时支持排序或因果排序。
批处理和合并:小的远程请求通常被批处理或合并,以减少每条消息的开销并提高吞吐量。
故障处理:
快速检测远程工作线程故障(超时、连接错误)并触发拓扑刷新和分区重新分配。
排空和重放:迁移分区时,工作线程排空未完成的消息,并可能在迁移期间重放或转发正在进行的操作。
7. 数据局部性与分区#
有关分区模型、放置和 partition -> worker 映射的全面说明,请参阅分区文档:./partitioning.md
分区放置:逻辑分区被分配给工作线程(partition_id -> worker_id)。工作线程保持放置的本地副本,并暴露其拥有分区的端点。
本地执行:本地工作线程拥有的分区的操作无需工作线程间 RPC 即可执行,利用缓存局部性和最小化锁定。
路由:客户端或适配器解析 partition -> worker 映射(通过拓扑),并打开绑定到目标工作线程的会话以实现直接局部性。
热分区缓解:可以监控热分区并将其移动,或拆分为更细粒度的分区,以在工作线程之间分配负载。
与每核心模型的交互:
由于每个工作线程集中了其分区的存储和执行,每核心 affordances(CPU 缓存、本地缓冲区、固定线程)放大了局部性优势。
分片 TCP 端口和每个工作线程的监听器提高了 accept 亲和性并减少内核网络争用,使网络流与分区所有权对齐。
总结
每核心工作线程模型通过将状态本地化并在每个工作线程内部使用合作式异步并发,同时依靠消息传递进行跨工作线程协调,从而平衡了高性能和操作简便性。它对于具有强局部性和可预测分区语义的工作负载特别有效。