Привет, Хабр! Если представить ваш высоконагруженный сайт в виде оркестра, а пользователей — в виде слушателей по всему миру (Москва, Владивосток, Берлин), то ситуация, когда все «музыканты» играют в одном ЦОДе, напоминает концерт, который кто-то слушает вживую, а кто-то — по плохой телефонной линии. Пинг растёт, пакеты теряются, трафик упирается в потолок возможностей ЦОДа, и в случае его отказа наступает тишина.

Решение — вынести «сцены» ближе к «зрителям»: построить геораспределённую инфраструктуру и научиться направлять пользователей на ближайший живой узел. В этом материале, основанном на моём докладе для Saint HighLoad++ 2025, мы разберём, как комбинировать BGP Anycast, DNS и HTTP-балансировку, чтобы снизить RTT, переживать падение целых площадок и равномерно «кормить» мир контентом. 

Меня зовут Дмитрий Криков, я CTO в NGENIX. Всё, о чём пойдёт речь, — это не теория, а ежедневная практика нашей платформы, которая уже 17 лет занимается ускорением и защитой веб-ресурсов и состоит из 50 узлов, разбросанных по России и ближнему зарубежью. Ёмкость нашей платформы уже превысила 7 Tbps. Мы обслуживаем десятки миллиардов запросов в сутки. Наши заказчики — крупнейшие российские проекты, начиная с e-commerce и заканчивая медиакомпаниями.

Если у вас есть активно посещаемый веб-ресурс, то в какой-то момент вы столкнётесь с проблемами масштабирования, балансировки, резервирования. Как решать эти проблемы оптимально при растущей нагрузке?

Почему одного ЦОДа недостаточно для высоконагруженного приложения?

Внутри одного дата-центра задачи балансировки и резервирования решаются относительно просто — есть проверенные инструменты и подходы. 

Однако, когда ваша аудитория географически распределена и пользователи сильно удалены от ЦОДа, то проявляются системные проблемы:

Задержки (RTT). Например, RTT между Владивостоком и Москвой составляет около 100 мс. Для современных веб-приложений это критично много.

Пропускная способность. Обеспечить в одном ЦОДе линки на терабиты сетевой емкости — сложная и дорогая задача.

Отсутствие георезервирования. Георезервирование никогда не бывает лишним, потому что если у нас проект крупный, то мы на нём зарабатываем деньги, и простои с задержками нам не нужны. Падение единственного ЦОДа означает полную недоступность сервиса для всех пользователей.

Решение этих проблем — геораспределённая инфраструктура

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

Ситуация усугубляется тем, что для веба клиенты пользуются как стандартными устройствами — компьютерами, телефонами, планшетами — так и нестандартными вроде телевизора или даже холодильника. Технологии, доступные на них, — самые базовые: операционные системы, браузеры, стандартные библиотеки. Приложение туда не всегда можно поставить, да и пользователь не всегда на это согласен. У нас в NGENIX — огромный операционный опыт, и всё чем я поделюсь, подтверждено на практике. Так что давайте разбираться!

Три технологии глобальной балансировки: BGP Anycast, DNS и HTTP

Для балансировки используется стек технологий, который поддерживается всеми:

1. BGP Anycast (уровень IP)

2. DNS

3. HTTP

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

BGP Anycast — балансировка силами интернета

Балансировка по BGP Anycast: как это работает

Интернет — это не единая сеть под единым управлением, а большое количество сетей под управлением разных операторов. Автономные системы (AS) взаимодействуют между собой по IP. У них есть свои номера (ASN). Распределением IP-адресов и ASN занимается ICANN через региональные и локальные Internet Registry. Но нужно, чтобы всё это работало как единое целое.

Протокол external BGP работает между автономными системами и обеспечивает в том числе:

● обмен IP-маршрутами между AS.

● выбор кратчайшего маршрута (по AS-PATH - с точки зрения количества AS по пути) при наличии нескольких.

● динамическое перестроение маршрутов при изменениях.

Для балансировки IP-префикс можно одновременно анонсировать из разных ЦОДов – как   из разных AS, так и с разных маршрутизаторов разделённой AS.

