Refund Tooli teenuse arendamise kogemus asünkroosse API-ga Kafka-l

Mis võib panna nii suurt ettevõtet nagu Lamoda, kellel on sujuv protsess ja kümneid omavahel seotud teenuseid, oluliselt lähenemist muutma? Motivatsioon võib olla täiesti erinev: alates seadusandlikest nõuetest kuni igale programmerimisega tegelejale iseloomuliku soovini katsetada.

Aga see ei tähenda, et ei saa loota lisahüvedele. Mida täpselt on võimalik võita, kui rakendada sündmuspõhise API-d Kafka-l, räägib Sergei Zaika (fewald). Kõikidest kogemustest ja huvitavatest avastustest tuleb samuti kindlasti juttu – ilma nendeta ei saa katsetamine juhtuda.

Refund Tooli teenuse arendamise kogemus asünkroosse API-ga Kafka-l

Disclaimer: See artikkel põhineb materjalidel, mis esitati meetapil, mille Sergei viis läbi novembris 2018 HighLoad++-il. Lamoda elav kogemus Kafka-ga tõmbas kuulajaid sama palju kui teised ettekanded ajakavas. Me arvame, et see on suurepärane näide sellest, et alati on võimalik ja vajalik leida mõttekaaslasi, ning HighLoad++ korraldajad jätkavad atmosfääri loomist, mis soosib seda.

Protsessi kohta

Lamoda — on suur e-kaubanduse platvorm, millel on oma kontaktikeskus, kohaletoimetamisteenus (ja palju partnereid), fotostuudio, suur laod ja kõik see töötab oma tarkvara peal. Olemas on kümneid makseviise, b2b-partnereid, kes saavad kasutada osa või kõiki neid teenuseid ja kes tahavad teada oma toodete kohta ajakohast teavet. Lisaks sellele töötab Lamoda kolmes riigis, välja arvatud RF, ja seal on kõik veidi teisiti. Kokku on tõenäoliselt rohkem kui sada viisi, kuidas konfiguratsiooni uut tellimust, mida tuleb teisiti töödelda. Kõik see töötab kümnete teenuste abil, mis suhtlevad vahel mitte alati ilmnel viisil. Lisaks on olemas ka kesksüsteem, mille peamine vastutus on tellimuste staatused. Me nimetame seda BOB-iks, mina töötan selle süsteemiga.

Tagasimakse tööriist events-driven API-ga

Sõna events-driven on üsna ülekasutatud, veidi hiljem täpsustame, mida sellega silmas peame. Alustan kontekstist, milles me otsustasime katsetada events-driven API lähenemist Kafka kaudu.

Refund Tooli teenuse arendamise kogemus asünkroosse API-ga Kafka-l

Igas poes, lisaks tellimustele, mille eest kliendid maksavad, on olukordi, kus poelt nõutakse raha tagastamist, kuna toode ei sobinud kliendile. See on suhteliselt lühike protsess: täiendame teavet, kui vajalik, ja kanname raha tagasi.

Kuid tagastamise protsess muutus keerulisemaks seadusanduse muutumise tõttu, mistõttu olime sunnitud selle kohandamiseks rakendama eraldi mikroteenust.

Refund Tooli teenuse arendamise kogemus asünkroosse API-ga Kafka-l

Meie motivatsioon:

  1. Seadus FZ-54 — lühidalt öeldes nõuab seadus iga rahatehingu, olgu see tagastus või sissevaart, teatamist maksuametile üsna lühikeses SLA-s, mõne minuti jooksul. Meie, kui e-kaubandus, teeme üsna palju tehinguid. Tehniliselt tähendab see uut vastutust (ja seega uut teenust) ning täiustusi kõigis seotud süsteemides.
  2. BOB split — ettevõtte sisemine projekt, et vabastada BOB suurest hulgast mitteprofesionaalsetest vastutustest ja vähendada selle üldist keerukust.

Refund Tooli teenuse arendamise kogemus asünkroosse API-ga Kafka-l

Sellel skeemil on kujutatud peamisi Lamoda süsteeme. Praegu esindab enamik neist pigem tähekuju 5–10 mikroteenuse ümber, mis koondub väheneva monoliidi ümber.. Nad vaikselt kasvavad, kuid me püüame neid väiksemaks teha, sest keskel fragmenti juurutamine on hirmutav — ei saa lubada, et see kukub. Kõik vahetused (nooled) peame varuma ja arvestama, et ükskõik milline neist võib osutuda kättesaamatuks.

