Схема динамической маршрутизации OpenResty сервиса

задняя часть

11 мая 2019 года сообщество OpenResty объединилось с Paiyun для проведения OpenResty × Open Talk National Tour Salon Station в Ухане, и главный евангелист Paiyun поделился на мероприятии «Схемой динамической маршрутизации услуг на основе OpenResty».

Национальный тур-салон OpenResty x Open Talk инициирован сообществом OpenResty и Paiyun, приглашая старших технических экспертов OpenResty в отрасли поделиться практическим опытом OpenResty, улучшить общение и обучение пользователей OpenResty, а также способствовать развитию проектов OpenResty с открытым исходным кодом. Мероприятие последовательно проводилось в Шэньчжэне, Пекине и Ухане и будет проходить в Шанхае, Гуанчжоу, Ханчжоу и других городах.

Шао Хайян, также главный евангелист Paiyun, директор по эксплуатации и техническому обслуживанию, старший архитектор по эксплуатации и обслуживанию систем, многолетний опыт проектирования архитектуры CDN, разработки эксплуатации и обслуживания, управления командой, опыт работы с Linux-системами и встроенными системами, высокопроизводительный Интернет проектирование архитектуры, ускорение CDN, виртуализация KVM и исследование облачной платформы OpenStack, в настоящее время основное внимание уделяется практике использования контейнеров и технологий виртуализации в облаке в частном облаке.

Ниже приводится полный текст обмена:

Сегодня я хотел бы представить решение динамической маршрутизации сервисов на основе ngx_lua. Это компонент всего процесса контейнеризации. Контейнеризация имеет большие проблемы с маршрутизацией сервисов, и Paiyun внедрила его через собственное решение, и оно стало стабильным. бегал около трех лет. В настоящее время исходный код этого решения открыт. Если вы столкнетесь с той же проблемой в будущем, вы можете использовать это решение напрямую.

Служба обновлений с нулевым временем простоя

При обновлении службы, как мы можем сделать так, чтобы служба не работала? Когда Paiyun выполняет обновления службы, сбой не допускается.Если запрос не будет выполнен из-за сбоя нашего обновления, даже если запрос очень маленький, репутация будет плохой, а если произойдет авария, он потеряет деньги. Это также важная причина, по которой мы используем динамическую маршрутизацию услуг.

Маршрутизация услуг в основном включает следующие части:

  • Регистрация службы означает, что когда поставщик службы встает, он переходит к регистрации обнаружения службы, чтобы указать службу, порт, IP-адрес и имя службы, которые он предоставляет;
  • Обнаружение служб — это место, где службами управляют централизованно, записывая, какие службы есть и где они находятся;
  • Балансировка нагрузки, поскольку существует много одинаковых контейнеров, предоставляющих одни и те же услуги, необходимо продумать, как сделать балансировку нагрузки в этих контейнерах.

Существует множество решений для обнаружения сервисов, но сценарии их применения и языки неодинаковы. Zookeeper — это относительно старомодный проект с открытым исходным кодом, относительно зрелый, но требовательный к ресурсам.Это одно из первых решений, которые мы использовали, включая нашу текущую kafka и очереди сообщений, которые полагаются на Zookeeper; etcd и Consul — восходящие звезды. , а K8S — для тех, кто полагается на etcd, etcd зависит от оркестрации контейнеров; Paiyun использует Consul для регистрации и обнаружения сервисов. Это универсальная технологическая станция, удобная для развертывания, визуализации и обслуживания. Это не только поддерживает KV Storage, а также собственный мониторинг служб, несколько центров обработки данных, функции DNS и т. д.

