# Итоги: расширение пула до четырёх бэкендов **Дата:** 2026-08-16 **Статус:** выполнено, проверено (64 из 64 проверок) **План:** [CHANGE_POOL_4_MEMBERS_PLAN.md](CHANGE_POOL_4_MEMBERS_PLAN.md) ## Что сделано Добавлено по одному бэкенду в каждый приватный сегмент — пул вырос с двух членов до четырёх. Алгоритм балансировки оставлен прежним, `symmetric_l4`. | Контейнер | Сеть | Адрес | MAC | ID члена | Слотов | |---|---|---|---|---|---| | `hpnn-be1` | priv2 | `10.20.0.2` | `02:42:0a:14:00:02` | 1 | 256 | | `hpnn-be3` | priv2 | `10.20.0.3` | `02:42:0a:14:00:03` | 3 | 256 | | `hpnn-be2` | priv3 | `10.30.0.2` | `02:42:0a:1e:00:02` | 2 | 256 | | `hpnn-be4` | priv3 | `10.30.0.3` | `02:42:0a:1e:00:03` | 4 | 256 | Дайджест раскладки: `0a16713c5a9eb94d` (был `2f0ca39d5f33efa6` на двух членах). Изменённые файлы: `docker-compose.yml`, `lb/topology.env`, `lb/pipeline.sh` (DNAT в таблице 12 и adjacency в таблице 21 для новых членов), `lb/entrypoint.sh` (статические ARP-записи для вторых бэкендов на портах проб), `lb/hc-config.sh`, `scripts/verify.sh`. ## Результаты проверок | Проверка | Результат | |---|---| | Обнаружение новых членов | оба перешли в `up` за 4 с после старта демона | | Раскладка | ровно 256 / 256 / 256 / 256, сумма 1024 | | Балансировка с клиента | в 24 запросах присутствуют все четыре бэкенда (7/5/6/6) | | Транзит между сегментами | все четыре направления: be1↔be2, be3↔be4 и обратные | | Маршруты бэкендов | у всех четырёх профиль A: default на шлюзе Docker | | Отказ члена | `pause be1` → его 256 слотов разошлись по трём оставшимся (341/342/341), трафик без ошибок | | Восстановление | дайджест вернулся к `0a16713c5a9eb94d` | | Fail-close | при отказе всех четырёх таблица слотов пуста, клиент получает таймаут | ## Главное измерение: возмущение раскладки на четырёх членах На двух членах проверка минимального возмущения была вырожденной — единственный оставшийся член забирал все слоты, и «чужих» переехавших слотов получалось ровно ноль по построению. На четырёх членах она стала содержательной. Вывод be1 из пула: - переехали **256** слотов самого be1 — это его четверть таблицы, они обязаны сменить владельца; - у трёх оставшихся членов сменили владельца **8** слотов из 768 — **1,0 %** их слотов, или 0,8 % всей таблицы. Это ожидаемое поведение классического Maglev: алгоритм гарантирует *малое*, а не строго нулевое возмущение. Проверка в `verify.sh` поэтому сформулирована как порог (не более 20 слотов), а не как равенство нулю. Предыдущая формулировка «ни один слот не сменил владельца» была верна только для пула из двух членов и на четырёх уже не выполняется. Для сравнения: группа `type=select` из шага 1 при изменении числа бакетов переложила бы **все** соединения, а не 1 %. ## Отклонения от плана Отклонений от плана нет. Уточнение по процедуре: `docker compose up -d --build` не пересоздал контейнер балансировщика — он поднял только новые бэкенды, и демон продолжил работать со старой конфигурацией на двух членах. Потребовалось явное `docker compose up -d --build --force-recreate lb-router`. Это стоит помнить при любых правках `topology.env` и `hc-config.sh`. ## Ограничения Все ограничения шага 2 сохраняются без изменений (stateful-датапас, отсутствие кворума, статический состав пула, только HTTP/TCP-пробы). Новое: - члены пула по-прежнему перечислены статически в трёх местах — `docker-compose.yml`, `lb/topology.env` и `lb/hc-config.sh`, плюс правила DNAT и adjacency в `lb/pipeline.sh`. Добавление пятого члена — снова ручная правка четырёх файлов. Это именно то, что снимет модель `Load_Balancer → Listener → Pool → Member` в OVSDB на следующем шаге.