Шаблони для збереження узгодженості в розподіленій системі, що базується на заходах?


12

Я читав про пошук подій останнім часом і дуже люблю ідеї, які стоять за ним, але я застряг у наступній проблемі.

Скажімо, у вас є N одночасних процесів, які отримують команди (наприклад, веб-сервери), генерують події в результаті і зберігають їх у централізованому магазині. Припустимо також, що всі перехідні стану додатків зберігаються в пам'яті окремих процесів шляхом послідовного застосування подій з магазину.

Скажімо, у нас є таке ділове правило: кожен окремий користувач повинен мати унікальне ім’я користувача.

Якщо два процеси отримують команду реєстрації користувача для одного і того ж імені користувача X, вони обидва перевіряють, чи X відсутній у їхньому списку імен користувачів, правило перевіряється для обох процесів, і вони обидва зберігають в магазині подію "новий користувач з ім'ям X" .

Зараз ми вступили в непослідовну глобальну державу, оскільки правило бізнесу порушено (є два різних користувачів з однаковим іменем користувача).

У традиційній системі N-сервера <-> 1 стиль RDBMS база даних використовується як центральна точка синхронізації, що допомагає запобігти подібним невідповідностям.

Моє запитання: як системи джерел подій зазвичай підходять до цієї проблеми? Чи просто вони обробляють кожну команду послідовно (наприклад, обмежте кількість процесу, який можна записати в магазин до 1)?


1
Чи таке обмеження контролюється кодом або це обмеження db? N подій можуть або не можуть бути відправлені та оброблені послідовно ... N подій може пройти валідацію одночасно, не відкидаючи один одного. Якщо замовлення має значення, вам потрібно буде синхронізувати перевірку. Або скористатися чергою, щоб підкреслити події в диспетчері в послідовностях
Laiv

@Laiv справа. Для простоти я припустив, що не існує бази даних, весь стан зберігається в пам'яті. Обробка конкретних типів команд послідовно через чергу була б варіантом, але здається, що це може бути складним рішенням, які команди можуть спричиняти вплив на інших, і я, швидше за все, ставлю всі команди в одній черзі, що означає наявність єдиних команд обробки обробки : / Наприклад, якщо у мене є користувач, який додає коментар до публікації в блозі, "видалити користувача", "призупинити користувача", "видалити повідомлення в блозі", "відключити коментарі до публікації в блозі" і т. Д. Повинні йти в одну чергу.
Олів'є Лалонде

1
Я згоден з вами, працювати з чергами або семафорами непросто. Ні для роботи з моделями одночасності чи джерел подій. Але в основному всі рішення закінчуються системою, яка оркеструє трафік події. Однак це цікава парадигма. Існують також зовнішні кеші, орієнтовані на кортежі на зразок Redis, які можуть допомогти керувати цим трафіком між вузлами, як кешування останнього стану сутності або якщо така сутність обробляється зараз. Спільні сховища є досить поширеними в подібних розробках. Це може здатися складним, але не поступайтеся ;-) це досить цікаво
Laiv

Відповіді:


6

У традиційній системі N-сервера <-> 1 стиль RDBMS база даних використовується як центральна точка синхронізації, що допомагає запобігти подібним невідповідностям.

У системах, що здійснюються за допомогою подій, "магазин подій" виконує ту саму роль. Для об'єкта, який посилається на подію, ваш запис - додаток ваших нових подій до певної версії потоку подій. Отже, так само, як і при одночасному програмуванні, ви можете отримати блокування цієї історії при обробці команди. Систем, які посилаються на події, частіше застосовують більш оптимістичний підхід - завантажують попередню історію, обчислюють нову історію, а потім порівнюють і міняють місцями. Якщо якась інша команда також записала в цей потік, то ваше порівняння та заміна не вдасться. Звідти ви або перезапускаєте свою команду, або відмовляєтесь від своєї команди, або, можливо, навіть об’єднуєте свої результати в історію.

