Легитимный трафик в сети DDoS-Guard недавно превысил сотню гигабит в секунду. Сейчас 50% всего нашего трафика генерируют веб-сервисы клиентов. Это многие десятки тысяч доменов, очень разных и в большинстве случаев требующих индивидуального подхода.


Под катом — как мы управляем фронт-нодами и выдаем SSL-сертификаты для сотен тысяч сайтов.




Настроить фронт для одного сайта, пусть даже очень большого, — это просто. Берём nginx или haproxy или lighttpd, настраиваем по гайдам и забываем. Если надо что-то поменять — делаем reload и опять забываем.


Всё меняется, когда вы на лету обрабатываете большие объемы трафика, оцениваете легитимность запросов, сжимаете и кэшируете пользовательский контент, и при этом изменяете параметры несколько раз в секунду. Пользователь хочет видеть результат на всех внешних нодах сразу после того, как он поменял настройки в личном кабинете. А еще пользователь может загрузить по API несколько тысяч (а иногда и десятков тысяч) доменов с индивидуальными параметрами обработки трафика. Все это тоже должно заработать сразу и в Америке, и в Европе, и в Азии — задача не самая тривиальная, учитывая, что в одной только Москве несколько физически разнесенных узлов фильтрации.


Зачем много больших надежных узлов по всему миру?


  • Качество обслуживания клиентского трафика — запросы из США нужно обрабатывать именно в США (в том числе на предмет атак, парсинга и прочих аномалий), а не тянуть в Москву или Европу, непредсказуемо увеличивая задержку обработки.

  • Атакующий трафик надо локализовывать — транзитные операторы могут деградировать во время атак, объем которых часто превышает 1Тbps. Транспортировать атакующий трафик по трансатлантическим или трансазиатским линкам — не лучшая идея. У нас были реальные кейсы, когда Tier-1 операторы говорили: «Объемы атак, которые вы принимаете, для нас опасны». Именно поэтому мы принимаем входящие потоки как можно ближе к их источникам.

  • Жесткие требования непрерывности обслуживания — центры очистки не должны зависеть ни друг от друга, ни от локальных событий нашего стремительно меняющегося мира. Обесточили на неделю все 11 этажей ММТС-9? — не беда. Не пострадает ни один клиент, не имеющий физического включения именно в этой локации, а веб-сервисы не пострадают ни при каких обстоятельствах.


Как всем этим управлять?


Конфигурации сервисов должны как можно быстрее (в идеале мгновенно) распространяться на всех фронт-нодах. Нельзя просто брать и перестраивать текстовые конфиги и делать перезагрузки демонов на каждом изменении — тот же nginx держит завершающиеся процессы (worker shutting down) еще несколько минут (а может и часов если там долгие websocket-сессии).


При перезагрузке конфигурации nginx вполне нормальна следующая картина:



По утилизации памяти:



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


Почему это не было проблемой, когда nginx только начинал развиваться? Не было ни HTTP/2, ни WebSocket, ни массовых длинных keep-alive соединений. 70% нашего веб-трафика — HTTP/2, а это очень долгие соединения.


Решение простое — не использовать nginx, не управлять фронтами на основе текстовых файлов, и уж точно не гонять зипованные текстовые конфигурации по транстихоокеанским каналам. Каналы, конечно, гарантированные и резервированные, но от этого не менее трансконтинентальные.


У нас собственный фронт-сервер-балансер, о внутренностях которого я расскажу в следующих статьях. Главное, что он умеет — применять тысячи изменений конфигураций в секунду на лету, без рестартов, релоадов, скачкообразного роста потребления памяти и вот этого всего. Это очень похоже на Hot Code Reload, например в Erlang. Данные хранятся в геораспределенной key-value базе и вычитываются сразу исполнительными механизмами фронтов. Т.е. вы загрузили SSL-сертификат через веб-интерфейс или API в Москве, а через несколько секунд он уже готов к работе в нашем центре очистки в Лос-Анжелесе. Если вдруг случится мировая война, и пропадет интернет во всем мире, наши ноды продолжат работать автономно и починят split-brain, как только станет доступен один из выделенных каналов Лос-Анжелес-Амстердам-Москва, Москва-Амстердам-Гон-Конг-Лос-Анжелес или хотя бы один из резервных оверлейных GRE.


Этот же механизм позволяет нам мгновенно выпускать и продлевать сертификаты Let's Encrypt. Очень упрощенно это работает так:


  1. Как только мы видим хотя бы один HTTPS-запрос для домена нашего клиента без сертификата (или с просроченным сертификатом), внешняя нода, принявшая запрос, сообщает об этом внутреннему центру сертификации.

  2. Если пользователь не запретил выдачу Let's Encrypt, центр сертификации формирует CSR, получает у LE токен подтверждения и рассылает его на все фронты по шифрованному каналу. Теперь любая нода может подтвердить валидирующий запрос от LE.


  3. Через несколько мгновений мы получим корректный сертификат и приватный ключ и точно так же разошлем фронтам. Опять же без перезагрузки демонов


  4. За 7 дней до даты экспирации инициируется процедура переполучения сертификата


Прямо сейчас мы в реалтайме ротируем 350к сертификатов совершенно прозрачно для пользователей.


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