> ## Documentation Index
> Fetch the complete documentation index at: https://private-7c7dfe99-parallel-read-in-order-multi-part.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Масштабирование кластеров

> Как масштабировать реплики и сегменты ClickHouse, а также участников кворума Keeper, и что оператор делает автоматически.

Чтобы масштабировать кластер, измените количество реплик и сегментов в пользовательском ресурсе. Оператор приводит работающий кластер к новой топологии: создает или удаляет StatefulSet для каждой реплики, синхронизирует схему и отражает ход выполнения в состояниях статуса.

В этом руководстве описано, как масштабировать реплики и сегменты `ClickHouseCluster`, как безопасно масштабировать кворум `KeeperCluster` и за какими состояниями нужно следить во время операции масштабирования.

<Note>
  Для `ClickHouseCluster` всегда требуется Keeper, на который ссылается обязательное поле `spec.keeperClusterRef` — оператор координирует кластер через него независимо от размера. Чтобы запускать более одной реплики на сегмент, данные также должны храниться в таблицах `ReplicatedMergeTree`, поскольку именно репликация позволяет второй реплике обслуживать те же строки.
</Note>

<div id="scaling-replicas">
  ## Масштабирование реплик
</div>

`spec.replicas` задаёт количество реплик в каждом сегменте. Каждая реплика запускается в собственном StatefulSet с именем `<cluster>-clickhouse-<shard>-<replica>`, поэтому в кластере с `shards: 2` и `replicas: 3` будет запущено шесть StatefulSets.

Увеличьте или уменьшите это количество прямо в существующей конфигурации:

```yaml theme={null}
spec:
  replicas: 3   # was 1
  keeperClusterRef:
    name: my-keeper
```

