ИТ развој

Beyond the Monolith: Architecting for Evolving System Resilience

Надвор од монолитот: Архитектура за отпорност на системите што се развиваат

Монолитите често се обвинуваат за проблеми што не ги создале. Една апликација што се распоредува како целина може брзо да се изгради, лесно да се разбере и да биде сосема соодветна за мал тим. Проблемот започнува кога нејзините граници престануваат да одговараат на променливите потреби на системот: бавно пребарување за извештаи го одложува наплатувањето, едно распоредување става во ризик неповрзани функционалности или прекин кај трета страна се претвора во инцидент за целата страница.

Отпорноста не е исто што и разделување на сè во сервиси. Таа е способноста да продолжите да ги испорачувате најважните резултати додека зависностите, обрасците на сообраќај и барањата се менуваат. Добрата архитектура ги прави тие промени поевтини, побезбедни и полесни за разбирање.

Започнете со точките на притисок, не со дијаграм за микросервиси

Пред да извлечете што било, утврдете каде монолитот навистина е под притисок. Барајте различни профили на скалирање, потреби за независни изданија, спротивставени барања за доверливост и нејаснотии околу сопственоста. Работен тек за плаќања и задача за извоз во PDF можеби денес се во истата PHP апликација, но не мора нужно да заслужуваат исто однесување при извршување.

Корисно прашање е: што мора да продолжи да работи ако оваа компонента е бавна, недостапна или се распоредува? Ако клиентите можат да нарачуваат без веднаш да добијат е-пошта за потврда, испораката на е-пошта е силен кандидат за асинхрона изолација. Ако распределбата на залихите мора да биде точна пред да се наплати плаќањето, нејзиното прерано разделување може да внесе повеќе ризик отколку што отстранува.

  • Извлекувајте според деловна способност: претпочитајте ограничена грижа како известувања, индексирање за пребарување или обработка на медиуми наместо технички слој како „целиот код за базата на податоци“.
  • Извлекувајте според оперативна потреба: компонентите со различен сообраќај, режими на откажување или ритам на распоредување најмногу имаат корист од независноста.
  • Зачувајте јасен извор на вистината: секој важен податок има потреба од недвосмислен сопственик, дури и додека системите се во транзиција.

Прво изградете споеви во монолитот

Најбезбедниот пат надвор од монолитот обично започнува во него. Направете ги модулите експлицитни, намалете ја скриената спрегнатост и дефинирајте интерфејси пред да воведете мрежна граница. Ова носи вредност дури и ако никогаш не се извлече сервис.

Во PHP, тоа често значи преместување на логиката на контролерите, обременета со рамката, кон апликациски сервиси со тесни зависности. Дејството за наплата треба да координира случај на употреба, а не директно да знае како се прикажува е-поштата, се резервираат залихите и се складираат аналитичките настани. Зависностите потоа може да се заменат, одложат или преместат зад API без повторно пишување на деловниот тек.

final class PlaceOrder
{
    public function __construct(
        private OrderRepository $orders,
        private InventoryGateway $inventory,
        private EventPublisher $events,
    ) {}

    public function handle(PlaceOrderCommand $command): Order
    {
        $order = Order::create($command->customerId, $command->items);

        $this->inventory->reserve($order->items());
        $this->orders->save($order);

        $this->events->publish(new OrderPlaced($order->id()));

        return $order;
    }
}

Интерфејсите се поважни од синтаксата. InventoryGateway првично може да повикува локален код. Подоцна, може да повикува сервис, да користи политика за повторни обиди или да изложува контролирана резервна опција. Повикувачот не треба да мора да ги учи тие оперативни детали.

Користете асинхрона работа за да го ограничите откажувањето

Синхроните синџири се кревки. Ако HTTP барање мора да запише нарачка, наплати картичка, генерира документ, извести магацин, испрати е-пошта и ажурира CRM пред да врати одговор, достапноста на крајната точка станува производ од достапноста на секоја зависност. Тоа исто така создава лоша латентност и тешка дијагноза на инциденти.

Преместете ја некритичната последователна работа во траен ред. Зборот траен е важен: објавувањето порака само откако ќе се потврди трансакција во базата на податоци спречува работниците да набљудуваат податоци што биле повлечени. За промени што мора сигурно да создадат и состојба во базата на податоци и настан, outbox табела е практичен образец. Зачувајте го настанот со деловното ажурирање, а потоа дозволете работник да го објави и означи како обработен.

Работниците мора да очекуваат дупликати и делумно откажување. Редот може повторно да испорача порака по истек на време, а процес може да откаже по спореден ефект, но пред да запише успех. Дизајнирајте ги потрошувачите да бидат идемпотентни: користете стабилен идентификатор на настан, наметнете уникатна обработка каде што е соодветно и направете повторното извршување да биде безопасно.