BOB-is on samuti üsna palju vahetusi: maksesüsteemid, kohaletoimetamine, teavitamine jne.

Tehniliselt on BOB see:

  • ~150k koodirida + ~100k testirida;
  • php7.2 + Zend 1 & Symfony Components 3;
  • >100 API & ~50 väljuvat integratsiooni;
  • 4 riiki oma äri loogikaga.

BOB-i juurutamine on kallis ja valus, koodi hulk ja lahendatavad ülesanded on sellised, et keegi ei suuda seda täielikult peas hoida. Ühesõnaga, palju põhjuseid selle lihtsustamiseks.

Tagastamisprotsess

Alguses on protsessis kaasatud kaks süsteemi: BOB ja Payment. Nüüd tulevad veel kaks:

  • Fiskaliseerimise teenus, mis võtab enda peale fiskaliseerimise probleemid ja suhtlemise välistena teenustega.
  • Tagasimakse tööriist, kuhu lihtsalt kantakse uued vahetused, et mitte BOB-i paisutada.

Nüüd näeb protsess välja järgmine:

Refund Tooli teenuse arendamise kogemus asünkroosse API-ga Kafka-l

  1. BOB saab tagasimakse taotluse.
  2. BOB teatab sellest Refund Tool-ile.
  3. Refund Tool ütleb Payment'ile: „Tagasta raha”.
  4. Payment tagastab raha.
  5. Refund Tool ja BOB sünkroonivad oma staatuseid, kuna nad vajavad seda praegu koos. Me ei ole veel valmis täielikult Refund Tooli üle minema, kuna BOB-is on UI, raamatupidamise aruanded ja palju andmeid, mida niisama lihtsalt ei saa üle kanda. Tuleb istuda kahe tooli peal.
  6. Fiskaliseerimise taotlus saadetakse.

Lõpuks olime loonud Kafka abil mingi sündmusete busi - event-bus, millele kõik toetuvad. Hurra, nüüd on meil üksik rikke punkt (sarcasm).

Refund Tooli teenuse arendamise kogemus asünkroosse API-ga Kafka-l

Plussid ja miinused on üsna ilmsed. Me oleme loonud busi, mis tähendab, et nüüd sõltuvad kõik teenused sellest. See lihtsustab projekteerimist, kuid toob süsteemi sisse ühtse rikke punkti. Kui Kafka kukub, siis protsess seiskub.

Mis on events-driven API

Hea vastus sellele küsimusele on Martin Fowleri raportis (GOTO 2017) «The Many Meanings of Event-Driven Architecture».

Lühidalt, mida me tegime:

  1. Kaasasime kõik asünkroonsed vahetused läbi events storage. Selle asemel, et teavitada igat huvitatud tarbijat võrgu kaudu staatuse muutumisest, kirjutame kesksete andmete ladudesse sündmuse oleku muutumisest ja teemaga huvitatud tarbijad loevad sealt kõike, mis seal ilmub.
  2. Sündmus (event) antud juhul on teade (teated) selle kohta, et midagi kuskil on muutunud. Näiteks tellimuse staatuse muutmine. Tarbija, kellele on olulised mõned saatmise staatus muutumised ja keda ei teavitata, saab ise nende staatust teada.
  3. Maksimaalne variant on täielik event sourcing, oleku ülekanne, kus sündmus sisaldab kogu infot, mis on vajalik töötlemiseks: kust ja millisesse olekusse mindi, kuidas täpselt andmed muutusid jne. Küsimus on vaid selle otstarbekuses ja infomahus, mida saate endale lubada salvestada.

Refund Tooli käivitamise raames kasutasime kolmandat varianti. See lihtsustas sündmuste töötlemist, kuna ei olnud vaja detaile välja kaevata, ja välistas stsenaariumi, kus iga uus sündmus tekitab tarbijatelt palju täpsustavaid GET-päringuid.

Refund Tool teenus ei ole koormatud, seega on Kafka seal pigem katse kui vajadus. Ma ei arva, et kui tagasiside teenus muutuks high-load projektiks, oleks äri rõõmus.

Async exchange AS IS

Asünkroonsete vahetuste jaoks kasutab PHP osakond tavaliselt RabbitMQ-d. Andmed kogutakse päringu jaoks, asetatakse järjekorda ja selle teenuse tarbija loeb selle üles ja saadab (või ei saada). API jaoks kasutab Lamoda aktiivselt Swaggerit. Kujundame API, kirjeldame seda Swaggeris, genereerime kliendi- ja serverikoodi. Samuti kasutame veidi laiendatud JSON RPC 2.0.

