Мікросервіси: обробка можливої ​​консистенції


22

Припустимо, у нас є функція, яка оновлює пароль користувача.

Після натискання кнопки "Оновити пароль" на оновлення теми, на яку підписано 3 інші послуги, надсилається UpdatePasswordEvent:

  1. Послуга, яка фактично оновлює пароль користувача
  2. Сервіс, який оновлює історію паролів користувача
  3. Послуга, яка надсилає електронний лист із повідомленням користувача про зміну його пароля.

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

Однак що робити, якщо служба не обробить подію? наприклад, раптове відключення, помилка бази даних тощо ... Яка хороша модель / практика для усунення цих помилок транзакцій?

Я думав створити RollbackTopic, де, якщо будь-яка подія не буде оброблена, буде створено RollbackEvent у темі, де "служби відкату" виконають свою роботу та повернуть дані назад


11
Ви не можете скасувати надісланий електронний лист :-)
Laiv

2
Тому що всі вони повинні бути частиною однієї служби. Мікросервіс протистоїть монолітам, це не означає, що потрібно проектувати їх якомога менше "фізично". Хоча це не пов’язано безпосередньо, слід прочитати це запитання та два найкращі відповіді: softwareengineering.stackexchange.com/questions/339230/…
Walfrat

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

Це електронний лист, щоб повідомити користувачеві, що транзакція завершена, чи це там, щоб повідомити користувачеві, що хтось (сподіваємось, їх) змінив пароль. "Якщо це не ти, то потрібно діяти". Якщо 2-го, то просто надішліть електронну пошту зараз, як тільки можете.
ctrl-alt-delor

Відповіді:


29

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

Ні, не обов’язково. Як я коментував, ми не можемо скасувати надісланий електронний лист, тому нам ще потрібна така собі "послідовність". IPC над керованими подіями керуванням даними не виключається з оркестрування 1 .

Наприклад, електронний лист не слід надсилати, якщо попередні транзакції не завершилися успішно і служба електронної пошти не отримає підтвердження цього. 3

Однак що робити, якщо служба не обробить подію? наприклад, раптове відключення, помилка бази даних тощо ... Яка хороша модель / практика для усунення цих помилок транзакцій?

Привітайтеся з помилками розподілених обчислень . Саме вони ускладнюють справи, і, як завжди, немає срібних куль, щоб з ними боротися.

Перш ніж розпочати нашу подорож у пошуках Втраченого ковчега, ми повинні розглянути питання про те, щоб спочатку запитати організацію. Часто рішення полягає в тому, як організація стикається з цими проблемами в реальному світі .

Що кожен (департаменти) робить, коли певні дані відсутні або неповні?

Ми зрозуміємо, що різні відділи мають різні рішення, які, як правило, складають рішення, яке потрібно реалізувати.

У будь-якому випадку, тут є деякі практики, які можуть допомогти нам в розробці стратегії.

Послідовна послідовність

Замість того, щоб гарантувати, що система постійно знаходиться у постійному стані, натомість ми можемо прийняти, що система отримає її в якийсь момент у майбутньому. Цей підхід особливо корисний для довготривалих бізнес-операцій.

Спосіб досягнення системи узгодженості змінюється від системи до системи. Це може залучати від автоматизованих процесів до якогось втручання людини. Наприклад, типова спроба її знову пізніше або контакт із службою обслуговування клієнтів .

Відмовитись від усіх операцій

Поверніть систему назад у стійкий стан за рахунок компенсації транзакцій . Однак ми маємо враховувати, що ці транзакції теж можуть провалитися, що може призвести до того, що непослідовність вирішити ще складніше. І, знову ж таки, ми не можемо скасувати надісланий електронний лист.

Для низької кількості транзакцій такий підхід є здійсненним, оскільки кількість компенсаційних транзакцій також є низькою. Якщо в МПК було задіяно кілька бізнес-транзакцій, обробка однієї компенсаційної транзакції для кожної з них була б складним завданням.

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

Розподілені транзакції

Ідея полягає в охопленні декількох транзакцій в рамках однієї транзакції за допомогою загального керуючого процесу, відомого як менеджер транзакцій . Загальний алгоритм обробки розподілених транзакцій - це двофазна фіксація .

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

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

