Проксирование запросов что это

Проксирование запросов что это

В этой мы рассмотрим возможности сервера NGINX в http проксировании, что помогает перенаправлять запросы на бекэнд сервера для дальнейшей обработки. Довольно часто Nginx настраивают в качестве реверсивного прокси для упрощения масштабирования инфраструктуры или для перенапраления запросов на сервера, которые не предназначены для работы при большой нагрузке.

Также мы затронем каким образом можно осуществить масштабирование при помощи встроенных в Nginx средствах балансировки и каким образом буферизация и кеширование помогут вам улучшить работоспособность прокси.

Общая информация по прокси

Если раньше вы сталкивались только с простыми односерверными настройками, то наверняка у вас возникает вопрос: «А зачем вообще перенаправлять запросы?».

Одна из основных причин — масштабирование инфраструктуры. Изначально Nginx был создан с возможностью обрабатывать множество одновременных соединений. Таким образом он способен перенаправлять запрос какому угодно количеству бекэнд-серверов, что позволяет вам распределить нагрузку. Также архитектура сервера помогает вам легко добавлять новые или отключать старые бекэнд-сервера.

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

Проксирование в Nginx работает путем изменения полученного запроса и передачи его серверам, отвечающим за его обработку. Результат отправляется обратно Nginx, который в свою очередь отвечает клиенту. В роли тех самых «других» серверов могут выступать удаленные или локальные машины, а иногда очередные виртуальные сервера, созданные в пределах Nginx. Сервера, на которые nginx перенаправляет запросы называются вышестоящими серверами ( upstream servers ).

Nginx способен перенаправлять запросы используя http(s), FastCGI, uwsgi или memcached протоколы посредством различных наборов директив для каждого типа прокси. В этой статье мы остановимся на протоколе http. Nginx отвечает за передачу запроса в таком виде, в котором вышестоящий сервер способен его понять.

Разбираем базовый проход через http прокси

Давайте взглянем на пример:

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

Приведем другой пример:

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

Разбираемся как Nginx обрабатывает заголовки

Стоит понимать, что одного только URI не достаточно, чтобы вышестоящий сервер корректно обработал запрос. Перенаправленный nginx запрос будет немного видоизменен. Больше всего будут затронуты заголовки запроса.

При передаче запроса Nginx вносит необходимые изменения в заголовки:

Nginx убирает все пустые заголовки. Нет никакого смысла загружать сервер пустыми заголовками.

Часто используемые значения заголовка host:

Установка или переназначение заголовков

Конечно, есть смысл перенести директиву proxy_set_header в раздел серверного или http контекста, чтобы можно было ссылаться на неё из разных мест настройки.

Определение вышестоящего контекста для балансировки прокси соединений

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

Эту возможность можно использовать при помощи директивы upstream задав ей список доступных серверов. Такая настройка подразумевает, что каждый сервер из этого списка способен полностью ответить на поступивший к нему запрос. То есть мы можем легко масштабировать свою инфраструктуру без лишних проблем. Директива upstream должна быть указана в контексте http настройки nginx сервера.

Разберем простой пример:

Изменение алгоритма балансировки

Изменить алгоритм в пределах пула серверов можно при задании определенных флагов и директив:

При изменении алгоритма балансировки блок настройки принимает следующий вид:

Указание весов серверов при балансировки

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

В этом примере сервер host1.example.com будет получать в три раза больше запросов, чем два других сервера. По-умолчанию значение веса для каждого сервера устанавливается в единицу.

Использованию буферов для освобождения бекэнд серверов

Главный вопрос при проксировании это насколько изменится скорость работы при добавлении дополнительного сервера. Переход на большее или меньшее количество серверов может быть значительно смягчен при помощи системы буферизации и кеширования nginx.

При передачи запроса серверу следует учитывать скорость обоих соединений:

соединение клиент — nginx сервер соединение nginx сервер — бекэнд сервер

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

Без использования буферов данные поступившие от прокси сервера сразу же возвращаются клиенту. Если вы отталкиваетесь от того, что клиентское соединение достаточно быстрое, то буферизацию можно отключить. При использовании буферов Nginx какое-то время хранит ответ полученный от бекэнд сервера и потом отправляет его клиенту. Если клиент не достаточно быстр, то nginx закрывает соединение с бекэнд-сервером как можно быстрее, а данные отправляет клиенту как только тот будет готов их принять.

