Задача: настроить шилдинг в CDN без выделенных железных серверов.

Представим, что у вас есть CDN, но нет необходимости/желания/денег ставить выделенные железные серверы под шилдинг(shielding). Шилдинг - это дополнительный уровень кэширования для защиты origin(источник контента), чтобы запросы от edge к origin шли через промежуточные серверы. Он необходим для снижения нагрузки на origin, так как edge-нод может быть очень много и если каждая будет обращаться к origin напрямую, то он начнет погибать под нагрузкой. С шилдингом на origin всегда будет обращаться только выделенная группа серверов.

Архитектура Есть 3 раздающие edge-ноды и 2 origin-сервера:

🔍edge-ноды: edge1, edge2, edge3 🔍софт: Nginx 🔍origin: origin1, origin2

Будет использоваться директива split_clients на каждой edge-ноде. Она делит запросы на три равные части (по 33%):

🔍33% - остаются на текущей edge-ноде и уходят напрямую в origin 🔍33% - уходят на первую соседнюю edge-ноду 🔍33% - уходят на вторую соседнюю edge-ноду

При этом split_clients гарантирует идемпотентность(красиво звучит): один и тот же $request_uri всегда попадает в одну и ту же группу. Благодаря этому 99% запросов к кластеру стабильно распределяются по всем трём edge-нодам и далее на origin без «скачков».

Пример конфигурации для архитектуры из 3-х edge-нод.

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

Базовый апстрим для origin на каждой edge-ноду: upstream origin{ server origin1; server origin2; }

Апстримы для шилдирования на соседние edge-ноды: upstream edge1-shield { server edge1; server origin1 backup; server origin2 backup; }

upstream edge2-shield { server edge2; server origin1 backup; server origin2 backup; }

upstream edge3-shield { server edge3; server origin1 backup; server origin2 backup; }

Итого, каждый апстрим смотрит на соседа по кластеру и бекапом на origin.

Далее настраиваем распределение трафика через split_clients на каждой edge-ноде.

edge1 split_clients $request_uri $upstream_backend { 33% origin; 33% edge2-shield; 33% edge3-shield;

  • origin; }

edge2 split_clients $request_uri $upstream_backend { 33% edge1-shield; 33% origin; 33% edge3-shield;

  • origin; }

edge3 split_clients $request_uri $upstream_backend { 33% edge1-shield; 33% edge2-shield; 33% origin;

  • origin; }

Как это работает. $request_uri - ключ, на основе которого происходит распределение/хэширование. $upstream_backend - переменная, в которую будет сохранён выбранный upstream.

То есть для примера 33% origin - это если хэш попадает в первые 33% диапазона, то переменной $upstream_backend присваивается значение origin.

    • значение по умолчанию для оставшихся случаев (1%).

Далее в location эта переменная используется для указания апстрима, например: location / { proxy_pass http://$upstream_backend; }

То есть в зависимости от того, в какой диапазон попал хэш $request_uri$, upstream_backend может принимать значения: 🔍origin 🔍edge1-shield 🔍edge2-shield 🔍edge3-shield

Это актуально, когда 50-100 edge-нод начнут идти за одним и тем же контентом на origin и ему станет тяжело, как минимум можно быстро упереться в емкость сетевых карт.

С использованием split_clients (один uri): Клиент1 -> edge1 -> edge2 -> origin (edge2 кэширует) Клиент2 -> edge1 -> edge2 -> из кэша edge2 (без origin!) Клиент3 -> edge2 -> из кэша edge2 (без origin!) Клиент4 -> edge2 -> из кэша edge2 (без origin!) Клиент5 -> edge3 -> edge2 -> из кэша edge2 (без origin!) Клиент6 -> edge3 -> edge2 -> из кэша edge2 (без origin!)

Работает только на уровне одного кластера edge и если их много (в разных городах), то каждый все равно будет обращаться на origin, но уже не каждая edge-нода!

Мы это использовали для определенного типа трафика, при котором origin-серверов было минимальное количество, была опасность их «положить».

🎤 Буднисетевика 😊 #Задача


В этом посте были ссылки, но мы их удалили по правилам Сетки