Итак, вы гиперскейлер, давайте отталкиваться от этого. Потому что если нет — собирайте хоть 3-tier на OSPF. А гиперскейлер вы в том случае, если у вас большая сеть на тысячи хостов, а лучше стоек. Вы уже попробовали топологию Клоза. Сначала вам очень нравилось. Она вся такая плотная, регулярная и масштабируемая — просто прелесть.
Как только кластер начал грозить вырасти за 2000 хостов, вы стали надстраивать ещё один уровень коммутации и докидывать в него всё новые и новые группы стоек. И продолжаете расти на десятки тысяч узлов. У вас отработанный дизайн, автоматизация ввода нового оборудования. Всё на потоке.
Но отчего‑то вы несчастливы. Вам плохо спится. Гложут сомнения и дурные мысли.
А всё дело в эпохе 400G! Вы долгие годы строили свою сеточку на 25+100, и всего всегда хватало. Раньше. А теперь надо на хосты соточку спустить. А значит и аплинки надо расширять, да вы и сами уже понимаете, что пора: ещё несколько лет — и эта сеть станет устаревшей. 200G, 400G, SerDes по 100 Гб/с на PSM4. Тут думать надо.
И новая сетка выглядит действительно привлекательной, даже почти изумительной.
Но как только вы подумаете, что её, такую красивую, нужно как‑то интегрировать с существующей, уже немного опостылевшей сетью, настроение сразу портится — фактически это означает, что нужно менять уровень S2 или строить ещё одну сетку рядом с нужной ёмкостью и каким‑то ужасным образом скрещивать их друг с другом иначе.
И вспомним, что сеть Клоза должна быть почти вся построена задолго до того, как вся её мощность реально будет нужна, а это значит — нужно вбухать весь CAPEX сразу.
А ещё один повод для серьёзного беспокойства — это стоимость новой сети на 400G (или, не дай бог, 800G). Цена трансиверов начинается с нового айфона, а их нужны тысячи. Потом сами коробки с чипами на десятки Тб/с — их нужно много. Да и линки — бесконечные километры мультика или синглы, — которые тянутся от S1 до S2 и обратно. Это всё нужно спланировать, купить, заказать строительство СКС, монтаж, скрестить как‑то устаревший и новый блестящий сегменты и когда‑то потом ещё миграция.
Страшно, в общем.
И закрадывается робкая мысль, а не пришло ли время...
Dragonfly
27 ноября на конференции Nexthop Роман Глебов расскажет про путь Яндекса к топологии Dragonfly+, наши прототипы и как мы уже используем её в коммерческой сети.
В этой статье:
-
Dragonfly
-
Dragonfly+
-
Блеск стрекозы
-
Нищета стрекозы
-
-
Маршрутизация в Dragonfly
-
MIN Routing
-
VAL Routing
-
Adaptive Routing
-
-
Dragonfly в продакшене
-
Арифметика Клоза
-
Арифметика Dragonfly+
-
MIN+3
В основе топологии Dragonfly очень простая идея — разбивать сеть на группы и соединять их между собой напрямую, без использования дополнительных слоёв коммутации.
Внутри группы хосты соединяются друг с другом с помощью роутеров.
У роутеров есть порты вниз — к хостам (локальные) — и вверх (глобальные) — в другие группы.
Между группами всегда full‑mesh, а от того, сколько линков между каждой парой групп, зависит плотность топологии.
Терминология Dragonfly:
-
Host или Terminal — конечный вычислительный элемент, по‑простому, сервер.
-
Group — группа хостов, связанных между собой через Router.
-
Router — устройство, связывающее хосты внутри группы. Оно может быть выделенным элементом, осуществляющим только коммутацию между хостами, а может быть частью хоста. Вместе все роутеры группы в масштабе всего кластера представляют из себя виртуальный роутер.
-
Local Channels — локальные линки, связывающие между собой хосты. Сокращается до
L
. -
Global Channels — глобальные линки, связывающие между собой группы. Сокращается до
G
.
И давайте возьмём нотацию из знаковой статьи:
-
a — число роутеров в группе,
-
p — число хостов, подключенных к каждому роутеру,
-
k — радикс каждого роутера (число портов на роутере),
-
k' — эффективный радикс всей группы — то есть сумма количества портов всех роутеров группы,
-
h — число линков «вверх» — к другим группам — с каждого роутера,
-
g — общее число групп в кластере.
Если каждую группу представить в виде обычного клозовского подика — Leaf+Spine, разделённого на привычные плейны, и плейны разных групп соединять друг с другом, то получается...
Dragonfly+
В Dragonfly+ мы соединяем спайны разных групп между собой напрямую.
Отступление про устройство топологии Клоза
Мы уже довольно свободно оперируем объектами из мира Клоза. Но, вероятно, не каждый читатель ещё так легко ориентируется в них.
За детальным разбором я отправлю читать статью, где я разбирал топологию Клоза по кирпичикам, а тут пройдёмся по самому важному.
Топология Клоза — подвид Fat‑Tree — регулярная плотная топология, стандарт де‑факто в датацентростроении. Другое распространённое название Leaf‑Spine.
Выглядит так:
Здесь Leaf (далее лиф) — это стоечный коммутатор для подключения серверов, прямоугольник Leaf‑Spine1 — это POD (Point Of Delivery, далее я буду называть его подом) — универсальный строительный кирпичик, которым прирастает сеть дата‑центра.
Внутри пода обычно от двух до восьми Spine1 (или S1, или просто спайн), которые формируют независимые плоскости (plane). Между слоями лиф и спайн — full‑mesh. Лифы друг с другом напрямую не соединяются, спайны — тоже.
Spine2 (или S2) — это дополнительный слой коммутации, который позволяет провязать друг с другом все поды.
Для подключения POD к S2 обычно используются длинные пролёты оптических трасс. Зачастую это дорогостоящая single‑mode оптика.
Топология Клоза хороша тем, что она позволяет построить масштабируемую сеть без переподписки на всех уровнях с высокой степенью отказоустойчивости. А также прекрасно работает весь классический стек протоколов и технологий.
Это реально вот настолько просто — не ставим дополнительный уровень спайнов (S2), соединяем спайны S1 разных групп прямыми линками — и вы красавчик.
Просто представьте, какая получается экономия — минус целая пачка железок S2, минус половина трансиверов — для соединения групп не нужно подниматься на S2 и делать оптико‑электрические преобразования — минус половина длинных линков (сингловых, то есть single‑mode, дорогих). Со всех сторон красота. И как только раньше не догадались?
И настроение как‑то само собой летит вверх.
Dragonfly+ или Megafly?
Это два термина, означающих одно и то же. Первый был введён группой авторов из Mellanox в 2017. Второй — Intel в 2018.
Поэтому исторически более справедливо называть такую топологию именно Dragonfly+, собственно так оно и пошло в народ, как когда‑то ксерокс и, простите, мультифора. Не далёк тот час, попомните мои слова, когда мы по‑русски будем писать «драгонфлайплас».
Далее в статье я буду использовать название Dragonfly, не уточняя, что это Dragonfly+. Но следует помнить, что классический Dragonfly — это директная топология, то есть такая, в которой нет отдельных коммутирующих элементов, в которые не подключаются хосты.
Но при пристальном взгляде всё становится не так уж радужно. Давайте вместе смотреть.
Максимальная ёмкость Dragonfly в плотной топологии — меньше, чем в сравнимом Клозе. Количество линков между группами тоже меньше, причём значительно.
Если же мы хотим увеличивать ёмкость, то жертвуем числом линков между группами, а следовательно полосой.
Блеск стрекозы
Давайте прям на примере — сравним сеть Клоза и Dragonfly.
Возьмём для этого какой‑то абстрактный идеализированный свитч с радиксом 8 портов. Всю сеть мы будем собирать из них — Leaf, Spine1, Spine2.
И Клоз и Dragonfly будут строиться из одинаковых кирпичиков Leaf‑Spine (для простоты под Клоза мы тоже будем называть группой).
Дополнительная терминология:
-
Leaf (лиф) — коммутатор для подключения конечных хостов.
-
Spine (Spine1, S1, спайн) — коммутатор для соединения Leaf друг с другом.
-
Spine2 (S2) — коммутатор для соединения между собой групп Leaf‑Spine1.
-
Radix (радикс) — общее количество портов коммутатора.
-
South Radix — количество портов коммутатора «вниз» (например, Leaf ➞ Host или Spine ➞ Leaf).
-
North Radix — количество портов коммутатора «вверх» (например, Leaf ➞ Spine или Spine1 ➞ Spine2).
Топология Клоза будет выглядеть так:
Формула ёмкости простая — Leaf South Radix * Spine1 South Radix * Spine2 Radix
. То есть в нашем случае 4 * 4 * 8 = 128
.
В этой сети у нас нет переподписки — всё, что приняли снизу, передали наверх.
Формула вычисления числа маршрутов между каждой парой групп получается такая: Leaf North Radix * Spine1 North Radix
. В нашем случае 4 * 4 = 16
.
Характеристики топологии Клоза (5 stage, radix 8)
Максимальное количество хостов — 128
Общее количество аплинков из группы — 16
Количество кратчайших маршрутов до любой другой группы — 16
Dragonfly в плотной топологии выглядит так и показывает такие характеристики.
Ёмкость равна Leaf South Radix * Spine South Radix * (Spine North Radix + 1)
. Получается 4 * 4 * 5 = 80
. Значительно меньше сети Клоза. А при увеличении радикса разница будет ещё больше.
Количество линков между группами — Leaf North Radix
— то есть всего лишь 4.
Характеристики топологии Dragonfly (5 stage, radix 8)
Максимальное количество хостов — 80
Общее количество аплинков из группы — 16
Количество линков в любую другую группу и кратчайших маршрутов до неё — 4
Линки и маршруты
Важно понимать, что в топологии Клоза нет, как таковых, линков между группами — есть аплинки в сторону более высокого слоя коммутации (S2). Все эти аплинки используются как равнозначные, и вся доступная через них полоса разделяется честно между трафиком во все существующие группы.
Поэтому в Клозе у нас 16 аплинков и 16 же маршрутов в каждую из групп.
В Dragonfly наружу доступны те же 16 аплинков в общей сложности, однако из‑за прямой связи между группами, количество линков между ними значительно меньше — в нашем примере 4 — через них же лежит и 4 кратчайших маршрута.
Это можно сравнить с буферами на сетевых коробках — Shared против Dedicated. Общий объём такой же, но в Shared этот объём разделяется между всеми портами коммутатора, а в Dedicated он нарезается на блоки одинакового размера и раздаётся каждому порту в отдельности. Так и тут — в сети Клоза все аплинки используются для доступа к любой группе, а в Dragonfly они нарезаны на отдельные пачки в отдельные группы.
Существенно экономя на линках,...
…мы существенно уменьшаем число линков.
Масштабирование Dragonfly
Итак, в сверхплотной топологии, собранной из коммутаторов с радиксом 8, мы можем собрать кластер из 5 групп по 16 хостов — 80. Сверхплотная означает, что у нас каждый спайн каждой группы имеет один линк в каждую другую группу.
Чтобы получить такую топологию, мы по одному линку от каждого спайна группы ведём в соответствующий спайн каждой другой группы. Поскольку при радиксе 8, на каждом спайне у нас 4 линка «наверх», мы можем соединить 5 групп.
Сверхплотный Dragonfly
5 групп
80 хостов максимум
4 линка между каждой парой групп
Если мы уменьшим плотность с 4 до 2 линков между каждой парой групп, а высвободившиеся линки используем под дополнительные группы, то число линков в уникальные группы увеличится с 4 до 8, а число групп, соответственно, до 9 — итого 16 * 9 = 144 хоста. То есть мы увеличили ёмкость почти вдвое. Magic?
Чтобы получить такую топологию, мы соединяем друг с другом не все спайны пары групп, а только часть. В примере на схеме — только два. То есть по одному линку от двух спайнов мы ведём в одну группу, а ещё от двух — в другую. После этого у нас получается не 4 пачки по 4 линка, а 8 по 2 — и, соответственно, мы можем соединить 9 групп.
Предположим, что каждый хост подключён на скорости 100G, тогда они могут внутри группы генерить 1,6 Тб/с, а полоса в каждую другую группу — 200 Гб/с.
Простоплотный Dragonfly
9 групп
144 хоста максимум
2 линка между каждой парой групп
А если мы оставим по одному линку в каждую группу, то число глобальных линков в уникальные группы увеличится в 4 раза — до 16. То есть 17 групп по 16 хостов — итого 272 хоста всего. Напомню, это на радиксе коммутаторов в 8 портов. Совсем неплохо!
Разреженный Dragonfly
17 групп
272 хоста максимум
1 линк между каждой парой групп
Но ооочень уж узкие линки между группами — в пределе, как мы видим, один! Один кратчайший в Dragonfly вместо 16 равнозначных в Клозе!
При скорости порта 100G всё так же 1,6 Тб/с могут нагенерить хосты одной группы, а в другую группу только 100 Гб/с!
Попробуйте прикинуть сами на радикс 16? И проверьте меня
В сверхплотной топологии:
-
16 групп в Клозе — 9 в Dragonfly
-
1024 хоста в Клозе — 576 в Dragonfly
-
64 маршрута в каждую группу в Клозе — 8 в Dragonfly
В простоплотной топологии:
-
16 групп в Клозе — 17 в Dragonfly
-
1024 хоста в Клозе — 1088 в Dragonfly
-
64 маршрута в каждую группу в Клозе — 4 в Dragonfly
В разреженной топологии:
-
16 групп в Клозе — 65 в Dragonfly
-
1024 хоста в Клозе — 4160 в Dragonfly
-
64 маршрута в каждую группу в Клозе — 1 в Dragonfly
И вот теперь с этим как‑то нужно жить дальше.
Резюме
-
Dragonfly — это топология, в которой отдельные хосты объединяются в группы, провязанные между собой каким‑то (произвольным) образом, а группы соединяются друг с другом напрямую без использования промежуточных коммутирующих устройств.
-
Dragonfly+ (или Megafly) — это Dragonfly, каждая группа которого представляет собой топологию Leaf‑Spine обычной двухуровневой (3-stage) сети Клоза.
-
Dragonfly выходит существенно дешевле Клоза, потому что мы убираем целую гору железок с уровня Spine2 (счёт идёт на десятки и даже сотни), в два раза сокращаем число оптических линков и трансиверов для соединения групп.
Дополнительно высвобождаем место, которое больше не нужно для Spine2, и электричество для них и для трансиверов (для справки: каждый 400G‑трансивер потребляет порядка 10 Вт). -
Плюс масштабируется Dragonfly заметно лучше Клоза.
-
И в дополнение — новые группы на новом оборудовании можно очень легко интегрировать в уже построенную сеть без необходимости менять S2 (ведь его нет совсем).
-
Однако платим мы за это в другом месте — снижением общей ёмкости сети и доступной полосой пропускания между группами.
Нищета стрекозы
В примере, разобранном выше, совокупно на весь кластер получается те же 4 * 4 * 100 Гб/с = 1,6 Тб/с
из группы наружу. То есть сколько трафика мы внутри группы максимально можем сгенерировать c 16 хостов, столько же полосы нам доступно наружу из группы — в таком грубом смысле переподписки нет.
Однако все эти линки, как уже отметили выше, распределены пачками в каждую конкретную группу — и число маршрутов в каждую другую группу ограничено.
И если трафик наружу будет распределён не равномерно между всеми хостами кластера, а в какие‑то из групп преобладать в данный момент времени, то он может переливаться через доступное число линков — получим дропы.
Обеспечить равномерность мы, скорее всего, не можем — во всяком случае в условиях обычных дата‑центров с разнообразными задачами — не HPC (High Performance Computing). Сделать больше физических линков — сложно.
MIN routing
Алгоритм маршрутизации по кратчайшим линкам по общепринятой терминологии в Dragonfly+ называется MIN.
В литерах Dragonfly такой маршрут называется LGL — Local ⬌ Global ⬌ Local
.
Соответственно, мы можем строить сколь угодно большую сеть, но с очень маленьким количеством кратчайших (MIN) путей.
Как будто бы пат?!
Маршрутизация в Dragonfly
Вот было бы здорово... если бы можно было бы использовать не только кратчайшие пути.
В сети Клоза всё просто — триллион равнозначных путей. Для этого подходит ровно любой протокол маршрутизации — с ECMP умеют работать все. Выбор основывается только на вопросах масштабируемости и скорости сходимости.
У гиперскейлеров тут, конечно, BGP на коне.
Но если посмотреть на Dragonfly, то хорошо видно, что из одной группы до любой другой можно добраться через третью.
Вот так — хоба!
И тогда, внезапно, число путей возрастает неимоверно. Было 4, а стало 16.
И если кратчайший путь мы назовём MIN, то вот такие пути будут MIN+1, потому что в путь добавляется дополнительный прыжок через спайн другой группы. В литерах Dragonfly это LGGL —Local ⬌ Global ⬌ Global ⬌ Local
.
Вы прямо сейчас, вероятно, захотите поспорить: «Но мы же так отъедаем полосу у другой группы?!». И будете правы. Вернёмся к этому попозже, обещаю!
Вот только для этого нужен протокол, который умеет использовать не кратчайшие пути. Опять без НО не обошлось.
Широкие возможности non-minimal маршрутизации
На самом деле все любопытные топологии требуют использования не кратчайших (non-minimal) путей.
И тут в лоб ни BGP, ни всякие ISIS не помогут.
Сюда хорошо ложится Source Routing, а в широком смысле даже Segment Routing — вот там хоть оборот вокруг Земли в чип прописывайте — всё сработает.
На самом деле даже просто как‑то добросить трафик до следующего хопа в случае MIN+1 было бы достаточно — там дальше уже как‑нибудь доберётся по обычному лучшему пути.
Но любому Source Routing нужен сразу же контроллер — и про это мы ещё поговорим.
Но можно как‑то без контроллера?
Можно!
2-VRF Non-minimal path
И опять все надежды на BGP. А именно на eBGP. Протокол на салфетке спасает мир уже многие десятилетия. Вот и тут, благодаря его гибкости, можно очень нежно управлять атрибутами маршрутов, влияющими на Best Path Selection.
Идея дальше с виду простая — все локальные линки мы помещаем в один VRF (назовём его LOCAL
), а глобальные — в другой (CORE
) — а между ними route leaking.
И чем нам это, собственно, поможет?
А вот смотрите — вот есть один маршрут, доступный через два разных пути (на самом деле, конечно, больше). У каждой группы свой номер AS, мы используем eBGP, а следовательно тот маршрут, что проходит транзитом через другую группу, имеет более длинный AS Path. Во всех иных отношениях маршруты равнозначны.
Поэтому, если при ликинге маршрутов мы добавим одну лишнюю AS‑ку в AS‑Path, то более длинный маршрут встанет в ECMP вместе с более коротким.
Применяя данный подход для всей сети, состоящей из пяти групп, мы вместо четырёх прямых маршрутов в ECMP получаем 16: 4 прямых MIN, с дополнительной AS и 12 MIN+1 через транзитные группы.
А это уже хорошо — мы существенно увеличили ёмкость между группами!
VAL routing
Такая маршрутизация называется алгоритмом Валианта (Valiant’s algorithm) (VAL) — мы распределяем трафик случайно-равномерно между MIN и MIN+1 маршрутами.
Forwarding
Внутри группы (то есть внутри VRF local
) трафик идёт кратчайшими маршрутами — если их несколько, соответственно, используется ECMP и балансировка. В случае Клоза внутри группы — это обычный Host ⬌ Leaf ⬌ Host
или Host ⬌ Leaf ⬌ Spine ⬌ Leaf ⬌ Host
.
Если трафик нужно передать за пределы группы, его нужно переложить из VRF local
в VRF core
. В нём он добирается или напрямую до группы назначения или через промежуточную группу. В группе назначения он снова попадает в VRF local
.
Рассмотрим ситуацию сверхплотного Dragonfly, состоящего из пяти групп. Посмотрим маршруты из нулевой группы G0
до сети 2001:db8:G1:7::/64
, размещённой в группе G1
за 7-м лифом. Здесь для удобства обозначения я в хекстетах IPv6 адреса проставляю номер группы — G1
— и спайна — S3
.
На лифе это выглядит как четыре равнозначных пути к четырём спайнам:
eucariot@group0-leaf5:~$ ip -6 route list match 2001:db8:G1:7::
2001:db8:G1::/64 dev vlan42 proto kernel metric 256 rt_offload pref medium
nexthop via fe80::G0:S0 dev swp49 weight 1 offload
nexthop via fe80::G0:S1 dev swp50 weight 1 offload
nexthop via fe80::G0:S2 dev swp51 weight 1 offload
nexthop via fe80::G0:S3 dev swp52 weight 1 offload
На Spine3
в группе g0
в VRF LOCAL
есть четыре равнозначных пути — MIN (через FE80::G1:S3
) и MIN+1 (три других):
<group0-spine3>dis ipv6 routing-table vpn-instance LOCAL 2001:db8:G1:7:: | i (NextHop :|Interface)
------------------------------------------------------------------------------
Routing Table : LOCAL
Summary Count : 4
NextHop : FE80::G1:S3
Interface : 100GE1/0/1
NextHop : FE80::G2:S3
Interface : 100GE1/0/2
NextHop : FE80::G3:S3
Interface : 100GE1/0/3
NextHop : FE80::G4:S3
Interface : 100GE1/0/4
При этом NextHop Interface находится в VRF CORE
, соответственно при передаче трафик перекладывается из VRF LOCAL
в VRF CORE
:
<group0-spine3>dis cur int 100GE1/0/1
interface 100GE1/0/1
description g1-spine3 100ge1/0/1
ip binding vpn-instance CORE
ipv6 enable
ipv6 address FE80::G0:S3 link-local
В VRF CORE
же уже всего один путь, потому что выбор между ECMP уже сделан на предыдущем шаге:
<group0-spine3>dis ipv6 routing-table vpn-instance CORE 2001:db8:G1:7:: | i (NextHop :|Interface)
------------------------------------------------------------------------------
Routing Table : CORE
Summary Count : 1
NextHop : FE80::G1:S3
Interface : 100GE1/0/1
Routing
-
Внутри группы используется любой обычный протокол маршрутизации и его результаты выбора лучшего пути.
-
При анонсировании маршрута по BGP за пределы группы используется Route Leaking из VRF
LOCAL
в VRFCORE
(и обратно).
Кроме того, к маршруту добавляется специальное community —C1
.
В соседние группы, доступные через прямые линки, такой маршрут импортируется сразу. -
При этом при переанонсировании чужого маршрута в другую группу дополнительно навешивается community
C2
. -
Когда группа получает маршрут с community
C2
, она его тоже импортирует. Но уже не будет никуда анонсировать — так достигается отсутствие петель маршрутизации.
Вот так будет выглядеть маршрутная информация BGP в VRF CORE
:
<group0-spine3>dis bgp vpnv6 vpn-instance CORE routing-table 2001:db8:G1:7:: | i (nexthop|AS-|Community)
BGP local router ID : 1.0.0.3
Local AS number : AS_G0_Spine
VPN-Instance CORE, Router ID 1.0.0.3:
Paths: 4 available, 1 best, 1 select, 0 best-external, 0 add-path
Original nexthop: FE80::G1:S3
Community: <C1>
AS-path AS_G1_Spine AS_G1_Leaf7, origin incomplete, localpref 100, pref-val 0, valid, external, best, select, pre 255
Original nexthop: FE80::G2:S3
Community: <C1>, <C2>
AS-path AS_G2_Spine AS_G1_Spine AS_G1_Leaf7, origin incomplete, localpref 100, pref-val 0, valid, external, pre 255, not preferred for AS-Path
Original nexthop: FE80::G3:S3
Community: <C1>, <C2>
AS-path AS_G3_Spine AS_G1_Spine AS_G1_Leaf7, origin incomplete, localpref 100, pref-val 0, valid, external, pre 255, not preferred for router ID
Original nexthop: FE80::G4:S3
Community: <C1>, <C2>
AS-path AS_G4_Spine AS_G1_Spine AS_G1_Leaf7, origin incomplete, localpref 100, pref-val 0, valid, external, pre 255, not preferred for router ID
-
AS_G1_Leaf7
— номер AS лифа номер 7 в группеG1
, за которым и находится сеть2001:db8:G1:7::
, и которую он анонсирует в мир. У всех лифов кластера разные номера AS -
AS_G1_Spine
— номер AS спайна в группеG1
. У всех спайнов группы один и тот же номер AS. -
AS_G[234]_Spine
— номера AS транзитных спайнов в MIN+1 путях. -
C1
— community, которым мы помечаем все дата-центровые анонсы. Оно висит на всех маршрутах. -
С2
— community, запрещающее спайнам переанонсировать маршрут в сторону других спайнов. Оно есть у всех, кроме самого первого маршрута — он получен напрямую из группыG1
, поэтому его спайн группыG0
переанонсирует в группыG2
,G3
,G4
, чтобы выступать транзитным в MIN+1 путях междуG2-G1
,G3-G1
иG4-G1
.
По AS-Path здесь, в VRF CORE
, выигрывает кратчайший маршрут, поскольку содержит в пути на одну автономную систему меньше — 1 select
и not preferred for AS-Path
. При этом все другие атрибуты одинаковые.
Соответственно, для того чтобы уравнять их, нам нужно при импорте в VRF LOCAL
сделать AS-Path prepend (номер AS AS_FOR_ECMP
). Здесь же описана конфигурация route-leaking между VRF.
ip vpn-instance CORE
ipv6-family
route-distinguisher 1.0.0.3:1
vpn-target RT1 export-extcommunity
vpn-target RT1 import-extcommunity
vpn-target RT2 import-extcommunity
ip vpn-instance LOCAL
ipv6-family
route-distinguisher 1.0.0.3:2
import route-policy VRF_LOCAL_IMPORT
vpn-target RT2 export-extcommunity
vpn-target RT1 import-extcommunity
vpn-target RT2 import-extcommunity
route-policy VRF_LOCAL_IMPORT permit node 10
apply as-path AS_FOR_ECMP additive
После этого маршруты встанут в ECMP в VRF LOCAL
:
<group0-spine3>dis bgp vpnv6 vpn-instance LOCAL routing-table 2001:db8:G1:7:: | i (nexthop|AS-|Community)
BGP local router ID : 1.0.0.3
Local AS number : AS_G0_Spine
VPN-Instance LOCAL, Router ID 1.0.0.3:
Paths: 4 available, 1 best, 4 select, 0 best-external, 0 add-path
Original nexthop: FE80::G1:S3
Community: <C1>
AS-path AS_FOR_ECMP AS_G1_Spine AS_G1_Leaf7, origin incomplete, localpref 100, pref-val 0, valid, external, best, select, pre 255
Original nexthop: FE80::G2:S3
Community: <C1>, <C2>
AS-path AS_G2_Spine AS_G1_Spine AS_G1_Leaf7, origin incomplete, localpref 100, pref-val 0, valid, external, select, pre 255, not preferred for router ID
Original nexthop: FE80::G3:S3
Community: <C1>, <C2>
AS-path AS_G3_Spine AS_G1_Spine AS_G1_Leaf7, origin incomplete, localpref 100, pref-val 0, valid, external, select, pre 255, not preferred for router ID
Original nexthop: FE80::G4:S3
Community: <C1>, <C2>
AS-path AS_G4_Spine AS_G1_Spine AS_G1_Leaf7, origin incomplete, localpref 100, pref-val 0, valid, external, select, pre 255, not preferred for router ID
4 select
говорит о том, что все четыре маршрута будут инсталлированы в чип.
И последнее, на что стоит взглянуть, это community, управляющее реанонсами и защищающее от петель маршрутизации.
bgp AS_G0_Spine
ipv6-family vpn-instance CORE
group S1 external
peer S1 route-policy S1_IMPORT_FROM_S1 import
peer S1 route-policy S1_EXPORT_TO_S1 export
route-policy S1_EXPORT_TO_S1 deny node 10
if-match community-filter C2
route-policy S1_EXPORT_TO_S1 permit node 20
apply community C1 additive
route-policy S1_IMPORT_FROM_S1 permit node 10
if-match community-filter C1
apply community C2 additive
То есть при экспорте маршрутов от спайнов к другим спайнам мы сначала проверяем, нет ли на нём community C2
(иначе запрещаем), и навешиваем community C1
. А при импорте маршрутов от других спайнов проверяем — если на них есть community C1
, то нужно добавить ещё C2
.
Интересный факт
Описанная выше схема была придумана несколько лет назад Дмитрием Афанасьевым (aka fl0w) и позднее реализована и протестирована совместно с Романом Глебовым в Яндексе.
eucariot [мск+4], [20 Nov 2024, 13:30:37]:
Слушай, а вот эта идея с 2vrf - твоя?
Dmitry Afanasiev, [20 Nov 2024, 13:32:56]:
хороший вопрос ) я ее придумал сам за пару месяцев до SIGCOMM, а потом гугль рассказал про свою конструкцию, и конечно же там тоже VRF:
"We eliminate loops by isolating the source and transit traffic into two virtual routing and forwarding (VRF) tables. Packets arriving on DCNI-facing ports but not destined for a local destination are annotated to the transit VRF. Here we match on the destination IP and forward the packet over the direct links to the destination block"
Так что внутри у них так было явно сильно раньше
Любознательный читатель уже томится вопросом: «Но мы же отъедаем полосу в других группах?!» Друг, ты снова совершенно прав. Несомненно.
Тут можно апеллировать к тому, что если у вас не HPC, то трафик распределяется неравномерно, и куда‑то идёт много, а где‑то линки пустуют. Это тоже правда. Но мы же не знаем, где именно пустуют?
Тут есть сразу несколько проблем:
-
Всё же лучше было бы использовать только кратчайшие пути, когда их достаточно. А неоптимальные подключать только в тот момент, когда кратчайшие перегружены. Всё же «Dragonfly — low latency topology» — не пустой звук, да и загружать без дела «чужие» линки — как‑то не по‑пацански, что ли.
-
Когда в ECMP у нас стоят неравнозначные маршруты, у них будет заметно разная задержка. То есть мы и так без дела растим её, просто сделав активными длинные пути, а тут ещё и делаем её существенно разной для двух потоков в одну и ту же сеть.
-
Без дополнительного контроля мы действительно легко перегружаем аплинки других групп.
В общем и целом, схема в лоб — заведомо не подходит для промышленной эксплуатации: мы создаём условия, в которых однозначно будут дропы — и сделать с этим нельзя совершенно ничего.
И что же тогда?
Adaptive routing
С MIN и VAL есть очевидная проблема — мы можем перелить линки, либо потому что их мало, либо потому что мы не учитываем (не можем) их загрузку.
Поэтому нужен хотя бы реактивный план Б — что делает сеть, когда плохое уже случилось или вот‑вот случится. А ещё лучше — проактивный план А, как до такого не довести.
UGAL
Такие механизмы называются UGAL — Universal Global Adaptive Routing.
UGAL-L
План Б — это когда мы работает с тем что есть — уже есть. Мы уже наблюдаем перегрузку или ситуацию близкую к ней — например, высокое заполнение буферов.
Здесь нам не нужен контроллер — для принятия решений мы оперируем только теми данными, что доступны локально на роутере, а значит в целом имеем дело с косвенными признаками перегрузок.
UGAL-L
UGAL-L — Universal Global Adaptive Routing — Local. Отправляющий роутер знает только о локальной утилизации очередей.
По сути в этом случае при выборе пути роутер опирается только на локальную загрузку очередей и, грубо, отправляет трафик в те пути, очередь в которые менее заполнена.
На первый взгляд — это слишком наивное решение, ведь на локальной стороне всё может быть хорошо, а в транзитной группе уже перегрузки.
Но на второй взгляд — при детальном рассмотрении — можно настроить PFC — Priority‑based Flow Control. Этот механизм позволяет сигнализировать перегрузку «назад» по пути (Backpressure). То есть, если на роутере начинает заполняться очередь, то он шлёт на своих соседей специальные сообщения «эй, притормози» — и те начинают подкапливать пакеты в своих буферах, чтобы избежать дропов дальше по пути.
Таким образом, после включения PFC у нас появляется дополнительный косвенный признак перегрузок на пути. Точнее признак тот же — утилизация очередей, но он более явно говорит о проблемах на всём пути, а не только о локальных.
И, видя низкую утилизацию очереди в направлении одного из путей, можно с некоторой немалой вероятностью предположить, что там всё хорошо — можно в него слать трафик.
И в целом UGAL‑L неплох, правда. Всем, кроме того, что обычное сетевое оборудование в массе своей не рассматривает при выборе пути такой фактор, как утилизация очереди — обычный Round Robin по 5-tuple.
Да и PFC, помимо того, что требует поддержки на железе и настройки на всём пути, имеет ещё и некоторые свои, скажем так, особенности в эксплуатации.
В итоге в обычных сетях передачи данных UGAL‑L не используется. Хотя в HPC (например, в кластерах InfiniBand) — вполне.
UGAL-G
План А предполагает, что сеть каким-то образом знает о состоянии линков и в какие из них сколько трафика отправлять. Мы заведомо знаем, как не допустить перегрузок.
UGAL‑G
UGAL‑G — Universal Global Adaptive Routing — Global. В этом случае отправляющий узел (или контроллер) знает об утилизации линков и/или очередей на роутерах в других группах.
То есть фактически существует некий центральный арбитр, программирующий пути и управляющий трафиком.
Этому арбитру кто‑то должен сообщать информацию о том, какой путь можно использовать, а какой нет. То есть система, грубо говоря, состоит из двух компонентов.
Коллектор статистики с сети. Самая понятная часть — скорее всего, вы и так уже собираете информацию в какую‑то систему типа заббикса и складываете в базу. Необходимый минимум тут — утилизация интерфейсов на сетевом оборудовании. Можно также снимать утилизацию очередей.
Контроллер, управляющий трафиком. Собственно, для того чтобы управлять путями трафика, нам нужна некая система, которая, с одной стороны, знает о фактическом состоянии сети — какие есть пути и насколько они сейчас загружены, а с другой — подключается к сетевым элементам и программирует их.
Опять же, довольно простая часть в этом случае находить MIN и MIN+1 линки — сплошная база графов и алгоритмов над ними. Наложить на обнаруженные пути утилизацию и отфильтровывать их по порогам — чуть ли не ещё проще.
А вот как «программировать сетевые элементы»?
Тут есть два варианта:
-
Очень сложный — Source/Segment Routing.
-
Просто сложный — динамическое управление политиками BGP.
Очень сложный вариант — очень сложный. Потому что нужно поддержать такой тип маршрутизации на всей сети — будь то MPLS SR или SRv6, или что‑то иное.
Сетевыми элементами, которые нужно программировать, могут выступать лифы или конечные хосты — так даже намного лучше. Оба варианта непросты в реализации.
В общем, нужно подходящее оборудование, нужна разработка, прототипирование, пилотирование, решить вопросы эксплуатации, отладки и эвакуации, когда всё перестало работать.
Это удел или крупных компаний, которые осилят разработку подобных контроллеров, или других крупных компаний, которые могут позволить себе сеть на InfiniBand. Поэтому особо останавливаться на этом варианте мы не будем.
Просто сложный вариант предполагает, что контроллер ходит на сетевое оборудование и динамически управляет маршрутами на нём через стандартный режим конфигурации.
Например:
-
По умолчанию работают только MIN‑пути, чем обеспечивается маленький диаметр и низкая задержка в нормальных условиях. MIN+1 вообще не принимаются из‑за настроек политик, например, помечены специальным запрещающим community.
-
По метрикам интерфейсов или очередей контроллер понимает, что MIN‑пути начинают испытывать перегрузки, и ищет MIN+1 с подходящей утилизацией.
-
Подключается к оборудованию через CLI/NETCONF/gNMI/и т. д., разрешает нужные MIN+1 маршруты (снимает запрещающие community) и делает, например, AS path prepend для MIN‑маршрутов, выравнивая с MIN+1. MIN+1 встают в ECMP — нагрузка размазывается.
-
Когда нагрузка возвращается в норму, тем же способом MIN+1 пути убираются.
-
А если используемые MIN+1 начинают перегружаться, то контроллер находит другие MIN+1 и снова играется политиками маршрутизации.
Этот вариант весьма приземлённый и вполне реализуем. Однако вам нужна зрелая система управления конфигурациями, и нельзя допускать конфигурационный дрейф на вашем дата‑центровом флоте.
ECN + Flow Label
Некое промежуточное положение между UGAL‑L и UGAL‑G занимает единственный механизм, к реализации которого можно приблизиться на существующем оборудовании, — это ECN (Explicit Congestion Notification). Точнее будет сказать, что это бедный родственник, пытающийся казаться состоятельным.
ECN — это поле, использование которого строго не регламентировано. Точнее, возможные значения ECN описаны, как на них реагирует хост‑получатель — тоже. Но что со всем этим делать хосту‑отправителю — решать нам самим: как мы настроим TCP‑стек, так и будет.
Более‑менее знакомая реакция на перегрузку в сети — будь то потеря пакета или флаг CWR (Congestion Window Reduced) в TCP — снизить скорость посылки данных отправителем, этакая добровольная жертва.
Это в целом поможет (скорее всего) — скорость снизится, и линки освободятся. Но это не то, чего мы желаем. Мы желаем, не снижая скорость, нагрузить другие линки, а не освободить эти.
Способа выбирать, в какой именно из ECMP‑путей отправить трафик, классические сети и оборудование не предоставляют.
Но нам трафик перебалансировать — уже было бы неплохо, авось разложится в линк посвободнее.
И вот тут кроется дьявол. Такой механизм есть. Но только в IPv6.
Flow Label. В IPv4 nexthop при ECMP определяется через некую функцию от 5-tuple (Src IP, Dst IP, Protocol, Src port, Dst port)
. Поскольку у одного потока 5-tuple и хеш‑функция, а следовательно и результат вычисления не меняются, то все пакеты с этим 5-tuple всегда ложатся в один путь. Это благо — так и было задумано, чтобы избежать переупорядочивания пакетов одного потока.
Но, если мы хотели бы управлять путями трафика, для нас это палка в колесе.
Ведь, чтобы поток лёг на другой путь, нужно, чтобы поменялось что‑то из (Src IP, Dst IP, Protocol, Src port, Dst port)
— а это будет уже совсем другая сессия.
А вот поле Flow Label в заголовке IPv6 как раз то, что нужно — с помощью него маркируются пакеты одного потока. Тогда для классификации потоков и дальнейшей балансировки используется 3-tuple — целиком из IP‑заголовка (Flow Label, Src IP, Dst IP)
. Предполагается, что у всех пакетов одного потока один и тот же Flow Label. Однако никто косо на вас не посмотрит, если у потока в ходе его жизни этот Flow Label всё же поменяется — и тогда тот же самый поток (та же самая TCP‑сессия) перейдёт на другой путь.
Это не выдумка, а уже эксплуатируемое решение.
То есть логика следующая:
-
Мы используем VAL — то есть балансировку по MIN и MIN+1 линкам.
-
В какой‑то момент промежуточный роутер замечает высокую утилизацию своего буфера — проставляет биты ECN в
11
— «Испытываем перегрузку». -
Пакет долетает до получателя, который понимает, что что‑то неладное происходит. Тогда он поднимает флаг CWR в TCP — Congestion Window Reduced. И отправляет ответный пакет изначальному отправителю.
-
Отправитель видит флаг CWR и меняет Flow Label — у этого потока (просто на случайный, чтобы хеш поменялся).
-
Промежуточные роутеры считают хеш‑функцию уже от нового 3-tuple и отправляют поток, вероятно, в новый путь. Один из всех MIN и MIN+1.
-
Мы надеемся, что новый путь не так загружен, как прежний, — и всё будет хорошо. Но, если вдруг это не так, кто‑то нам снова выставит ECN — и всё начнётся сначала, рано или поздно мы найдём для этого потока свободный путь.
Всё красиво, кроме трёх принципиальных вещей:
-
Нужен IPv6, а с этим у некоторых есть проблемки.
-
Это всё более‑менее работает с TCP. Есть вопросики к UDP (там нет механизма оповещения аналогичного CWR в TCP).
-
Нужна полноценная поддержка схемы на конечных хостах — никто в транзите не сможет Flow Label переписывать. А это доступно ещё меньшему количеству компаний. С другой стороны, если вы задумались о Dragonfly, то у вас точно всё хорошо с управлением вашим флотом хостов.
Эти вопросы действительно принципиальны — использование ECN бессмысленно без ответов на них. А без контроллера это единственный способ управления трафиком в Dragonfly.
А как у них?
Google Jupiter Network
У Google уже некоторое время как топология до смешения напоминающая Dragonfly+ в проде. Они рассказывали о своей сети Jupiter на SIGCOMM 2022:
В ней как раз используется глобальный адаптивный роутинг на базе ECN и Flow Label. А для более быстрой реакции ещё и включен PFC, позволяющий принимать локальные решения при перегрузках. При этом адаптивный роутинг использует уже имеющиеся сигналы congestion транспортных протоколов и взаимодействует с congestion control — там, где раньше можно было только притормозить, появляется выбор: притормозить или попробовать переложить трафик на другой путь.
На самом деле их решение очень любопытное — советую закопаться в него.
-
На малых масштабах времени (единицы RTT) работает PLB (Protective Load Balancing) — это как раз ECN+Flow Label. Это то, что позволяет очень быстро на удачу перекинуть поток на другой путь засчёт изменения заголовка IPv6.
-
На средних (ориентировочно от десятков секунд) — Traffic Engineering, например по описанной выше схеме с динамическими политиками или с SRv6.
-
На длинных (часы) — Topology Engineering — тут перестраиваются линки между группами. Для этого Google использует управляемые оптические кросс‑коннекты, позволяющие собирать практически произвольные топологии. Как минимум в Dragonfly есть возможность при изменении профиля нагрузки на сеть часть линков перекинуть из одного сегмента в другой.
InfiniBand
Ровно всё, что мы разбирали выше, и даже гораздо больше, реализовано в InfiniBand (IB).
Больша́я часть суперкомпьютеров из ТОП-500 построены на нём.
Там тебе и поддержка разных топологий, и использование не‑кратчайших путей через Virtual Lanes, и динамическая адаптивная маршрутизация. К тому же участие самой сети в вычислениях (SHARP от NVidia). В IB используется система токенов, выдающая разрешение на передачу данных, а также центральный контроллер (например, OpenSM), управляющий используемыми путями.
Вообще весь High Performance Computing — это удивительная Вселенная со своими законами, топологиями и протоколами — практически ничего общего с привычными нам Ethernet и TCP. И на Dragonfly (как и других топологиях) строится большое число суперкомпьютеров. Например, часть линеек Cray, которые используются в основе таких машин, как Cori и Piz Daint, построены на Dragonfly.
А, например, IBM Blue Gene работает на 164 000 процессорных ядрах в 40 стойках, соединённых через 3D torus.
Но это компании, весь бизнес которых сосредоточен на создании компактных высокопроизводительных «недорогих» суперкомпьютеров, и они продают решение под ключ.
Когда вы решаете более или менее узкую задачу: научные исследования с большим количеством вычислений, анализ больших данных, обучение нейросетей, какая‑то индустриальная или промышленная математика, — вот такой узкоспециализированный кластер, собранный под ключ по нераспространённым практикам, вполне подходящий вариант — сверхдорого, скорее всего, vendor‑lock, но сверхэффективно.
Подробнее про InfiniBand можно послушать в подкасте linkmeup telecom № 90. InfiniBand.
Все сигмы выбирают InfiniBand!
Необязательные дополнения
Арифметика Клоза
Ниже будут очень грубые расчёты.
Давайте посчитаем Клоз на 1000 вычислительных узлов
Предположим, что в серверный шкаф помещается 32 сервера — сами сервера мы не считаем — только сеть. Для размещения 1000 хостов нужно будет 1000 / 32 = 32 шкафа
.
В каждом из хостов — по одной сетевой карточке. Предполагаем подключение сервера только в один свитч, то есть single‑homed network. Пусть скорость подключения будет 25 Гб/с.
Стоимость карточки 25G с медным интерфейсом сегодня примерно 200 $. Итого сетевых карт в каждой стойке — на 32 шт * 200$ = 6400 $
.
Каждый сервер включается в Leaf‑коммутатор медным DAC‑кабелем со средней стоимостью допустим 20 $. Итого кабелей Host‑Leaf в каждой стойке — 32 шт * 20$ = 640 $
.
Возьмём всё ещё распространённый вариант Leaf‑коммутатора — 48×25G + 8×100G — примерной стоимостью 5000 $.
Итого: 6400 (NIC) + 640 (DAC) + 5000 (Leaf) = 12 040 $
Стоимость сети для коммутации в пределах одного шкафа
NIC + DAC + Leaf: 12 040 $
Вот это неизменные расходы, которые будут примерно одинаковы для любых топологий и расти будут линейно с ростом количества серверов. Тут есть место для различных оптимизаций, таких как один Leaf на две стойки, или большой‑большой Leaf с тыщей портов на весь ряд стоек. Но они принципиально не влияют на арифметику.
Далее. 32 серверных шкафа мы легко можем подключить в Spine‑коммутаторы с радиксом 64×100G — и ещё половина портов останутся свободными.
Положим, что нам нужно 8 плоскостей, то есть 8 штук Spine‑ов. Каждый из них стоит порядка 10 000 $ — итого 8 шт * 10 000 $ = 80 000 $
.
На каждом из 32-х лифов нам нужно организовать 8 аплинков в Spine. Обычно они состоят из следующих сегментов:трансивер ⬌ патч-корд ⬌ патч-панель ⬌ оптическая трасса ⬌ патч-панель ⬌ патч-корд ⬌ трансивер
Трансивер 100 Гб/с: 100 $.
Патч‑панелью давайте просто пренебрежём для упрощения счёта.
Оптические трассы — нам нужно по 8 на каждый серверный шкаф (то есть пару Leaf ⬌ Spine). Не будем усложнять длинами, синглой против мультика — просто возьмём условную цену всего оптического тракта в 50 $.
Стоимость коммутаций Leaf ⬌ Spine тогда будет 32 (Leaf) * 8 (Spine) * (2 * 100 (Transceiver) + 50 (Link)) = 64 000 $
.
Итого, грубый CAPEX для сети на 1000 машин (вмещающей на самом деле порядка 2000 машин в пределе) без переподписки: 32 (Racks) * 12 040 $ + 80 000 $ (Spines) + 64 000 $ (Fabric Links) = 529 280 $
Визуализация Клоза и его арифметика
Посоветую вот этот простой, но изящный инструмент, который рассчитает количество и возможных хостов, и необходимых свитчей, и кабелей.
Хотя есть и проблемка — все свитчи он считает с одинаковым радиксом.Я склонировал репу себе, и вы можете поиграться прямо сейчас.
А ещё детальные вычисления для сети Клоза даны тут.
Стоимость сети Клоза для коммутации 1000 серверов
Rack + Spine + Fabric links: 529 280 $
Для начала зафиксируем — это приличная сумма. Для грубой оценки: если каждый сервер стоит по 10 000 $, то бюджет на них составит 1000 * 10 000 = 10 000 000 $
. А общая стоимость такого кластера 10 529 280 $. В данном случае цена сети составляет 5% от общей.
А теперь давайте посчитаем Клоз на 10 000 хостов
Часть до спайнов остаётся такой же — этот строительный блок, как мы уже выше определяли, называется подом — 32 серверных шкафа по 32 сервера, связанных друг с другом через Leaf‑Spine. Стоимость сети такого пода мы уже вычислили — 529 280 $
А вот дальше нам нужно кое‑что принципиально изменить — вместить 10 000 серверов можно только в 5-stage Clos, то есть нам надо надстроить ещё один уровень коммутации, используя Spine2 для соединения подов.
Для 10к хостов нам нужно будет 10 подов.
Возьмём самый каноническую топологию Клоза, где второй уровень спайнов собирается из такого же точно железа и для обеспечения отсутствия переподписки число портов от Spine1 к Spine2 должно быть равно числу портов от Spine1 к Leaf.
Тогда для каждого из 8 плейнов нужно будет по 32 S2, то есть 256 таких же коммутаторов по 64×100 Гб/с — или 256 * 10 000 $ = 2 560 000 $
.
От каждого из 8 Spine-1 на уровень Spine-2 нужно будет по 32 линка, которые тоже составные:
Трансивер ⬌ патч-корд ⬌ патч-панель ⬌ оптическая трасса ⬌ патч-панель ⬌ патч-корд ⬌ трансивер
Эту цену мы уже знаем для сети из предыдущего примера — 2 * 100 + 50 = 250 $
. Мы всё ещё грубо считаем все оптические пролёты по одинаковой стоимости.
И давайте прикинем цифру:
10 (PODs) * 529 280 $ + 2 560 000 $ (S2) + 10 (PODs) * 8 (S1) * 32 (S1-S2 Links) * 250 $ = 8 492 800 $
.
Стоимость сети Клоза для коммутации 10 000 серверов
POD + S2 + Fabric Links: 8 492 800 $
Стоимость кластера — 10 000 шт * 10 000 $ + 8 492 800 $ = 108 492 800 $
. Доля сети в этом случае — 7,8%.
5-stage Clos в такой конфигурации вместит на самом деле 64 000 серверов в пределе.
Тогда получится так:
64 (PODs) * 529 280 $ + 2 560 000 $ + 64 (PODs) * 8 (S1) * 32 (S1-S2 Links) * 250 $ = 40 529 920 $
или 6% от цены кластера.
А если предположить, что мы хотим надстроить ещё один уровень спайнов, то забивать надо только половину портов на S2 — это 32 пода — 32 (PODs) * 529 280 $ + 2 560 000 $ + 32 (PODs) * 8 (S1) * 32 (S1-S2 Links) * 250 $ = 21 544 960 $
21 544 960 $ — Стоимость сети одного пода второго уровня — понадобится дальше. В каждом таком поде по 32 768 хостов
Ну и давайте уже посчитаем сеть Клоза для 100 000 серверов
Как вы уже заметили выше, в 5-stage Clos они не поместятся (там можно максимум 64к хостов).
Поэтому нужен 7-stage с добавлением Spine3. Логика подключения Spine2-Spine3 такая же, как в Spine1-Spine2 с поправкой на число и радикс — 256 (S2) * 32 (North Radix) = 8192
. 8192 штуки S3 понадобится в правильном полноценном 7-stage Clos, построенном на Spine‑коммутаторах 64×100G.
И нам нужно будет 4 пода второго уровня, которые мы получили на прошлом шаге — 131 072 хостов.
От каждого Spine2 к Spine3 будет нужно по 32 линка и получаем такую арифметику:
4 (POD второго уровня) * 21 544 960 $ + 8 192 (S3) * 10 000 $ + 4 (POD второго уровня) * 256 (S2) * 32 (S2 North Radix) * 250 $ = 176 291 840 $
.
Стоимость сети Клоза для коммутации 100 000 серверов
POD второго уровня + S3 + Fabric Links: 176 291 840 $
Доля сети — 14,9%.
В пределе в такую фабрику можно будет включить уже 64 пода второго уровня по 32 000 серверов — 2 048 000. Итого — 7,2%.
Вот такие цифры. И это мы считаем только капитальные затраты, а сколько ещё мы будем тратить на всё это царство электричества и человеческих ресурсов!
Заметно, что стоимость сети растёт нелинейно с ростом кластера. И пусть даже 100 000 хостов — это умопостроение, если вы не Гугл, но и в кластерах с топологией Клоза поменьше цена сети доходит до 8–10% от стоимости всего кластера и занимает одну из верхних строчек в бюджете. И речь о миллионах долларов. Что весьма ощутимо, чтобы попытаться тут сэкономить.
Давайте теперь подсчитаем аналогичные цифры для Dragonfly.
Арифметика Dragonfly
Берём топологию Dragonfly+, где каждая группа — это Leaf‑Spine топология. Собираем группы по 32 шкафа и получаем стандартный под сети Клоза. Его цена нам уже известна — 529 280 $.
Если мы берём сверхплотный Dragonfly, в котором каждый плейн каждой группы имеет линк в такой же плейн каждой другой группы, то мы можем собрать кластер на 33 группы, то есть на 33 792 серверов.
На 10 000 серверов нам достаточно 10 групп.
Количество линков в таком случае будет 10 * (10-1) / 2 * 8 = 360
(full‑mesh десяти групп по восьми плейнам). Для сравнения в Клозе линков было 2560 (10 * 8 * 32).
Общая стоимость сети составит — 10 (Groups) * 529 280 $ + 360 (Links) * 250 $ = 5 382 800 $
. В Клозе было 8 492 800 $. Пыщ‑пыщ, и мы сэкономили больше 3 млн долларов!
Стоимость сети Dragonfly для коммутации 10 000 серверов
Groups + Fabric Links: 5 382 800 $
В Клозе было 8 492 800 $
Что же для 100 000 хостов? Сверхплотный Dragonfly тут уже не подходит, как мы увидели выше.
Нам нужно 100 групп, то есть нужно проредить топологию в 3 раза. 8 плейнов в 3 раза прореживать неудобно, поэтому давайте в 4. То есть было по 8 линков между любой парой групп, а теперь — 2.
Это позволит собрать кластер из 32 * 4 групп или 131 072 серверов.
Для единообразия с Клозом посчитаем сеть на 100 000 серверов. Это будет стоить нам:
100 (Groups) * 529 280 $ + 100 (Groups) * (100 - 1) / 2 * 2 * 250 $ = 55 403 000 $
. В Клозе было 184 483 840 $. Сэкономили больше чем в три раза! Я даже несколько раз перепроверил расчёты — настолько они впечатляют. Причём основную стоимость тут составляет сеть группы, которая одинакова для Клоза и Dragonfly. А количество глобальных линков в Dragonfly при этом практически не меняется, потому что радикс спайнов тот же самый, а никаких слоёв коммутации мы не добавляем — просто прореживаем плотность глобальных линков между группами.
Стоимость сети Dragonfly для коммутации 100 000 серверов
Groups + Fabric Links: 55 403 000 $
В Клозе было 184 483 840 $
Но помним, что это всё возможно только когда мы делаем инжиниринг трафика между MIN и MIN+1 линками, избегая перегрузок.
MIN+3
Считая арифметику Dragonfly на 100к хостов, мы собрали довольно разреженную топологию — между каждой парой групп только по 2 линка — это действительно мало. С MIN+1 линков больше.
С MIN+1 линков больше, но не сказать, что прям значительно, как видно из схемы. Мы прыгаем через транзитные группы, оставаясь в рамках тех же плейнов, с которых начали.
В случае 100 групп у нас получается 2 MIN линка и (100 — 2) * 2 = 196 линков MIN+1. А что, если они все уже работают на пределе, и ещё в них ничего пихать не стоит? При этом есть простаивающие линки.
На этот случай есть техническая возможность с наиболее низким приоритетом использовать ещё более длинные линки — MIN+3.
Это довольно экзотический сценарий, но выглядит он примерно так:
То есть мы оказываемся в транзитной группе на Spine‑коммутаторе, не имеющем связи с группой назначения, либо все MIN и MIN+1 пути уже заполнены. В этом случае трафик может спуститься до уровня Leaf‑коммутатора и подняться на тот Spine, что имеет свободный линк в нужную группу. Получается такая последовательность:
Host ⬌ Local Leaf ⬌ Local Spine ⬌ Transit Spine‑A ⬌ Transit Leaf ⬌ Transit Spine‑B ⬌ Destination Spine ⬌ Destination Leaf ⬌ Destination Host
Или в литерах Dragonfly — LGLLGL.
То есть
MIN — это LGL (Local ⬌ Global ⬌ Local
)
MIN+1 — LGGL (Local ⬌ Global ⬌ Global ⬌ Local
)
MIN+3 — LGLLGL (Local ⬌ Global ⬌ Local ⬌ Local ⬌ Global ⬌ Local
).
При наличии контроллера настройка и эксплуатация такой маршрутизации в целом ещё сравнительно не сложна. Однако, если собирать это на классическом оборудовании и стеке с использованием VRF (что тоже возможно), это превращается в преддверие ада. А отладка в любом из случаев приключение на 20 минут.
Разбираться мы с этим, конечно, не будем. Просто будьте в курсе — и не так ещё вывернешься, когда сэкономить хочешь, так можно.
Подводя печальный итог всей этой истории
Dragonfly — это хорошо масштабируемая топология, эффективная с точки зрения стоимости и обладающая маленьким диаметром.
Кластер разбивается на группы стандартного размера и дизайна.
Топология внутри каждой группы произвольна. Это может быть Клоз, тогда топология будет называть Drgaonfly+ или Megafly. Может быть 3-tier. Или даже директная топология, где нет выделенных коммутирующих узлов, а серверы связаны напрямую — но в этом случае есть серьёзное ограничение по радиксу групп из‑за небольшого количества портов на хосте, а это в свою очередь накладывает ограничения на размер кластера.
Группы между собой соединяются в full‑mesh прямыми линками без использования дополнительного слоя коммутации, в отличие от многоуровневой сети Клоза.
В сверхплотном Dragonfly каждый роутер в группе соединяется с минимум одним роутером в каждой другой группе.
В плотном Dragonfly каждая группа имеет по несколько линков в каждую другую группу. Но не обязательно каждый роутер имеет линк в каждую группу.
В разреженном Dragonfly между каждой парой групп есть минимум один линк.
Классический Dragonfly, вероятно, хорошо применим для приложений с равномерным распределением трафика между всеми хостами кластера (HPC, анализ данных, обучение, инференс).
Чем более разрежена топология, тем у́же каналы между группами и больше вероятность того, что их будет недостаточно. Поэтому применяется маршрутизация не только через кратчайшие пути (MIN), но и через неоптимальные — MIN+1.
Бóльшая часть полосы в Dragonfly доступна не через кратчайшие пути.
Для такой маршрутизации нужны специальные протоколы, умеющие использовать не только кратчайшие пути.
Альтернативный вариант — используя eBGP, VRF и политики маршрутизации, выравнивать MIN и MIN+1 маршруты и устанавливать их в ECMP. Однако этот вариант плох тем, что не учитывает загрузку линков в сети. Но если научиться заранее замечать перегрузки и сигнализировать об этом хостам или сетевым устройствам, заставляя их выбирать новые пути, такой вариант обретает практический смысл.
Так специальный контроллер, знающий всё о текущем состоянии сети, может, просто настраивая политики BGP, управлять активными маршрутами (через CLI/NETCONF/gNMI).
А самым многообещающим выглядит Segment Routing (особенно SRv6) совместно с контроллером — он позволяет реализовать сколь угодно гибкую маршрутизацию и взвешенную балансировку, причём прямо с хоста. Но этот вариант требует серьёзной разработки и нетривиален в эксплуатации и отладке.
Ну когда уже я смогу использовать такой классный Dragonfly?
Хочется ещё раз привлечь к этому внимание — преимущества топологии Dragonfly доступны в том и только в том случае, когда вы умеете маршрутизировать по не‑кратчайшим путям с учётом загрузки линков и очередей на сети.
На классическом сетевом оборудовании и сетях IP/Ethernet есть только три трудных способа сделать это:
-
IPv6 ECN + Flow Label. Если у вас IPv4, MPLS, если вы не можете управлять сетевым стеком и приложениями на хостах — вам этот способ не подходит.
-
Source Routing с центральным контроллером, управляющим сетью. Если у вас нет команды разработки и если вы не можете управлять сетевым стеком и приложениями на хостах — вам этот способ тоже не подходит.
-
Динамическое управление маршрутизацией на Leaf и Spine за счёт политик BGP и community.
Без решения одной из этих трёх задач использовать топологию Dragonfly нельзя!
А что в Яндексе?
Эксперименты с новой топологией в Яндексе начались ещё пару лет назад. Небольшой сегмент сети во Владимире был переведён на Dragonfly+ для проверки решения в бою. Без контроллера гибко управлять трафиком мы бы не могли. Но в случае проблем этот сегмент всегда можно было отключить, и трафик ходил бы только через классический клозовский сегмент.
Время показало, что решение по маршрутизации рабочее. И если мы научимся динамически перераспределять трафик между MIN и MIN+1, то можно внедрять это в прод широко.
Прямо сейчас мы разрабатываем контроллер под эти задач — по той схеме, что была выше в статье — контроль утилизации и динамическое управление BGP‑политиками на спайнах.
В Yandex Cloud мы в данный момент прототипируем Dragonfly+ в лаборатории. Серьёзных причин переходить на него, учитывая наши масштабы, у нас нет. Более того, топология, хорошо подходящая для HPC‑кластеров и нейронок, вполне возможно, совсем неприменима для профиля трафика в публичном облаке. Это предмет наших дальнейших исследований.
Полезные ссылки
-
Доклад Романа Глебова на предстоящем Nexthop 2024: IP‑роутинг в сетях дата‑центров, построенных в топологии Dragonfly
-
Статья на linkmeup: Как построить Гугл. Или сети современных дата‑центров
-
Арифметика Клоза на Packetpushers: Demystifying DCN Topologies: Clos/Fat Trees
-
Знаковая статья Cray, Google, Stanford: Technology‑Driven, Highly‑Scalable Dragonfly Topology
-
Доклад Дмитрия Афанасьева, Романа Глебова и Джефа Танцуры на IETF 117: Routing in Dragonfly Topologies
-
Рассказ про внутреннее устройство дата‑центровых сетей Google (вот где экзаскейл): Jupiter evolving: transforming google's datacenter network via optical circuit switches and software‑defined networking
-
Использование ECN и Flow Label для управления трафиком: PLB: congestion signals are simple and effective for network load balancing
-
Сети для обучения Искусственного Интеллекта за 18 минут: RDMA over Ethernet for Distributed AI Training at Meta Scale (SIGCOMM'24, Paper 246)
-
Диссертация со сверхподробным разбором маршрутизации UGAL: LOAD‑BALANCED ROUTING IN INTERCONNECTION NETWORKS
-
Про Dragonfly+ и другие топологии: Super‑Connecting the Supercomputers — Innovations Through Network Topologies
-
Слайдики про Flattened Butterfly, но есть любопытное и про радиксы, и про latency: Flattened Butterfly: A Cost‑Efficient Topology for High‑Radix Networks
-
Про пропускные полосы в разных топологиях: A Throughput‑Centric View of the Performance of Datacenter Topologies
-
Доклад про использование IPv6 Flow Label на NextHop 2020: Сеть, которая лечит себя сама: магия Flow Label и детектив вокруг ядра Linux
-
Подкасты linkmeup:
-
Визуализация топологий fat‑tree/clos: ftree‑vis
Спасибы
-
Дмитрию Афанасьеву и Роману Глебову за разработку схемы маршрутизации в топологии Dragonfly в классических сетях TCP/IP с использованием BGP. Дмитрию безусловная благодарность за вычитывание и важные дополнения про продакшн из мира бигтехов
-
Павлу Остапенко за технический взгляд со стороны и придирчивое вчитывание во все детали.
-
Николаю Кованёву за молчаливое одобрение и проверку арифметики Dragonfly+
-
Алисе Бережной за восхитительные иллюстрации.
Ну и теперь, когда вы прочитали статью (или даже пробежали её по длинной стороне), ещё раз приглашаю приходить с вопросами на Nexthop➞2024.
Автор: eucariot