proxy_busy_buffer_size : эта директива указывает максимально возможное количество занятых буферов. Хотя клиент может читать информацию только из одного буфера за подход, буферы образуют очередь для отправки данных клиентам. Таким образом она указывает на объем информации в буфере, которая имеет такое состояние.

proxy_max_temp_file_size : максимальный размер временного файла на диске на каждый запрос. Они создаются в случае, если ответ бекэнд сервера не помещается в один буфер. proxy_temp_file_write_size : максимально возможный объем информации, которая записывается за один подход в файл, если ответ сервера не помещается в буфер. proxy_temp_path : путь к месту на диске, где Nginx разрешается хранить временные файлы, если ответ не умещается в буфер.

Настройка прокси кеширования для уменьшения времени ответа

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

Настройка прокси кеша

В следующем примере мы выполним необходимые настройки для поднятия системы кеширования:

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

Директива proxy_chache_key задает ключ для хранения кешированных значений. Он же применяется при поиске данных в кеше. Мы используем комбинацию из схемы соединения, метода, хоста и URI.

Директива proxy_cache_valid может быть указана несколько раз. Она указывает срок хранения данных в зависимости от кода ответа. В нашем примере мы храним данные в течение 10 минут для удачных и перенаправленных ответов и всего лишь одну минуту для ответов со статусом 404.

Итак мы настроили зону кеширования, но не указали Nginx, когда именно применять кеширование.

Эта информация указывается в контексте location для бекэнд серверов:

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

Нюансы кешированных ответов

Кеширование значительно повышает скорость работы вашего прокси-сервера. Но не стоит забывать о нескольких моментах.

No-cache : указывает, что ответ не должен отправляться до тех пор, пока сервер не проверит не изменились ли данные на бекэнд-сервере. Такое значение используется при работе с динамическими данными. Хешированные метаданные заголовка Etag проверяются при каждом запросе. Если бекэнд отдает такие же значения, то тогда данные отправляются из кеша.

No-store : в этом случае ни при каких условиях данные не должны храниться в кеше. Такой подход является самым безопасным при работе с личными данными.

private : данные не должны кешироваться в общем пространстве кеша. При таком подходе, например, браузер пользователя может кешировать данные в то время как, прокси сервер нет.

Public : данные разрешается кешировать везде.

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

Источник

Проксируем и спасаем

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

В данном пособии мы узнаем как быстро и просто сделать рабочее зеркало любого сайта, что позволяет сменить IP и назначить любое доменное имя. Мы даже попробуем спрятать домен в url, после чего можно сохранить локально полную копию сайта. Все упражнения можно сделать на любом виртуальном сервере — лично я использую хостинг Хетцнер и OS Debian. И конечно мы будем использовать лучший веб-сервер всех времен и народов — NGINX!

К этому абзацу пытливый читатель уже приобрел и настроил какой нибудь выделенный сервер или просто запустил Linux на старом компьютере под столом, а так же запустил Nginx последней версии со страничкой «Save me now».

Перед началом работы необходимо скомпилировать nginx c модулем ngx_http_substitutions_filter_module, прежнее название — substitutions4nginx.

Дальнейшая конфигурация будет показана на примере сайта www.6pm.com. Это сайт популярного онлайн магазина, торгующего товарами с хорошими скидками. Он отличается категорическим нежеланием давать доступ покупателям из России. Ну чем не оскал цензуры капитализма?

У нас уже есть работающий Nginx, который занимается полезными делом — крутит сайт на системе Livestreet о преимуществах зарубежного шоппинга. Чтобы поднять зеркало 6pm прописываем DNS запись с именем 6pm.pokupki-usa.ru который адресует на IP сервера. Как вы понимаете, выбор имени для суб-домена совершенно произволен. Это имя будет устанавливаться в поле HOST при каждом обращении к нашему новому ресурсу, благодаря чему на Nginx можно будет запустить виртуальный хостинг.

В корневой секции конфигурации nginx прописываем upstream — имя сайта-донора, так будем его называть в дальнейшем. В стандартных гайдах сайт обычно называется back-end, а reverse-proxy называется front-end.

Дальше нужно создать секцию server, вот как она выглядит

Стандартные директивы listen и server определяют имя виртуального хоста, при обращении к которому будет срабатывать секция server. Файлы логов лучше сделать отдельными.

$uri — переменная nginx, которая содержит путь из HTTP запроса

Префикс “@” задаёт именованный location. Такой location не используется при обычной обработке запросов, а предназначен только для перенаправления в него запросов. Такие location’ы не могут быть вложенными и не могут содержать вложенные location’ы

