Задача: настроить шилдинг в 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-серверов было минимальное количество, была опасность их «положить».
🎤 Буднисетевика 😊 #Задача
В этом посте были ссылки, но мы их удалили по правилам Сетки