ИТ развој

Beyond the API Gateway: Architecting Service Interactions for Predictable Scale

Над API-порталот: Архитектирање на интеракции меѓу услуги за предвидливо скалирање

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

Предвидливото скалирање се одредува од тоа што се случува откако барањето ќе ја премине таа граница. Која услуга ги поседува податоците? Кои повици се синхрони? Што се случува кога зависноста е бавна? Може ли потрошувач безбедно да се обиде повторно? Ова се прашања на дизајн на интеракции и тие се поважни од бројот на услуги во дијаграмот.

Дајте ѝ на секоја услуга јасна граница на сопственост

Услугата треба да поседува деловна способност и податоците потребни за нејзино управување. „Услуга за корисници“, „услуга за база на податоци“ или „заедничка услуга“ обично се предупредувачки знаци бидејќи опишуваат техничка инфраструктура наместо одговорност.

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

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

Користете синхрони повици за одлуки, не за долги синџири

Синхроните HTTP или RPC повици се соодветни кога на барањето навистина му е потребен непосреден одговор. Проверките за автентикација, преземањето тековна цена или потврдувањето дека сметка смее да изврши дејство може да одговараат на овој модел.

Проблемот почнува кога едно влезно барање активира синџир од зависни повици:

Gateway -> Order -> Customer -> Inventory -> Payment -> Shipping

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

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

Дизајнирајте експлицитни асинхрони работни текови

Откако нарачката ќе биде прифатена, услугата за нарачки може да објави настан како OrderPlaced. Компонентите за залихи, плаќање и исполнување може да реагираат независно. Ова не значи дека работниот тек станува нејасен; значи дека неговите состојби мора да бидат намерно дефинирани.

  • Забележете трајна состојба на нарачката пред да го објавите настанот.
  • Направете ги потрошувачите идемпотентни, за истата порака да може да се обработи повеќе од еднаш.
  • Моделирајте компензирачки дејства, како ослободување резервација на залиха по неуспешно плаќање.
  • Прикажувајте значајни статуси како pending_payment, confirmed и cancelled.

Асинхроната работа ја заменува непосредната конечност со отпорност. Таа размена често е исправна, но само кога корисничкото искуство може искрено да ја објасни. „Нарачката е примена; потврдата е во тек“ е подобро од враќање успех додека се крие ненадежен синџир на работа.

Третирајте ги повторните обиди како производ на дизајнот на договорот

Мрежите откажуваат на незгодни начини. Клиентот може да истече по време откако серверот веќе ја завршил операцијата. Брокерот за пораки може повторно да достави порака. Работник може да падне откако ќе запише во својата база на податоци, но пред да ја потврди редицата.

Затоа повторните обиди се нормално, а не исклучително однесување. Договорот мора да ги направи безбедни.

За операции за запишување, прифатете клуч за идемпотентност и поврзете го со резултирачката операција. Ако клиент повторно го испрати истиот клуч, вратете го оригиналниот резултат наместо да создадете втора нарачка или двапати да наплатите картичка. За потрошувачите на настани, зачувајте доволно информации за да препознаат дека пораката веќе е применета.

public function createOrder(string $idempotencyKey, array $payload): Order
{
    $existing = $this->orders->findByIdempotencyKey($idempotencyKey);

    if ($existing !== null) {
        return $existing;
    }

    return $this->transaction->run(
        fn () => $this->orders->create($idempotencyKey, $payload)
    );
}

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

Чувајте ги податоците локални, споделувајте факти преку договори

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

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

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

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

Вградете контроли за притисок во секоја граница

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

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

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

Набљудувајте ја интеракцијата, не само услугата

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

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

Скалирајте ги одлуките пред да ја скалирате инфраструктурата

Порталот е влезна врата, а не замена за добри граници. Услугите скалираат предвидливо кога ги поседуваат своите податоци, ги минимизираат синхроните зависности, претпоставуваат дека ќе има повторни обиди и ги прават асинхроните состојби видливи.

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

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

Mihajlo

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