---
url: /zh/operate/scaling.md
description: 服务怎样跨节点伸缩、选择多少个分区、节点对命令、查询和订阅施加的限制，以及负载增长时要关注什么。
---

# 伸缩与容量

服务通过增加节点来伸缩：节点在彼此之间划分它的分区，每个节点运行它拥有的分区的命令和订阅，而底下的数据库承载所有节点的追加。本页说明要确定什么的大小、节点为了降级而不是崩溃所施加的限制，以及下一个瓶颈通常在哪里。分区与归属见[部署模型](./topology#services-and-nodes)。

## 节点与分区 {#nodes-and-partitions}

每个上下文的日志有固定数量的分区 `wow.log.partitions`，默认 64 个。每个分区同一时刻只有一个属主，它运行该分区内聚合的每条命令，以及该分区上的每个订阅。所以：

* **节点越多，吞吐越高**，只要数据库跟得上：N 个节点时，每个节点拥有大约 64 / N 个分区。
* **每个分区至多一个节点在工作。** 超出分区数的节点不拥有任何分区，只转发命令。64 个分区适合大多数服务；可能需要比这更多节点的服务，选择一个更大的 2 的幂，最多 4,096。
* **分区数是固定的**，日志有了条目之后就不能改，所以要在首次部署之前选定。

节点加入或离开时，大约 N 分之一的分区会移动，它们的订阅在新属主上从检查点继续。宕掉的节点会一直持有它的租约，直到租约过期，即 `wow.cluster.lease-ttl`（10 秒）：它的分区要等这么久才有新属主。分区没有可达属主的聚合，其命令在收到它的节点上运行；聚合的版本保证结果正确。

## 命令发往属主 {#commands-go-to-the-owner}

命令可以到达任何节点；节点经内部端口把它转发给分区的属主，所以每个聚合的命令在一个节点上、基于它缓存的状态逐条运行。转发的代价是集群内的一跳。负载均衡器无法按聚合路由，也不需要这样做。

## 节点施加的限制 {#limits-a-node-enforces}

节点限制它接受的量，并让调用方稍后再来，而不是无休止地排队：

| 限制 | 默认值 | 超出时 |
| --- | --- | --- |
| `wow.executor.max-in-flight`：节点上的在途命令 | 4,096 | 命令以 `wow.command.busy` 拒绝（429，带 `Retry-After`） |
| `wow.executor.lane-capacity`：等待同一个聚合的命令 | 1,024 | 同上，针对这个聚合 |
| 存储的并发查询 | PostgreSQL 上为追加连接池的一半，自适应 | 查询以 `wow.query.busy` 拒绝（429） |
| `wow.query.dataset.max-concurrent`：同时运行的数据集查询 | 固定上限，不自适应 | 查询在一个短队列中等待，然后以 `wow.query.busy` 拒绝 |

带 `Retry-After` 的拒绝是背压，不是错误：客户端稍后重试，遇到它的 Saga 会放慢它的分区，而不是停放任何东西（[失败与重试](../guide/failures#how-a-failure-is-classified)）。

**查询永远不会让追加饿死。** 每个存储的快照查询和 `events` 查询都在它们自己的上限下运行。除非 `wow.query.max-concurrent` 把它固定下来，这个上限会随存储的写入压力自适应：追加变慢或等待连接时减半，恢复后再增长回来。为查询使用单独的连接池或只读副本，可以完全消除这种争用（[PostgreSQL](./postgresql#size-the-pools)）。

## 订阅 {#subscriptions}

分区的订阅在它的属主上运行，每个订阅至多领先它的检查点 `wow.subscription.max-in-flight`（1,024）个条目。落后的订阅不会让节点停止服务：它表现为降级的健康状况和不断增长的 `wow.subscription.backlog`。原因通常是它的处理函数的延迟：缓慢的外部调用，或者写入读模型存储时缺少索引。更多节点能分散它的分区；更快的处理函数帮助更大。

## 要关注什么 {#what-to-watch}

| 负载增长时 | 关注 | 然后 |
| --- | --- | --- |
| 命令延迟上升 | `wow.command.commit`、存储的追加延迟 | 存储跟得上就增加节点；否则扩容存储 |
| 命令被拒绝 | 带 `wow.command.busy` 的 `wow.command.refused` | 增加节点，或者找出缓慢的存储或聚合 |
| 某个聚合很热 | 它的车道上的拒绝 | 把它的工作拆分到多个聚合：一个聚合的命令按设计就是串行的 |
| 订阅落后 | `wow.subscription.backlog`、`wow.subscription.lag` | 加快处理函数，增加节点 |
| 查询被拒绝 | `wow.query.limit`、`wow.query` | 查询连接池或只读副本、更窄的查询、索引 |

指标见[健康、指标与追踪](./observability)。
