Посів баз даних мікросервісів


10

Дана послуга A (CMS), яка керує моделлю (Product, припустимо, єдині поля, які вона має, це id, назва, ціна) та послуги B (Доставка) та C (E-mail), які повинні відображати задану модель, яким повинен бути підхід синхронізувати інформацію даних моделей між цими службами у випадку підходу до пошуку подій? Припустимо, що каталог товарів рідко змінюється (але змінюється) і що є адміністратори, які дуже часто можуть отримувати доступ до даних про відправлення та електронні листи (наприклад, функціональні можливості: B: display titles of products the order containedі C display content of email about shipping that is going to be sent:). У кожної із служб є своя БД.

Рішення 1

Надсилайте всю необхідну інформацію про Продукт в рамках події - це означає наступну структуру для order_placed:

{
    order_id: [guid],
    product: {
        id: [guid],
        title: 'Foo',
        price: 1000
    }
}

Інформація про послуги B і C зберігається в productатрибуті JSON на ordersтаблиці

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

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

Рішення 2

Надсилайте лише посібник продукту протягом події - це означає наступну структуру для order_placed:

{
    order_id: [guid],
    product_id: [guid]
}

Про послуги B і C інформація про продукт зберігається в product_idатрибуті ordersтаблиці

Інформацію про продукт отримують служби B і C, коли це вимагається, виконуючи виклик API до A/product/[guid]кінцевої точки

Проблеми : це робить B і C залежними від A (у всі часи). Якщо схема продукту змінюється на A, зміни повинні бути зроблені для всіх служб, що залежать від них (раптово)

Рішення 3

Надсилайте лише посібник продукту в рамках події - це означає, що структура для розміщення замовлення:

{
    order_id: [guid],
    product_id: [guid]
}

Про послуги B і C інформація про продукт зберігається в productsтаблиці; ще є product_idна ordersстолі, але є реплікація productsданих між A, B і C; B і C можуть містити іншу інформацію про Продукт, ніж A

Інформація про продукт A/productвиводиться під час створення служб B і C та оновлюється кожного разу, коли інформація про Продукти змінюється шляхом виклику до кінцевої точки (який відображає необхідну інформацію про всі продукти) або шляхом прямого доступу БД до А та копіювання необхідної інформації про продукт, необхідну для даної інформації сервіс.

Проблеми : це робить B і C залежними від A (при посіві). Якщо схема продукту змінюється на A, зміни потрібно внести на всі сервіси, що залежать від них (при посіві)


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


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

Що стосується зберігання даних (схем тощо) для запитів і додавання / видалення полів тощо., Ми використовували себе cosmosDB, що зберігає дані в JSON, як це було в той час. Єдине, що тоді потребує версії, - це події та / або команди. Вам також потрібно оновити договори про кінцеві точки та об'єкти цінності, що містять дані, що відповідають на запити клієнта (веб, мобільний телефон тощо). Старі дані, які не мають поля, матимуть значення за замовчуванням або порожнє, що коли-небудь підходить для бізнесу, але історія подій залишається в такті та рухається лише вперед.
Nope

@Nope updating event historyя маю на увазі: пройти всі події, скопіювавши їх з одного потоку (v1) в інший потік (v2), щоб підтримувати послідовну схему подій.
вийшов

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

@CPerson yup - ціна може бути одним із атрибутів, переданих у межах самої події. З іншого боку, URL-адреса для зображення може існувати в рамках події (представляє наміри display image at the point when purchase was made) або не може (що представляє наміри display current image as it within catalog)
написано

Відповіді:


3

Рішення №3 дійсно близьке до правильної ідеї.

Спосіб подумати над цим: B і C - це кешування "локальних" копій потрібних їм даних. Повідомлення, оброблені в B (а також на C), використовують інформацію, кешовану локально. Аналогічно, звіти складаються з використанням локально кешованої інформації.

Дані реплікуються з джерела в кеші через стабільний API. B і C навіть не потрібно використовувати один і той же API - вони використовують будь-який протокол вибору, що відповідає їх потребам. По суті, ми визначаємо договір - схему протоколів та повідомлень - який обмежує постачальника та споживача. Тоді будь-який споживач цього договору може бути підключений до будь-якого постачальника. Невідповідні зміни потребують нового контракту.

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

Це дає вам "самостійність", в тому сенсі, що B і C можуть продовжувати надавати ділову цінність, коли A тимчасово недоступний.

Рекомендоване читання: Дані зовні, Дані зсередини , Пат Хелланд, 2005.


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