Один и тот же префикс можно анонсировать сразу из нескольких точек, и тогда клиенты пойдут в ближайшую точку. Соответственно, разные пользователи придут на разные узлы, ближайшие к ним с точки зрения сети, что очень удобно. При этом необязательно для этого иметь несколько автономных систем. Можно разделить одну автономную систему, чтобы разные несвязанные между собой узлы обладали одной AS. Они могут анонсировать разные (или для anycast одинаковые) префиксы, и это будет работать.

Кроме того, что балансировка получается автоматически, бонусом мы получаем дополнительные приятные эффекты: клиент пойдёт в ближайший (по AS-PATH) ЦОД, а при отказе ЦОДа маршруты автоматически перестроятся. То есть,   если ЦОД упал, либо мы его осознанно вывели из эксплуатации — пропадает анонс, и клиенты идут в другой ЦОД.

Какие могут быть проблемы с BGP Anycast и как их решить

Проблема 1: риски динамического перестроения маршрутов

Первая проблема: многие опасаются, что при динамическом перестроении маршрутов у соединений начнутся проблемы. Пакет пришёл на один узел, соединение установилось, потом — раз! — что-то в интернете изменилось, и следующие пакеты отправились на другой узел. Проблема!

Как ее решить?

Теоретически такое может случиться. Но на практике об этом стоит задумываться разве что для постоянных длительных соединений. В случае с обычным HTTP этот риск де-факто не влияет никак. За 25 лет опыта я ни разу на практике с такой проблемой не сталкивался. Поэтому это решение смело можно использовать не только для кейсов, когда нет установки сессии, например, при работе по UDP, но и в варианте с HTTP.

Проблема 2: «le 24»

Вторая проблема: минимальный префикс IPv4, который можно анонсировать по BGP в интернете - это /24 или крупнее. Более мелкие префиксы обычно отфильтровывают; если бы разрешили анонсировать более мелкие префиксы или отдельные адреса, то таблицы маршрутизации у всех выросли бы до огромных размеров. 

Если отказал единственный сервис или сервер в этой сети, мы не можем снять анонс одного адреса, мы должны вывести целиком сеть. 

Как ее решить?

1. Вывод префикса/узла целиком. Можно выводить всю сеть, если у нас есть достаточное количество подсетей либо мало сервисов.

2. Резервирование внутри ЦОДа - классика, про которую все знают. 

3. Проброс в другой ЦОД, где этот сервис живой. Причём не обязательно это делать симметрично -  можно пробрасывать пакеты в одну сторону, а ответы асимметрично отправлять из того ЦОДа, где обслуживается сервис.

Проблема 3: мониторинг сервисов с BGP Anycast

Адрес у нас один, анонсируется с разных узлов, а нам интересно понимать доступность его для пользователей. 

Возможные решения:

1. Распределённый мониторинг из сетей разных операторов и от реальных клиентов (RUM). Даже в случае с BGP Anycast, когда IP один, мы можем поставить большое количество пробников в разных операторах и понять, как оттуда доступен наш сервис. Также можно воспользоваться технологией RUM, когда в страничку сайта встраивают JavaScript, который уже со стороны реальной аудитории опрашивает те или иные наши ресурсы и репортит об их состоянии.

2. В ответах возвращать идентификаторы узлов/серверов. Чтобы чётко понимать, какой сервер ответил, полезно возвращать его идентификатор. Ведь не получив такого ответа, мы не знаем, к какому серверу пришли.

3. Собирать статистику с серверов и мониторить их по unicast-адресам. Кроме anycast-адресов в каждом ЦОДе же есть и свои адреса.

Бонус

Кстати, BGP Anycast можно использовать и для резервирования внутри ЦОДа, это тоже вполне себе рабочее решение.

Можно поставить не классический балансировщик, а проанонсировать один и тот же адрес с нескольких серверов, чтобы трафик распределился между ними. Этот механизм называется ECMP (Equal Cost Multipath), его можно использовать с BGP. Бонусом можно получить автоматический вывод ЦОДа, если с этих же серверов проанонсировать не только конкретный 32-й адрес, а и целиком /24. То есть не будем анонсировать его непосредственно с маршрутизатора, а сделаем это с серверов. Тогда, если все сервера пропадут, анонс /24 из ЦОДа тоже пропадёт, а весь трафик пойдёт в другой ЦОД — бинго!

Суммируем: плюсы и минусы балансировки по BGP Anycast

Плюсы:

Прозрачность для вышележащих протоколов (DNS, HTTP).

Кратчайший маршрут по AS-PATH.

Нативное автоматическое резервирование при отказе ЦОДа.

Масштабирование. Теоретически, можно использовать неограниченное количество узлов и серверов при всего одном IP-адресе сервиса.

Минусы:

Минимальный префикс – /24. Нужно анонсить целую отдельную сетку.

Недоступна информация выше L3.

Низкий уровень управляемости. Мы можем очень слабо управлять тем, что происходит с BGP. Максимум - сделать какие-то препенды, подкрутить комьюнити и т.п.

Кратчайший маршрут по AS-PATH – не кратчайший. На самом деле автономная система может быть растянута на всю страну. Поэтому насколько этот маршрут на практике короткий, вопрос спорный.

Не всегда хватит компетенций. Сеть – отдельный мир, не все с ним знакомы. Сетевики обычно не те люди, которые хорошо понимают сервисы более высокого уровня, соответственно, успех зависит от того, кто всё это будет настраивать.

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

DNS-балансировка — как это работает

DNS-балансировка - как это работает

Действующие лица в случае с DNS такие:

● Клиент, которого интересуют значение тех или иных записей (в данном случае обычно A или AAAA).

● Резолвер(ы), которым клиенты задают интересующие их вопросы.

● Авторитативные Name-сервера (NameServers, NS), которые отвечают за зоны.

Клиент просит у резолвера значение ресурсной записи (RR) для sub.domain.tld.

После резолвер обращается по очереди к авторитативным NS разного уровня до тех пор, пока не получит интересующий его ответ, кэширует ответы на получаемые с ними TTL и сообщает ответ клиенту.

В этом случае существует несколько подходов к балансировке, каждый из них имеет свои тонкости.

DNS-балансировка: базовый round-robin

Можно в ответе отдавать клиентам разные адреса, как по одному, так и сразу пачками, потому что в DNS по умолчанию работает round-robin. Адреса отдаются в разном порядке, что обеспечивает некоторую равномерность в балансировке.

Как можно балансировать по распределённой инфраструктуре с помощью DNS?

Geo-балансировка: особенности и подводные камни

Первый способ, который сразу приходит в голову всем, - это GEO-балансировка.

Пользователь пришёл с DNS-запросом, ему ответили адресом ближайшего сервера, и он отправился туда. Казалось бы, всё работает из коробки, даже есть стандартные гео-базы, можно пользоваться.

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

DNS-балансировка с учетом топологии сети

Эта задача гораздо более сложная, потому что для этого нужно собирать информацию о том, куда и как ходят IP-пакеты.

Откуда брать информацию? Отовсюду, докуда дотянетесь. Типовые источники:

BGP - из BGP может быть полезна информация о длине маршрута, через каких операторов проходит маршрут, номера AS, комьюнити.

Мониторинг со стороны серверов:

— пассивный (анализ запросов на разных уровнях). Мы анализируем, как обслуживается запрос и с какой скоростью сервер отвечает для разных сетей. 

— активный — pings и т. п. Например, можно периодически пинговать интересующие сети и собирать статистику. Это дополнительный источник ценной информации.

— внешний распределённый мониторинг. Он важен, когда нужно понимать, как системы и серверы отвечают клиентам. Здесь нужно иметь сеть пробников и RUM (Real User Monitoring) с реальной аудиторией;

Публичные базы, в том числе и geo, в качестве дополнения к собранной информации.

Обратная связь от пользователей ресурсов. Вам повезло, если вы управляете своим ресурсом и пользователи сообщают какую-то дополнительную информацию, например: «Я с такого-то оператора, у меня такая-то связанность». 

Если проанализировать эти данные в совокупности и учесть их с определёнными весами, то получаем хороший источник информации для приоритизации.

DNS-кэширование: мифы и реальность

Кэш. Это страшное слово. Многие опасаются, что ошибки в настройке кэширования всё сломают. Разберем эти опасения.

Миф первый: «Резолверы закэшируют ответ навсегда». Первое опасение, связанное с кэшом, я слышал ещё лет 25 назад: резолверы принудительно надолго, чуть ли не навсегда, закэшируют ответы ваших серверов, потому что они экономят трафик и ограничивают нагрузку. Закэшируют и всё — никакие изменения не применятся. 

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