Суперечка стає головною проблемою, якщо всі N серверів зі своїми командами M намагаються записати в єдиний потік. Звичайна відповідь тут - розподілити історію для кожної сутності, що походить у вашій моделі. Таким чином, Користувач (Боб) матиме відмінну історію від Користувача (Аліса), і запис до одного не блокує записування іншому.

Моє запитання: як системи джерел подій зазвичай підходять до цієї проблеми? Вони просто обробляють кожну команду послідовно?

Грег Янг на встановлення валідації

Чи є елегантний спосіб перевірити унікальні протипоказання на атрибути об’єкта домену без переміщення бізнес-логіки в рівень обслуговування?

Коротка відповідь, у багатьох випадках більш глибоко досліджуючи цю вимогу, виявляє, що або (a) недостатньо зрозумілий проксі для якоїсь іншої вимоги, або (b) що порушення "правила" є прийнятними, якщо їх можна виявити (звіт про виключення) , пом'якшені протягом певного часового періоду або низькі частоти (наприклад: клієнти можуть перевірити, чи є ім'я, перш ніж відправити команду для його використання).

У деяких випадках, коли ваш магазин подій хороший у встановленні перевірки (тобто: реляційна база даних), ви реалізуєте цю вимогу, записуючи в таблицю "унікальних імен" в тій же транзакції, що зберігає події.

У деяких випадках ви можете виконати вимогу, лише опублікувавши всі імена користувачів в одному потоці (що дозволяє оцінити набір імен в пам'яті як частину вашої доменної моделі). - У цьому випадку два процеси оновлять спробу оновлення історії потоку, але одна з операцій порівняння та заміни не вдасться, і повтор цієї команди зможе виявити конфлікт.


1) Дякую за пропозиції та рекомендації. Коли ви говорите "зіставити та замінити", ви маєте на увазі, що процес під час зберігання події виявив би нові події, що надійшли з моменту початку роботи команди? Я думаю, для цього знадобиться магазин подій, який підтримує семантику "порівняння та заміни", так? (наприклад, "написати цю подію лише і лише якщо в останній події є ідентифікатор X")?
Олів'є Лалонде

2) Мені також подобається ідея прийняти тимчасові невідповідності та усунути їх врешті-решт, але я не впевнений, як би я кодував це надійним способом ... можливо, маю спеціальний процес, який підтверджує події послідовно і створює події відкату, коли він виявляє щось пішло не так? Дякую!
Олів'є Лалонде

(1) я б сказав "нова версія історії", а не "нові події", але у вас є ідея; замінити історію лише в тому випадку, якщо ми її очікуємо.
VoiceOfUnreason

(2) Так. Це трохи логіки, яка читає події з магазину партіями, а в кінці партії транслює звіт про винятки ("у нас занадто багато користувачів на ім'я Боб") або розсилає команди для компенсації проблеми (якщо припустити, що правильна відповідь - це обчислюється без втручання людини).
VoiceOfUnreason

2

Здається, що ви могли реалізувати бізнес-процес ( sagaв контексті Domain Driven Design) для реєстрації користувача, коли користувач трактується як CRDT.

Ресурси

  1. https://doc.akka.io/docs/akka/current/distributed-data.html http://archive.is/t0QIx

  2. "CRDT з розподіленими даними Akka" https://www.slideshare.net/markusjura/crdts-with-akka-distributed-data, щоб дізнатися про

    • CmRDTs - CRDT на основі операцій
    • CvRDTs - CRTD на основі штату
  3. Приклади коду в Scala https://github.com/akka/akka-samples/tree/master/akka-sample-distributed-data-scala . Можливо, "кошик" найбільше підходить.

  4. Тур по кластеру Акка - Акка Поширювані дані https://manuel.bernhardt.io/2018/01/03/tour-akka-cluster-akka-distributed-data/
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.