Существует также много решений для балансировки нагрузки.Одним из преимуществ LVS является то, что после завершения первых двух уровней, если производительность не очень хорошая, вы можете добавить еще один LVS, потому что он находится на четвертом уровне, нижнем уровне, и будет не разрушить первоначальную структуру сети, но ее расширение очень сложно. HA_PROXY и Nginx имеют свои преимущества. HA_PROXY потребляет меньше ресурсов ЦП для разбора HTTP-заголовка. Если используется чистая переадресация, такая как WAF, можно использовать HA_PROXY. -25%, но Nginx более масштабируем. Nginx может пересылать и балансировать нагрузку протоколы TCP, UDP и HTTP, но HA_PROXY поддерживает только TCP и HTTP. Самое большое изменение HA_PROXY заключается в том, что он был рефакторинг с использованием lua, и последующая разработка будет тесно интегрирована с lua, что эквивалентно еще одной возможности, и они также охватывают экосистему K8S. Наше решение — выбрать Nginx, потому что он ориентирован на HTTP, обладает хорошей масштабируемостью и поддерживает TCP.

Как показано выше, мы поместили Nginx и Consul на одну картинку. Чтобы выделить услугу, здесь опущены некоторые менее важные услуги. Делаем управление услугами на базе Mesos, Docker, Marathon. Одним из специальных сервисов является Registrator, который через Docker API будет запускать контейнер на каждой физической машине, и через Docker API периодически отчитываться о состоянии контейнера в Consul. Вышеупомянутый Nginx выполняет балансировку нагрузки, потому что наши сервисы в настоящее время основаны на Nginx прямо в контейнере.

Как обновить сервисы в Consul до Nginx

На предыдущем рисунке проблемы с Nginx в контейнер и регистрацией сервиса в конфигурационный файл нет, а вот с Consul на Nginx будут проблемы, т.к. у Consul есть вся информация, но как уведомить Nginx об этой информации? Запускается новая служба или служба зависает.После того, как Консул узнает эту информацию, как Nginx может удалить эти проблемные службы и добавить некоторые вновь написанные службы.Это проблема, которую мы хотим решить.

Проблема здесь в том, как обновить сервисы в Консуле до Nginx.Если эта проблема будет решена, модель Nginx+Консул+Регистратор будет завершена. Есть также много решений для решения этой проблемы:

1. Вариант 1: Consul_template

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

image

Вышеприведенное изображение является примером.Есть шаблон для создания upstream.conf, а в середине находятся некоторые переменные, которые будут отображаться в будущем.Если K/v изменится, шаблон сгенерирует реальный файл конфигурации, а затем выполнит local, Nginx -s reload, повторно сгенерируйте файл конфигурации и перезагрузите его, чтобы новая служба вступила в силу.

Конечно, Reload также имеет некоторые недостатки:

  • Во-первых, если будет частая перезагрузка, будет потеря производительности;
  • Во-вторых, старый процесс находится в состоянии выключения в течение длительного времени. Если в соединении есть долгое соединение, старый процесс всегда будет в среднем процессе. Это время неопределенно, и вы не знаете, когда Перезагрузка действительно завершена;
  • В-третьих, внутрипроцессный кеш недействителен.Некоторая информация и некоторые коды базы данных будут кэшироваться локально, так что весь кеш будет недействителен;
  • Самым важным моментом является то, что он не соответствует первоначальному замыслу дизайна.Первоначальный замысел его дизайна состоит в том, чтобы облегчить эксплуатацию и обслуживание, не влияя на текущий запрос.Это эквивалентно использованию Docker в качестве виртуальной машины.пит, так что это схема в то время не использовалась.

2. Схема 2: Внутренняя схема NDS

Решение DNS является относительно распространенным, например, IP-адрес предыдущего Сервера теперь заменен доменным именем, если он разрешает ряд IP-адресов, как этот звук, и сам Консул поддерживает DNS, нам не нужно поддерживать дополнительный DNS, пока этот идентификатор в домене просто отлично.