Mõnes kohas kasutatakse esb-busse, mõned elavad activeMQ peal, kuid üldiselt, RabbitMQ on standard.

Asünkroonne vahetus TO BE

Kujundades vahetust events-buse kaudu, on jälgitav analoogia. Kirjeldame tulevasi andmevahetusi sarnasel viisil, nagu kirjeldame event'i struktuuri. YAML formaat, koodi genereerimine tuli ise teha, genereerija vastavalt spetsifikatsioonile loob DTO-d ja õpetab kliente ja servereid nendega töötama. Genereerimine toimub kahele keelele - golang ja php. See võimaldab hoida teeke kooskõlas. Geneerija on kirjutatud golangis, mille tõttu sai nimeks gogi.

Event-sourcing Kafka peal on tüüpiline asi. On lahendus peamisest ettevõtteversioonist Kafka Confluent, on nakadi, lahendus meie "vennadelt" domeeni valdkonnas Zalando. Meie motiiv alustada vanilla Kafka'ga — see on jätta lahendus tasuta, kuni otsustame, kas me kavatseme seda laialdaselt kasutada, samuti jätta endale manööverdusruumi ja arendustööd: me soovime oma toetust JSON RPC 2.0, genereerijad kahe keele jaoks ja vaatame, mis veel.

Ironiseeriv on see, et isegi sellises õnnelikus olukorras, kus on umbes sarnane ettevõte Zalando, mis tegi umbes sarnase lahenduse, ei saa me seda tõhusalt kasutada.

Arhitektuuriliselt on käivitamisel muster selline: loeme otse Kafka-st, kuid kirjutame ainult läbi events-bus. Kafka-s on palju valmis lahendusi: vahendajad, tasakaalustajad ja see on enam-vähem valmis horisontaalseteks skaleerimiseks, mida tahtsime säilitada. Kirjutamine, aga meie soov oli mähkida see ühe Gateway ehk Events-bus kaudu, ja sellepärast.

Events-bus

Või sündmuste buss. See on lihtsalt stateless http gateway, mis võtaks enda kanda mitmeid olulisi rolle:

  • Produksiooni valideerimine — kontrollime, et sündmused vastavad meie spetsifikatsioonile.
  • Sündmuste meister-süsteem, see, see, see see see ,见 see 这种情况下这个 产品是 . it 公司的主要和唯一的系统,它负责回答哪些 events 和哪些结构被视为合法的。 这个验证简单包括数据类型和 enums 用于内容的严格规范。
  • Hash-funktsioon ja , seal on sharding — Kafka sõnumi struktuur on key-value ja see arvutab, kuhu see panna, vastavalt key hash'ile.

Miks

Tegeleme suure ettevõttega, kus on sissetöötatud protsess. Miks peaks midagi muutma? See on eksperiment, ja me loodame saada mitmeid eeliseid.

1:n+1 vahetused (üks-kui-mitmed)

Kafka ühendamine uute tarbijatega on väga lihtne.

Oletame, et teil on register, mida tuleb mitmes süsteemis korraga ajakohasena hoida (ja mõnes uues). Varem kasutasime bundlet, mis rakendas set-API-d, ning teatasime peamisele süsteemile tarbijate aadressid. Nüüd saadab peamine süsteem värskendusi teemasse ja kõik, keda huvitab, loevad seda. Ilmus uus süsteem — registreerisime selle teemasse. Jah, jälle bundle, aga lihtsam.

Refund-tool, mis on osa BOB-ist, suudame me lihtsalt läbi Kafka neid sünkroonida. Payment ütleb, et raha on tagasi antud: BOB ja RT saavad sellest teada, muudavad oma staatuseid, Fiscalization Service saab samuti teada ja väljastab arve.

Refund Tooli teenuse arendamise kogemus asünkroosse API-ga Kafka-l

Meie plaan on luua ühine Notifications Service, mis teavitaks klienti tema tellimuse/tagastuste kohta. Praegu on see vastutus hajutatud süsteemide vahel. Meie jaoks piisab, kui õpetada Notifications Service'ile Kafka kaudu asjakohast teavet hankima ja sellele reageerima (ja teistes süsteemides need teavitused välja lülitama). Uusi otseseid vahetusi pole vaja.

Andmepõhine

