Надвор од микросервисите: Архитектура за стабилност на дистрибуираните системи
Микросервисите често се претставуваат како неизбежен следен чекор по монолитот: подели ја апликацијата, распореди ги услугите независно и дозволи им на тимовите да се движат побрзо. Привлечноста е реална. И скриената цена е реална.
Дистрибуираниот систем не станува поедноставен затоа што неговиот код живее во помали складишта или контејнери. Тој станува мрежа од делумни откажувања, задоцнети пораки, некомпатибилни договори, дуплирани податоци и оперативни одлуки што мора да останат разумни под притисок. Добрата архитектура помалку се однесува на изборот на „микросервиси“, а повеќе на изборот на најмалото ниво на дистрибуција што решава реален проблем.
Почнете со граници, а не со единици за распоредување
Најсилната причина да се оддели услуга не е тоа што некој модул станал голем. Туку тоа што има посебна деловна граница, животен циклус, профил на скалирање, безбедносна поставеност или модел на сопственост.
Работниот тек на нарачка, на пример, може да содржи пребарување на каталог, одредување цени, авторизација на плаќање, резервација на залихи, исполнување и известувања. Овие способности не заслужуваат автоматски посебни услуги. Прво прашајте дали им се потребни независни изданија, независно складирање или независно справување со откажувања. Ако одговорот е не, нивното задржување заедно може да биде поотпорниот избор.
Модуларниот монолит често е одлична меѓуархитектура. Тој обезбедува јасни внатрешни граници без веднаш да бара мрежни повици за вообичаена соработка. Во PHP апликација, тоа може да значи организирање на кодот околу доменски модули наместо само околу технички слоеви:
src/
Orders/
Application/
Domain/
Infrastructure/
Inventory/
Application/
Domain/
Infrastructure/
Payments/
Application/
Domain/
Infrastructure/
Секој модул може да изложува тесен интерфејс на ниво на апликација. Другите модули не треба да пристапуваат до неговите модели или табели за перзистенција како кратенка. Таа дисциплина овозможува подоцнежно извлекување, но и го подобрува монолитот денес.
Секој оддалечен повик е одлука за доверливост
Во рамки на еден процес, повикот на функција е брз и обично сигурен. Преку мрежа, може да истече времето откако оддалечениот систем ја завршил работата. Може да откаже пред да прими одговор. Може да биде повторен и да создаде дупликат операција. Ова се нормални исходи, а не гранични случаи.
Разгледајте checkout API што повикува услуга за плаќање. Наивната имплементација го третира истекувањето на времето како неуспех и веднаш се обидува повторно. Но првото барање можеби стигнало до давателот на плаќање и успеало. Повторниот обид би можел двапати да го авторизира клиентот, освен ако операцијата не е идемпотентна.
За команди што ја менуваат состојбата, прифатете идемпотентен клуч и зачувајте го резултатот поврзан со него. Повторено барање со истиот клуч треба да го врати првичниот исход наместо повторно да го изврши дејството.
$key = $request->getHeaderLine('Idempotency-Key');
if ($existing = $idempotencyStore->find($key)) {
return $existing->toResponse();
}
$result = $paymentService->authorize($command);
$idempotencyStore->save($key, $result);
return $result->toResponse();
На овој пример сè уште му е потребен внимателен дизајн на трансакции: зачуваниот одговор и деловното дејство не смеат да се раздвојат ако процесот падне. Поентата не е универзален исечок; туку препознавање дека повторните обиди бараат дефиниран семантички договор.
Користете истекувања на време, повторни обиди и редици намерно
Повторните обиди се корисни само кога е веројатно неуспехот да биде привремен и операцијата може да поднесе повторување. Поставете кратки, изречни истекувања на време. Обидете се повторно ограничен број пати со постепено зголемување на чекањето. Не обидувајте се повторно при неуспеси на валидација, неуспеси на авторизација или барања што не се идемпотентни.
За работа што не е непосредна, редицата често создава поздрава граница од синхрониот HTTP. Испраќањето е-пошта за потврда на нарачка не треба да го забавува успешно завршеното купување. Објавувањето на настан како OrderPlaced им овозможува на следните работници независно да обработуваат известувања и аналитика.
Но редиците не ја отстрануваат сложеноста. Потрошувачите може да примат порака повеќе од еднаш, пораките може да пристигнат доцна, а обработката може постојано да откажува. Изградете ги потрошувачите да бидат идемпотентни, испраќајте ги отровните пораки на патека за неуспеси што може да се прегледува и следете ја староста на редицата, како и нејзината должина.
Сопственоста на податоците е местото каде што архитектурата станува реална
Најштетната кратенка во дистрибуиран систем е заедничката база на податоци. Таа изгледа ефикасна бидејќи секоја услуга може да ги пребарува податоците што ѝ се потребни. Во пракса, таа ги поврзува распоредувањата, открива внатрешни претпоставки и ги прави промените на шемата ризични.
Услугата треба да ги поседува податоците што ги запишува. Другите услуги треба да го користат нејзиниот API, да ги консумираат нејзините настани или да одржуваат сопствен модел за читање. Тоа може да воведе евентуална конзистентност, па корисничкото искуство мора искрено да го признае тоа. „Вашата нарачка се потврдува“ е подобро отколку да се прикаже неповратен статус пред да завршат залихите и плаќањето.
Не секое пребарување има потреба од барање меѓу услуги во реално време. Известувањето, пребарувањето и контролните табли често работат подобро со модели за читање изградени од настани. Компромисот е свежина и оперативен товар, што треба да биде изречен наместо случаен.
- Чувајте ги трансакциските податоци блиску до услугата што ја поседува деловната одлука.
- Објавувајте стабилни настани за факти што се случиле, а не внатрешни записи обликувани според базата на податоци.
- Верзионирајте ги API и договорите за настани кога промените не се наназад компатибилни.
- Планирајте усогласување за работни текови каде што привремената неконзистентност има финансиско влијание или влијание врз клиентите.
Контејнерите ја стандардизираат испораката, а не дизајнот на системот
Docker е вреден затоа што ги прави зависностите за извршување повторливи. Тој не ја прави апликацијата независно распоредлива, набљудлива или безбедна за работа. Контејнеризираниот дистрибуиран систем сè уште има потреба од управување со конфигурација, здравствени проверки, логови, метрики, трасирање и сигурен пат за миграции на шемата.
Одржувајте ги сликите мали и предвидливи, извршувајте еден примарен процес по контејнер и обезбедете значаен крај за проверка на здравјето. Крајот за проверка на здравјето треба да разликува „процесот работи“ од „апликацијата може да го опслужува потребниот сообраќај“. Избегнувајте да зависи од секоја опционална надолна интеграција, или привремен прекин на известувањата може да направи здравите checkout инстанци да исчезнат.
Миграциите на базата на податоци заслужуваат особена грижа. Автоматското извршување миграции од секој веб-контејнер носи ризик од натпревари за време на постепено распоредување. Третирајте ги миграциите како изречен чекор на распоредување, направете ги наназад компатибилни каде што е можно и користете низа на проширување и повлекување: додајте нови структури, распоредете код што ги поддржува двете форми, мигрирајте ги податоците, па подоцна отстранете ги застарените структури.
Направете го неуспехот видлив пред да стане мистериозен
Кога барањето минува низ неколку услуги, логовите од еден процес ретко се доволни. Пренесувајте идентификатор за корелација низ влезните барања, излезните повици, асинхроните пораки и структурираните логови. Забележувајте ја операцијата, исходот, латентноста и релевантните идентификатори без да откривате тајни или лични податоци.
Мерете го однесувањето што го доживуваат корисниците: стапка на грешки, латентност, доцнење во редицата, заситеност и успех на критичните деловни текови. API што враќа HTTP 200 не е нужно здраво ако нарачките се натрупуваат необработени во редица.
Оперативната едноставност е карактеристика. Помалку подвижни делови значат помалку контролни табли, предупредувања, акредитиви, патеки за распоредување и режими на откажување. Тим што не може самоуверено да дијагностицира услуга во 2 часот наутро нема добиено многу со нејзиното издвојување.
Смирената архитектура обично е подобрата
Микросервисите можат да бидат вистинскиот одговор кога независни тимови и навистина независни домени треба да се развиваат со различни брзини. Тие не се значка на зрелост. Зрелото инженерство е да се знае која сложеност купува вистинска способност, а која само преместува повик на функција на мрежата.
Почнете со јасни доменски граници, наметнете сопственост, дизајнирајте ја секоја оддалечена операција за делумен неуспех и извлекувајте услуги само кога придобивката го надминува оперативниот товар. Целта не е дијаграм со повеќе полиња. Таа е систем што останува разбирлив, променлив и смирен кога реалниот свет се однесува несовршено.