本页译自英文,由模型翻译。若与英文原文存在差异,以英文原文为准。
工作分区
一个订阅为每个空闲 worker 保持一次进行中的领取,上限是连接池大小减一;workers_by_key(n) 让每个分区键留在一个工作分区上。
以文字阅读本图
- InboxQueue 订阅,workers(4):为每个 空闲 worker 保持一次进行中的领取 → Worker 1 处理器 和结算: 领取
- Worker 1 处理器 和结算 → 8 个连接的连接池:订阅最多占用 7 个, 留一个给处理器自己的查询
- InboxQueue 订阅,workers(4):为每个 空闲 worker 保持一次进行中的领取 → Worker 2 处理器 和结算
- Worker 2 处理器 和结算 → 8 个连接的连接池:订阅最多占用 7 个, 留一个给处理器自己的查询
- InboxQueue 订阅,workers(4):为每个 空闲 worker 保持一次进行中的领取 → Worker 3 处理器 和结算
- Worker 3 处理器 和结算 → 8 个连接的连接池:订阅最多占用 7 个, 留一个给处理器自己的查询
- InboxQueue 订阅,workers(4):为每个 空闲 worker 保持一次进行中的领取 → Worker 4 处理器 和结算
- Worker 4 处理器 和结算 → 8 个连接的连接池:订阅最多占用 7 个, 留一个给处理器自己的查询
- 同一时间只有一次进行中的领取:SQLite 上、FIFO 表上、 带 partition_key 列的表上, 以及 MySQL 或 MariaDB 的租约表上
- workers_by_key(n):行在其 partition_key 对应的 工作分区上运行,同一个键保持领取顺序
运行时为每个空闲 worker 轮询一次订阅的流。逐条投递的订阅对每次轮询以一次领取作答;批订阅一次领取一个批。订阅统计自己处理中的投递,同时见过的最大数量告诉它有多少个 worker,它为每个空闲的 worker 保持一次进行中的领取。与其他领取并行的领取,只在连接池还有空余连接时才开始,订阅占用的连接从不超过连接池大小减一:最后一个连接服务于处理器自己的查询、它们的发布,以及需要连接的结算。连接池空间不足时,同时运行的投递就少一些,共用一个连接池的订阅会彼此留出空间。一次领取什么也没取到之后,订阅每次只领取一次,直到领取再次取到行,因此空表每次等待只看到一次领取,而不是每个 worker 一次。
处理中的投递占用什么,取决于领取方式。在行锁方式和咨询锁方式下,每个投递在结算前都占用一个连接,因此 workers(n) 最多占用 n 个。在租约方式下,领取和结算只在执行语句时占用连接,订阅每隔半个租约取一个连接为租约续约。在事务模式下,无论哪种方式,每个投递都占用它的事务所在的连接。确定连接池大小时,要算上每个占用连接的订阅,再为连接池加一个,以及处理器为自己的查询取用的连接。
有些表同一时间只保持一次进行中的领取,因为并行的领取得不偿失。SQLite 同一时间只接受一个写入者,并发的领取只会互相冲突。在 FIFO 表和带 partition_key 列的表上,两次并发的领取可能不按领取顺序完成。在 MySQL 和 MariaDB 上,租约领取在一个包含多条语句的事务中给行打上租约,这个事务在提交前会锁住它读到的行,包括处理中的租约。worker 仍然并行运行,只是领取轮流进行。
在 SQLite 上,租约领取用一条语句为订阅见过的每个 worker 各取一行。SQLite 的忙等处理器不会让发现写锁被占用的写入者排队:它睡眠一毫秒或更久,然后重试。如果每次投递只领取一行,领取就会在每次投递时都在写锁处撞上 worker 的结算,它睡眠时所有 worker 都在空等。超出空闲 worker 的行在订阅中等待下一个空闲的 worker,它们已经登记在租约簿中,所以等待期间租约会被续期;订阅停止时会立即把它们交还队列。
workers_by_key(n) 运行 n 个工作分区,行进入其 partition_key 的哈希所对应的工作分区。同一个键的行绝不会分散到两个工作分区上,因此它们按领取顺序运行。FIFO 组更进一步:在读取它的所有 Broker 和实例之间,一个组同一时间只有一行处于处理中,因为领取只取组的首行,而方言的守卫会锁住这个组。
计算密集的处理器可以用 on_threads(n) 在专用线程上运行。订阅仍然在应用的运行时上领取,每个线程通过自己的一个小连接池查询,未设置时为一个连接。connection_limit 把服务的连接池和每个线程的连接总数限制在数据库允许的范围内:会超出这个限制的订阅不会启动。
服务的两个副本读同一张表时,无需协调就能共享它的行:每个副本各自领取,领取方式保证一行同一时间只在一处。