Но мы чувствуем, что использование решения DNS не так хорошо, как и для перезагрузки, причина

  • Во-первых, есть дополнительный уровень времени разрешения DNS, который увеличивает время обработки;
  • Во-вторых, кеш DNS, что является основной причиной, потому что наличие кеша не может сразу отрезать проблемную машину.Если вам нужно облегчить эту проблему, вы должны установить кеш короче, но количество разрешений будет уменьшено. , слишком много.
  • В-третьих, изменится номер порта, и физическая машина, как правило, будет настроена на тот же порт, что также можно сделать в Docker, но для некоторых приложений, не очень чувствительных к сети, таких как некоторые приложения с сильным процессором, мы настроим сеть контейнеров напрямую. Она подключена мостом, и в это время порты назначаются случайным образом, и каждый контейнер может быть назначен по-разному, поэтому это невозможно.

Мы хотим динамически изменять список вышестоящих сервисов Nginx через HTTP-интерфейс.Мы нашли готовое решение под названием ngx_http_dyups_module.

3. Вариант 3: ngx_http_dyups_module

ngx_http_dyups_module может запрашивать некоторую текущую информацию через интерфейс GET, POST может обновлять апстрим, а также может удалять апстрим через Delete.

На изображении выше показан пример с тремя запросами:

  • Во-первых, после отправки запроса на сервисный порт 8080 обнаруживается, что вышестоящего сервиса нет вообще, поэтому он 502;
  • Во-вторых, добавьте два служебных адреса через запрос Curl;
  • Третий, пересмотреть, третья инструкция точно такая же, как и первая инструкция, потому что вторая уже добавила сервис, так что это нормальный вывод.

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

Этот модуль очень хорошо написан, но мы отказались от него после того, как какое-то время им пользовались.Главная причина не в том, что он плохой, а в том, что мы объединили некоторые наши собственные ситуации и обнаружили некоторые проблемы:

  • Во-первых, это приводит к использованию алгоритма балансировки нагрузки самого Nginx. Если мы будем использовать Ngx_lua, чтобы много писать внутри, после использования этого модуля мы будем очень зависимы от модуля C, то есть некоторых наших собственных алгоритмов балансировки нагрузки, у нас есть свои уникальные требования, такие как «сначала локальные», приоритетный доступ к этому модулю Звучит как странная балансировка нагрузки.Если мы хотим делать такие вещи, мы должны изменить код C;
  • Во-вторых, вторичная эффективность разработки низка, а эффективность разработки C намного меньше, чем у Lua;
  • В-третьих, чистое lua-решение использовать нельзя, нам не нужно иметь один проект, чтобы использовать такое решение, но лучше, чтобы его могли использовать другие проекты.

Возможности Slardar для динамической балансировки нагрузки

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

image

Это колесо состоит из четырех частей:

  • Первая часть — это самый простой nginx, мы хотим использовать некоторые нативные инструкции и стратегии повторных попыток;
  • Вторая часть — это модуль Lua;
  • Третья часть - lua_resty_checkups, это модуль управления нашей версии lua, который реализует динамическое управление восходящим потоком.Этот модуль реализует около 30% функций, а также имеет некоторые активные функции проверки работоспособности.Его размер кода составляет около 1500 строк или около того. , если это модуль C, предполагается, что он содержит не менее 10 000 строк;
  • Четвертая часть — это luasocket, который нельзя использовать, когда Nginx обрабатывает запросы.

1. lua-resty-проверки

Кратко представим шаблон lua_resty_checkups, который имеет несколько функций:

  • Первый - это динамическое управление вверх по течению, что реализует синхронизацию между работниками на основе общей памяти;
  • Второй - это пассивная проверка здоровья, которая является особенностью самой Nginx;
  • Третий — активная проверка работоспособности.Этот модуль будет активно отправлять пакеты сердцебиения на серверную часть, которые можно отправлять каждые 15 секунд, чтобы проверить, работает ли серверная служба. У нас также могут быть некоторые персонализированные проверки, такие как heratbeat, регулярно отправляющий пакеты пульса восходящему потоку, чтобы проверить, жив ли сервис;
  • В-четвертых, алгоритм балансировки нагрузки, локальный приоритет позволяет экономить внутрисетевой трафик и так далее.

2. Сервисное отличие

image