1
Я думаю, у вас є рішення з рішенням №3. Якщо вам потрібно повторити узгодженість з каталогом, також покладіть джерело події. Відтворювати потрібно лише під час повторного набору даних, що, ймовірно, при запуску - після того, як ви встанете, вам потрібно лише переглянути нові події, тому кількість даних, ймовірно, не є справжньою проблемою. Однак, навіть тоді у вас є можливість (якщо потрібно) використовувати контрольні точки, тобто "ось стан станом на 1000 подій", тож ви берете це, і тепер вам залишається лише відтворити подію на 1 001-поточну замість усієї історії. .
Майк Б.

2

У Комп'ютерній науці є дві важкі речі , і одна з них - недійсність кешу.

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

  1. Виклик API до служби A викликає проблеми з продуктивністю.
  2. Вартість Сервісу зменшення та неможливість отримати дані є важливими для бізнесу.

Проблеми з продуктивністю дійсно є головним рушієм. Існує багато способів вирішити номер 2, які не передбачають кешування, як, наприклад, забезпечення послуги A є високодоступною.

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

З цієї чудової статті Уді Дахана:

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

Крім того, якщо вам потрібен конкретний запит даних про продукт, це слід обробляти так, як дані зберігаються в базі даних продукту (наприклад, дати початку / кінця), повинні бути чітко викриті в API (дата введення в дію повинна бути бути входом для виклику API для запиту даних).


1
@SavvasKleanthous "Мережа є надійною" - одна з помилок розподілених обчислень. Але відповідь на цю помилку не повинна бути "кешувати кожен біт даних від кожної служби в будь-якій іншій службі" (я розумію, що це трохи гіперболічно). Очікуйте, що служба може бути недоступною, і вирішуватимете її як стан помилки. Якщо у вас є рідкісна ситуація, коли Сервіс Зниження має великий вплив на бізнес, то (уважно!) Розгляньте інші варіанти.
Філ Сандлер

1
@SavvasKleanthous також вважає (як я вже згадував у своїй відповіді), що повернення застарілих даних у багатьох випадках може бути набагато гіршим, ніж помилка.
Філ Сандлер

1
@eithed Я мав на увазі цей коментар: "Якщо ми все ж хочемо відслідковувати зміни в каталозі, це вимагає і пошуку подій". У будь-якому випадку ви маєте правильну ідею - Служба Продукту повинна відповідати за відстеження змін протягом часу, а не нижчестоящих служб.
Філ Сандлер

1
Крім того, зберігання даних, які ви спостерігаєте, хоча має певну схожість із кешуванням, не викликає тих самих проблем. Більш конкретно, недійсність не потрібна; ви отримуєте нову версію даних, коли це відбувається. Що ви відчуваєте - це затримка послідовності. Однак навіть за допомогою веб-запиту існує вікно невідповідності (хоч і крихітного).
Саввас Клеантоус

1
@SavvasKleanthous У будь-якому випадку, моя головна суть - не намагатися вирішувати проблеми, які ще не існують, особливо з рішеннями, які приносять власні проблеми та ризики. Варіант 2 є найпростішим рішенням, і він повинен бути вибором за замовчуванням до тих пір, поки він не відповідає вимогам бізнесу . Якщо ви думаєте, що вибір найпростішого рішення, яке може спрацювати, є (як ви сказали) "справді поганим", то я думаю, ми просто не згодні.
Філ Сандлер

2

Дуже важко просто сказати, що одне рішення краще, ніж інше. Вибір одного з розчинів №2 та №3 залежить від інших факторів (тривалість кешу, толерантність узгодженості, ...)

Мої 2 копійки:

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

Рішення №1 (NOK)

  • Дані дублюються у кількох системах

Рішення №2 (ОК)

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

Рішення №3 (Складне, але бажане)

  • Віддайте перевагу API-підходу замість прямого доступу до БД для отримання інформації про продукт
  • Коли послуги, що споживають продукти, не впливають на стійкі послуги
  • Споживчі програми (послуги доставки та електронної пошти) отримують деталі продукту одразу після публікації події. Можливість того, що послуга продукту знизиться протягом цих кількох мілісекунд, дуже віддалена.

1

Взагалі кажучи, я настійно рекомендую проти варіанту 2 через тимчасову зв’язок між цими двома послугами (якщо спілкування між цими службами не є надзвичайно стабільним і не дуже частим). Тимчасове сполучення - це те, що ви описуєте як this makes B and C dependant upon A (at all times), і означає, що якщо A вниз або недоступний від B або C, B і C не можуть виконувати свою функцію.

Я особисто вважаю, що в обох варіантах 1 і 3 є ситуації, коли вони є дійсними варіантами.