В нашем случае конструкция используется только для подмены файла robots.txt, чтобы запретить индексацию содержимого сайта. Однако таким образом делается зеркалирование и кеширование в nginx.

include ‘6pm.conf’ — логика модуля substitutions.

proxy_cookie_domain — новая функция, которая появилась в nginx версии 1.1.15, без этой директивы приходилось делать так. Больше не нужно ломать голову, прописываете одну строчку и куки просто начинают работать.

proxy_set_header Accept-Encoding «»; — очень важная команда, которая заставляет сайт донор отдавать вам контент не в сжатом виде, иначе модуль substitutions не сможет выполнить замены.

proxy_set_header Host — еще одна важная команда, которая в запросе к сайту донору выставляет правильное поле HOST. Без нее будет подставляться имя нашего прокси сервера и запрос будет ошибочным.
proxy_pass — прямая адресация не работает в именованном локейшине, именно поэтому мы прописали адрес сайта донора в директиве upstream.
proxy_redirect — многие сайты используют редиректы для своих нужд, каждый редирект нужно отловить и перехватить здесь, иначе запрос и клиент уйдет за пределы нашего уютного доменчика.

Теперь посмотрим содержимое 6pm.conf. Я не случайно вынес логику трансформации в отдельный файл. В нем можно разместить без какой либо потери производительности тысячи правил замены и сотни килобайт фильтров. В нашем случае мы хотим лишь завершить процесс проксирования, поэтому файл содержит всего 5 строк:

Меняем коды google analytics:

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

Меняем все прямые ссылки на новые.

Как правило, в нормальных сайтах все картинки лежат на CDN сетях, которые не утруждают себя проверкой источника запросов, поэтому достаточно замены ссылок только основного домена. В нашем случае 6pm выпендрился и разместил часть картинок на доменах, которые отказывают посетителям из России. К счастью, модуль замены поддерживает регулярные выражения и не составляет никакого труда написать общее правило для группы ссылок. В нашем случае обошлось даже без regexp, просто поменяли два символа в домене. Получилось так:

Единственное, но очень серьезное ограничение модуля замены — он работает только с одной строкой. Это ограничение заложено архитектурно, поскольку модуль работает на этапе, когда страница загружена частично (chunked transfer encoding) и нет никакой возможности выполнить полнотекстовый regexp.

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

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

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

Вернемся к нашему пациенту:

Конфигурация сервера претерпела некоторые изменения.

Во-первых, вся логика перенесена из директивы sever напрямую в location. Нетрудно догадаться, что мы решили создать директорию /6pm в которую будем выводить проксируемый сайт.

proxy_cookie_path / /6pm/ — переносим куки из корня сайта в поддиректорию. Это делать не обязательно, но в случае если проксируемых сайтов окажется много, их куки могут пересечься и затереть друг друга.

rewrite ^/6pm/(.*) /$1 break; — эта магия вырезает из клиентского запроса поддиректорию, которую мы добавили, в результате директива proxy_pass отправляет на сервер-донор корректное значение.

Чуть сложнее стало ловить редиректы. Теперь все ссылки на корень нужно перебросить на /6pm.

Посмотрим на логику трансформации:

Во-первых, мы включили фильтрацию файлов css и javascript (парсинг html включен по-умолчанию)
Во-вторых, начинаем аккуратно находить и заменять разные типы ссылок относительно корня. Нам попался средней сложности сайт, в котором часть скриптов содержат такие пути.

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

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

Источник

Введение в современную сетевую балансировку и проксирование

Проксирование запросов что это

Недавно я осознал нехватку вводных обучающих материалов о современной сетевой балансировке и проксировании. Я подумал: «Почему так? Балансировка нагрузки — одна из ключевых концепций для построения надёжных распределённых систем. Ведь должна быть доступна качественная информация об этом?» Я поискал и обнаружил, что информации мало. Статьи в Википедии о балансировке и прокси-серверах содержат обзоры некоторых концепций, но не могут похвастаться последовательным описанием предмета, особенно в том, что касается современных микросервисных архитектур. Поиск в Google информации о балансировке в основном возвращает сайты вендоров, заполненные модными терминами и скупые на подробности.

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

Что такое сетевая балансировка и проксирование?

Википедия определяет балансировку нагрузки так:

В вычислительной технике балансировка нагрузки улучшает распределение рабочих нагрузок по нескольким вычислительным ресурсам: компьютерам, компьютерным кластерам, сетевым подключениям, центральным процессорам или дисковым устройствам. Балансировка нагрузки призвана оптимизировать использование ресурсов, максимально увеличить пропускную способность, минимизировать время отклика и избежать перегрузки отдельных ресурсов. Применение вместо одного компонента нескольких компонентов с балансировкой может повысить надёжность и доступность благодаря получившемуся запасу мощностей. Балансировка нагрузки обычно подразумевает использование специального ПО или оборудования вроде многоуровневого коммутатора или DNS-сервера.

Это определение применимо ко всем аспектам обработки данных, а не только к работе с сетью. Операционные системы используют балансировку для диспетчеризации задач среди нескольких физических процессоров. Контейнерные оркестраторы вроде Kubernetes используют балансировку для диспетчеризации задач среди нескольких вычислительных кластеров. А сетевые балансировщики распределяют сетевые задачи среди доступных бэкендов. Эта статья посвящена только сетевой балансировке.

Проксирование запросов что это
Иллюстрация 1: сетевая балансировка

На иллюстрации 1 показана упрощённая схема сетевой балансировки. Некоторые клиенты запрашивают ресурсы с некоторых бэкендов. Балансировщик находится между клиентами и бэкендами и выполняет несколько важных задач:

Правильное использование балансировки в распределённой системе даёт несколько преимуществ:

Балансировщик или прокси?

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

L4 (подключения/сессии)-балансировка

Современные балансировочные решения по большей части можно разделить на две категории: L4 и 7. Они относятся к уровню 4 и уровню 7 модели OSI. По причинам, которые станут очевидны в ходе обсуждения L7-балансировки, выбор этих терминов я считаю неудачным. Модель OSI очень слабо отражает сложность балансировочных решений, включающих в себя не только традиционные протоколы четвёртого уровня, такие как TCP и UDP, но зачастую и элементы протоколов других уровней OSI. Например, если L4 TCP-балансировщик предлагает ещё и TLS-прерывание, то он теперь L7-балансировщик?

Проксирование запросов что это
Иллюстрация 2: прерывающий L4 TCP-балансировщик

Иллюстрация 2 отражает традиционный L4 TCP-балансировщик. В данном случае клиент создаёт TCP-подключение к балансировщику, тот прерывает подключение (т. е. отвечает напрямую SYN), выбирает бэкенд и создаёт новое подключение к этому бэкенду (т. е. отправляет данные новому SYN). Подробности схемы сейчас не так важны, мы обсудим их в разделе, посвящённому L4-балансировке.

Ключевая мысль — L4-балансировщик обычно оперирует только на уровне L4 TCP/UDP-подключений/сессий. Следовательно, балансировщик перемещает байты так, чтобы байты из одной сессии приходили на один бэкенд. Такому балансировщику неважны особенности приложений, чьими байтами он манипулирует. Это могут быть байты HTTP, Redis, MongoDB или любого иного протокола приложений.

L7 (приложения)-балансировка

L4-балансировка проста и широко применяется. Какие же её особенности заставляют вкладываться в L7-балансировку на уровне приложений? Рассмотрим в качестве примера конкретный случай L4:

Если бэкенд решает обрабатывать трафик клиента А, то он будет обрабатывать нагрузку примерно в 3000 раз меньше, чем если бы обрабатывал трафик клиента Б! Это большая проблема, из-за которой в первую очередь теряется смысл балансировки. Также обратите внимание, что проблема действительна для любого протокола мультиплексирования, поддерживающего постоянные подключения (keep-alive) (мультиплексирование — это отправка конкурентных запросов приложений через одно L4-соединение, а keep-alive — это сохранение подключения в отсутствие активных запросов). Все современные протоколы одновременно и мультиплексирующие, и поддерживающие постоянные подключения, этого требуют соображения эффективности (в целом создавать подключение дорого, особенно если оно шифруется с помощью TLS), так что рассогласование нагрузки в L4-балансировщике со временем усиливается. Эта проблема решается с помощью L7-балансировщика.

Проксирование запросов что это
Иллюстрация 3: прерывающий L7 HTTP/2-балансировщик

На иллюстрации 3 показан L7 HTTP/2-балансировщик. В этом случае клиент создаёт одно HTTP/2 TCP- подключение к балансировщику, который затем создаёт два подключения к бэкендам. Когда клиент отправляет в балансировщик два HTTP/2-потока, первый поток уходит в бэкенд 1, а второй — в бэкенд 2. Так что даже мультиплексируемые клиенты с очень разными трафиками по запросам будут эффективно сбалансированы по бэкендам. Поэтому L7-балансировка так важна для современных протоколов (у неё есть ещё куча преимуществ благодаря возможности инспектировать трафик приложений, но об этом мы поговорим ниже).