Миф второй: «Изменения распространяются очень медленно». Эта возможная проблема более реалистичная: изменения будут распространяться очень долго. Явно дольше чем BGP-анонсы. А если в цепочке еще и несколько резолверов…

Многие боятся, что изменения распространяются с задержкой за счёт кэширования TTL, особенно если сравнить с BGP, особенно с включенным BFD. А если в цепочке ещё несколько резолверов, каждый из них закэширует, потом следующий закэширует также на TTL, и т.д., то всё будет плохо.

Как на самом деле? Это работает немного не так. Небольшой TTL (<30 сек.) -> адекватная сходимость! 

Резолверы в цепочке кэшируют ответы на оставшийся TTL, соответственно, каждый следующий будет на меньшее время кэшировать. Поэтому общий TTL мы никогда не превысим. Считать BGP очень быстрым тоже не стоит, по умолчанию таймеры BGP — это десятки секунд, BFD не везде включен и не сильно помогает на практике. Фактически, даже когда TTL составляет 30 секунд, что, кажется, довольно много, всё работает достаточно хорошо. 

Уменьшение TTL существенного эффекта на доступность не оказывает, проверено на реальных проектах. Например, в каких-то проектах использовали 5 секунд, но если TTL в пределах 30 секунд, то на практике разница не заметна.

Надо учесть пару важных моментов: 

Первое. TTL необходимо уменьшать в зоне заранее. Если DNS-ответ где-то уже закэширован на неделю, то повлиять вы на это не сможете. Поэтому заранее нужно подумать об уменьшении TTL. 

Второе. Надо учитывать скорость реакции мониторинга и на мониторинг. Самое страшное — не применение изменений по сети и не распространение информации в DNS, а то, каким образом вы обнаружите отказ и каким образом инициируете это переключение. Часто это происходит гораздо дольше, чем 30 секунд. Эта проблема гораздо серьёзнее кэширования на маленький TTL.

Миф третий: Кэширование на публичных резолверах даст дисбаланс. Есть, например, 8.8.8.8, 1.1.1.1 и т.п.. Что же, выходит, они получат ответ, закэшируют, и всем будут отдавать одно и то же?

Как на самом деле?   Такой проблемы тоже нет, потому что все крупные публичные сервера — это не один сервер, а большое количество серверов, которые работают с использованием BGP Anycast и кэшируют ответы независимо. Кроме того, в DNS есть расширение EDNS – о нем чуть позже. Это решение также способствует тому, чтобы пользователи получали адекватные ответы.

Как перестать бояться и начать использовать DNS для балансировки?

Чтобы избежать разных подводных граблей при DNS-балансировке, напомню о ряде технических нюансов. 

Транспорт для DNS-запросов: UDP vs. TCP

Обычно DNS-запросы уходят по UDP на port 53. Трансфер зон происходит по TCP. Но бывают случаи, когда и запросы обрабатываются по TCP.

Это происходит так. Клиент (обычно через резолвер) спрашивает DNS сервер о ресурсной записи. Сервер формирует ответ и видит, что он не влезает в UDP-пакет, который пройдёт без фрагментации - есть ограничения. Тогда сервер возвращает клиенту UDP-ответ с флагом truncated response (информация о том, что ответ урезан). После этого клиент делает перезапрос, подключаясь по TCP, чтобы получить полный ответ. К сожалению, это медленно и долго, а мы хотим быстро. 

Проблема: ограничения UDP. Разберемся и сделаем экскурс в историю.

Первые RFC по DNS (198x): DNS Message в UDP: up to 512 bytes. Когда DNS приняли как протокол, в RFC было указано, что максимальный размер DNS-сообщения — это 512 байт, что довольно мало.

EDNS extensions (1999): управление макс. размером ответа по UDP. В 1999 году появились DNS-extensions, в которых можно управлять допустимым размером ответа по UDP. Но какой размер можно указать, чтобы всё работало на практике?

DNS Flag Day 2019: поддержка EDNS обязательна. В 2019 году возникла инициатива DNS Flag Day, на базе которой решили, что поддержка EDNS обязательна. В результате все публичные крупные резолверы стали рассчитывать на то, что все авторитативные сервера будут поддерживать EDNS.