Teave süsteemide vahel muutub läbipaistvaks — ükskõik kui suur "verine ettevõte" teil on ja kui mahukas teie backlog on. Lamodas on Data Analytics osakond, mis kogub andmeid süsteemidelt ja viib need edasi kasutatavasse vormi nii äri kui ka intellektuaalsete süsteemide jaoks. Kafka võimaldab kiiresti neile palju andmeid anda ja hoida seda infovooge ajakohasena.

Replikatsiooni logi

Sõnumid ei kao pärast lugemist, nagu RabbitMQ-s. Kui sündmus sisaldab piisavalt teavet töötlemiseks, tekib meil objekti viimaste muudatuste ajalugu ning soovi korral ka võimalus neid muudatusi rakendada.

Replikatsioonilogide säilitamise aeg sõltub salvestamise intensiivsusest sellele teemale; Kafka võimaldab paindlikult seadistada talletamise ajapiire ja andmemahtu. Intensiivsete teemade puhul on oluline, et kõik tarbijad suudaksid teavet lugeda enne, kui see kaob, isegi lühiajalise töökatkestuse korral. Tavaliselt õnnestub andmeid säilitada päevade kaupa, mis on täiesti piisav toe jaoks.

Refund Tooli teenuse arendamise kogemus asünkroosse API-ga Kafka-l

Edasi natuke dokumentatsiooni juttu, neile, kes ei ole Kafka'ga tuttavad (pilt ka dokumentatsioonist)

AMQP-s on järjekorrad: kirjutame sõnumid järjekorda tarbijale. Üldiselt töötleb ühte järjekorda üks süsteem, millel on sama äriloogika. Kui on vaja teavitada mitmeid süsteeme, saab rakendust õpetada kirjutama mitmesse järjekorda või seadistada vahetus (exchange) fanout-mehhanismiga, mis kopeerib neid automaatselt.

Kafkas on sarnane abstraktsioon teema, kuhu saadate sõnumeid, kuid need ei kao pärast lugemist. Vaikimisi, kui ühendate Kafka-sse, saate kõik sõnumid ja teil on võimalus salvestada koht, kus peatusite. See tähendab, et loete järjekorras, saate mitte märkida sõnumit loetuks, kuid salvestate id, kust jätkate lugemist. Id, kus te peatusite, nimetatakse offsetiks, ja mehhanismiks on commit offset.

Seega on võimalik rakendada erinevat loogikat. Näiteks meie BOB eksisteerib 4 instantsis erinevates riikides — Lamoda on Venemaal, Kazahstanis, Ukrainas ja Valgevenes. Kuna need paigaldatakse eraldi, on neil veidi oma konfiguratsioonid ja oma äriloogika. Me määrame sõnumis, millele riigile see kuulub. Iga BOB tarbija igas riigis loeb erinevate groupId-dega ja kui sõnum ei kuulu tema alla, jääb see vahele, t.j. kommitib kohe offset +1. Kui sama teemat loeb meie Makseteenus, siis teeb ta seda eraldi grupiga ja seetõttu offsetid ei kattu.

Nõuded sündmusele:

  • andmete täielikkus. Soovime, et sündmusel oleks piisavalt teavet töötlemiseks.

  • Täiuslikkus. Me kasutame Events-bus'i, et kontrollida, kas sündmus on järjepidev ja kas seda saab töödelda.
  • Järjekord on oluline. Tagastamise korral peame tuginema ajaloole. Teavituste puhul pole järjekord oluline, kuna homogeensetel teavitustel on e-kiri sama, sõltumata tellimuse saabumise järjekorrast. Tagastamise korral on protsess selge, ja kui järjekorda muuta, võivad tekkida erandid: tagasimakset ei genereerita ega töödeldud — me jõuame teise staadiumisse.
  • Konsistentsus. Meil on salvestusruum, ja nüüd loome me API asemel sündmusi. Meil on vaja kiiret ja odavat viisi, kuidas edastada meie teenustele teavet uutest sündmustest ja juba olemasolevate muudatustest. See saavutatakse üldise spetsifikatsiooni kaudu eraldi git-repositooriumis ja koodigeneraatorite abil. Seega on klientide ja serverite ühtsus tagatud erinevates teenustes.

Kafka Lamodas

Meil on kolm Kafka installatsiooni:

  1. Logid;
  2. R&D;
  3. Events-bus.

