Об Anycast

2020-06-13

Как сделать так, чтобы ваш сервис был всегда доступен? Дублировать, запускать несколько экземпляров. Собственно, та самая балансировка нагрузки. Когда за одним балансировщиком стоит несколько серверов, и запросы распределяются между ними. Но сам балансировщик становится узким местом.

Как «продублировать» сервис «глобально»? Если наши пользователи сидят в разных уголках земного шара, и мы хотим, чтобы им всем было быстро и хорошо. Как работают CDN? Ладно, до CDN я ещё не замахнулся.

Один из простейших способов: несколько IP адресов. Пусть пользователи ходят на app.example.com. Но на самом деле app.example.com — это аж три сервера с адресами 1.2.3.4, 5.6.7.8 и 9.0.1.2. С точки зрения DNS у одного домена вполне может быть больше одной A записи. Но, на какой сервер пойдёт пользователь, определяется в данном случае совершенно случайно.

А как работает гугловый DNS 8.8.8.8? Или CloudFlareовый 1.1.1.1? Наверняка тут замешан BGP Anycast.

BGP — Border Gateway Protocol. Это высшие секретные знания сисадминов. Это протокол глобальной маршрутизации. Это то, на чём держится весь Интернет.

Anycast — это когда за одним IP адресом скрывается несколько разных серверов. Но, в отличие от Multicast или Broadcast, пакет, направленный на этот IP адрес, дойдёт не до всех серверов, а до одного. Желательно, чтобы это был ближайший к отправителю пакета сервер.

Если за адресом 8.8.8.8 скрывается множество серверов, то на наши DNS запросы туда будет отвечать некий ближайший к нам сервер. Можете проверить трассу, до 8.8.8.8 из Омска не дальше, чем до Москвы. Собственно, это и есть anycast.

Anycast можно сделать с помощью BGP.

BGP строит маршруты не между IP сетями, а между автономными системами, Autonomous System, AS. У каждой автономной системы есть зарегистрированный номер. Сведения о владельце AS можно получить через WHOIS: whois AS20473.

А вот уже с автономными системами связаны сети. Одна или больше. Для IPv4 в BGP анонсируются сети с маской /24 или больше.

Автономная система — это какой-то набор сетей, подконтрольных какому-то одному лицу, чаще всего юридическому лицу. Эти сети где-то расположены в Интернете. И где-то граничат с другими сетями, другими автономными системами. Часто и не с одной.

Вот тут, на границе между автономными системами, и начинает работать BGP. Пограничные маршрутизаторы двух соседствующих автономных систем настраиваются таким образом, чтобы обмениваться маршрутной информацией друг с другом.

Пара маршрутизаторов настраивается на явное взаимодействие друг с другом. Они знают IP адреса друг друга. У них есть общий секрет, чтобы авторизовывать сообщения друг друга.

Каждый маршрутизатор сообщает соседу (буквально, neighbour) номер своей AS, а также IP сети в своей AS. Это называется анонсом. Также маршрутизатор получает другие анонсы, от соседей. Раз он получил анонсы, значит есть связь в теми автономными системами, что видны в этом анонсе. Поэтому маршрутизатор берёт номера AS из анонса, добавляет в начало номер своей AS, что означает что из своей AS есть пути до полученных в анонсе AS, и пересылает модифицированный анонс своим соседям.

анонсы

Если маршрутизаторы не фильтруют анонсы, рано или поздно у каждого из них накопится полная информация о том, из каких AS можно добраться до каких AS через какие промежуточные AS. Ну и какие сети присутствуют в каждой AS. Таких BGP маршрутов между автономными системами в сегодняшнем Интернете получается порядка 400-500 тысяч. Вроде даже не сильно много.

Но большинство маршрутизаторов фильтруют анонсы. Их, как правило, не интересуют сети на другой стороне земного шара. Поэтому обычно маршрутизатор оперирует меньшим числом маршрутов.

Из BGP маршрутов формируются уже обычные записи в таблице маршрутизации IP. С точки зрения BGP вполне может существовать более одного маршрута отсюда до конкретной IP сети. В путях между автономными системами вполне могут быть разветвления и слияния, и даже циклы. Маршрутизатор, как правило, выбирает наиболее короткий (по числу промежуточных AS) путь, а также руководствуется другими критериями. Это в основном настройки локального маршрутизатора, его предпочтения о том, в какую соседнюю AS предпочтительнее засылать трафик. В итоге в таблицу маршрутизации попадает один маршрут.

Вот, вкратце, весь BGP. Как тут сделать anycast?

Во-первых, нужна сеть публичных адресов. Для IPv4 размером не менее /24. Не спрашивайте меня, где её взять, тем более, что IPv4 адреса вроде уже закончились. Наш заказчик где-то раздобыл. Похоже, мелкие провайдеры ещё распродают остатки.

