Рубрики
Без рубрики

Магазины событий: Сохранение правильного типа байта[]

Мой коллега недавно начал изучать источники финансирования мероприятий. В то время как его внимание сосредоточено на .NET, а мое – на нем… Помечен как источник событий, java, csharp.

Мой коллега недавно начал изучать источники финансирования мероприятий. В то время как его внимание сосредоточено на .NET а мой – на Яве, я был более чем рад ему помочь. Я указал ему на Магазин событий как на отличное место для начала. Пару часов спустя он поделился ссылкой на свой github, заявив, что “сделал это”.

Теплое чувство, которое испытываешь, помогая коллеге открыть что-то новое, поднималось во мне… пока его снова не забрали, когда он бросил мне следующую реплику.

Жаль, что мне приходится вручную сериализовать свои объекты в byte[]…

Я сразу же открыл веб-сайт магазина событий только для того, чтобы обнаружить, что сериализация ваших объектов в byte [], по-видимому, является способом сохранения событий по умолчанию при использовании библиотеки C#. Хотя существуют и другие способы создания byte[], похоже, нет никаких указаний относительно того, что вы должны помещать в свое хранилище событий .

Итак… какие байты подходят для хранилища событий? Чтобы принять решение, давайте сделаем шаг назад к одной из фундаментальных истин в нашем секторе.

Изменение как константа по сравнению с источником событий

Возможно, одним из самых важных уроков, которые я усвоил в школе, было следующее: “Перемены – единственная константа” . Написание кода – это итеративный процесс, в ходе которого мы учимся и открываем лучшие способы самовыражения. Мы проводим рефакторинг, получаем новые идеи, а иногда и бизнес, на который мы работаем.

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

Неизменяемое Хранилище событий против Фундаментальная истина перемен

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

Давайте рассмотрим некоторые из вариантов создания наших событий byte[] с учетом изменений .

Сериализация объектов JAVA/C#

Мой коллега выбрал для сериализации свои объекты C#. В этом выборе есть несколько очевидных подводных камней.

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

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

Как бы то ни было, здесь есть более серьезная проблема. Сериализуя объекты, вы привязываете свои события к определенному языку программирования. Это может быть сознательным выбором но это не то, к чему следует относиться легкомысленно, поскольку оно будет преследовать вас вечно.

JSON

Чтобы устранить зависимость от определенного языка программирования, мы могли бы использовать JSON . JSON имеет большой успех как формат общения в среде полиглотов. Мы находимся на этапе, когда ожидается, что общедоступный API будет возвращать данные в формате JSON! Но как это работает в качестве формата для мероприятий в нашем магазине?

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

{
  "event": "UserAddedEvent",
  "data": {
    "userid": "123456789",
    "name": "Tom",
    "lastname": "Cools"
  }
}

Развивая наш код, мы замечаем, что в нашей системе есть разные типы пользователей, каждый из которых означает что-то свое. Вы хотите иметь возможность проводить различие между “Клиентами”, “Сотрудниками” и, возможно, тип пользователя “Администратор” . Поскольку добавление сотрудников является новым для системы, все сохраненные в настоящее время пользователи являются “Клиентами”. Что вы на самом деле хотите сделать, так это изменить событие на следующее:

{
  "event": "CustomerAddedEvent",   <- Change event name
  "data": {
    "customerid": "123456789",  <- change field name
    "name": "Tom",
    "lastname": "Cools"
  }
}

Однако при использовании JSON это не сработает.

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

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

Другим недостатком является то, что JSON по своей сути является строкой . Это означает, что вам нужно будет избегать специальных символов. Те из вас, кто потерял несколько часов с escape-последовательностями, должны были почувствовать дрожь по спине, читая последние абзацы…

Библиотеки сериализации данных

Библиотеки сериализации данных часто упоминаются в контексте межпроцессного взаимодействия. Подумайте о том, что вы размещаете в Kafka, RabbitMQ или каком-либо другом брокере сообщений. Обычным делом является использование библиотеки для преобразования сообщений в байт[], чтобы передать их по проводу. Так почему бы не использовать эти библиотеки для сериализации и сохранения наших событий?

Там есть такие, как Авро и Бережливость , но мой личный фаворит – библиотека буферов протокола Google . Используя буферы протокола, вы объявляете схему, которая используется для генерации (де)кода сериализации для определенного языка программирования.

Сериализованный результат каждый раз один и тот же, поэтому вы можете сериализовать данные с помощью библиотеки Java и снова десериализовать эти данные с помощью библиотеки .NET.

message CustomerAddedEvent {
  required string customerId = 1;
  required string name = 2;
  optional string lastname = 3;
}

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

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

Я создал пример проекта на github , где я использую плагин Maven для создания классов Java из схем Protobuf.

Том Охлаждает/протокол-буферы-пример

Пример хранилище для буферов протокола

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

Так что же вы выбираете?

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

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

Полиглот
Удалить поле из события
Добавить поле к событию
Изменить имя поля
Читаемый человеком

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

На данный момент Я буду придерживаться буферов протокола как формат для моих мероприятий. Что бы вы ни выбрали для использования, убедитесь, что вы знаете о последствиях. Выбор формата мероприятия – это решение дня 1 , поэтому, что бы вы ни делали, имейте в виду:

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

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

Оригинал: “https://dev.to/tomcools/event-stores-saving-the-right-kind-of-byte-388p”