Täna räägime ainult viimasest punktist. Events-bus'is on meil mitte eriti suured installatsioonid — 3 maaklerit (serverit) ja kokku 27 teemat. Üldiselt on üks teema üks protsess. Kuid see on delikaatne küsimus ja sellele me peagi jõuame.

Refund Tooli teenuse arendamise kogemus asünkroosse API-ga Kafka-l

Ülal on rps graafik. Tagastusprotsess on tähistatud türkiissinise joonega (jah-jah, see, mis asub X-teljel), ja roosa joonega on sisu värskendamise protsess.

Lamoda kataloog sisaldab miljoneid tooteid, samas kui andmed uuendatakse pidevalt. Ühed kollektsioonid kaovad moest, nende asemele tulevad uued, kataloogis ilmuvad pidevalt uued mudelid. Püüame ennustada, mis võib meie klientidele homme huvi pakkuda, seetõttu ostame pidevalt uusi asju, pildistame neid ja uuendame vitriini.

Roosad tipud tähistavad toote värskendust, see tähendab muudatusi toodetes. Näha on, et poisid pildistasid, pildistasid ja siis äkki — laadisid korraliku koguse sündmusi üles.

Lamoda sündmuste kasutusjuhtumid

Ehitatud arhitektuuri kasutame selliste operatsioonide jaoks:

  • Tagastuste staatuste jälgimine: call-to-action ja seisundite jälgimine kõikidest seotud süsteemidest. Maksmine, seisundid, fiskaalprobleemid, teavitused. Siin katsetasime lähenemist, lõime tööriistad, kogusime kõik vead, kirjutasime dokumentatsiooni ja rääkisime kolleegidele, kuidas seda kasutada.
  • Toote kaartide värskendamine: konfiguratsioon, metaandmed, omadused. Üks süsteem loeb (mis kuvab), mitmed kirjutavad.
  • Email, push ja sms: tellimus on kogutud, tellimus on kohale jõudnud, tagastus on aktsepteeritud jne., neid on palju.
  • Laoseis, laovaru värskendamine — kvantitatiivne värskendamine nimedest, lihtsalt numbrid: laoseis, tagastus. On vajalik, et kõik süsteemid, mis on seotud kauba reserveerimisega, töötaksid maksimaalselt aktuaalsete andmetega. Praegu on laovaru värskendamine üsna keeruline, Kafka lihtsustab seda.
  • Andmeanalüüs (R&D-osakond), ML- tööriistad, analüüs, statistika. Soovime, et teave oleks läbipaistev — selleks sobib Kafka hästi.

Nüüd huvitavam osa vigadest ja huvitavatest avastustest, mis toimusid poole aasta jooksul.

Disainiprobleemid

Oletame, et tahame luua midagi uut — näiteks viia kogu kohaletoimetamise protsess üle Kafka. Praegu toimub osa protsessist Order Processingus BOBis. Tellimuse edastamine tarneteenusele, liikumine vahepealsesse ladustamisse ja muu on staatuse mudel. Seal on terve monoliit, isegi kaks, pluss palju API-sid, mis on pühendatud kohaletoimetamisele. Need teavad kohaletoimetamisest palju rohkem.

Tundub, et need on sarnased valdkonnad, kuid Order Processing BOBis ja kohaletoimetamise süsteemi staatused erinevad. Näiteks mõned kulleriteenused ei edasta vahepealseid staatusi, vaid ainult lõplikud: „toimetatud” või „kadunud”. Teised, vastupidi, annavad väga detailselt teavet kauba liikumise kohta. Igalühel on oma valideerimise reeglid: mõne jaoks on e-mail kehtiv, seega töödeldakse seda; teiste jaoks ei ole see kehtiv, kuid tellimust töödeldakse siiski, sest on olemas telefon, mida kasutada, ja mõni ütleb, et sellist tellimust ei hakata üldse töötlema.

Andmevoog

Kafka puhul kerkib esile andmevoo korraldamise küsimus. See ülesanne on seotud strateegia valimisega mitmes punktis, vaatame neid kõiki läbi.

Ühte teemat või erinevatesse?

Meil on sündmuse spetsifikatsioon. BOBis kirjutame, et konkreetne tellimus tuleb kohaletoimetada ja näitame: tellimuse number, selle sisu, mingid SKU-d ja baarikoodid jne. Kui kaup jõuab laole, saavad kohaletoimetajad staatuseid, ajatempleid ja kõik vajalikud andmed. Siiski tahame BOBis saada nende andmete põhjal uuendusi. Meil tekib tagasisideandmete protsess kohaletoimetamisest. Kas see on sama sündmus? Või on see eraldi vahetus, mis väärib eraldi teemat?