L7-балансировка и модель OSI

Как уже говорилось выше, проблематично использовать модель OSI для описания свойств балансировки. Причина в том, что L7, как минимум согласно модели OSI, сама по себе охватывает несколько дискретных уровней абстракции балансировки. Например, для HTTP-трафика есть несколько подуровней:

Сложный L7-балансировщик работает со всеми этими подуровнями. Более простой L7-балансировщик может обладать лишь небольшим набором свойств, по которым его относят к L7. Иными словами, свойства L7-балансировщиков варьируются гораздо шире, чем в категории L4. И конечно, здесь мы коснулись лишь HTTP, но Redis, Kafka, MongoDB и другие — всё это примеры L7-протоколов приложений, выигрывающих от использования L7-балансировки.

Свойства балансировщика

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

Определение сервисов

Определение сервисов — это способ определения балансировщиком набора доступных бэкендов. Делать это можно по-разному, например с помощью:

Проверка состояния

Это определение, может ли бэкенд обрабатывать трафик. Проверка состояния бывает:

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

Да, балансировщики должны ещё балансировать нагрузку! Как будет выбираться бэкенд для обработки конкретного подключения или запроса при наличии рабочих бэкендов? Алгоритмы балансировки — это область активных исследований; они варьируются от таких простых, как случайный выбор и round-robin, до более сложных, учитывающих различия в задержках и нагрузках на бэкенды. Один из самых популярных алгоритмов благодаря производительности и простоте — power of 2.

Sticky-сессии

Для определённых приложений важно, чтобы запросы из одной сессии попадали на один и тот же бэкенд. Это связано с кешированием, временным сложным состоянием и прочими вещами. Есть разные определения термина «сессия», она может включать в себя HTTP-куки, свойства клиентского подключения и прочие атрибуты. Многие L7-балансировщики поддерживают sticky-сессии. Отмечу, что «липкость» сессии по своей сути хрупка (бэкенд, хостящий сессию, может умереть), так что держите ухо востро, проектируя систему, полагающуюся на sticky-сессии.

TLS-прерывание

Тема TLS и его роли в обработке и обеспечении безопасности межсервисного взаимодействия заслуживает отдельной статьи. Многие L7-балансировщики выполняют большой объём TLS-обработки, включая прерывания, проверку и закрепление сертификатов, обслуживание сертификатов с помощью SNI и т. д.

Наблюдаемость

Как я люблю повторять: «Наблюдаемость, наблюдаемость, наблюдаемость». Сети априори ненадёжны, и балансировщик часто отвечает за экспортирование статистики, отслеживание и журналирование: он помогает оператору понять, что происходит, и устранить проблему. У балансировщиков бывают самые разные возможности предоставления результатов наблюдения за системой. Самые продвинутые предоставляют обширные данные, включая числовую статистику, распределённую трассировку и настраиваемое журналирование. Отмечу, что продвинутая наблюдаемость достаётся не бесплатно: балансировщикам приходится выполнять дополнительную работу. Однако выгода от получаемых данных намного перевешивает относительно небольшое снижение производительности.

Безопасность и уменьшение последствий DoS

Балансировщики часто реализуют различные функции безопасности, особенно в краевой топологии развёртывания (см. ниже), включая ограничение скорости, аутентификацию и уменьшение последствий DoS (например, маркирование и идентификацию IP-адресов, tarpitting и пр.).

Конфигурация и уровень управления

Балансировщики нужно конфигурировать. В больших развёртываниях это превращается в важную обязанность. Система, конфигурирующая балансировщики, называется уровнем управления (control plane), её можно реализовать по-разному. За подробностями обращайтесь к статье.

И многое другое

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

Виды топологий балансировщиков

Теперь перейдём к топологиям распределённых систем, в которых развёртываются балансировщики. Каждая топология применима и к L4, и к L7.

Промежуточный прокси

Проксирование запросов что это
Иллюстрация 4: топология балансировщика с промежуточным прокси

