# 置放群组

**置放群组**（Placement Group）用于控制 Zenlayer 弹性算力（ZEC）实例在某个区域内的**物理主机**上的分布方式。如需管理置放群组，请在控制台导航至[置放群组](https://console.zenlayer.com/zec/placement-group)页面。若不使用置放群组，调度器可将任意两个实例部署在同一台物理主机上——一旦该主机故障，同一服务的多个副本可能同时下线。置放群组的作用恰恰相反：它将一组实例声明为一个容错集合，平台会将其分散部署在**不同的物理主机**上，确保单台主机故障最多只会影响其中已知比例的实例。

***

## 什么是置放群组

置放群组是一个区域级对象，将一组实例绑定到**不同的物理主机**上。它由两个参数控制：

* **`partition_num`**——群组最多可容纳的成员实例数量。平台的目标是将每个成员部署在独立的主机上。取值范围 2–5，默认值为 3。
* **`affinity`**——当无法实现完全分散时，平台允许在同一主机上共置的群组成员数量上限。这是一个**容忍阈值**，而非目标值或倍增因子。取值范围为 1 到 `partition_num / 2`，默认值为 1。

群组的**容量为 `partition_num`** 个实例。平台的首选策略始终是完全分散——每台主机一个成员。`affinity` 仅用于回退场景：若该区域无法为每个成员提供独立主机，则最多允许 `affinity` 个成员共置于同一主机，超出此限制的请求将被拒绝。

平台会上报 `constraint_status`，方便您随时确认分散策略是否已生效。

> 置放群组仅限于**单个区域**（例如 `asia-east-1`），不跨区域延伸。如需在整个区域故障时保持可用，请在每个区域分别创建一个置放群组，并在应用层实现数据复制。

> **分区粒度目前为主机级别。**

***

## 为什么要使用置放群组

| 场景                                             | 是否适合使用置放群组 | 说明                             |
| ---------------------------------------------- | ---------- | ------------------------------ |
| 分布式仲裁（etcd、ZooKeeper、Consul）——奇数节点集群           | ✅ 适合       | 每个成员部署在独立主机上，单主机故障最多只损失一个仲裁成员。 |
| 有状态副本（数据库主节点 + 副本、Kafka Broker、Cassandra 环形集群） | ✅ 适合       | 将副本共置于同一主机失去了部署多副本的意义。         |
| 无状态 Web 层，N > 1 个副本部署在负载均衡器后                   | ✅ 适合       | 避免单台主机故障导致 VIP 后端整层下线。         |
| 跨区域高可用——抵御整个区域故障                               | ❌ 不够       | 需在每个区域分别建立置放群组，并结合应用层复制。       |
| 单个虚拟机，无副本                                      | ❌ 意义不大     | 单成员群组没有实际效果。                   |
| HPC / 时延敏感型任务，希望实例**更近**而非更分散                  | ❌ 功能不匹配    | 置放群组强制实现反亲和性，目前不支持共置模式。        |

***

## `partition_num` 与 `affinity` 的协同作用

![每个成员理想情况下部署在各自独立的物理主机上](/files/r5aGWvaLJWTaDNUe16LH)

`partition_num` 和 `affinity` 表达的是两件不同的事：

* **`partition_num`** 决定群组可容纳**多少个成员**（同时也表示群组期望跨越多少台不同主机——每个成员一台）。
* **`affinity`** 决定在主机资源紧张时**允许多大程度的共置**。`affinity=1` 时，任何主机最多承载一个成员；`affinity=2` 时，回退场景下最多两个成员可共享一台主机，但绝不允许三个。

容量始终是 `partition_num`，`affinity` 不会扩充容量，它只控制当调度器无法为成员分配独立主机时（或恢复事件导致两个成员回到同一主机后），允许分散程度下降到何种程度后才拒绝分配（或将群组标记为*不满足约束*）。

### 两个示例

**`partition_num=5, affinity=1`**——5 节点仲裁集群的严格分散策略。\
群组最多容纳 5 个成员，所有成员必须部署在不同主机上，平台绝不共置任意两个成员。若无符合条件的空闲主机，该分配请求将被拒绝。

**`partition_num=5, affinity=2`**——具备回退容忍的容错分散策略。\
群组最多容纳 5 个成员，平台仍优先将所有成员部署在不同主机上。若主机容量不足，最多允许 2 个成员共享一台主机，但绝不超过此限。这样可确保群组大多数成员部署在不同主机上，单台主机故障不会同时击垮仲裁多数。

两种情况下，`partition_num` 均将群组上限设为 5 个成员；`affinity` 只改变分配被拒绝前允许的分散程度下限。

### 如何选择 `partition_num`

将 `partition_num` 与您希望分散的集群规模对齐：

| 集群规模                   | `partition_num` |
| ---------------------- | --------------- |
| 主节点 + 1 个副本            | 2               |
| 主节点 + 2 个副本            | 3               |
| 3 节点仲裁（etcd、ZK、Consul） | 3               |
| 5 节点仲裁                 | 5               |

若集群规模超过 `partition_num=5`，请将工作负载拆分到多个置放群组。

### 如何选择 `affinity`

`affinity` 是您对共置的容忍度，适用于无法实现完全分散的情形。对于小型仲裁集群和有状态副本（任意两个副本同时下线均不可接受），建议保持默认值 `1`，以获得最严格的"每主机一成员"保证。若您宁可在主机资源紧张时接受部分共置，也不希望分配请求被拒绝，可适当提高该值（上限为 `partition_num / 2`）。上限设为 `partition_num / 2` 的原因是：确保单台主机故障永远不会导致群组多数成员同时下线。

***

## 生命周期

![生命周期：先创建群组，再逐一分配实例](/files/aVEqZXpQED45BKPoWus0)

置放群组创建时为空，之后逐一为其分配实例。成员关系与实例创建是独立的操作。

1. **创建**群组。`region_id` 和初始 `partition_num` 在创建时确定。区域一旦设定终身不可更改；`partition_num` 和 `affinity` 后续可修改。
2. **分配实例**至群组。实例必须与群组位于同一区域，平台将为其选择满足分散策略的主机。
3. 可随时**移除实例**，其在群组中的槽位随即释放。
4. 后续可**修改** `partition_num` 或 `affinity`。若将 `partition_num` 降低至当前成员数以下，该操作将被拒绝。
5. 成员清空后可**删除**群组。

成员关系具有**排他性**：一个实例最多属于一个置放群组。跨群组重新分配是单步操作——平台将实例从旧群组移出，再将其加入新群组。

> **硬性上限：** `instance_count ≤ partition_num`。向已满的群组添加成员将被拒绝。

***

## 约束状态

`constraint_status` 反映当前部署是否仍满足分散策略：

| 状态     | 含义                                                  |
| ------ | --------------------------------------------------- |
| 约束已满足  | 所有主机上最多部署一个成员——完全分散生效中。稳定状态。                        |
| 约束存在风险 | 某台主机承载了多于一个成员，但未超过 `affinity` 上限。处于容忍范围内，但安全余量有所降低。 |
| 约束已违反  | 某台主机承载的成员数超过 `affinity`。极少出现，通常仅在异常恢复路径下发生。         |

平台会主动避免违反约束的分配，因此大多数群组会长期保持*已满足*状态。

***

## 实例管理

### 添加已有实例

只要群组有空余槽位且实例与群组位于同一区域，即可将正在运行的实例加入置放群组。平台会在实例的下一次分配事件（通常是下一次停止/启动）时应用新的部署位置。在此之前，实例已与群组关联，但其所在主机不会改变。

> 若实例当前所在主机与群组约束冲突，加入操作**不会触发热迁移**。请手动执行一次停止/启动操作，平台将重新为其选择合适的主机。

### 移除实例

移除操作在成员关系层面立即生效。实例继续运行在当前主机上，仅反亲和性的计账信息会更新。

### 替换故障成员

只要替换实例创建完成，立即将其分配至群组，空出的槽位即可复用。

***

## 限制

| 属性              | 值                               |
| --------------- | ------------------------------- |
| 作用范围            | 单个区域（如 `asia-east-1`），不支持跨区域群组。 |
| `partition_num` | 2–5，默认值为 3。                     |
| 每个群组的成员实例数      | ≤ `partition_num`。              |
| 每个实例的群组成员关系数    | 最多 1 个。                         |
| `affinity`      | 1 到 `partition_num / 2`，默认值为 1。 |
| 分区粒度            | 主机级别。                           |

***

## 常见问题

**置放群组能否跨区域？**\
不能。置放群组终身绑定于单个区域。如需跨区域高可用，请每个区域单独创建一个群组，并在应用层实现复制。

**成员数可以超过 `partition_num` 吗？**\
不能。请提高 `partition_num`（最大为 5），或将工作负载拆分到多个群组。

**提高 `affinity` 会增加容量吗？**\
不会。容量始终由 `partition_num` 决定。`affinity` 是调度器在无法完全分散时允许共置于单台主机的最大成员数——它控制的是允许的退化程度，而非群组容量。

**成员实例发生热迁移时会怎样？**\
目标主机的选择会确保约束依然满足，迁移过程中成员关系和 `constraint_status` 均保持不变。

**能否将实例在两个置放群组之间移动？**\
可以。重新分配是单步操作——实例离开旧群组的槽位，占用新群组的空闲槽位。两个群组必须与实例位于同一区域。

**使用置放群组会产生额外费用吗？**\
不会，每个群组均免费。

**为什么我的分配请求被拒绝了？**\
原因可能是群组已满（`instance_count == partition_num`），或该区域内没有主机能在当前 `affinity` 限制下满足约束。请尝试提高 `partition_num`、提高 `affinity`（允许更多共置作为回退），或选择其他区域。

**能否按机架或交换机而非主机进行分散？**\
目前不支持，仅暴露主机级别的分区粒度。

**置放群组与资源组有何区别？**\
**资源组**是组织/计费边界；**置放群组**是*物理部署*约束，控制实例可在哪里运行。两者相互独立。

***

## 延伸阅读

* [**实例规格**](/welcome/cn/elastic-compute/instance-specification.md) — 为每个成员选择合适的实例规格。
* [**网卡**](/welcome/cn/elastic-compute/networking/network-interface.md) — 虚拟网卡如何随实例热迁移。


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.console.zenlayer.com/welcome/cn/elastic-compute/placement-group.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