Tõenäoliselt on nad väga sarnased ja kiusatus teha üks teema on põhjendatud, kuna eraldi teema tähendab eraldi tarbijaid, eraldi seadistusi, eraldi genereerimist. Kuid see ei ole fakt.

Uus väli või uus sündmus?

Kuid kui kasutada samu sündmusi, siis tekib teine probleem. Näiteks ei suuda kõik kohaletoimetamissüsteemid genereerida sellist DTO-d, mida BOB suudaks genereerida. Saame neile id, kuid nad ei salvesta neid, kuna need pole neile vajalikud. Siiski on see väli vajalik ürituste bussi protsessi käivitamiseks.

Kui me seame event-bus'i jaoks reegli, et see väli on kohustuslik, siis peame BOB-is või algse sündmuse töötlejas seadma täiendavad valideerimise reeglid. Valideerimine hakkab levi­mass teenuses — see ei ole väga mugav.

Veel üks probleem on inclemental arendamise ahvatlus. Meile öeldakse, et peame sündmusele midagi lisama, ja võib-olla, kui hästi mõelda, oleks see pidanud olema eraldi sündmus. Kuid meie skeemis on eraldi sündmus eraldi teema. Eraldi teema on kogu see protsess, mida ma eespool kirjeldasin. Arendajal on kiusatus lihtsalt lisada JSON skeemile veel üks väli ja uuesti genereerida.

Refundide puhul jõudsime poole aasta jooksul sündmuste sündmuseni. Meil oli üks meta-sündmus, mille nimi oli refund update, milles oli väli type, mis kirjeldas, milles see uuendus täpselt seisneb. Sellega olid meil "suurepärased" lülitid valideerijatega, mis ütlesid, kuidas seda sündmust selle type'iga valideerida.

Sündmuste versioonimine

Kafka sõnumite valideerimiseks saab kasutada Avro, kuid seda pidi kohe arvesse võtma ja kasutama Confluent'i. Meie versioonimisjuhtumi puhul tuleb olla ettevaatlik. Kõikide teateid replication log'ist uuesti lugeda ei pruugi alati õnnestuda, kuna mudel 'põgeneb'. Peamiselt õnnestub ehitada versioone nii, et mudel oleks tagasi ühilduv: näiteks võib teha välja ajutiselt mitte kohustuslikuks. Kui erinevused on liiga suured, hakkame kirjutama uude teema ja kliendid vahetavad, kui nad on vana lõpetanud.

Partitsioonide lugemise järjekorra garantii

Kafka sees jagunevad teemad partitsioonideks. See ei ole kuigi oluline seni, kuni projekteerime entiteete ja vahetusi, kuid see on oluline, kui otsustame, kuidas seda tarbida ja skaleerida.

Tavaliselt kirjutate Kafka-sse ühe teema. Vaikimisi kasutatakse ühte partition'i, ja kõik selle teema sõnumid lähevad sinna. Tarbija loeb need sõnumid järjestikku. Oletame, et nüüd on vajalik süsteemi laiendamine nii, et sõnumeid loeksid kaks erinevat tarbijat. Kui teil näiteks saata SMS, siis saate paluda, et Kafka teeks täiendava partition'i, ja Kafka hakkab sõnumeid kahe osa peale jagama — poole sinna, poole tänne.

Kuidas Kafka neid jagab? Igal sõnumil on sisu (kus me hoiame JSON-i) ja on olemas key. Sellele võtmele saab rakendada hash-funktsiooni, mis määrab, millisesse partition'i sõnum satub.

Meie puhul, mis puudutab tagasimakseid, on see oluline: kui võtame kaks partition'i, on võimalus, et paralleelne tarbija töötleb teise sündmuse enne esimest ja see on probleem. Hash-funktsioon tagab, et sama võtmega sõnumid satuvad ühte ja samasse partition'i.

Sündmused vs käsud

See on veel üks probleem, millega me silmitsi seisame. Üritus on konkreetne sündmus: me räägime, et midagi kuskil juhtus (something_happened), näiteks, et ese tühistati või toimus tagasimakse. Kui keegi neid sündmusi kuulab, siis 'ese tühistati' loob tagasimakse (refund) entiteedi, ja 'toimus tagasimakse' registreeritakse kuskil seadistustes.