Во-вторых, нужно зарегистрировать автономную систему, получить номер для AS. Тут технических проблем быть не должно, номера AS вроде заканчиваться не собираются, там нынче 32-битное число для номера используется. Просто бюрократическая процедура.

В-третьих, вам нужен хостинг, который умеет в BGP. Vultr, например, умеет. Digital Ocean, по-видимому, нет. AWS Direct Connect, вроде, умеет BGP, но не умеет публичные анонсы в Интернеты. То есть в AWS можно использовать BGP для организации маршрутов между датацентрами, но нельзя использовать тот самый глобальный BGP в Интернетах. Ищите поддержку BGP session (это как раз когда два пограничных маршрутизатора договариваются о взаимовыгодном обмене маршрутами) и анонсирования публичных AS (автономные системы тоже могут быть приватными, как и IP адреса).

Сосредоточимся на инструкции от Vultr.

Сначала нам предлагают заполнить форму, которая включает поддержку BGP. Там нужно указать уже известные нам: нашу сеть и номер нашей AS, придумать пароль для авторизации с соседним маршрутизатором. А ещё нужно приложить загадочный документ под названием LOA.

LOA — это Letter of Authorization, или Letter of Agency. Занятная бюрократическая формальность. Настоящее письмо с подписью, в виде PDF, примерно такого содержания. Письмо, подписанное владельцем IP сети и автономной системы, удостоверяет, что, в данном случае, Vultr, имеет право анонсировать эти сеть и номер автономной системы в интернеты. Vultr будет показывать эту бумагу всяким регуляторам, если появится вопрос, что за хрень он тут анонсирует. Авторизация на бумаге.

На хосты, которым нужен anycast, нужно установить демона, который будет делать BGP. Vultr рекомендует BIRD — Bird Internet routing daemon. Рекурсивный акроним, ага. Также можно использовать когда-то более популярный Quagga. Если интересно, Квагга — это разновидность зебры.

Vultr говорит, что нашим BGP соседом будет AS64515 по адресу 169.254.169.254. На самом деле это приватная AS. А этот IP адрес — это local-link адрес, который работает только между интерфейсами в одной сети. Выходит, Vultr нас в настоящий Интернет и прямой контакт с BGP не пускает. Ну и ладно, не очень-то и хотелось сломать глобальную маршрутизацию.

Наша задача: анонсировать нашу сеть. Вот она, здесь, за этим нашим хостом. Поэтому export all;. При этом все чужие анонсы нам по-барабану. Поэтому import none;.

Там в инструкции нарисовано, что, мол, после запуска BIRD будет отфильтровано 581674 входящих маршрутов. На самом деле, если в конфигурации BGP в Vultr сказать, что нас чужие маршруты не интересуют, то он ничего присылать и не будет.

Самое главное на этом этапе получить состояние BGP сессии Established. Это значит, что с соседним маршрутизатором мы снюхались, договорились и сессия установлена.

# birdc show proto vultr
BIRD 1.4.5 ready.
name     proto    table    state  since       info
vultr    BGP      master   up     2020-05-21  Established

Мы явно анонсируем нашу сеть:

protocol static
{
    route  198.51.100.0/24 via 203.0.113.123;
}

При этом мы говорим странную вещь. Мол, наша сеть 198.51.100.0/24, доступна через IP адрес нашего же хоста 203.0.113.123. Типа этот хост с BIRD — это маршрутизатор, а anycast сеть где-то за ним. Но на самом деле этот наш хост — не маршрутизатор. Он сам входит в anycast сеть.

Это можно исправить. Нужно поднять на хосте интерфейс с IP адресом внутри anycast сети. Vultr предлагает использовать интерфейс типа dummy. Есть такой в Linux. Этому интерфейсу не назначаются никакие маршруты, всем будет рулить BIRD.

Автоматическое создание такого интерфейса при запуске системы в Debian можно описать так:

auto anycast1
iface anycast1 inet manual
    pre-up /sbin/ip link add anycast1 type dummy
    pre-up /sbin/ip link set anycast1 up
    up /sbin/ip addr add dev anycast1 198.51.100.1/32
    post-down /sbin/ip link set anycast1 down
    post-down /sbin/ip link delete anycast1

Адрес у интерфейса уже в сети /32, то есть сети на один адрес.

А BIRD у нас будет анонсировать такие адреса у всех anycast* интерфейсов:

protocol direct
{
    interface "anycast*";
    import all;
}

Наш BIRD в результате анонсирует и нашу anycast сеть размером /24, и индивидуальный адрес этого хоста в этой сети — сеть размером /32.