DNS Flag Day 2020: An EDNS buffer size of 1232 bytes will avoid fragmentation on nearly all current networks. This is based on an MTU of 1280. В 2020 году на такой же инициативе был опубликован труд, в котором сказали, что теперь буфер для ответа по EDNS можно выставлять в 1232 байта, потому что он пролезет везде с учётом современных сетей. Но с тех пор мы далеко от этого не ушли.

Сегодня: стандартный MTU в Ethernet – 1500. Реальная цифра будет чуть меньше из-за дополнительных инкапсуляций, но всё равно размер ограничен.

Решение: используйте UDP, минимизируйте использование TCP. Я настоятельно рекомендую стараться уложиться в UDP, TCP в данном сценарии работает медленнее. Для этого надо уменьшать размер ответов. Поэтому:

● Ограничивайте число записей в ответах DNS:

● Сегментируйте платформу по топографии аудитории.

● Если нужно много записей – их можно ротировать.

● Можно уменьшить количество отдаваемых записей в ответе. Для этого нужно более точно сегментировать аудиторию, чтобы не отдавать всем все сервера. Но если всё равно нужно отдать большую пачку серверов, делаете round-robin и ограничивайте их количество на стороне DNS-сервера. 

Например, выбираете 10 подходящих серверов, сделали round-robin, отрезали лишние, в результате, отдали четыре. На самом деле цифра будет больше, может вместиться и 10 — зависит от длины записи. Но постарайтесь минимизировать переходы на TCP!

Если IP резолвера != IP клиента 

Теперь рассмотрим другую реальную ситуацию: клиент спрашивает всё, что его интересует в части DNS, у своего резолвера. Резолвер в интересах клиента приходит к авторитативному серверу (наш DNS-балансировщик, по сути, является таким авторитативным сервером ) со своего IP адреса. И возникает вопрос: что теперь делать, если мы хотим отбалансировать клиента, а наш балансировщик видит не его IP, а IP резолвера.

Проблема: балансировщик не знает IP клиента. Замечу, что в случае если резолвер стоит в корпоративной сети клиента, проблемы как таковой нет. В принципе, всю сеть имеет смысл балансировать на один и тот же узел, так как у неё одинаковая связность (помним про маршрутизацию префиксов не меньше /24 в  интернете). А если это публичные резолверы, то проблема есть.

Решение: используйте EDNS Client Subnet extension. В EDNS есть extension Client Subnet, когда резолвер вместе с запросом передаёт информацию о сети, из которой пришёл клиент — не конкретный IP-адрес (чтобы не было вопросов в части сохранения privacy), а именно о сети. С точки зрения балансировки этого более чем достаточно, потому что анонсы в интернете и сетевая связь, минимум, /24. То есть полная информация у нас есть.

Балансировка балансировщика 

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

1. Классический подход: балансировка и резервирование внутри ЦОДов. Вариантов много, нам нравится BGP anycast.

2. Нативные механизмы клиентов DNS => N x /24. Обязательно используйте. Пусть у вас на разных адресах в разных сетях работает DNS. Если DNS-клиент не достучится до одного сервера - пойдет на другой.

3. BGP Anycast N x /24. Вы можете резервировать DNS по неограниченному количеству разных ЦОДов и разных операторов даже на одном адресе. Но не советую использовать адрес только из одной сети. Используйте несколько сетей, потому что если у вас откажет DNS на одном узле, а анонс почему-то не снимется - с одним адресом у клиента не будет шансов, а если клиент видит несколько адресах - он придет на следующий. Поэтому лучше Anycast’ом анонсировать несколько сетей, причём из разных ЦОДов. Тогда нам всегда будет откуда обслужить клиента.

4. Подстраховка: анонс 2 x /24 + 1 x /23. Чтобы даже при полном отказе всех узлов, анонсирующих одну из /24, не было задержки на отработку тайм-аута на резолверах, можно из всех ЦОДов анонсировать еще и обобщающую /23; тогда если полностью пропадёт анонс /24, клиент всё равно сразу придёт к DNS по менее специфичному маршруту к /23.

Суммируем: плюсы и минусы балансировки по DNS

Плюсы:

Прозрачность для протоколов. Это стандартный механизм работы интернета.

Нативное резервирование. И клиент, и резолвер устроены так, что при недоступности одного IP-адреса они автоматически пробуют следующий из списка.

