# Placement Group

A **Placement Group** controls how Zenlayer Elastic Compute (ZEC) lays out a set of instances across the **physical hosts** of a region. To manage placement groups, navigate to the [Placement Group](https://console.zenlayer.com/zec/placement-group) page in the console. Without one, the scheduler is free to land any two instances on the same host — so a single host failure can take down both replicas of your service. A placement group declares the opposite: the listed instances belong together as one fault-tolerant set, and the platform spreads them across **different underlying hosts** so that no single host failure can take more than a known share of them down.

***

## What a Placement Group Is

A placement group is a region-scoped object that pins a set of instances to **distinct physical hosts**. Two parameters shape it:

* **`partition_num`** — the maximum number of member instances the group can hold. The platform aims to put each member on its own host. Range 2–5, default 3.
* **`affinity`** — how many group members the platform is allowed to co-locate on the same host when full spread isn't achievable. It is a *tolerance*, not a target or a multiplier. Range 1 to `partition_num / 2`, default 1.

The group's **capacity is `partition_num`** instances. The platform's first choice is always full spread — one member per host. `affinity` only governs the fallback: if the region cannot give each member a distinct host, up to `affinity` members may share a host rather than fail the placement. Anything beyond `affinity` is refused.

The platform reports a `constraint_status` so you can confirm at a glance whether the spread is currently honored.

> A placement group lives entirely in **one region** (for example `asia-east-1`). It does not stretch across regions. To survive the loss of an entire region, run a separate placement group per region and replicate at the application layer.

> **Partition granularity is host-level today.**

***

## Why Use One

| Scenario                                                                 | Placement Group?  | Notes                                                                               |
| ------------------------------------------------------------------------ | ----------------- | ----------------------------------------------------------------------------------- |
| Distributed quorum (etcd, ZooKeeper, Consul) — odd-number cluster        | ✅ Yes             | Each member on its own host. A single host failure loses at most one quorum member. |
| Stateful replicas (DB primary + replicas, Kafka brokers, Cassandra ring) | ✅ Yes             | Co-locating replicas defeats the point of having them.                              |
| Stateless web tier with N>1 replicas behind a load balancer              | ✅ Yes             | Keeps a single host fault from taking out the whole tier behind the VIP.            |
| Cross-region HA — survive a full region outage                           | ❌ Not enough      | Use one placement group per region plus application-level replication.              |
| A single VM, no replicas                                                 | ❌ Overkill        | A group with one member adds nothing.                                               |
| HPC / latency-sensitive workloads that want VMs *closer*, not apart      | ❌ Wrong primitive | Placement groups enforce anti-affinity. There is no co-location mode today.         |

***

## How `partition_num` and `affinity` Work Together

![Each member ideally lands on its own physical host](/files/smrR0bRBMSY70qI7Fwjh)

`partition_num` and `affinity` express two different things:

* **`partition_num`** sets **how many members** the group can hold (and equivalently, how many distinct hosts the group prefers to span — one per member).
* **`affinity`** sets **how much co-location is tolerated** when free hosts are scarce. With `affinity=1`, no host may carry more than one member. With `affinity=2`, up to two members may share a host as a fallback — but never three.

Capacity is `partition_num`, period. `affinity` does not multiply it. The setting only controls how far the spread is allowed to degrade before the scheduler refuses an assignment (or marks the group *unsatisfied* after a recovery event lands two members back on one host).

### Two Worked Examples

**`partition_num=5, affinity=1`** — strict spread for a 5-node quorum. The group holds at most 5 members. All 5 must land on different hosts. The platform never co-locates two members. If no qualifying host is free, the assignment is rejected.

**`partition_num=5, affinity=2`** — fault-tolerant spread with a fallback. The group holds at most 5 members. The platform still tries to place all 5 on different hosts. If host capacity prevents that, up to 2 members may share one host — but never more. This keeps a majority of the group on distinct hosts, so a single host failure cannot take a quorum down at once.

In both cases `partition_num` caps the group at 5 members. `affinity` only changes how much spread can degrade before the platform refuses placement.

### Picking `partition_num`

Match `partition_num` to the size of the cluster you want to spread:

| Cluster shape                    | `partition_num` |
| -------------------------------- | --------------- |
| Primary + 1 replica              | 2               |
| Primary + 2 replicas             | 3               |
| 3-node quorum (etcd, ZK, Consul) | 3               |
| 5-node quorum                    | 5               |

To grow past `partition_num=5`, split the workload across multiple placement groups.

### Picking `affinity`

`affinity` is your tolerance for co-location when full spread isn't achievable. Leave it at the default `1` for the strictest "one-member-per-host" guarantee — the right choice for small quorums and stateful replicas, where any two replicas going down together is unacceptable. Raise it (within `partition_num / 2`) when you'd rather accept partial co-location than have an assignment refused during a host shortage. The cap of `partition_num / 2` exists so a single host failure can never bring down a majority of the group.

***

## Lifecycle

![Lifecycle: create the group, then assign instances one by one](/files/2L74yJ6VDfNFsVAKH1uK)

A placement group is created empty and populated by assigning instances to it one at a time. Membership is a separate operation from instance creation.

1. **Create** the group. `region_id` and the initial `partition_num` are set up front. The region is fixed for life; `partition_num` and `affinity` can be modified later.
2. **Assign an instance** to the group. The instance must be in the group's region. The platform picks a host that satisfies the spread.
3. **Remove an instance** at any time. Its slot in the group frees up.
4. **Modify** `partition_num` or `affinity` later. Decreasing `partition_num` below the current member count is rejected.
5. **Delete** the group once it has no members.

Membership is **exclusive**: an instance belongs to at most one placement group. Reassigning across groups is a single operation — the platform removes the instance from the old group and slots it into the new one.

> **Hard cap:** `instance_count ≤ partition_num`. Adding a member to a full group is rejected.

***

## Constraint Status

`constraint_status` reports whether the current placement still honors the spread:

| Status              | Meaning                                                                                                                 |
| ------------------- | ----------------------------------------------------------------------------------------------------------------------- |
| Constraint met      | No host carries more than one member — full spread is in effect. Steady state.                                          |
| Constraint at risk  | Some host carries more than one member but no more than `affinity`. Within tolerance, but the safety margin is reduced. |
| Constraint violated | Some host carries more than `affinity` members. Rare; arises only under unusual recovery paths.                         |

The platform actively avoids placements that would violate the rule, so most groups stay *met* indefinitely.

***

## Working with Instances

### Adding an existing instance

You can move a running instance into a placement group as long as a slot is free and the instance is in the group's region. The platform applies the placement on the instance's next placement event — typically the next stop/start. Until then, the instance is associated with the group but its host does not change.

> If the instance is currently on a host that conflicts with the group, joining does **not** trigger a live migration. Schedule a stop/start so the platform can re-place it.

### Removing an instance

Removal is immediate at the membership level. The instance keeps running on its current host; only the anti-affinity bookkeeping changes.

### Replacing a failed member

Assign the replacement to the group as soon as it exists. The freed slot is reused.

***

## Limits

| Property                       | Value                                                    |
| ------------------------------ | -------------------------------------------------------- |
| Scope                          | One region (e.g. `asia-east-1`). No cross-region groups. |
| `partition_num`                | 2–5, default 3.                                          |
| Member instances per group     | ≤ `partition_num`.                                       |
| Group memberships per instance | At most 1.                                               |
| `affinity`                     | 1 to `partition_num / 2`, default 1.                     |
| Partition granularity          | Host-level                                               |

***

## Frequently Asked Questions

**Can a placement group span regions?** No. A placement group is bound to one region for life. For cross-region HA, run one group per region and replicate above.

**Can I add more instances than `partition_num`?** No. Raise `partition_num` (up to 5) or split the workload across multiple groups.

**Does raising `affinity` give me more capacity?** No. Capacity is always `partition_num`. `affinity` is the maximum number of members the scheduler may co-locate on a single host when full spread isn't possible — it controls how much the spread is allowed to degrade, not how many members the group holds.

**What happens during live migration of a member?** The destination host is chosen so the constraint still holds. Membership and `constraint_status` are preserved across the migration.

**Can I move an instance between two placement groups?** Yes. Re-assigning is one operation — the instance leaves the old group's slot and takes a free slot in the new one. Both groups must be in the instance's region.

**Does a placement group cost extra?** No. There is no per-group charge.

**Why was my assignment rejected?** Either the group is full (`instance_count == partition_num`) or no host in the region can satisfy the constraint at this `affinity` level. Raise `partition_num`, raise `affinity` (allow more co-location as a fallback), or pick a different region.

**Can I spread across racks or switches instead of hosts?** Not today — only host-level placement is exposed.

**How is a placement group different from a resource group?** A **resource group** is an organizational/billing boundary. A **placement group** is a *physical-placement* constraint — it controls where instances may run. They are independent.

***

## Learn More

* [**Instance Specification**](/welcome/elastic-compute/instance-specification.md) — pick the instance shape for each member.
* [**Network Interface**](/welcome/elastic-compute/networking/network-interface.md) — how vNICs follow instances across live migration.


---

# 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/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.