Aga tavaliselt, kui te disainite sündmusi, ei taha te neid ju asjata kirjutada — te loodate, et keegi neid loeb. On suur kiusatus kirjutada mitte something_happened (item_canceled, refund_refunded), vaid something_should_be_done. Näiteks, ese on tagastamiseks valmis.

Ühelt poolt annab see vihje, kuidas sündmust hakatakse kasutama. Teiselt poolt, see näeb palju vähem välja nagu normaalne sündmuse nimetus. Lisaks sellele ei ole sellest kaugel ka käsk do_something. Kuid teil ei ole garanteeritud, et keegi seda sündmust üldse luges; ja isegi kui luges, siis võib-olla mitte edukalt; ja kui luges edukalt, siis tegi midagi, ja see midagi läks edukalt. Selle hetke jooksul, kui sündmus muutub do_something'iks, muutub tagasiside vajalikuks, ja see on probleem.

Refund Tooli teenuse arendamise kogemus asünkroosse API-ga Kafka-l

RabbitMQ asünkroonses suhtluses, kui olete sõnumi lugenud, läinud HTTP-sse ja saanud vastuse — vähemalt selle, et sõnum on vastu võetud. Kui olete Kafka'sse kirja pannud, siis on sõnum, et olete Kafka'sse kirjutanud, kuid selle töötlemise kohta ei tea te midagi.

Seetõttu pidime meie puhul rakendama tagasiside sündmuse ja seadistama monitooringu, et kui teatud arv sündmusi on välja heidetud, siis mingisuguse aja jooksul peaks tulema sama palju vastavaid sündmusi. Kui seda ei juhtunud, siis näib, et midagi läks valesti. Näiteks, kui me saatsime sündmuse «item_ready_to_refund», siis ootame, et tagasimakse luuakse, kliendile tagastatakse raha ja meile tuleb sündmus «money_refunded». Kuid see ei ole kindel, seetõttu on monitooring vajalik.

Nüansid

On üsna ilmselge probleem: kui loete järjestikku topikust ja teil on mõni halb sõnum, siis tarbija kukub välja ja edasi te ei liigu. Teil on vaja peatada kõik tarbijad, kommitida edasiminek, et edasi lugemist jätkata.

Me teadsime sellest, me arvestasime sellega, ja see juhtus ikka. Ja see juhtus sellepärast, et sündmus oli valideeritud events-bus'i seisukohalt, sündmus oli valideeritud rakenduse valideerija seisukohalt, kuid see ei olnud valideeritud PostgreSQL'i seisukohalt, kuna meil oli ühes süsteemis MySQL, kus oli UNSIGNED INT, ja värskelt kirjutatud süsteemis oli PostgreSQL lihtsalt INT. Selle suurus on veidi väiksem ja Id ei mahtunud ära. Symfony suri erandisse. Loomulikult püüdsime me erandi kinni, kuna olime selle jaoks arvestanud, ja kavas oli kommitida see offset, aga enne seda soovisime probleemide loendit suurendada, kuna sõnum töötati ebaõnnestunult läbi. Loendurid selle projekti jaoks on samuti andmebaasis, kuid Symfony oli juba lõpetanud suhtluse andmebaasiga, ja teine erand tappis kogu protsessi ilma võimaluseta offset'i kommitida.

Mõnda aega service seisis - õnneks, Kafka puhul pole see nii hirmus, kuna sõnumid jäävad alles. Kui töö taastub, saab neid edasi lugeda. See on mugav.

Kafkal on võimalik tööriistade kaudu seada suvaline offset. Kuid selleks, et seda teha, tuleb kõik tarbijad peatada — meie puhul tähendab see eraldi väljaande ettevalmistamist, kus ei ole tarbijaid, redeployments. Siis saab Kafkas tööriistade kaudu offseti nihutada ning sõnum läbib.

Teine nüanss — replikatsioonilog vs rdkafka.so — on seotud meie projekti spetsiifikaga. Meil on PHP ja PHP-s suhtlevad enamasti kõik raamatukogud Kafkaga läbi rdkafka.so hoidla, ja edasi tuleb mingisugune wrapper. Võib-olla on need meie isiklikud raskused, kuid selgus, et lihtsalt varem loetud osa üle lugemine ei ole sugugi nii lihtne. Kokkuvõttes esines programmeerimisprobleeme.