При масштабировании вверх оператор создает новые StatefulSets для каждой реплики, ждет, пока каждый под перейдет в состояние Ready, а затем синхронизирует схему с новыми репликами (см. [Автоматическая синхронизация схемы](#automatic-schema-sync)). При масштабировании вниз он удаляет лишние StatefulSets и очищает устаревшие записи о репликах реплицируемой базы данных, оставшиеся после удаления реплик.

<div id="scaling-shards">
  ## Масштабирование сегментов
</div>

`spec.shards` задаёт количество сегментов. Каждый новый сегмент добавляет полный набор StatefulSet для каждой реплики, а оператор создаёт один [PodDisruptionBudget на сегмент](/ru/products/kubernetes-operator/guides/configuration#pod-disruption-budgets), чтобы сбой в одном сегменте не учитывался при расчёте для другого.

```yaml theme={null}
spec:
  shards: 3   # was 1
  replicas: 2
```

Каждый сегмент хранит отдельную часть данных, и оператор не копирует и не перемещает строки между сегментами. Таблица `Distributed` или явная схема маршрутизации определяет, в какой сегмент попадёт строка, поэтому добавление сегмента просто даёт новым записям новое место для записи, не затрагивая строки, уже хранящиеся в существующих сегментах.

<div id="automatic-schema-sync">
  ## Автоматическая синхронизация схемы
</div>

Когда `spec.settings.enableDatabaseSync` имеет значение `true` (по умолчанию), оператор поддерживает согласованность схемы при изменении топологии:

* **При масштабировании вверх** — как только готовы как минимум две реплики, оператор реплицирует определения баз данных на вновь созданные реплики, чтобы новая реплика присоединилась с теми же базами данных `Replicated` и базами данных интеграций, что и остальные узлы кластера.
* **При масштабировании вниз** — прежде чем реплика исчезнет, оператор удаляет регистрацию этой реплики из каждой базы данных `Replicated` с помощью `SYSTEM DROP DATABASE REPLICA`, чтобы уменьшенный кластер не ожидал реплику базы данных `Replicated`, которой больше не существует.

Это относится к базам данных `Replicated` и движкам баз данных интеграций. Табличные данные при этом не перемещаются — данные строк хранятся в таблицах `ReplicatedMergeTree` и реплицируются через Keeper независимо от этой синхронизации схемы. Если готова только одна реплика, реплицировать некуда, поэтому оператор пропускает этот шаг и записывает в журнал, что целевой реплики нет.

Установите `enableDatabaseSync: false`, чтобы отключить это поведение, например если за распространение схемы отвечает внешний инструмент. В этом случае оператор указывает причину `SchemaSyncDisabled` в условии `SchemaInSync`.

<div id="scaling-conditions">
  ## Состояния, за которыми стоит следить
</div>

Проверяйте состояние пользовательского ресурса во время операции масштабирования:

```bash theme={null}
kubectl get clickhousecluster sample -o yaml | sed -n '/conditions:/,/^[^ ]/p'
```

| Условие | Причина | Значение |
| - | - | - |
| `ClusterSizeAligned` | `UpToDate` | Число запущенных реплик соответствует запрошенной топологии |
| `ClusterSizeAligned` | `ScalingUp` | Оператор добавляет реплики |
| `ClusterSizeAligned` | `ScalingDown` | Оператор удаляет реплики |
| `SchemaInSync` | `ReplicasInSync` | Базы данных есть на всех репликах, а устаревшие метаданные удалены |
| `SchemaInSync` | `DatabasesNotCreated` | Оператор еще не завершил создание баз данных на новых репликах |
| `SchemaInSync` | `ReplicasNotCleanedUp` | Устаревшие метаданные реплик после уменьшения числа реплик еще не удалены |
| `SchemaInSync` | `SchemaSyncDisabled` | `enableDatabaseSync` имеет значение `false` |
| `Ready` | `AllShardsReady` | В каждом сегменте есть готовая реплика |
| `Ready` | `SomeShardsNotReady` | Как минимум в одном сегменте нет готовой реплики |

Операция масштабирования считается завершенной, когда `ClusterSizeAligned` имеет значение `UpToDate`, `SchemaInSync` — `ReplicasInSync`, а `Ready` — `AllShardsReady`.

<div id="scaling-keeper">
  ## Масштабирование Keeper
</div>

`KeeperCluster` работает с RAFT-кворумом, поэтому оператор изменяет его состав **по одной реплике за раз** и только когда кластер находится в стабильном состоянии. Это защищает кворум: кластер `2F+1` допускает отказ `F` участников, поэтому кластер из 3 узлов продолжает работать при отсутствии одного участника, а кластер из 5 узлов — двух.

```yaml theme={null}
spec:
  replicas: 5   # was 3
```

При масштабировании вверх оператор добавляет в кворум реплику с наименьшим свободным ID; при масштабировании вниз — удаляет реплику с наибольшим ID. На каждом шаге оператор ждёт, пока кворум стабилизируется, прежде чем начинать следующий. Для [Keeper PodDisruptionBudget](/ru/products/kubernetes-operator/guides/configuration#pod-disruption-budgets) по умолчанию задано `maxUnavailable: replicas/2`, чтобы сохранять кворум во время плановых прерываний.

Условие `ScaleAllowed` показывает, может ли кворум изменить состав прямо сейчас:

| Причина | Значение |
| - | - |
| `ReadyToScale` | Кворум стабилен, и оператор может добавить или удалить участника |
| `ReplicaHasPendingChanges` | У реплики всё ещё есть ожидающее применения изменение конфигурации |
| `ReplicaNotReady` | Реплика не готова, поэтому изменение состава откладывается |
| `NoQuorum` | В кластере нет кворума, и безопасно изменить состав нельзя |
| `WaitingFollowers` | Оператор ждёт, пока followers догонят лидера |

Масштабируйте Keeper по одному шагу и давайте `ScaleAllowed` вернуться к `ReadyToScale` между изменениями. Переход сразу на несколько участников не отменяет пошаговое согласование — оператор всё равно изменяет кворум по одному участнику за шаг.