Различайте услуги по хосту: например, два завитка на рисунке выше отправляются на один и тот же адрес, но они разные.

3. Процесс запроса

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

4. Динамическое обновление вверх по течению

Это то же самое, что и модуль dyups C. Он также динамически обновляет список восходящих потоков через HTTP-интерфейс. После добавления вы можете увидеть две только что добавленные службы на странице управления.Там будут адреса серверов, некоторые сообщения проверки работоспособности, изменения статуса и времени, а также количество неудачных попыток, на рисунке ниже показана активная проверка работоспособности.

image

Зачем нужны профилактические проверки здоровья? Все обычно используют какие-то пассивные проверки здоровья, то есть после отправки запроса он не знает, что он не работает Активная проверка заключается в отправке пакета сердцебиения, и вы можете узнать, есть ли проблема с сервисом до запроса .

5. Динамическая загрузка lua

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

Кроме того, мы также можем комбинировать с некоторым контролем разрешений, чтобы выполнить простую проверку параметров. По нашей статистике не менее 10% наших запросов являются повторными запросами.Если все эти повторные запросы выполняются, то это ненужное потребление.Мы вернем 304, что означает, что результат такой же, как и предыдущий, а предыдущий результат можно использовать напрямую. В то же время возвращая 304, если нам нужно, чтобы серверная служба судила, мы примем весь запрос, а затем отправим его обратно, что эквивалентно увеличению пропускной способности интрасети, которая фактически сэкономила пропускную способность и может обратно не отправить..

image

Это пример загрузки динамической загрузки.Если запихнуть этот код в Slardar, он будет выполнен.Если выполнить операцию удаления, то вернет 403, то есть через этот код можно сразу отключить эту операцию.Что еще делает это сделать?шерстяная ткань? Любая функция, которую вы можете себе представить, может быть выполнена, и процесс является динамическим.Если код загружен, вы также можете увидеть его информацию на странице состояния.

Реализация динамической балансировки нагрузки Slardar

Предыдущие введения — это все особенности Slardar.Далее я кратко представлю процесс реализации, который разделен на три части: динамическое управление восходящим потоком, балансировка нагрузки и динамическая загрузка кода lua.

1. Динамическое управление вверх по течению

Подгружайте файл конфигурации из консула через luasocket при запуске.Если сервис зависает без причины, как узнать, что произошло, когда вы только что встали после его зависания? Таким образом, должен быть способ закрепить эти вещи, и мы выбрали консул, поэтому он должен быть загружен из консула при запуске.После запуска он должен контролировать управляемый порт, получать инструкции по обновлению вышестоящего уровня и запускать таймер. timer Для синхронизации между рабочими процессами регулярно проверяйте общую память на наличие обновлений, и если есть обновления, вы можете синхронизировать их в своем собственном рабочем процессе.

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

2, балансировка нагрузки

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

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

3. Динамическая загрузка lua

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

4. Преимущества динамической балансировки нагрузки Slardar

Это колесо мы построили, в основном используя модуль lua-resty-checkups и balance_by_lua_* , которое имеет следующие преимущества:

  • Чистая реализация lua не зависит от сторонних модулей C, поэтому вторичная разработка очень эффективна и снижает нагрузку на обслуживание;
  • Вы можете использовать собственный прокси-сервер Nginx_, потому что мы делаем это только на этапе выбора пиров в запросе.После того, как пиры выбраны, этап отправки данных должен перейти непосредственно к собственным инструкциям Nginx, поэтому он может использовать собственный прокси Nginx_инструкция;
  • Он работает практически с любым проектом ngx_lua и может удовлетворить как чистую схему lua, так и схему C.

Какой Слардр может сделать в архитектуре микросервисов

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

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

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

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

Наконец, перефразируя слова мастера:Говорить дешево, покажи мне код. В настоящее время мы открыли исходный код проекта Sladar, и адрес проекта:GitHub.com/upcloud/связка подтягивания….

Выступление видео и PPT:

Схема динамической маршрутизации сервисов на основе OpenResty