Высокая точность распределения. Мы сами можем решать, какой IP кому отдавать, учитывая географию, топологию сети и текущую загрузку серверов.

Минусы:

Всё ещё мало информации о контенте и клиенте. Нам хочется иметь больше информации о клиенте и контенте, чтобы более точно балансировать. Не просто отдать ему адрес на основе его адреса, а сделать балансировку более осмысленной. 

Невозможно балансировать с точностью до запроса.

Тут нас выручает HTTP-балансировка.

HTTP-балансировка — максимальная гибкость

Говоря про HTTP-балансировку, я имею в виду не балансировку внутри ЦОДа, когда мы в нём что-нибудь проксируем и т.п., а именно балансировку между ЦОДами, когда мы балансируем клиента по точкам входа в нашу распределённую инфраструктуру.

Глобальная балансировка по HTTP: как это работает 

Есть два разных подхода к такой балансировку по точкам входа в инфраструктуру на уровне HTTP.

Первый: Прямые перенаправления / redirection messages (HTTP 3xx):

● HTTP 302 Found (Moved Temporarily)

● HTTP 307 Temporary Redirect

Это редиректы, прямые перенаправления, когда мы в ответ на запрос выдаём HTTP-редирект с кодом 302 или 307, уже с целевым именем хоста, с которого эффективнее всего обслужить нашего клиента.

Обращу внимание, редирект нужно использовать только временный, иначе клиент запомнит, куда идти, и с балансировкой будет не очень.

Второй: Подмена ссылок в отдаваемых ответах, когда возможно:

● В HTML-коде / на страницах.

● В плейлистах/манифестах видео (HLS / MPEG-DASH / …).

● …

Например, в HTML-страничках можем подменять ссылки на интересующие нас объекты сразу с указанием нужных серверов в качестве хостов. В плейлистах и манифестах видео-потоков можем указывать сразу нужные хосты. Так мы исключим лишний запрос, и всё будет быстро и чётко работать.

HTTP-балансировка: особенности и подводные камни

Важно учесть ряд особенностей и рекомендаций, чтобы всё работало эффективно. 

Если возможно — выдавайте прямые ссылки, потому что это не потребует дополнительных запросов.

Если подмена ссылок невозможна, например, потому что кто-то другой за нас выдаёт исходную ссылку, приоритетные варианты такие:

● Для крупного контента – перенаправления / redirects. Если мы отдадим крупный контент (видео, апдейты), то оптимальная стратегия — это HTTP-редирект, потому что время редиректа ничтожно по сравнению с общей скоростью отдачи контента. Мы ничего не теряем, а, наоборот, приобретаем за счет точной балансировки.

● Для мелкого – DNS или BGP Anycast. Если контент мелкий (картинки на сайт и так далее), то лишний редирект будет очень дорогим. Поэтому используйте то, что позволяет быстро решить данный вопрос — DNS-балансировку или BGP Anycast.

Также я порой слышу опасения, связанные с HTTP-балансировкой по разным доменным именам. 

Проблема: множество доменов вызывает дополнительные сложности. Ведь это означает дополнительные походы к DNS, соединения и SSL-сертификаты. Кажется, что это всё будет сложно, медленно и так далее. Чтобы этого не случилось - важно структурировать свой контент.

Решение: сокращение доменов для HTTP-балансировки. Если у вас будет немного доменов – всё будет норм. Как можно этого добиться?

 

● Группируйте домены   в ссылках по принципу <группа контента> + <сервер/узел>

● Используйте небольшое число групп контента в ответе.

● Используйте поддомены одного уровня.

К примеру: https://a3569456006-video.cdn.domain.tld/

DNS отлично кэшируется, возможен высокий TTL; соединения могут переиспользоваться.

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

Балансировка HTTP-балансировщика

Балансировка балансировщика обязательна и в случае с HTTP, и здесь все технологии пригодятся:

● балансировка внутри ЦОДов;

● DNS-балансировка;

● BGP Anycast.

Мы стараемся использовать все преимущества слоёв ниже, чтобы пользоваться слоями выше. Но! Любой балансировщик не должен быть узким местом. В случае с HTTP-балансировщиком используется больше логики - то есть, он "тяжелее", поэтому из него проще получить узкое место. Чтобы это не случилось — надо не только балансировать нагрузку на него, но и грамотно выбирать разумные точки балансировки контента.