Декомпозиція операцій. Чому?

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

Сем Ньюмен

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

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

Наприклад, у нашому випадку ми усвідомлюємо, що транзакції №1 та №2 тісно пов’язані між собою і, ймовірно, обидва можуть належати до одних і тих самих обмежених контексту Облікові записи , Користувачі , Реєстрація , що б там не було ...

Подумайте про розміщення обох операцій в межах однієї транзакції. Це полегшило б всю операцію. Також зважує рівень критичності кожної транзакції. Ймовірно, якщо транзакція №2 провалиться, це не повинно ставити під загрозу всю операцію. У разі сумнівів зверніться до організації .


1: Не такий тип оркестрації, як ви думаєте. Я не кажу про оркестрацію ESB. Я говорю про те, щоб служби реагували на належну подію.

2: Можливо, ви знайдете цікаві думки Сема Ньюмена щодо розподілених транзакцій.

3: Перевірте відповідь Девіда Паркера щодо цього питання.


3
Дуже гарна відповідь. Я хотів би лише наголосити на важливості врахування ризиків, які виникають при використанні розподілених транзакцій - головним чином блокування ресурсів, що створюють тупикові місця та системи-зупинки. Щодо продукту електронної комерції, над яким я працював близько 3 років тому, нам довелося замінити DT на систему обміну повідомленнями, оскільки кількість користувачів, доступних у системах, дуже схильна до помилок. Проблеми з DT здебільшого виникають при зростанні бази користувачів.
Енді

7

У вашому випадку ви не можете просто обробити всі три речі одночасно. Що вам потрібно - це процес. Ось надзвичайно спрощений приклад:

Оркестрація команд та подій

Важливо знати, що операції зі зміни держави ОБОВ'ЯЗКОВО проводитись на послідовному об'єкті. Якщо ви не можете гарантувати міцну послідовність , це повинно бути внесено до основного запису.

Ваша система повинна гарантувати, що перед тим, як відбуватиметься будь-яка подія у вашій зміні системи, ОБОВ'ЯЗКОВО слід спочатку зберігати безпеку транзакцій. Це потрібно для того, щоб піднята подія справді була підтвердженням того, що насправді сталося.

Є кілька складних частин процесу, як це є, і я ігнорую очевидні - наприклад: Що робити, якщо сервер вашої бази даних загине при збереженні користувача зі зміненим паролем? Ви просто знову видаєте UpdatePassword. Однак про деякі частини потрібно подбати про вас, а це:

  • обробка дублювання повідомлень,
  • обробка електронної пошти.

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

Коли PO знаходиться в Newстані та обробляє UserPasswordHasBeenUpdated, він змінює свій стан на UserPasswordHasBeenUpdated(або те, що назва держави працює для вас). Якщо PO все ще знаходиться в a UserPasswordHasBeenUpdatedі UserPasswordHasBeenUpdatedприбуде інший , PO повністю ігнорує повідомлення, знаючи, що це дублювання. Аналогічний механізм буде застосований і для інших держав.

Обробка фактичного надсилання електронної пошти трохи складніше. Тут у вас є два варіанти:

  1. надішліть його не пізніше,
  2. надішліть її хоча б раз.

Надішліть його не більше одного разу

При такому варіанті, коли PO досягає UserPasswordHistoryHasBeenSavedстану, команда надсилати електронну пошту відправляється як реакція на зміну стану. Ваша система забезпечила UserPasswordHistoryHasBeenSavedб збереження стану перед відправленням електронної пошти, тобто дублюване повідомлення не призведе до повторного надсилання електронної пошти. При такому підході ви гарантуєте, що правильний стан збережено для PO, але не можете гарантувати наступних операцій.

Надішліть його хоча б раз

Це те, на що я б пішов.

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

У вашому випадку ви хочете переконатися, що користувач насправді отримує електронне повідомлення. Тому я вибрав би другий варіант, ніж перший.


2

Системи в черзі не такі крихкі, як можна подумати.

Якщо ми записували всі три процеси в реляційний db, ми могли б використовувати транзакцію для обробки помилки середнього процесу.

