Сила выбора запроса

Настройка сцены

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

Среды в BigPanda полностью управляются как код с использованием Terraform. Недавно я опубликовал пару полезных советов по Terraform, которые помогут вам в путешествии по Инфраструктуре как коду с использованием Terraform.

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

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

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

Резервные копии

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

Процесс восстановления среды BigPanda включает все данные с отслеживанием состояния, включая кластеры Elasticsearch. Но этот процесс, хотя и проверенный и испытанный, все еще выполнялся вручную.

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

Процесс

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

Часть 1 — Резервное копирование

Сюда входит автоматизация резервного копирования данных кластера и периодическое обновление идентификатора резервного копирования в базе данных.

Часть 2 — Восстановление

Сюда входит автоматизация восстановления кластера Elasticsearch из идентификатора моментального снимка, сохраненного в процессе резервного копирования.

Концепции

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

  • Curator — это исполняемый файл для управления моментальными снимками индексов Elasticsearch, который уже некоторое время является частью проекта Elasticsearch Open Source.
  • Снимок. Один запуск Curator сохраняет инкрементный момент времени состояния индексов Elasticsearch. Снимки также являются событием, которое можно настроить различными способами. Например, работа только с определенными индексами или поддержка хранения индексов путем удаления данных по истечении срока, определенного в конфигурации задания куратора.
  • Репозиторий — целевое расположение, в котором куратор сохраняет снимки. Куратор управляет файлами в репозитории в сжатом двоичном формате для ускорения и создания добавочных резервных копий. Репозиторий, который мы используем в качестве цели резервного копирования, — это корзина S3.

Процесс

Резервное копирование

Мы разработали автоматизацию резервного копирования как непрерывный процесс, который выполняет резервное копирование каждого кластера Elasticsearch в корзину S3 и создает новое имя моментального снимка. Затем уникальный идентификатор или имя снимка записывается и обновляется в базе данных. Интересный анекдот, мы выбрали репозиторий Git в качестве нашей базы данных для хранения данных идентификатора моментального снимка.

Шаг 1.1

Непрерывно выполняйте резервное копирование каждого кластера Elasticsearch в корзину S3 с помощью Elasticsearch Curator, каждый кластер создает резервную копию в свою собственную папку в корзине S3 в каждой среде. В Terraform это определяется как выпуск Helm для каждого кластера из диаграммы Helm, которая развертывает Curator как Kubernetes CronJob.

Шаг 1.2

Обновление внутренней базы данных с помощью идентификатора моментального снимка куратора для каждого кластера при каждом изменении моментального снимка. Мы разработали функцию Lambda для каждого кластера, которая будет запрашивать у API кластера имя последнего моментального снимка куратора, а затем обновлять базу данных с новым именем. Функция Lambda определяется как код с использованием Terraform. Мы также разработали собственный API для обновления и извлечения данных об именах моментальных снимков из базы данных репозитория Git.

См. схему ниже для резервного копирования и архитектуры обновления идентификатора моментального снимка.

Восстановить

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

Шаг 2.1

Получите идентификатор моментального снимка для каждого кластера. Мы делаем это с помощью контейнерной службы Docker, которая работает в Argo Workflows и запрашивает идентификатор моментального снимка из разработанного нами API, который запрашивает базу данных репозитория Git.

Шаг 2.2

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

Баг

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

Я проверил журналы функций Lambda, выполняющих запрос для этого кластера, и нашел кое-что интересное.

[INFO] 2023-02-27T00:22:05.649Z Getting latest curator snapshot name.
Error: Runtime exited with error: signal: killed
Runtime.ExitError
REPORT Duration: 45710.09 ms Billed Duration: 45711 ms Memory Size: 128 MB Max Memory Used: 128 MB

Память лямбда-функции была исчерпана! Я знал, что это не может быть связано с тайм-аутом Lambda, так как я установил тайм-аут функции на 5 минут, но он вылетел всего через 40 секунд.

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

Я выполнил запрос GET /_snapshot/<REPOSITORY_NAME>/_all/ в том же кластере. Это заняло около 30+ секунд. Ладно, со временем у нас все в порядке. Давайте проверим размер ответа полезной нагрузки.

60 MB

Вау, это большой файл JSON.

Функция Lambda загружает в память ответ JSON размером 60 МБ для хранения всей информации обо всех моментальных снимках при попытке найти имя текущего моментального снимка. Это должно потребовать много оперативной памяти. Я попытался увеличить память функции Lambda до 256 МБ.

Но при повторном запуске памяти все равно не хватило, и произошел сбой!

Я попытался настроить его на 512 МБ.

Теперь, наконец, это сработало! Функция завершила свою работу, и я получил успешный ответ примерно через 50 секунд.

Когда функция вышла, использование памяти составляло 346 МБ из 512 МБ ОЗУ.

Это слишком близко для комфорта. Это означает, что мне нужно настроить ограничение памяти как минимум на 1024 МБ, чтобы быть в безопасности. Это целый ГБ памяти! А поскольку мы используем один и тот же модуль Terraform для создания всех функций Lambda для всех кластеров во всех средах, это увеличение объема оперативной памяти значительно повлияет на использование памяти стека, поскольку оно будет умножаться на все среды и кластеры. Это показалось мне немного чрезмерным, и мне нужно было лучшее решение.

Используйте кошку!

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

Я попытался использовать это в том же негабаритном кластере.

GET /_cat/snapshots/<REPOSITORY_NAME>/

Вуаля! Я мог запросить API, чтобы получить список снимков. Запрос был не намного быстрее по времени отклика. Это по-прежнему занимало около 30 секунд вместо 40 секунд, которые потребовались с /_snapshot/ API. Но когда я измерил размер полезной нагрузки ответа, полезной нагрузки, которую я получил для тех же данных, которые представляли собой только список снимков и некоторую информацию, было всего 83 КБ!
Таким образом, несмотря на то, что запрос занял примерно столько же времени, чтобы получить информацию от кластера (30–40 секунд), возвращаемая полезная нагрузка была значительно меньше, всего 83 КБ!

83 KB

Тестирование нового запроса показало, что использование памяти функцией Lambda снизилось с 346MB до 50MB, т. е. на 85%!

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

🥳🥳🥳

Единственная оговорка заключалась в том, что ответ от /_cat API не был отформатирован как JSON, как ответы от /_snapshot/ API, поэтому мне нужно было преобразовать текст ответа в объект, который легко решался с помощью Python.

Кроме того, на всякий случай я изменил требования к памяти для функции в Terraform на 256MB, что было намного меньше, чем 1024MB, которые мне потребовались бы с /_snapshot/ API.

Заключение

Выбор правильного запроса API может существенно повлиять на производительность функции Lambda и использование ресурсов. Как показано в нашем случае, выбор одного запроса API Elasticsearch вместо другого сократил использование памяти на 85%.

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

Мысли? Инсайты? Не стесняйтесь оставлять комментарии или связаться со мной через LinkedIn.