Топология с промежуточным прокси, показанная на иллюстрации 4, — один из самых известных способов балансировки. К таким балансировщикам относятся аппаратные решения Cisco, Juniper, F5 и др.; облачные программные решения вроде Amazon ALB и NLB, Google Cloud Load Balancer; чисто программные автономные решения вроде HAProxy, NGINX и Envoy. Преимущество схемы с промежуточным прокси заключается в простоте. Пользователи подключаются к балансировщику через DNS и больше ни о чём не беспокоятся. А недостаток схемы в том, что прокси (даже кластеризованный) — это единая точка отказа, а также узкое место при масштабировании. Кроме того, промежуточный прокси часто бывает чёрным ящиком, что затрудняет оперирование. Проблема возникла на клиенте? В физической сети? В самом прокси? В бэкенде? Иногда очень трудно определить.

Оконечный прокси

Проксирование запросов что это
Иллюстрация 5: топология балансировщика с оконечным прокси

Топология на иллюстрации 5 — вариант топологии с промежуточным прокси, в которой балансировщик доступен через интернет. А в данном случае балансировщик обычно предоставляет дополнительные возможности «API-шлюза» вроде TLS-прерываний, ограничения скорости, аутентификации и продвинутой маршрутизации трафика. Преимущества и недостатки такие же, как у предыдущей топологии. Обычно невозможно избежать использования топологии с оконечным прокси в больших, открытых в интернет распределённых системах. Как правило, клиентам нужен доступ к системе по DNS с использованием различных сетевых библиотек, не контролируемых владельцем сервиса (нецелесообразно использовать прямо на клиентах встроенные клиентские библиотеки или топологии с побочным прокси, описанные в следующих разделах). Кроме того, по соображениям безопасности лучше иметь единый шлюз, через который в систему поступает весь интернет-трафик.

Встроенная клиентская библиотека

Проксирование запросов что это
Иллюстрация 6: балансировка через встроенную клиентскую библиотеку

Чтобы избежать единой точки отказа или проблем с масштабированием, свойственных топологиям с промежуточным прокси, в более сложных инфраструктурах применяется встраивание балансировщика посредством библиотеки прямо в сервисы, как показано на иллюстрации 6. Библиотеки поддерживают разные функции, самые известные и продвинутые решения — Finagle, Eureka/Ribbon/Hystrix и gRPC (основанный на внутренней системе Google под названием Stubby). Главное преимущество решения на основе библиотеки в том, что функциональность балансировщика полностью распределяется по всем клиентам, а значит, единой точки отказа и трудностей масштабирования нет. Основной недостаток — библиотека должна быть реализована на каждом языке, используемом организацией. Распределённые архитектуры становятся настоящими полиглотами (многоязычными). В такой среде главное препятствие — стоимость реализации крайне сложной сетевой библиотеки на многих языках. Наконец, развёртывание обновления библиотеки в архитектуре большого сервиса превращается в огромную головную боль, и в результате в продакшен обычно работает куча разных версий библиотеки, что повышает операционную когнитивную нагрузку.

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

Побочный прокси

Проксирование запросов что это
Иллюстрация 7: балансировка через побочный прокси

Топология с побочным прокси — вариант топологии со встроенной клиентской библиотекой. В последние годы эта топология была популяризирована в качестве service mesh. Идея в том, что можно получить все преимущества варианта со встроенной библиотекой без заморочек с языками программирования, но за счёт небольшого увеличения задержки при переходе к другому процессу. Сегодня самые популярные балансировщики с побочным прокси — это Envoy, NGINX, HAProxy, и Linkerd. Почитать подробнее о подходе можно в моей статье об Envoy, а также в статье об уровне данных service mesh и уровне управления.

Преимущества и недостатки разных топологий

Я считаю, что топология с побочным прокси (service mesh) в межсервисном взаимодействии постепенно сменит все остальные топологии. Схема с оконечным прокси всегда будет нужна до того, как трафик попадёт в service mesh.

Текущие достижения в L4-балансировке

L4-балансировщики всё ещё актуальны?

Мы уже говорили о преимуществах L7-балансировщиков для современных протоколов, а ниже обсудим их возможности подробнее. Означает ли это, что L4-балансировщики больше не актуальны? Нет! Хотя я считаю, что L7-балансировщики полностью заменят L4 в межсервисном взаимодействии, однако L4-балансировщики всё ещё очень актуальны на концах сети, потому что почти все современные большие распределённые архитектуры используют для интернет-трафика двухуровневую архитектуру L4/L7-балансировки. Вот преимущества размещения выделенных L4-балансировщиков перед L7-балансировщиками на концах:

Дальше я опишу несколько разных схем L4-балансировщиков с промежуточным/оконечным прокси. Эти схемы неприменимы для топологий с клиентской библиотекой и побочным прокси.

Прерывающие TCP/UDP-балансировщики

Проксирование запросов что это
Иллюстрация 8: прерывающий L4-балансировщик

Первый тип L4-балансировщиков, всё ещё используемый. Это тот же балансировщик, что и в ознакомительном разделе об L4-балансировщиках. Здесь два отдельных TCP-подключения: одно между клиентом и балансировщиком, второе между балансировщиком и бэкендом.

Прерывающие L4-балансировщики всё ещё используются по двум причинам:

Балансировщики с TCP/UDP-транзитом

Проксирование запросов что это
Иллюстрация 9: транзитный L4-балансировщик

Второй тип L4-балансировщика — транзитный — показан на иллюстрации 9. Здесь TCP-подключение балансировщиком не прерывается. Вместо этого после отслеживания подключения и преобразования сетевых адресов (NAT) пакеты для каждого подключения направляются на выбранный бэкенд. Сначала давайте определимся с отслеживанием подключения и NAT:

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

Прямой возврат с сервера (DSR)

Проксирование запросов что это
Иллюстрация 10: L4 прямой возврат с сервера (DSR)

На иллюстрации 10 показан балансировщик с прямым возвратом с сервера. Он создаётся на базе транзитного балансировщика. По сути, DSR — это оптимизация, при которой входящие пакеты запросов проходят через балансировщик, а исходящие пакеты ответов обходят его и идут прямо к клиенту. Выгода от использования DSR в том, что при многих видах нагрузок трафик ответов многократно больше трафика запросов (например, это характерно для HTTP-запросов/ответов). Допустим, 10 % трафика — это запросы, а остальные 90 % — ответы, и тогда при использовании DSR будет достаточно балансировщика с производительностью в 1/10 пропускной способности системы. Поскольку балансировщики исторически очень дороги, такая оптимизация сильно снижает стоимость системы и повышает надёжность. DSR-балансировщики — развитие концепции транзитного балансировщика:

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

Устойчивость к сбоям благодаря высокодоступным парам (high availability pairs)

Проксирование запросов что это
Иллюстрация 11: L4 устойчивость к сбоям благодаря HA-парам и отслеживанию подключений

Пока что мы рассматривали схему L4-балансировщиков без учёта окружения. Транзитному и DSR-балансировщику необходимо какое-то количество данных отслеживания подключений и состояний. А что, если балансировщик умирает? Если он был один, то все подключения, шедшие через него, оборвутся. В зависимости от ситуации это может сильно повлиять на производительность приложения.

Исторически сложилось, что L4-балансировщики представляли собой аппаратные решения разных производителей (Cisco, Juniper, F5 и пр.). Эти устройства очень дороги и обрабатывают большой объём трафика. Чтобы избежать обрыва всех подключений из-за сбоя единственного балансировщика, обычно делают два балансировщика, объединяя их в высокодоступные пары, как показано на иллюстрации 11. Схема типичной HA-пары устроена так:

Эта схема сегодня используется во многих интернет-приложениях с высоким трафиком. Но у неё есть несколько значительных недостатков:

Устойчивость к сбоям и масштабирование с помощью кластеров с распределённым консистентным хешированием

Проксирование запросов что это
Иллюстрация 12: L4 устойчивость к сбоям и масштабирование с помощью кластеров с распределённым консистентным хешированием

С середины 2000-х в больших интернет-инфраструктурах начали внедрять новые, сильно распараллеленные L4 балансировочные системы, как на иллюстрации 12. Их задачами были:

Такую схему можно описать как устойчивую к сбоям и масштабируемую с помощью кластеризации и распределённого консистентного хеширования. Работает она так:

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

Когда заходит речь об этой схеме, то обычно спрашивают: «Почему оконечные роутеры не общаются напрямую с бэкендами через ECMP? Зачем нам вообще нужны балансировщики?» В основном причина в защите от DoS и простоте работы с бэкендами. Без балансировщиков каждый бэкенд вынужден использовать BGP, и к тому же было бы гораздо сложнее проводить развёртывание.

Сегодня все системы L4-балансировки перенимают эту схему (или один из её вариантов). Два самых известных примера — Google Maglev и Amazon Network Load Balancer (NLB). Пока не существует OSS-балансировщика, использующего эту схему, но я знаю, что одна компания планирует выпустить такой в 2018-м. Жду с нетерпением, потому что современный L4-балансировщик — важная часть отсутствующего OSS при работе с сетью.