Без остаточного вчинення часткова робота була б відкинута.

У системі баз черг у вас будуть подібні параметри, коли ви читатимете повідомлення з черги для вирішення середніх відмов процесу.

Наприклад, Amazon SQS просто приховує прочитані повідомлення. якщо не буде надіслано остаточну команду Delete, повідомлення знову з’явиться або буде розміщено в черзі з мертвою літерою.

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

Потенційно ви можете створити "послугу відкату", яка контролювала б ці повідомлення про помилки, знала про пов'язані повідомлення та минулий стан та виконувала відкат.

Однак! Зазвичай краще просто надіслати повідомлення про помилки. Адже це, як правило, крайові справи. Або сервер катастрофічно вийшов з ладу, або сталася помилка в обробці певного типу повідомлення.

Повідомлявши про помилку, сервіс можна відремонтувати та повідомлення успішно обробити. Приведення системи в цілому до сталого стану.


2

З чим ти стикаєшся, це проблема двох генералів . По суті: як ви можете бути впевнені, що повідомлення отримано, і відповідь на це повідомлення відбудеться? У багатьох випадках ідеального рішення не існує. Насправді в розподіленій системі часто неможливо отримати рівномірну доставку повідомлень.

Першим очевидним зауваженням є те, що служба, яка змінює пароль, повинна надсилати подія зміни пароля. Таким чином, історія паролів та послуги надсилання пошти спрацьовують лише тоді, коли пароль фактично змінюється, незалежно від того, чому він змінився.

Насправді вирішити вашу проблему я б не розглядав розподілених транзакцій, а натомість дивився у напрямку як мінімум одного разу доставки повідомлень та ідентифікаційної обробки.

  • Принаймні, один раз

    Щоб переконатися, що подію зміни пароля насправді бачать усі споживачі, вам потрібно використовувати міцний канал зв’язку, де повідомлення можна використовувати в стилі "хоча б один раз". Споживачі визнають повідомлення про спожите лише тоді, коли вони повністю його обробили. Наприклад, якщо служба історії паролів виходить з ладу під час написання запису в історію, вона перечитає ту саму подію зміни пароля після перезавантаження та повторіть спробу, визнавши цю подію такою, що читається лише після її написання в історію. Ви повинні вибрати рішення з черги повідомлень виходячи з його здатності повторно надсилати повідомлення до їх підтвердження.

  • Ідентифікація

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

У будь-якому випадку, будьте уважні, наскільки мікрофони ви робите свої послуги. Чи справді послуга історії паролів повинна бути незалежною від служби зміни паролів?


1

Я не згоден з великою кількістю відповідей.

  1. Надішліть електронний лист зараз "Хтось змінив ваш пароль. Якщо це були ви, то вам нічого не потрібно робити. Якщо не панікувати ». Це надійде, коли він прибуде.
  2. Змініть пароль. Хоча у вас є можлива послідовність. Ви хочете переконатися, що цей сеанс бачить зміни, внесені користувачем.

Є й інші обіцянки послідовності, які ви можете додати.

  • Переконайтесь, що зміни відбуваються в часовому порядку.
  • Переконайтесь, що користувач ніколи не бачить відкат, але інші користувачі можуть все-таки не побачити зміни.
  • Є й інші

Ці додаткові узгодженості потрібно буде реалізовувати залежно від дій заявки.


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


Якщо ви можете надіслати електронний лист на початку, тоді ваш підхід прекрасний. Якщо вам потрібно надіслати щось поряд з електронним листом. Може бути свого роду посилання / дані, які можна отримати лише після досягнення послідовності, тоді ви не можете спочатку надіслати електронний лист. Саме це я і прокоментував consider asking the organization first.. Ви, ймовірно, праві. Однак я виявив важливим умовою тих подій, які ми не можемо скасувати. Наприклад, сповіщення кінцевому користувачеві. Повідомлення про реальний стан даних користувача можуть спричинити погане враження.
Лаїв

Однак, для цього конкретного сценарію (повідомлення про зміну пароля) я погодився з таким підходом. Як тільки він відповідає вимогам.
Лаїв
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.