Балансировка по HTTP: разумные точки балансировки

Проиллюстрирую на примере выдачи видео, в данном случае с протоколом HLS.

На страничке отдаются плееры и ссылка на плейлист. В плейлисте содержатся ссылки на несколько так называемых чанк-листов, соответствующих разным уровням качества. Они уже содержат ссылки непосредственно на сегменты видео.

Работает это так. Загружается страница, затем плеер, потом мастер-плейлист. Дальше плеер периодически запрашивает чанк-лист нужного качества, потому что по мере live-трансляции появляются новые сегменты. Обращаю внимание еще раз: чанк-листы запрашиваются регулярно. А сегменты с видео запрашиваются уже по одному разу.

В данном случае имеет смысл балансировать нагрузку на уровне мастер-плейлиста, потому что тогда не надо будет каждые несколько секунд обрабатывать запрос к чанк-листу балансировщиком. Мы в мастер-плейлисте при балансировке переписываем адреса чанк-листов, клиент приклеивается к соответствующему серверу и получает оттуда чанк-листы и видео.

В случае, если с сервером возникает проблема, плеер перезапрашивает мастер-плейлист, мы его пропускаем через наш балансировщик и опять выдаём ему оптимальный работающий сервер.

Синхронизация балансировщиков

Когда вы ставите много HTTP-балансировщиков, хочется сделать между ними общую логику. Кажется, что нужно между ними синхронизировать какую-то информацию, чтобы эффективно распределять нагрузку.

Как избежать проблем с синхронизацией?

1. Предпочтительно избежать необходимости синхронизации вообще – то есть, сделать, чтобы каждый балансировщик работал независимо. 

Как это сделать?

a) Сформируйте единые правила балансировки и шардинга, чтобы каждый балансировщик действовал одинаково.

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

b) Распределяйте свободный ресурс и запросы поровну (1/N)

Есть вариант проще — остатки полосы в моменте разделять поровну между всеми балансировщиками, и пусть каждый распоряжается своей частью. Конечно, возможно, что они сразу полностью всю эту полосу не использует, возникнет неравномерность. Но если раз в какое-то время, например, в 10 секунд, эту информацию обновлять, то в итоге все серверы будут загружены равномерно и эффективно. А балансировщики будут работать независимо.

2. Не храните состояние конкретного клиента на балансировщике (be stateless).

Постарайтесь не держать state на балансировщиках, чтобы они были максимально легкими. Если вам что-то нужно передавать между запросами, это можно сделать, например, через клиента с использованием cookies. Он повторно сообщит вам то, что вы ему передали.

3. Ограничьте синхронное взаимодействие, особенно в рамках запроса.

Если не можете обойтись без взаимодействия на этапе балансировки, постарайтесь, чтобы оно было асинхронным, запрос желательно не тормозить. То есть, что бы ни происходило, желательно, чтобы запрос был обслужен без задержек. Это важно.

Суммируем: плюсы и минусы балансировки по HTTP:

Плюсы:

В запросах много информации о контенте и клиенте. Несомненный плюс в том, что у нас есть вся информация. Мы получаем с клиента заголовки, знаем, что это за клиент и его IP-адрес, откуда он пришёл и за каким контентом, а не просто в курсе про запрашиваемый домен. Поэтому мы можем точно распределять и дозировать нагрузку, гибко распределять и шардить контент, учитывать температуру (популярность) контента и др. Например, можно держать в центре крупные узлы, на которых есть весь контент, а узлы с популярным контентом распределить по миру, и таким образом обеспечить максимальную эффективность.

Можно не кэшировать ответы балансировщика. Мы можем по желанию отдавать заголовки, управляющие кэшированием ответов наших балансировщиков. Хотим - разрешаем кэшировать. Не хотим — отдаём соответствующий Cache-Control, и они не кэшируются. 

С HTTP-балансировкой мы получаем максимальную управляемость. Но за неё приходится платить.

Минусы:

Более ресурсоёмкая технология. У всего есть своя цена. И в данном случае она измеряется бОльшими требованиями к ресурсам.

Как видите,   тонкостей и нюансов довольно много – поэтому придется позаботиться о мониторинге подобных распределенных конструкций.

Мониторинг распределенных инфраструктур 

Зачем нужен мониторинг?

Мы мониторим не для того, чтобы у нас был красивый красно-желтый дашборд, а для того, чтобы принимать решения:

По необходимому реагированию. Что необходимо или, наоборот, не стоит делать в данной ситуации, что мы можем автоматизировать.

По возможности использования. В распределённой системе нам интересно, можем ли мы использовать конкретный сервер в конкретный момент. Или, возможно, туда больше не надо направлять клиентов, потому что он перегрузится и откажет.

По приоритетам. Мы можем из мониторинга получать информацию, куда эффективнее всего в данном случае направить клиентов.

Что нужно мониторить 

Чтобы понимать состояние здоровья сервера, мы можем мониторить сервера из одной точки. Получим:

● Внутренние метрики серверов и сервисов;

● Работоспособность;

● Доступность;

● Показатели связности.

Но поскольку нам интересна доступность для клиента, нужно по возможности мониторить сервер распределённо и использовать полученную информацию для балансировки.

Какой нужен мониторинг?

К организации мониторинга распределенных инфраструктур есть разные, эффективно дополняющие друг друга подходы. 

Активный распределённый мониторинг 

Для мониторинга «здоровья» сервисов можно поставить пробники в разных ЦОДах. Нужно понимать, что их количество всегда ограниченно, они имеют хорошую связность и работают БЕЗ реальной аудитории.

Если мы ставим пробники в ЦОДах и синтетически начинаем мониторить сеть, мы получаем синтетику без учёта последней мили, на которой обычно случаются потери и которая добавляет много неопределённости. Мы не видим реальной аудитории. Но зато мы всегда понимаем состояние здоровья нашей платформы, серверов — неважно, есть ли там активная аудитория или нет.

RUM – Real User Monitoring 

Real User Monitoring — это когда мы из браузеров реальных пользователей веб-ресурсов опрашиваем нашу платформу. RUM работает на реальной аудитории с реальной связностью и является инструментом мониторинга скорости и доступности и ценным источником данных для приоритизации.

С помощью RUM мы узнаем что-то только тогда, когда активные  пользователи есть и смогли достучаться, как минимум, до базовых страниц, с которых подгружается скрипт Real User Monitoring. В результате мы видим картинку с реальной аудиторией на реальной связности и можем эту информацию использовать для балансировки и приоритизации. Чем у вас больше аудитории и разных ресурсов, тем более точная база для балансировки у вас получится и тем лучше вы сможете балансировать и эффективнее распределять нагрузку на основе Real User Monitoring.

Главное – не допустить типовых ошибок при использовании RUM. 

● Не используйте RUM на сайте с другой аудиторией. Например, типичная ошибка — мониторить платформу в России с сайта, ориентированного на другую страну, и получить очень плохие показатели, потому что пользователи будут ходить в основном с другого континента.

● Не используйте основное доменное имя сайта для тестовых объектов при сравнении инфраструктур.

● Не используйте НЕвыделенные объекты для тестирования.

При тестировании используйте отдельные доменные имена и отдельные объекты. Если вы воспользуетесь тем же объектом, который загрузился с вашего ресурса, возможно, уже будет установлено соединение, возможно, он будет уже закэширован, и так далее. У вас получатся некорректные сравнения.

В чём сила, брат?

Итого, что я хотел до вас донести в этой статье:

Сила – в грамотной комбинации: BGP Anycast + DNS + HTTP.

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

Распределённый мониторинг критически важен.

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

Используйте максимум доступных данных для балансировки.

Важно иметь хорошие данные для балансировки. Чем до большего количества данных вы сможете дотянуться, тем качественнее будет распределение нагрузки, тем быстрее пользователи  получат свой контент, тем лучше будет работать ваш ресурс и тем довольнее будут бизнес и пользователи. Профит!

Распределённые облачные платформы – альтернатива DIY.

Можно использовать платформы, которые уже умеют всё это делать и решают часть этих задач, потому что строить свою систему — это долго, дорого и нужна большая экспертиза. Но вам всё равно полезно понимать, как это работает, потому что в противном случае даже с таким решением результат может оказаться не очень.

А если вы дочитали до конца и вас так же волнуют темы масштабирования, балансировки и устойчивости при высоких нагрузках, как нас, — приходите на следующий сезон конференции HighLoad.

Комментарии (0)