# birdc show route
BIRD 1.4.5 ready.
198.51.100.1/32     dev anycast1 [direct1 2020-05-21] * (240)
198.51.100.0/24     via 203.0.113.123 on eth0 [static1 2020-05-21] * (200)

Вроде как из сети на 256 адресов мы используем только один. Но ничего не мешает нам на соседнем хосте тоже поднять BIRD и анонсировать другой адрес в anycast сети. /32 маршруты, конечно, не «настоящие», Vultr не будет их пересылать в интернеты. Будет анонсироваться только сеть /24. С точки зрения интернетов вся сеть /24 будет где-то там, за Vultr. А Vultr уже разрулит, на какой конкретно хост засылать пакеты. Потому что сеть /32 меньше по размеру и маршрут туда приоритетнее. Но это уже маршрут внутри Vultr.

И где тут Anycast? А просто эту процедуру установки и настройки BIRD нужно провести в разных датацентрах. И назначить хостам один и тот же IP адрес. BGP анонсы в интернеты пойдут тоже из разных датацентров. И до нашей сети станет известно несколько маршрутов. И уже другие маршрутизаторы в Интернет будут выбирать ближайший маршрут из нескольких.

Однако нужно, чтобы одни и те же IP адреса был подняты во всех датацентрах, которые анонсировали нашу anycast сеть. BGP маршрутизирует только сети, на 256 адресов в данном случае. И уж если пакет забрёл в этот датацентр, ему бы найти и конкретный адрес.

Кстати, у самого Vultr лишь одна публичная автономная система AS20473. И она «размазана» по всем его датацентрам. То есть автономная система-то одна, но физически она расположена в разных местах. Тоже, в общем-то, anycast.

Как проверить, что Anycast работает?

Можно попинговать и построить трассы до наших anycast адресов из разных точек мира. Можно воспользоваться RIPE Atlas или любым другим сервисом мониторинга, который это позволяет.

Видно, что задержки пинга низкие даже из разных углов шарика (через любой океан — это плюс 100 миллисекунд минимум):

задержки

Atlas даже может построить трассы:

трассы

Видно, что почти все пути ведут через AS20473, то есть через Vultr.

Однако оказалось, что маршрутизаторы не всегда выбирают, казалось бы, оптимальные маршруты. Например, из США запросы отправляются в Европу, хотя там же в США есть несколько датацентров с нашей anycast сетью. Если изучать маршруты, то оказывается, что действительно, до Европы меньше хопов, но задержки, как и положено, больше.

Что тут можно сделать? Мне кажется, как владельцы конечных, не транзитных, автономных систем, мы мало можем повлиять на поведение чужих маршрутизаторов. Конечно, можно поднять приоритет какого-нибудь одного датацентра. Но этот приоритет будет виден для всех, а не только для ближайших маршрутизаторов. Таким образом можно добиться несимметричности трафика, но не честного выбора самого ближайшего сервера.

А вот что думают другие маршрутизаторы о наших анонсах, вполне можно узнать. Для этого нужно искать то, что называется BGP Looking Glass. Это совершенно разные веб интерфейсы для доступа к маршрутной информации разных маршрутизаторов. Можно посмотреть, почему этот противный американский маршрутизатор думает, что Европа ему ближе. Если, конечно, удастся найти его looking glass.

На bgp.he.net можно найти кучу интересной информации обо всех автономных системах. Например, можно найти, как расходятся анонсы нашей AS:

анонсы

Вот как выглядят маршруты до нашей anycast сети с одного из американских маршрутизаторов этого самого Hurricane Electric:

маршруты

Самое интересное — колонка Path. Видно, что у этого маршрутизатора есть прямой линк до Vultr. Первые пять маршрутов ведут прямо в вультровую AS20473, за которой сразу видна наша AS. А Metric у маршрутов различается. Интересно, почему.

Но это не тот маршрутизатор, который заруливал в Европу. Его Looking Glass я найти не могу. Это ж дело добровольное, рисовать сайт для публичного доступа к маршрутной информации.

Кстати, оказалось, что часто сайты Looking Glass начинаются с lg.. Например: lg.sibir-ix.ru, lg.cloud-ix.net, lg.msk-ix.ru, lg.omsk-ix.ru, lg.ttk.ru. IX — это Internet eXchange, точки обмена трафиком. Такие специальные маршрутизаторы на стыке нескольких автономных систем для прямого обмена трафика между ними.

P.S. Большинство туториалов по BGP посвящено изучению соответствующих команд для Cisco. Я же тут постарался объяснить на пальцах.

P.P.S. Я тут нигде не называю настоящего номера нашей получившейся AS и настоящих адресов нашей Anycast сети, потому что у меня нет на это разрешения.