Якщо зв’язок між A та B&C настільки високий, або кількість даних, необхідних для участі у заході, є достатньо великим, щоб викликати занепокоєння, тоді варіант 3 є найкращим варіантом, оскільки навантаження на мережу значно нижча , а затримка операцій зменшиться зі зменшенням розміру повідомлення. Тут слід врахувати й інші проблеми:

  1. Стабільність контракту: якщо контракт повідомлення, який залишає A, часто змінюється, то розміщення багатьох властивостей у повідомленні призведе до великих змін у споживачів. Однак я вважаю, що це не є великою проблемою, оскільки:
    1. Ви згадали, що система A - це CMS. Це означає, що ви працюєте над стабільним доменом, і тому я не вірю, що ви будете бачити часті зміни
    2. Оскільки B і C доставляють та надсилають електронну пошту, а ви отримуєте дані від A, я вважаю, що ви будете зазнавати додаткових змін замість порушення, які можна безпечно додавати, коли ви виявите їх без переробки.
  2. З'єднання: Зв'язок тут дуже мало. По-перше, оскільки спілкування здійснюється за допомогою повідомлень, не існує зв'язку між службами, окрім короткого тимчасового під час вилучення даних, та договором цієї операції (який не є з'єднанням, якого ви можете або повинні намагатися уникати)

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

Ще один варіант, який я б запропонував, - це невелика зміна до 3, яка полягає в тому, щоб не запускати процес під час запуску, а натомість спостерігати за подією "ProductAdded and" ProductDetailsChanged "на B і C, якщо в каталозі товарів є зміна. в А. Це зробило б ваші розгортання швидше (і так простіше виправити проблему / помилку, якщо ви знайдете).


Редагувати 2020-03-03

У мене визначений порядок пріоритетів при визначенні інтеграційного підходу:

  1. Яка вартість консистенції? Чи можемо ми прийняти кілька мілісекунд невідповідності між зміненими в А речами та їх відображенням у B & C?
  2. Вам потрібні конкретні запити (також звані тимчасовими запитами)?
  3. Чи є джерело правди для даних? Служба, яка їм належить і вважається вище за течією?
  4. Якщо є власник / єдине джерело правди, це стабільно? Або ми очікуємо, що ми будемо часто змінювати зміни?

Якщо вартість невідповідності висока (в основному, дані про продукт у A потрібно якомога швидше узгоджувати з продуктом, кешованим в B і C), то ви не можете уникнути необхідності приймати недоступність та робити синхронний запит (наприклад, в Інтернеті / запит на відпочинок) від B&C до A для отримання даних. Бережись! Це все ще не означає транзакційно послідовної, а просто мінімізує вікна для невідповідності. Якщо ви абсолютно позитивно повинні бути негайно послідовними, вам потрібно домогтися обмеження своїх службових меж. Однак я дуже твердо вважаю, що це не повинно бути проблемою. З досвіду, насправді вкрай рідко компанія не може прийняти кілька секунд невідповідності, тому вам навіть не потрібно робити синхронні запити.

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

Якщо вам не потрібен момент часу, і немає чіткого, єдиного власника даних (який у моїй початковій відповіді я припускав, що це ґрунтується на вашому запитанні), то дуже розумною схемою було б проведення представлень товару в кожній службі окремо. Коли ви оновлюєте дані для продуктів, ви оновлюєте параметри A, B і C паралельно, роблячи паралельні веб-запити до кожного з них, або у вас є API команд, який надсилає кілька команд кожному A, B і C. B&C використовують їх локальна версія даних, яка виконує свою роботу, яка може бути, а може бути і необов’язковою. Це не будь-який із варіантів, описаних вище (хоча це може бути близьким до варіанту 3), оскільки дані в А, В і С можуть відрізнятися, а "ціле" продукту може бути складом усіх трьох даних джерела.

Знання, чи є джерело істини стабільний договір, корисно, оскільки ви можете використовувати його для використання домену / внутрішніх подій (або подій, які ви зберігаєте у своїх джерелах подій, як шаблон зберігання в А) для інтеграції в А та служби B і C. Якщо контракт стабільний, ви можете інтегруватися через події домену. Однак тоді ви маєте додаткове занепокоєння у випадку, коли зміни є частими або той договір повідомлення є досить великим, що викликає занепокоєння транспорту.

Якщо у вас чіткий власник, з контрактом, який, як очікується, буде стабільним, найкращими варіантами буде варіант 1; замовлення міститиме всю необхідну інформацію, і тоді B і C виконують свою функцію, використовуючи дані у випадку.

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


Так, я згоден. Поки ProductAddedабо ProductDetailsChangedдодаємо складності відстеження змін каталогу товарів, нам потрібно якось утримувати ці дані синхронізованими між базами даних, у випадку, якщо події перетворюються, і нам потрібно отримати доступ до даних каталогу з минулого.
eithed

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