Повторните обиди имаат потреба од граници

Повторувањето на секое откажување не е отпорност. Повторувањето на невалидно барање троши капацитет; повторувањето на привремено недостапна зависност може да помогне. Користете ограничен број обиди, растечки одложувања и патека за неиспорачани пораки за пораки што бараат истрага. Запишете доволно контекст за да следите откажување, но избегнувајте да ставате ингеренции или непотребни лични податоци во дневниците.

За оддалечено API, намерно поставете истекувања на време за поврзување и одговор. Недостасувачко истекување на време може да ги зафати PHP работниците додека целата апликација не стане бавна. Ако зависноста очигледно откажува, прекинувач на коло или привремено намалување на функционалноста може да го заштити примарниот работен тек. „Нарачката е примена; потврдата ќе следи“ често е подобар исход отколку наплатувањето да биде недостапно затоа што давателот на известувања не работи.

Дозволете сопственоста на податоците внимателно да се развива

Разделувањето на базата на податоци е еден од најтешките делови на дистрибуираната архитектура. Заедничка база на податоци го прави извлекувањето да изгледа лесно, но ги задржува сервисите спрегнати преку шеми, миграции, заклучувања и недокументирани пребарувања. Таа често е преоден чекор, а не крајна состојба.

Кога некоја способност станува независна, дајте ѝ сопственост над нејзините запишувања и изложете ги податоците што има намера другите да ги користат преку договор. Другите компоненти може да задржат локални модели за читање кога им е потребен брз пристап. Ова воведува евентуална конзистентност, па корисничкото искуство и деловните правила мора да го признаат тоа. Индексот за пребарување може да заостанува зад ажурирање на производ; книгата на плаќања не може лежерно да го прави истото.

Избегнувајте дистрибуирани трансакции како стандардна излезна врата. Претпочитајте експлицитни состојби и компензирачки дејства. На пример, нарачката може да стане pending_payment, потоа paid кога плаќањето ќе успее, или payment_failed кога не успева. Овие состојби го прават закрепнувањето видливо и оперативно управливо.

Направете го распоредувањето здодевно и набљудливо

Контејнерите помагаат да се стандардизира извршувањето, но Docker сам по себе не создава отпорност. Корисна слика има предвидливо извршно опкружување, конфигурација обезбедена преку околината или механизам за тајни и нема скриена зависност од датотеки создадени од претходно распоредување. Извршувајте миграции на базата на податоци внимателно: проширете ги шемите пред кодот да зависи од нив, распоредете компатибилен код, а потоа отстранете ги застарените полиња во подоцнежно издание.

Набљудливоста треба од почеток да ги преминува границите. Пренесете идентификатор на барање или корелација во дневниците, пораките во редот и излезните HTTP повици. Следете ги сигналите што помагаат да се одговорат практични прашања: дали крајната точка е бавна, дали задачите се таложат, дали зависност откажува и која деловна операција е засегната? Метриките, структурираните дневници и траговите се највредни кога ги поврзуваат техничките симптоми со конкретна патека низ системот.

  • Дефинирајте проверки на здравјето што разликуваат активен процес од компонента способна да испорача корисна работа.
  • Поставете ограничувања на ресурсите за еден потрошувач на ред или задача за извештај да не може да го исцрпи домаќинот.
  • Тестирајте враќање назад и деградирано однесување, не само распоредување по среќната патека.
  • Документирајте ги сопственоста, договорите и процедурите за закрепнување заедно со кодот.

Отпорноста е архитектонска навика

Целта не е да се елиминира монолитот или да се максимизира бројот на распоредливи единици. Таа е да се создадат граници што одразуваат вистински одговорности, ги ограничуваат откажувањата и му дозволуваат на системот да се менува без секоја промена да се претвора во координиран настан.

Добро структуриран монолит често е првиот израз на таа дисциплина. Сервисите, редовите, одделните бази на податоци и контејнерите стануваат корисни кога решаваат докажан проблем. Архитектирајте за следната значајна точка на притисок, држете ја критичната патека мала и направете го закрепнувањето дизајнирано однесување наместо импровизирано. Така системот останува доверлив додека сè околу него се развива.

Портрет на автор на блогот

Mihajlo

Јас сум Михајло - развивач поттикнат од љубопитност, дисциплина и постојаната желба да создадам нешто значајно. Споделувам увиди, упатства и бесплатни услуги за да им помогнам на другите да ја поедностават својата работа и да растат во постојано развивачкиот свет на софтверот и вештачката интелигенција.