Rääkides partitsioonide töötamisest, on otse dokumentatsioonis kirjas tarbijad >= teemade partitsioonid. Kuid ma sain sellest teada palju hiljem, kui oleksin soovinud. Kui soovite skaleeruda ja omada kahte tarbijat, vajate vähemalt kahte partitsiooni. See tähendab, et kui teil oli üks partitsioon, kuhu on kogunenud 20 tuhat sõnumit, ja te tegite uue, siis sõnumite arv ei tasandu kohe. Seega, et omada kahte paralleelset tarbimist, tuleb tegeleda partitsioonidega.

Jälgimine

Arvan, et meie jälgimise põhjal on veel selgem, millised probleemid esinevad praeguses lähenemisviisis.

Näiteks loeme, kui palju kaupu andmebaasis on hiljuti staatust muutnud, ja vastavalt sellele peaks toimuma sündmused, ning saadame selle arvu oma jälgimisse süsteemi. Seejärel saame Kafkast teise arvu, kui palju tegelikult sündmusi on registreeritud. Ilmselgelt peaks nende kahe arvu vahe olema alati null.

Refund Tooli teenuse arendamise kogemus asünkroosse API-ga Kafka-l

Lisaks tuleb jälgida, kuidas läheb producentidel, kas events-bus on sõnumeid vastu võtnud, ja kuidas läheb tarbijatel. Näiteks allolevatel diagrammidel on Refund Toolil kõik hästi, kuid BOB-iga on selgelt probleeme (sinised tipud).

Refund Tooli teenuse arendamise kogemus asünkroosse API-ga Kafka-l

Olen juba maininud tarbijagruppi viivitust. Teisisõnu, see on lugemata sõnumite arv. Üldiselt töötavad meie tarbijad kiiresti, seega on viivitus tavaliselt 0, kuid mõnikord võivad esineda lühiajalised tipud. Kafka suudab seda karbis hallata, kuid tuleb määrata mingisugune intervall.

On projekt Burrow, mis annab rohkem teavet Kafka kohta. See tagastab lihtsalt API kaudu consumer-group'i staatuse, kuidas selle grupi asjad edenevad. Lisaks OK ja Failed'on seal ka warning, ja saate teada, et teie tarbijad ei suuda tootmispeed'iga sammu pidada — ei jõua lugeda seda, mis kirjutatakse. Süsteem on üsna nutikas, seda on mugav kasutada.

Refund Tooli teenuse arendamise kogemus asünkroosse API-ga Kafka-l

Nii näeb välja API vastus. Siin on grupp bob-live-fifa, jagu refund.update.v1, staatuse OK, lag 0 — viimane lõplik offset on selline.

Refund Tooli teenuse arendamise kogemus asünkroosse API-ga Kafka-l

Jälgimine updated_at SLA (kinni jäänud) ma olen juba maininud. Näiteks, toode on läinud staatusele, et see on tagastamiseks valmis. Seame Croni, mis ütleb, et kui selle objekti staatust ei muudetud 5 minuti jooksul refund'iks (tagastame raha maksesüsteemide kaudu väga kiiresti), siis on midagi kindlasti valesti, ja see on kindlasti juhtum, millega tegeleb tugi. Seetõttu võtame lihtsalt Croni, mis loeb selliseid asju, ja kui need on rohkem kui 0, siis saadab häire.

Kokkuvõtteks, sündmuste kasutamine on mugav, kui:

  • teave on vajalik mitmele süsteemile;
  • tulemuse töötlemine pole oluline;
  • sündmusi on vähe või sündmused on väiksed.

Esmapärane, et artikli teema on üsna konkreetne - asünkroonne API Kafka põhjal, kuid selle taga on palju soovitusi.
Esiteks, järgmine HighLoad++ ei pea ootama novembrini, juba aprillis on selle Peterburi versioon ja juunis räägime suurtest koormustest Novosibirskis.
Teiseks, ettekande autor Sergei Zaika kuulub meie uue konverentsi teadmiste haldamise programmkotta KnowledgeConf. Konverents on ühepäevane ja toimub 26. aprillil, kuid programmil on väga tihe sisu.
Ja maikuus toimub PHP Russia ja RIT++ (DevOpsConfi koosseisus) - sinna saab veel oma teemat pakkuda, rääkida oma kogemusest ja kurtma oma kogetud probleemidest.

Allikas: habr.com

Osta usaldusväärne veebihosting DDoS kaitsega, VPS VDS serverid 🔥 Osta usaldusväärne veebihosting DDoS kaitsega, VPS VDS serverid | ProHoster