Добавлена локальная локальная балансировка
This commit is contained in:
1 parent
afd4f057be
commit
d80a6c44b0
17 files changed
+1628
-369
No files matched your search
@@ -1,11 +1,16 @@
|
||||
# hpnn_v2 — стенд OVS-маршрутизатора и балансировщика нагрузки
|
||||
|
||||
Контейнерный прототип основы сервиса: один узел на Open vSwitch, который
|
||||
одновременно выполняет две функции — **маршрутизацию** между сегментами и
|
||||
**балансировку нагрузки** на четыре бэкенда. Всё форвардинг-решение принимается
|
||||
в OpenFlow: сетевой стек ядра контейнера транзитный трафик не обрабатывает.
|
||||
Состав пула ведёт подсистема health-check: мёртвые бэкенды выводятся из
|
||||
балансировки, восстановившиеся возвращаются.
|
||||
выполняет три функции — **маршрутизацию** между сегментами, **балансировку
|
||||
нагрузки** на четыре бэкенда и **коммутацию приватных сегментов**. Всё
|
||||
форвардинг-решение принимается в OpenFlow: сетевой стек ядра контейнера
|
||||
транзитный трафик не обрабатывает. Состав пула ведёт подсистема health-check:
|
||||
мёртвые бэкенды выводятся из балансировки, восстановившиеся возвращаются.
|
||||
|
||||
Листенеры есть и в публичном сегменте, и в приватных. Приватный листенер
|
||||
обслуживает клиента, стоящего **в одном сегменте с бэкендами**, сохраняя его
|
||||
исходный IP и транслируя порт 80 на 8080 — при этом в ОС виртуальных машин не
|
||||
настраивается ничего.
|
||||
|
||||
Развивает дизайн-концепцию `../hpnn_v1/docs/design.md`.
|
||||
|
||||
@@ -14,9 +19,14 @@
|
||||
| 1 | Окружение, маршрутизация, балансировка | [план](docs/STEP1_IMPLEMENTATION_PLAN.md) | [итоги](docs/STEP1_SUMMARY.md) |
|
||||
| 2 | Health-check и таблица слотов | [план](docs/STEP2_IMPLEMENTATION_PLAN.md) | [итоги](docs/STEP2_SUMMARY.md) |
|
||||
| — | Расширение пула до четырёх бэкендов | [план](docs/CHANGE_POOL_4_MEMBERS_PLAN.md) | [итоги](docs/CHANGE_POOL_4_MEMBERS_SUMMARY.md) |
|
||||
| 3 | Листенер в приватном сегменте, коммутация сегментов | [план](docs/STEP3_IMPLEMENTATION_PLAN.md) | [итоги](docs/STEP3_SUMMARY.md) |
|
||||
| — | Разделение документации по потокам данных | [план](docs/CHANGE_SPLIT_DATAFLOW_DOCS_PLAN.md) | [итоги](docs/CHANGE_SPLIT_DATAFLOW_DOCS_SUMMARY.md) |
|
||||
|
||||
Диаграммы потоков данных подсистемы маршрутизации —
|
||||
[docs/ROUTING_DATAFLOW.md](docs/ROUTING_DATAFLOW.md).
|
||||
Потоки данных описаны отдельно для каждого вида балансировки:
|
||||
[публичный трафик](docs/PUBLIC_LB_DATAFLOW.md) — клиент из клиентской сети на
|
||||
`192.168.5.21:80`, целиком маршрутизируемый путь;
|
||||
[приватный трафик](docs/PRIVATE_LB_DATAFLOW.md) — клиент внутри приватного
|
||||
сегмента, рядом с бэкендами, на `10.20.0.100:80`.
|
||||
|
||||
## Топология
|
||||
|
||||
@@ -25,23 +35,34 @@
|
||||
│
|
||||
[ enp3s0, macvlan ] сеть 1 — публичный сегмент
|
||||
│ pub0 · ofport 1
|
||||
┌─────────────────┴─────────────────────┐
|
||||
│ hpnn-lb (Open vSwitch, br-lb) │ узел 192.168.5.20
|
||||
│ маршрутизатор + балансировщик │ VIP 192.168.5.21
|
||||
│ hcd: health-check + таблица слотов │
|
||||
└──┬──────────────────────────────┬─────┘
|
||||
p2 ·2 │ 10.20.0.1 10.30.0.1 │ p3 ·3
|
||||
hcif-p2 ·4 10.20.0.253 10.30.0.253 │ hcif-p3 ·5 (источники проб)
|
||||
сеть 2 │ 10.20.0.0/24 сеть 3 │ 10.30.0.0/24
|
||||
hpnn-be1 │ 10.20.0.2 hpnn-be2 │ 10.30.0.2
|
||||
hpnn-be3 │ 10.20.0.3 hpnn-be4 │ 10.30.0.3
|
||||
┌─────────────────┴─────────────────────────────┐
|
||||
│ hpnn-lb (Open vSwitch, br-lb) │ узел 192.168.5.20
|
||||
│ маршрутизатор + балансировщик + коммутатор │ VIP 192.168.5.21
|
||||
│ hcd: health-check + таблица слотов │
|
||||
└──┬─────────────────────────────────────┬──────┘
|
||||
сеть 2 │ 10.20.0.0/24 сеть 3 │ 10.30.0.0/24
|
||||
шлюз ·1 │ VIP 10.20.0.100:80 шлюз ·1 │ VIP 10.30.0.100:80
|
||||
│ │
|
||||
p2 ·2 ──┤ аплинк к шлюзу Docker .254 p3 ·3 ├── аплинк .254
|
||||
hcif-p2·4│ 10.20.0.253 (пробы) hcif-p3 ·5│ 10.30.0.253
|
||||
be1 ·10 │ 10.20.0.2:8080 be2 ·20│ 10.30.0.2:8080
|
||||
be3 ·11 │ 10.20.0.3:8080 be4 ·21│ 10.30.0.3:8080
|
||||
cli2 ·12 │ 10.20.0.10 (клиент) cli3 ·22│ 10.30.0.10
|
||||
```
|
||||
|
||||
Каждая ВМ приватного сегмента — **отдельный порт моста**. Так балансировщик
|
||||
видит и ответ бэкенда клиенту-соседу по подсети, а значит может снять с него
|
||||
трансляцию. В целевой среде это выполняется само собой: ВМ подключены к
|
||||
vSwitch. В стенде порты создаёт [scripts/attach-segment.sh](scripts/attach-segment.sh)
|
||||
(`make attach`) — он же назначает адреса и маршруты снаружи, как это делают
|
||||
гипервизор и DHCP.
|
||||
|
||||
| Контейнер | Роль |
|
||||
|---|---|
|
||||
| `hpnn-lb` | OVS, все три сети, маршрутизация и балансировка |
|
||||
| `hpnn-lb` | OVS: маршрутизация, балансировка, коммутация сегментов |
|
||||
| `hpnn-be1`, `hpnn-be3` | web-сервис на Go в приватном сегменте 2 |
|
||||
| `hpnn-be2`, `hpnn-be4` | тот же сервис в приватном сегменте 3 |
|
||||
| `hpnn-cli2`, `hpnn-cli3` | клиенты внутри сегментов; в их ОС настроен только адрес |
|
||||
|
||||
### Адресный план
|
||||
|
||||
@@ -49,7 +70,9 @@
|
||||
|---|---|
|
||||
| Клиентская сеть | `192.168.5.0/24` |
|
||||
| Адрес узла в публичном сегменте | `192.168.5.20` |
|
||||
| **VIP балансировщика** | **`192.168.5.21:80`** |
|
||||
| **VIP публичного листенера** | **`192.168.5.21:80`** |
|
||||
| **VIP приватных листенеров** | **`10.20.0.100:80`, `10.30.0.100:80`** |
|
||||
| Клиенты внутри сегментов | `10.20.0.10`, `10.30.0.10` |
|
||||
| Шлюз OVS в сети 2 / бэкенды be1, be3 | `10.20.0.1` / `10.20.0.2:8080`, `10.20.0.3:8080` |
|
||||
| Шлюз OVS в сети 3 / бэкенды be2, be4 | `10.30.0.1` / `10.30.0.2:8080`, `10.30.0.3:8080` |
|
||||
| Источники health-проб (internal-порты OVS) | `10.20.0.253`, `10.30.0.253` |
|
||||
@@ -64,11 +87,15 @@ OpenFlow** — на интерфейсах они не настроены. ARP-
|
||||
## Запуск
|
||||
|
||||
```bash
|
||||
make up # modprobe openvswitch + сборка образов + запуск
|
||||
make up # modprobe openvswitch + сборка образов + запуск + attach
|
||||
make verify # проверки
|
||||
make down # остановка
|
||||
```
|
||||
|
||||
`make up` вызывает `make attach`: порты ВМ приватных сегментов создаются
|
||||
скриптом, а не Docker. Повторить `make attach` нужно после пересоздания любого
|
||||
контейнера сегмента — вручную созданные veth вместе с ним исчезают.
|
||||
|
||||
Проверка с самого хоста требует macvlan-shim: интерфейс macvlan контейнера и
|
||||
физический интерфейс хоста по устройству macvlan не видят друг друга. Клиенту
|
||||
из 192.168.5.0/24 никакой shim не нужен.
|
||||
@@ -91,6 +118,21 @@ ping 192.168.5.21 # VIP
|
||||
for i in $(seq 20); do curl -s http://192.168.5.21/; done
|
||||
```
|
||||
|
||||
Из приватного сегмента — с клиента, который стоит рядом с бэкендами:
|
||||
|
||||
```bash
|
||||
docker compose exec cli2 curl -s http://10.20.0.100/
|
||||
docker compose exec cli2 ip route # маршрутов нет: настроен только адрес
|
||||
```
|
||||
|
||||
```
|
||||
backend=be1 time=2026-08-17 15:29:23 MSK client=10.20.0.10:46064 served=10.20.0.2:8080 req=1
|
||||
```
|
||||
|
||||
`client=10.20.0.10` — исходный адрес клиента, `served=…:8080` — трансляция
|
||||
порта 80 → 8080. Ответ бэкенда клиенту-соседу уходит по L2 напрямую, но
|
||||
проходит через мост, где таблица 24 снимает трансляцию.
|
||||
|
||||
```
|
||||
backend=be1 time=2026-08-16 21:35:02 MSK client=192.168.5.13:47734 served=10.20.0.2:8080 req=24
|
||||
backend=be3 time=2026-08-16 21:35:02 MSK client=192.168.5.13:47740 served=10.20.0.3:8080 req=11
|
||||
@@ -187,6 +229,8 @@ docker compose unpause be1 # возвращается за rise × interval =
|
||||
make ports # порты моста
|
||||
make conns # таблица соединений ct
|
||||
make trace SRC=192.168.5.13 # ofproto/trace сессии клиент -> VIP
|
||||
make trace SRC=10.20.0.10 SEG=p2 # то же для приватного листенера
|
||||
make fdb # выученные MAC сегментов и счётчики рассылки
|
||||
make flows # перечитать pipeline.sh и перезалить правила
|
||||
docker compose exec lb-router lbctl flows 21 # правила конкретной таблицы
|
||||
docker compose exec lb-router lbctl status # состояние пула в JSON
|
||||
@@ -200,20 +244,43 @@ docker compose exec lb-router lbctl status # состояние пула в
|
||||
|
||||
| Таблица | Назначение |
|
||||
|---|---|
|
||||
| 0 | Классификация по входному порту; обучение MAC клиентов для обратного пути |
|
||||
| 5 | ARP-респондер для адресов узла, VIP и источников проб |
|
||||
| 0 | Сегмент по входному порту (`reg0`); обучение MAC (FDB) и adjacency |
|
||||
| 1 | Классификация: ARP, ICMP, листенер, трафик к маршрутизатору, коммутация |
|
||||
| 5 | ARP-респондер для адресов узла, VIP и источников проб; прочий ARP — в коммутацию |
|
||||
| 6 | ICMP echo-респондер для адресов узла и VIP |
|
||||
| 10 | Листенеры: `VIP:80` → `multipath` кладёт номер слота в `reg1`; прочий IP → маршрутизация |
|
||||
| 11 | **Таблица слотов**: `reg1` → `reg2` (член пула). Ведёт демон `hcd` |
|
||||
| 12 | DNAT выбранным членом пула (`ct(commit, nat)`) |
|
||||
| 15, 16 | Обратный путь: `ct(nat)` снимает DNAT, источник снова становится VIP |
|
||||
| 12 | Применение члена: DNAT и выдача — коммутацией либо через маршрутизацию |
|
||||
| 15, 16 | Обратный путь L3: `ct(nat)` снимает DNAT, источник снова становится VIP |
|
||||
| 20 | Маршрутизация: приоритет = длина префикса, `dec_ttl`, MAC источника |
|
||||
| 21 | Adjacency: MAC next-hop и выходной порт |
|
||||
| 24 | Обратная трансляция коммутируемого трафика сегмента |
|
||||
| 25 | L2-коммутация сегмента: FDB, broadcast и рассылка неизвестного unicast |
|
||||
|
||||
Регистры: `reg1` — номер слота, `reg2` — идентификатор члена пула.
|
||||
Регистры: `reg0` — сегмент (1 — публичный, 2 и 3 — приватные), `reg1` — номер
|
||||
слота, `reg2` — идентификатор члена пула.
|
||||
|
||||
Нумерация таблиц не произвольна: `goto_table` разрешает переход только вперёд,
|
||||
поэтому обратный путь (15/16) стоит до общей маршрутизации (20).
|
||||
поэтому обратный путь (15/16) стоит до общей маршрутизации (20), а коммутация
|
||||
(24/25) — после неё: в неё попадают и кадры, прошедшие DNAT в таблице 12.
|
||||
|
||||
### Два пути внутри одного пула
|
||||
|
||||
Приватный листенер и публичный делят пул, таблицу слотов и хэш. Различается
|
||||
только выдача:
|
||||
|
||||
- **член в сегменте клиента** — меняется лишь MAC назначения, кадр отдаётся в
|
||||
коммутацию. `dec_ttl` не выполняется: клиент и бэкенд остаются L2-соседями,
|
||||
и ответ приходит к клиенту с исходным TTL. Обратную трансляцию делает
|
||||
таблица 24, когда бэкенд отвечает соседу напрямую;
|
||||
- **член в другом сегменте либо публичный листенер** — прежний маршрутизируемый
|
||||
путь через таблицы 20/21 с `dec_ttl` и обратной трансляцией в таблице 15.
|
||||
|
||||
Для клиента оба пути неотличимы: ответ приходит от `VIP:80`.
|
||||
|
||||
Какие приватные листенеры подняты, задаёт `PRIV_LISTENERS` в
|
||||
[lb/topology.env](lb/topology.env): пусто — ни одного, `"p2"` — один сегмент,
|
||||
`"p2 p3"` — оба.
|
||||
|
||||
### Чего нет у чисто-OpenFlow узла
|
||||
|
||||
|
||||
Reference in new issue
Block a user