Не Только Обработка: Как Мы Делали Распределённую Базу Данных Из Kafka Streams И Что Из Этого Вышло

Привет, Хабр! Напоминаем, что после книги о Кафка мы опубликовали не менее интересную работу о библиотеке API потоков Кафки .



Не только обработка: Как мы делали распределённую базу данных из Kafka Streams и что из этого вышло

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

Итак, недавно вышла статья, с переводом которой мы хотели бы вас познакомить.

Автор на собственном опыте рассказывает, как превратить Kafka Streams в распределенное хранилище данных.

Наслаждайся чтением! библиотека Apache Кафка Стримы используется во всем мире на предприятиях для распределенной потоковой обработки поверх Apache Kafka. Одним из недооцененных аспектов этой платформы является то, что она позволяет хранить локальное состояние, созданное на основе обработки потоков.

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

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

Для нас это шаг вперед как с точки зрения надежности, так и с точки зрения простоты поддержки.

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

Почему мы решили, что пришло время изменить способ работы с общим состоянием Нам нужно было поддерживать состояние различных объектов на основе отчетов агентов (например: был ли сайт атакован)? До перехода на Kafka Streams мы часто полагались на единую центральную базу данных (+ сервисный API) для управления состоянием.

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

База данных может стать узким местом или оказаться в аварийном состоянии.

состояние гонки и страдают от непредсказуемости.



Не только обработка: Как мы делали распределённую базу данных из Kafka Streams и что из этого вышло

Рисунок 1. Типичный сценарий разделения состояния, наблюдаемый до перехода к Kafka и Kafka Streams: агенты передают свои взгляды через API, обновленное состояние рассчитывается через центральную базу данных.

Познакомьтесь с Kafka Streams, упрощающим создание микросервисов с общим состоянием.

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

Мы сразу решили попробовать Kafka Streams — мы знаем, насколько он масштабируем, высокодоступен и отказоустойчив, а также насколько богат его потоковый функционал (преобразования, в том числе с сохранением состояния).

Именно то, что нам было нужно, не говоря уже о том, насколько зрелой и надежной стала система обмена сообщениями в Kafka. Каждый из созданных нами микросервисов с сохранением состояния был построен на базе экземпляра Kafka Streams с довольно простой топологией.

Он состоял из 1) источника 2) процессора с постоянным хранилищем ключей 3) приемника:

Не только обработка: Как мы делали распределённую базу данных из Kafka Streams и что из этого вышло

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

Обратите внимание, что здесь также есть репозиторий, содержащий метаданные планирования.

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



Не только обработка: Как мы делали распределённую базу данных из Kafka Streams и что из этого вышло

Рис.

3. Новый пример потока задач для сценария с общими микросервисами: 1) агент генерирует сообщение, которое поступает в исходную тему Kafka; 2) микросервис с общим состоянием (с использованием Kafka Streams) обрабатывает его и записывает вычисленное состояние в финальную тему Kafka; после чего 3) потребители принимают новое состояние Ого, это встроенное хранилище ключей/значений на самом деле очень полезно! Как упоминалось выше, наша топология общего состояния содержит хранилище значений ключа.

Мы нашли несколько вариантов его использования, и два из них описаны ниже.

Вариант 1. Используйте хранилище ключей-значений для вычислений.

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

Например, в некоторых случаях общее состояние определялось по принципу «большинства голосов».

В хранилище могут храниться все последние отчеты агентов о состоянии какого-либо объекта.

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



Не только обработка: Как мы делали распределённую базу данных из Kafka Streams и что из этого вышло

Иллюстрация 4: Открываем доступ к хранилищу ключ-значение для метода обработки процессора (после этого каждый скрипт, работающий с общим состоянием, должен реализовать метод

doProcess

)
Вариант № 2. Создание CRUD API поверх Kafka Streams. Определив основной поток задач, мы начали пытаться написать RESTful CRUD API для наших микросервисов с общим состоянием.

Мы хотели иметь возможность получать состояние некоторых или всех объектов, а также устанавливать или удалять состояние объекта (полезно для серверной поддержки).

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

В этом случае становится довольно просто реализовать такой API с использованием одного экземпляра Kafka Streams, как показано в листинге ниже:

Не только обработка: Как мы делали распределённую базу данных из Kafka Streams и что из этого вышло

Рисунок 5. Использование встроенного хранилища значений ключа для получения предварительно вычисленного состояния объекта.

Обновление состояния объекта через API также легко реализовать.

По сути, все, что вам нужно сделать, это создать производитель Kafka и использовать его для создания записи, содержащей новое состояние.

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



Не только обработка: Как мы делали распределённую базу данных из Kafka Streams и что из этого вышло

Рисунок 6. Вы можете установить состояние объекта с помощью производителя Kafka. Небольшая сложность: в Kafka много разделов.

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

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

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

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

Для каждого хранилища состояний в Kafka Streams создается реплицируемая тема с журналом изменений (который отслеживает локальные обновления).

Таким образом, Кафка постоянно создает резервную копию хранилища состояний.

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

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

При переходе от одного микросервиса с общим состоянием к кластеру микросервисов реализация API Get State становится менее тривиальной.

В новой ситуации хранилище состояний каждого микросервиса содержит лишь часть общей картины (те объекты, ключи которых были сопоставлены с определенной партицией).

Нам нужно было определить, какой экземпляр содержит нужное нам состояние объекта, и мы сделали это на основе метаданных потока, как показано ниже:

Не только обработка: Как мы делали распределённую базу данных из Kafka Streams и что из этого вышло

Рисунок 7: Используя метаданные потока, мы определяем, из какого экземпляра запрашивать состояние нужного объекта; аналогичный подход использовался с API GET ALL. Основные выводы Хранилища состояний в Kafka Streams могут де-факто служить распределенной базой данных.

  • постоянно тиражируется в Кафке
  • CRUD API можно легко построить поверх такой системы.

  • Обработка нескольких разделов немного сложнее.

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

    Эту опцию можно использовать для:

  • Долговременное хранение данных, необходимых для вычислений при потоковой обработке.

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

  • гораздо более.

Эти и другие преимущества делают Kafka Streams хорошо подходящим для поддержания глобального состояния в такой распределенной системе, как наша.

Kafka Streams оказался очень надежным в работе (с момента его развертывания у нас практически не было потерь сообщений), и мы уверены, что его возможности на этом не остановятся! Теги: #Высокая производительность #Большие данные #kafka #java #Распределенные системы #Apache #распределенные вычисления #kafka потоки

Вместе с данным постом часто просматривают:

Автор Статьи


Зарегистрирован: 2019-12-10 15:07:06
Баллов опыта: 0
Всего постов на сайте: 0
Всего комментарий на сайте: 0
Dima Manisha

Dima Manisha

Эксперт Wmlog. Профессиональный веб-мастер, SEO-специалист, дизайнер, маркетолог и интернет-предприниматель.