Текущие достижения в L7-балансировке

Прокси-войны — это практически буквально прокси-войны. Или «войны прокси». Nginx плюс, HAProxy, linkerd, Envoy, все буквально сражаются с этим. И proxy-as-a-service/routing-as-a-service SaaS-вендоры тоже повышают планку. Очень интересные времена!
— @copyconstruct

И действительно, в последние годы мы наблюдали возрождение разработки L7-балансировщиков/прокси. Это очень хорошо согласуется с движением в сторону микросервисных архитектур в распределённых системах. Эффективно управлять сетями, склонными по своей природе к сбоям, становится тем труднее, чем чаще они используются. Более того, расцвет автомасштабирования, контейнерных диспетчеров и прочих инструментов означает, что времена предоставления статичных IP в статичных файлах давно прошли. Системы не только активнее используют сети, они становятся гораздо динамичнее, требуют от балансировщиков больше функций. В этой части мы кратко рассмотрим направления, которым уделяется больше всего внимания при разработке современных L7-балансировщиков.

Поддержка протоколов

Современные L7-балансировщики привносят явную поддержку многочисленных протоколов. Чем больше балансировщик знает о трафике приложения, тем более сложные действия он может с ним выполнять, опираясь на данные наблюдений, продвинутую балансировку и маршрутизацию и т. п. Например, Envoy явно поддерживает парсинг L7-протоколов и маршрутизацию для HTTP/1, HTTP2, gRPC, Redis, MongoDB и DynamoDB. И в будущем наверняка будут добавляться новые протоколы, включая MySQL и Kafka.

Динамическая конфигурация

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

Продвинутая балансировка

L7-балансировщики сегодня часто имеют встроенные возможности продвинутой балансировки, такие как таймауты, повторные попытки, ограничение скорости, разрыв цепи (circuit breaking), теневое копирование (shadowing), буферизация, маршрутизация в зависимости от содержимого и др.

Наблюдаемость

Развёртываемые сегодня всё более динамические системы становится всё труднее отлаживать. Пожалуй, самая важная функция современных L7-балансировщиков — предоставление надёжных данных наблюдений, характерных для конкретных протоколов. Численная статистика, распределённые трейсы и настраиваемое журналирование сегодня нужны практически любому решению по L7-балансировке.

Расширяемость

Пользователям современных L7-балансировщиков часто нужна возможность легко их расширять и добавлять свою функциональность. Это делается с помощью написания подключаемых фильтров, которые загружаются в балансировщик. Также многие балансировщики поддерживают скрипты, обычно Lua.

Устойчивость к сбоям

Я довольно много написал выше об устойчивости L4-балансировщиков к сбоям. А что насчёт L7-балансировщиков? В целом с ними можно работать как с расширяемыми и не хранящими состояние (stateless). Можно легко горизонтально масштабировать L7-балансировщики с помощью обычного ПО. Более того, обработка и отслеживание состояний, выполняемые L7-балансировщиками, гораздо сложнее, чем это делают L4. Создание высокодоступной пары L7 теоретически возможно, но очень трудоёмко.

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

И прочее

L7-балансировщики развиваются ошеломляюще быстро. Например, вот что предлагает Envoy.

Глобальная балансировка и централизованный уровень управления

Проксирование запросов что это
Иллюстрация 13: глобальная балансировка

В будущем всё больше станут использовать отдельные балансировщики в виде типовых устройств. Я считаю, что все реальные инновации и коммерческие возможности связаны с управлением. На иллюстрации 13 приведён пример системы глобальной балансировки. Здесь происходит несколько важных событий:

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

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

Эволюция от аппаратных до программных решений

Пока что я лишь мельком сравнивал аппаратные и программные решения, в основном в контексте высокодоступной пары L4-балансировщиков. Каковы тенденции в этой сфере?

Я пробовал новый OSI-стек из восьми программных уровней. Думаю, это что-то подобное:
Проксирование запросов что это
— @infosecdad

Конечно, это юмористическое преувеличение, но в этом сообщении как раз и собраны современные тенденции:

Заключение и будущее балансировки

Я считаю, что мы живём в очень увлекательное для сетевой индустрии время! Переход к OSS и программным решениям в большинстве систем на порядки ускоряет циклы итераций. Более того, по мере роста динамичности распределённых систем благодаря «бессерверным» парадигмам в равной степени будут усложняться и лежащие в их основе сети и балансировочные системы.

Источник

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *