Mis võib sundida nii suurt ettevõtet nagu Lamoda, kellel on sujuv protsess ja kümneid omavahel seotud teenuseid, oluliselt oma lähenemist muutma? Motivatsioon võib olla täiesti erinev: seadusandlikest põhjustest kuni kõigile arendajatele omase katsetussoovini.
Kuid see ei tähenda sugugi, et ei saa loota lisakasu peale. Mida konkreetselt võib võita, kui rakendada events-driven API-d Kafka peal, selgitab Sergei Zaika (). Ka kepiga käidud teed ja huvitavad avastused tulevad kindlasti juttu – eks katse ei saa ilma nendeta olla.

Eesõigus: See artikkel põhineb materjalidel, mis tulenesid meetapist, mille Sergei viis läbi novembris 2018 HighLoad++-il. Lamoda elukogemus Kafka kasutamisest tõmbas kuulajate tähelepanu mitte vähem kui teised ettekanded ajakavas. Me arvame, et see on suurepärane näide sellest, kuidas alati ja tuleb leida üksteisemõistvaid inimesi, ning HighLoad++ korraldajad jätkavad püüdlust luua sellele soodsa atmosfääri.
Protsessist
Lamoda on suur e-kaubanduse platvorm, millel on oma kontaktikeskus, kohaletoimetamisteenused (ja palju partnerite teenuseid), fotostuudio, suur ladu ja kõik see töötab oma tarkvaral. On kümneid makseviise, b2b-partnereid, kes saavad kasutada osa või kõiki neid teenuseid ja tahavad teada oma toodete kohta jooksvalt teavet. Lisaks tegutseb Lamoda kolmes riigis väljaspool Venemaad, kus kõik on veidi teistsugune. Seega on tõenäoliselt olemas rohkem kui sada viisi, kuidas uut tellimust konfigureerida, mida tuleb eraldi töödelda. Kõik see toimib kümnete teenuste abil, mis suhtlevad kohati mitteüheselt. On ka keskne süsteem, mille peamine vastutus on tellimuste staatused. Me nimetame seda BOB-iks, mina töötan selle nimel.
Refund Tool with events-driven API
Sõna events-driven on üsna kasutatud, veidi hiljem määratleme, mida selle all mõistetakse. Alustan kontekstiga, milles otsustasime events-driven API-d Kafka peal proovida.

Igas poes, peale tellimuste, mille eest kliendid maksavad, on hetki, kus poelt oodatakse raha tagastamist, kuna toode ei sobinud kliendile. See suhteliselt lühike protsess: täpsustame teavet, kui see on vajalik, ja kanname raha tagasi.
Kuid tagastamise protsess on muutunud keeruliseks seadusandlikest muudatustest tulenevalt ja me pidime selle jaoks rakendama eraldi mikroteenuse.

Meie motivatsioon:
- Seadus FZ-54 — lühidalt, seadus nõuab igast rahalisest tehingust, olgu see tagastus või sisse tulek, teavitamist maksuhaldurile üsna lühikese SLAga, mõne minuti jooksul. Meie, kui e-kaubandus, teeme üsna palju tehinguid. Tehniliselt tähendab see uut vastutust (ehk siis uut teenust) ja täiustusi kõigis seotud süsteemides.
- BOB split — ettevõtte sisemine projekt, et vabaneda BOBist suurest hulgast mitteprofiilsest vastutusest ja vähendada selle üldist keerukust.

Sellel skeemil on kujutatud Lamoda põhitehnoloogiaid. Praegu esindavad enamik neist pigem 5-10 mikroteenuse tähtkuju, mis keerleb väheneva monoliidi ümber.Need kasvavad tasapisi, kuid püüame neid vähendada, sest keskmise osa välja andmine on hirmutav — ei tohi lubada, et see kukub. Kõik vahetused (nooled) peame varundama ja arvestama, et üks neist võib olla kättesaamatu.
BOB-is on samuti palju vahetusi: maksesüsteemid, tarne, teavitused jne.
Tehniliselt on BOB:
- ~150k koodirida + ~100k testide rida;
- php7.2 + Zend 1 & Symfony Components 3;
- >100 API & ~50 väljuvat integratsiooni;
- 4 riiki oma äriloogikaga.
BOB-i rakendamine on kulukas ja valus, koodihulk ja sellega lahendatavad ülesanded on nii suured, et keegi ei saa seda täielikult oma peasse paigutada. Üldiselt on palju põhjuseid selle lihtsustamiseks.
Tagastamisprotsess
Alguses on protsessis kaasatud kaks süsteemi: BOB ja Maksmine. Nüüd lisanduvad veel kaks:
- Fiskalisatsiooni teenus, mis võtab enda kanda fiskaliseerimise probleemid ja suhtlemise välistest teenustest.
- Tagastamise tööriist, kuhu lihtsalt viidatakse uued vahetused, et mitte paisutada BOB-i.
Nüüd näeb protsess välja nii:

- BOB saab raha tagastamise taotluse.
- BOB teavitab sellest Tagastamise tööriista.
- Tagastamise tööriist ütleb Maksmisele: „Tagasta raha.”
- Maksmine tagastab raha.
- Tagastamise tööriist ja BOB sünkroniseerivad omavahel staatuseid, sest see on neile mõlemale endiselt vajalik. Me pole veel valmis täielikult üle minema Tagastamise tööriistale, kuna BOB-is on kasutajaliides, raamatupidamisteatised ja üldiselt palju andmeid, mida ei saa nii lihtsalt üle viia. Peame istuma kahel toolil.
- Teave saadetakse fiskaliseerimiseks.
Lõpuks tegime me Kafka põhjal mingi ürituste buss - event-bus, millele kõik tuginevad. Hooray, nüüd on meil üksik tõrkepunkt (sarcasm).

Plussid ja miinused on üsna ilmsed. Me tegime bussi, seega sõltuvad kõik teenused sellest. See lihtsustab projekteerimist, kuid toob süsteemi ühe tõrkepunkti. Kui Kafka seab end, siis protsess peatub.
Mis on events-driven API
Hea vastus sellele küsimusele on Martin Fowler'i ettekandes (GOTO 2017) .
Lühidalt, mida me tegime:
- Käppisime kõik asünkroonsed vahetused läbi events storage. Selle asemel, et teavitada iga huvitatud tarbijat võrgu kaudu staatuse muutumisest, kirjutame me tsentraliseeritud salvestusse sündmuse staatuse muutumisest, ja teemaga huvitatud tarbijad loevad sealt kõik, mis ilmub.
- Sündmus (event) antud juhul on teade (notifications) selle kohta, et midagi kuskil on muutunud. Näiteks, tellimuse staatust on muudetud. Tarbija, kellele on olulised teatud saatemuutuste andmed, mida teates ei ole, saab nende seisundit ise teada.
- Maksimaalne variant on täielik event sourcing, state transfer, kus sündmus sisaldab kogu vajalikku teavet töötlemiseks: kust ja millisesse staatusesse liikusid, kuidas andmed täpselt muutusid jne. Küsimus on ainult otstarbekuses ja teabe mahus, mida saate endale lubada salvestada.
Refund Tool'i käivitamise raames kasutasime me kolmandat varianti. See lihtsustas sündmuste töötlemist, kuna pole vaja hankida detailselt teavet, pluss välistas stsenaariumi, kus iga uus sündmus tekitab tarbijatelt hulgaliselt täpsustavaid get-päringuid.
Refund Tool teenus ei ole koormatud, seega on Kafka seal pigem katse kui vajadus. Ei arva, et kui tagastusteenus muutuks suure koormuse projektiks, oleks äri sellega rahul.
Async exchange AS IS
Asünkroonsete vahetuste jaoks kasutab PHP osakond tavaliselt RabbitMQ. Koondame andmed päringu jaoks, paneme järjekorda ja selle sama teenuse tarbija loeb need ja saadab (või ei saada). Lamoda kasutab API jaoks aktiivselt Swaggerit. Projekteerime API, kirjeldame seda Swaggeris, genereerime kliendi- ja serverikoodi. Veel kasutame me veidi laiemat JSON RPC 2.0.
Kohati kasutatakse esb-busse, keegi elab activeMQ peal, kuid üldiselt, RabbitMQ - standard.
Async exchange TO BE
Projekteerides vahetust events-bus kaudu, võib märgata sarnast mustrit. Me kirjeldame sarnasel viisil tulevast andmevahetust event'i struktuuri kirjeldustega. YAML-formaat, koodigeneratsiooni pidime tegema ise, generaator vastavalt spetsifikatsioonile loob DTO ja õpetab kliente ja servereid nendega töötama. Generatsioon toimub kahes keeles - golang ja php. See võimaldab hoida raamatukogud kooskõlas. Generaator on kirjutatud golang'is, mille tõttu sai ta nimeks gogi.
Event-sourcing Kafka peal on tüüpiline. On lahendus peamisest ettevõtte versioonist Kafka Confluent, on , lahendus meie "vendadelt" valdkonna alal Zalando. Meie motivation alustada vanilla Kafka'ga on see, et jätta lahendus tasuta, kuni me lõpuks ei otsusta, kas me kavatseme seda laialdaselt kasutada, ning jätta endale ruumi manööverdamiseks ja täiustamiseks: me tahame toetada JSON RPC 2.0, generaatorid kahes keeles ja vaatame, mis veel.
Ironiline on see, et isegi sellises õnnelikus olukorras, kus on umbes sarnane äri nagu Zalando, mis on teinud umbes sarnase lahenduse, ei saa me seda tõhusalt kasutada.
Arhitektuuriliselt on käivitamise musternäide järgmine: loeme otse Kafka'st, kuid kirjutame ainult läbi events-bus'i. Kafka lugemiseks on palju valmis lahendusi: broker'id, tasakaalustajad ja see on enam-vähem valmis horisontaalseks skaleerimiseks, seda soovisime säilitada. Kirjutamine, soovisime aga mähkida ühe Gateway aka Events-bus'i kaudu ja just sellepärast.
Events-bus
Või sündmuste buss. See on lihtsalt stateless http gateway, mis võtab endale mitu olulist rolli:
- Tootmise valideerimine kontrollime, et sündmused vastavad meie spetsifikatsioonile.
- Sündmuste meistrisüsteem, see tähendab, et see on ainus ja peamine süsteem ettevõttes, mis vastab küsimusele, millised sündmused milliste struktuuridega loetakse kehtivaks. Valideerimisse kuuluvad lihtsalt andmetüübid ja enums sisu range spetsifikatsiooni jaoks.
- Hash-funktsioon shardimise jaoks - Kafka sõnumite struktuur on key-value ja just key hash'i järgi arvutame, kuhu see panna.
Miks
Me töötame suures ettevõttes, kus on välja töötatud protsess. Miks midagi muuta? See on eksperiment, ja me loodame saada mitmeid eeliseid.
1:n+1 vahetused (üks-mitmele)
Kafka'ga on väga lihtne ühendada uusi tarbijaid API-le.
Oletame, et teil on kataloog, mida tuleb üheaegselt mitmes süsteemis ajakohasena hoida (ja mingites uutes süsteemides samuti). Varem koostasime kimbu, mis rakendas set-API-d, ning master-süsteemile edastasime tarbijate aadressid. Nüüd saadab master-süsteem värskendusi teema, mida kõik huvilised loevad. Ilmus uus süsteem – registreerisime selle teemale. Jah, samuti kimp, kuid lihtsam.
Refund-tool'i puhul, mis on osa BOB-ist, on meil mugav hoida neid Kafka kaudu sünkroonitud. Maksmine ütleb, et raha on tagastatud: BOB ja RT said sellest teada, muutsid oma staatuseid ning Fiskalitise teenus sai sellest teada ja väljastas tšeki.

Meil on plaanis luua ühtne Teavitusteenus, mis teavitaks klienti tema tellimuste/tagastuste uudistest. Praegu on see vastutus jaotatud süsteemide vahel. Meil piisab, kui õpetame Teavitusteenusele välja püüda Kafka-st asjakohast teavet ning sellele reageerida (ja välja lülitada teiste süsteemide teavitused). Uusi vahetusi ei ole vaja.
Andmepõhine
Teave süsteemide vahel muutub läbipaistvaks – olenemata sellest, kui „verine” ettevõte teil parasjagu on ja kui mahukas on teie backlog. Lamodas on andmeanalüüsi osakond, mis kogub süsteemidest andmeid ja viib need taassendrisse kasutatavasse vormi, nii äri kui ka intellektuaalsete süsteemide jaoks. Kafka võimaldab kiiresti anda neile palju andmeid ja hoida seda infovoogu ajakohasena.
Replikatsiooni ajalugu
Sõnumid ei kao pärast lugemist, nagu RabbitMQ-s. Kui sündmus sisaldab piisavalt teavet töötlemiseks, siis meil on viimaste muudatuste ajalugu objekti kohta ja vajadusel võimalus neid muudatusi rakendada.
Replikatsiooni ajaloos säilitamise tähtaeg sõltub selle teema kirjutamisintensiivsusest, Kafka võimaldab paindlikult seadistada säilitamise ajapiiranguid ja andmemahtusid. Intensiivsete teemade puhul on oluline, et kõik tarbijad jõuaksid teavet lugeda enne, kui see kaob, isegi lühiajalise töökatkestuse korral. Tavaliselt õnnestub andmeid hoida päevade kaupa, mis on piisav toetuse jaoks.

Edasi läheb veidi dokumentatsiooni rääkimist nendele, kes ei tunne Kafka't (pilt on samuti dokumentatsioonist)
AMQP'is on järjekorrad: kirjutame sõnumeid tarbija järjekorda. Üldjuhul töötlebs üks süsteem sama äri-logikaga ühte järjekorda. Kui on vaja teavitada mitmeid süsteeme, saab rakendust õpetada kirjutama mitmesse järjekorda või seadistada exchange fännideadme süsteemiga, mis kloonib neid.
Kafkas on sarnane abstraktsioon teema, kuhu kirjutate sõnumeid, kuid need ei kao pärast lugemist. Vaikesätte järgi, kui ühendate Kafkasse, saate kõik sõnumid, ja samas on võimalus salvestada koht, kus te lõpetasite. See tähendab, et loete järjestikku, ei pea sõnumit loetuks märgima, kuid saate salvestada id, kust hiljem lugemisega jätkata. Id, kus te lõpetasite, nimetatakse offset'iks (nihe), ja mehhanismiks on commit offset.
Seega saab rakendada erinevat loogikat. Näiteks BOB eksisteerib neljas instantsis erinevates riikides – Lamoda on Venemaal, Kasahstanis, Ukrainas, Valgevenes. Kuna neid rakendatakse eraldi, on neil natuke erinevad konfiguratsioonid ja äri-loogika. Me märgime sõnumis, millisele riigile see kuulub. Iga BOB tarbija igas riigis loeb erineva groupId'ga ja kui sõnum ei kuulu neile, siis nad jätavad selle vahele, st nad kommitivad kohe offset +1. Kui sama teema loeb meie Makseteenus, siis teeb ta seda eraldi grupiga ja seega offset'id ei ristile.
Nõuded sündmustele:
- Andmete täielikkus. Sooviks, et sündmuses oleks piisavalt andmeid, et seda saaks töödelda.
- Terviklikkus. Delegeerime Events-bus'ile kontrolli, et sündmus oleks järjekindel ja ta saaks selle töödelda.
- Järjekord on oluline. Tagastamise korral peame töötama ajaloo baasil. Teavituste puhul ei ole järjekord tähtis, kui need on ühtsed teavitused, e-kiri on sama, olenemata sellest, milline tellimus saabus esimesena. Tagastamise korral on selge protsess, kui järjekorda muuta, siis võivad tekkida erandid, tagasimakset ei luu või ei töödelda – satume teise olekusse.
- Sisukaal. Meil on salvestusruum ja nüüd loome sündmusi, mitte API-d. Me vajame kiiret ja odavat viisi, et edastada teenustele teavet uutest sündmustest ja juba olemasolevate muutustest. Selle saavutame ühiselt määratletud spetsifikatsiooni ja koodigeneraatoreid kasutades eraldi git-repositooriumis. Seetõttu on meie kliendid ja serverid erinevates teenustes kooskõlastatud.
Kafka Lamodas
Meil on kolm Kafka installeerimist:
- Logs;
- R&D;
- Events-buss.
Täna räägime ainult viimase punktist. Events-bussis ei ole meil väga suuri installeerimisi – 3 pakkujat (serverit) ja kokku 27 teemat. Reeglina on üks teema üks protsess. Kuid see on delikaatne teema, ja me käsitleme seda kohe.

Ülal on rps graafik. Tagasimaksete protsess on märgitud türkiissinise joonega (jah, jah, see, mis asub X-teljel), ja roosa on sisu uuendamise protsess.
Lamoda kataloogis on miljoneid tooteid, ja andmeid uuendatakse pidevalt. Ühed kollektsioonid kaovad moest, nende asemele tulevad uued, ning kataloogis tekivad pidevalt uued mudelid. Püüame ennustada, mis võiks meie klientidele homseks huvi pakkuda, seetõttu ostame pidevalt uusi asju, pildistame neid ja uuendame väljapanekut.
Roosad tipud on tooteuuenduse, see tähendab muudatusi toodetes. Näha on, et meie mehed pildistasid, pildistasid, ja siis järsku! — laadisid üles hulga sündmusi.
Lamoda sündmuste kasutusjuhtumid
Ehitatud arhitektuuri kasutame selliste toimingute jaoks:
- Tagasimaksete staatuste jälgimine: üleskutse ja staatuste jälgimine kõigilt osalevatelt süsteemidelt. Maksmine, staatused, maksustamine, teavitamine. Siin katsetasime lähenemist, tegime tööriistad, kogusime kõik vead, kirjutasime dokumentatsiooni ja rääkisime kolleegidele, kuidas seda kasutada.
- Tooteinfo uuendamine: konfiguratsioon, metaandmed, omadused. Üks süsteem loeb (mis kuvab), ja mitu kirjutab.
- Email, push ja sms: tellimus on kokku pandud, tellimus on kohal, tagasimakse on vastu võetud jne, neid on palju.
- Laoseis, laouuendus — kvantitatiivne uuendus nimedele, lihtsalt numbrid: lao saabumine, tagastamine. Vajame, et kõik toote reserveerimisega seotud süsteemid töötaksid võimalikult värskete andmete alusel. Praegu on laouuendamise süsteem üsna keeruline, Kafka lihtsustab seda.
- Andmeanalüüs (R&D-osakond), ML-tööriistad, analüütika, statistika. Me soovime, et teave oleks läbipaistev - selleks sobib Kafka hästi.
Nüüd huvitavam osa kogemustest ja huvitavatest avastustest, mis on toimunud poole aasta jooksul.
Projekteerimise probleemid
Oletame, et soovime teha midagi uut - näiteks viia kogu tarneprotsessi üle Kafka peale. Praegu on osa protsessist ellu viidud Order Processing'is BOB-is. Tellimuse edastamise, vahehoidlasse liikumise ja muude asjade jaoks on olemas staatuse mudel. Seal on üks korralik monoliit, isegi kaks, pluss hulk API-sid, mis on seotud tarnega. Need teavad tarne kohta palju rohkem.
Tundub, et need on sarnased valdkonnad, kuid Order Processing BOB-is ja tarne süsteemi staatused erinevad. Näiteks mõne kullerteenuse puhul ei saadeta vahepealseid staatuseid, vaid ainult lõppsidet: 'toimetatud' või 'kadunud'. Teised, vastupidi, annavad väga detailset teavet kauba liikumise kohta. Kõigil on oma valideerimisreeglid: kellegi jaoks on e-post kehtiv, seega töötlevad nad seda; teiste jaoks on e-post kehtetu, kuid tellimus töödeldakse ikkagi, kuna kontaktiks on telefon, ja mõned ütlevad, et sellist tellimust ei hakata üldse töötlema.
Andmevoog
Kafka puhul tekib andmevoo korraldamise küsimus. See ülesanne on seotud strateegia valikuga mitmel korral, liigume nende kõigi kaudu.
Kas ühte teemasse või erinevatesse?
Meil on sündmuse spetsifikatsioon. BOB-is kirjutame, et seda ja seda tellimust tuleb toimetada, ning märkime: tellimuse number, selle koosseis, mõned SKU-d ja bar-koodid jne. Kui kaup jõuab hoiukohta, suudab tarne saada staatuseid, ajatempleid ja kõike vajalikku. Kuid edaspidi soovime BOB-is saada neid andmeid uuendustena. Meil tekib tagasisuunaline protsess andmete hankimiseks tarne kaudu. Kas see on sama sündmus? Või on tegemist eraldi vahetusega, mis väärib eraldi teemat?
Tõenäoliselt on nad väga sarnased, ja ahvatlus teha üks teema on põhjendatud, kuna eraldi teema tähendab eraldi tarbijaid, eraldi konfiguratsioone, selle kõik eraldi genereerimist. Kuid see pole kindlasti kindel.
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 suudab genereerida BOB. Saadame neile id, kuid nad ei salvesta neid, kuna need neile ei ole vajalikud, ning protsessi event-bus alustamise seisukohalt on see väli kohustuslik.
Kui me kehtestame event-bus’i jaoks reegli, et see väli on kohustuslik, peame lisama BOB-is või start-sündmuse töötlejas täiendavad valideerimise reeglid. Valideerimine hakkab teenuse peale laiali valguma — see ei ole väga mugav.
Veel üks probleem on inkrementaalse arenduse külgetõmme. Meile öeldakse, et peaksime sündmusele midagi lisama ja võib-olla, kui korralikult mõelda, oleks see pidanud olema eraldi sündmus. Kuid meie skeemis on eraldi sündmus eraldi teema. Eraldi teema on kõik see protsess, mida ma ülal kirjeldasin. Arendajal tekib kiusatus lihtsalt lisada JSON skeemi veel üks väli ja regenererida.
Refundide puhul jõudsime kuue kuu jooksul sündmuste sündmuseni. Meil oli üks meta-sündmus, mida nimetatakse refund update, milles oli väli type, mis kirjeldas, milles see uuendus seisneb. Selle tõttu olid meil "suurepärased" lülitid valideerijatega, mis ütlesid, kuidas seda sündmust selle type-ga valideerida.
Sündmuste versioonimine
Kafka sõnumite valideerimiseks saab kasutada , kuid seda tuli kohe ette näha ja kasutada Confluent'i. Meie puhul tuleb versioonimisega ettevaatlik olla. Mitte alati ei pruugi olla võimalik sõnumeid lugeda replication log'ist, kuna mudel on "lahkunud". Üldiselt tuleb luua versioone nii, et mudel oleks tagurpidi ühilduv: näiteks teha väli ajutiselt mitte-kohustuslikuks. Kui erinevused on liiga suured, hakkame kirjutama uude teema ja liigume klientidega üle, kui nad on vana lugenud.
Lugemise järjekorra garantii jagunemistes
Teemad Kafka-s on jagatud partitsioonideks. See ei ole väga tähtis, kuna projekteerime entiteete ja vahetusi, kuid on oluline, kui otsustame, kuidas seda tarbida ja skaleerida.
Tavaliselt kirjutate Kafka-sse ühe teema. Vaikimisi kasutatakse ühte partitsiooni, kuhu kõik selle teema sõnumid satuvad. Ja tarbija loeb vastavalt järjestikku neid sõnumeid. Oletame, et nüüd tuleb süsteemi laiendada nii, et sõnumeid loeks kaks erinevat tarbijat. Kui te näiteks saadate SMS-i, saab öelda, et Kafka loob täiendava partitsiooni, ja Kafka hakkab sõnumeid jagama kahe osa vahel – pooled siia, pooled sinna.
Kuidas Kafka need jagab? Igal sõnumil on sisu (kus me hoiame JSON-i) ja klahv. Sellele klahvile võib rakendada hash-funktsiooni, mis määrab, millisesse partitsiooni sõnum satub.
Meie tagastuste juhtumiga on see oluline; kui võtame kaks partitsiooni, on võimalus, et paralleelne tarbija töötleb teist sündmust enne esimest ja see toob kaasa probleeme. Hash-funktsioon tagab, et sama klahviga sõnumid satuvad samasse partitsioon.
Sündmused vs käsud
See on veel üks probleem, millega kokku puutusime. Sündmus on mingisugune juhtum: me ütleme, et midagi juhtus kuskil (something_happened), näiteks, ese tühistati või toimus tagastamine. Kui neid sündmusi keegi kuulab, siis «ese tühistati» toob endaga kaasa tagastuse loomise, ja «toimus tagastamine» salvestatakse kuskil seadistustes.
Kuid tavaliselt, kui te projekteerite sündmusi, ei soovi te neid asjata kirjutada – te loote seda, et keegi neid loeb. Suur kiusatus on kirjutada mitte something_happened (item_canceled, refund_refunded), vaid something_should_be_done. Näiteks, ese on tagastamiseks valmis.
Ühelt poolt viitab see, kuidas sündmust kasutatakse. Teiselt poolt, see ei sarnane tavalise sündmuse nimetusega. Lisaks sellele ei ole siin kaugel käsust do_something. Kuid teil ei ole garantiid, et keegi selle sündmuse lõi; ja kui keegi seda luges, siis kas ta luges selle edukalt; ja kui ta luges edukalt, siis ta tegi midagi, ja see midagi läks edukalt läbi. Hetkel, kui sündmus muutub do_something-iks, on vajalik tagasiside ning see on probleem.

Asünkroonse vahetuse korral RabbitMQ-s, kui olete sõnumi lugenud, läinud http-sse, on teil vastus – vähemalt, et sõnum oli vastu võetud. Kui te kirjutate Kafka-sse, on teade, et olete kirjutanud Kafka-sse, kuid te ei tea, kuidas see töödeldi.
Seega meie puhul pidime sisse viima vastusürituse ja seadistama jälgimise sellele, et kui on juhtunud nii palju sündmusi, peaks teatud aja pärast saabuma sama palju vastusüritusi. Kui seda ei toimu, siis tundub, et midagi on valesti läinud. Näiteks, kui me saatsime sündmuse „item_ready_to_refund“, ootame, et tagasimakse luuakse, klient saab raha tagasi ja me saame sündmuse „money_refunded“. Kuid see ei ole täpne, seega on jälgimine vajalik.
Nüansid
On üsna ilmne probleem: kui loete teemadelt järjestikku ja teil on mingi halb sõnum, lõppeb tarbija töö ja edasi ei saa minna. Teil on vaja peatada kõik tarbijad, salvestada offset edasi, et jätkata lugemist.
Me teadsime sellest, olime sellele seadnud reservi ja see juhtus ikkagi. Ja see juhtus, kuna sündmus oli kehtiv events-busi vaatenurgast, sündmus oli kehtiv rakenduse valideerija vaatenurgast, kuid see ei olnud kehtiv PostgreSQL vaatenurgast, sest ühes süsteemis oli meil MySQL UNSIGNED INT ja uues süsteemis oli PostgreSQL lihtsalt INT. Selle suurus on veidi väiksem ja ID ei mahuks sisse. Symfony jooksis välja erandi tõttu. Loomulikult püüdsime me erandi kinni, sest olime selle peale ette valmistanud ja plaanisime seda offsetit salvestada, kuid tahtsime enne seda probleemide arvu suurendada, kuna sõnumi töötlemine ebaõnnestus. Arvutid on selles projektis samuti andmebaasis, ja Symfony on juba lõpetanud ühenduse andmebaasiga ning teine erand hävitas kogu protsessi ilma võimaluseta offseti salvestada.
Mõnda aega töötas teenus – õnneks ei ole Kafka puhul see nii hirmus, kuna sõnumid püsivad. Kui töö taastub, siis saab need läbi lugeda. See on mugav.
Kafkal on võimalik tööriistade kaudu seada suvaline offset. Kuid selleks tuleb peatada kõik tarbijad – meie puhul valmistada eraldi versioon, kus tarbijaid ei ole, uue juurutamise puudumisel. Siis saab Kafkas tööriistade kaudu offseti nihutada ja sõnum läbib.
Teine nüanss - replication log vs rdkafka.so — on seotud meie projekti spetsiifikaga. Meil on PHP, ja PHP-s suhtlevad kõik raamatukogud tavaliselt Kafka'ga läbi rdkafka.so reposte, millele järgneb mingi ümbermõtestamine. Võib-olla on need meie isiklikud raskused, aga selgus, et lihtsalt uuesti lugeda varem loetud teksti ei ole sugugi lihtne. Ühesõnaga, olid tarkvaraprobleemid.
Naastes partitsioonide töötamise eripärade juurde, on otse dokumentatsioonis kirjutatud tarbijad >= teema partitsioonid. Aga ma sain sellest teada palju hiljem, kui oleks soovinud. Kui soovite skaleeruda ja omada kahte tarbijat, vajate vähemalt kahte partitsiooni. See tähendab, et kui teil oli üks partitsioon, kuhu oli kogunend 20 tuhat sõnumit, ja lõite uue, siis sõnumite arv ei tasandu varsti. Seetõttu, et saada kaks paralleelset tarbijat, tuleb osata partitsioonidega töötada.
Jälgimine
Ma arvan, et meie jälgimise põhjal on veel selgem, millised probleemid on olemasolevas lähenemises.
Näiteks loeme, kui palju tooteid andmebaasis on hiljuti staatust muutnud, ja vastavalt sellele peaksid olema toimunud sündmused, ning saadame selle arvu oma jälgimissüsteemi. Hiljem saame Kafka'st teise arvu, kui palju tegelikult sündmusi registreeriti. Ilmselgelt peaks nende kahe arvu vahe alati olema null.

Lisaks tuleb jälgida, kuidas on producer'i asjad, kas events-bus on sõnumid vastu võtnud, ja kuidas on tarbijaga. Näiteks allolevatel graafikutel on Refund Tool'il kõik korras, aga BOB'il on selgelt mingid probleemid (sinised tipud).

Olen juba maininud tarbijagruppi jääki. Üldiselt on see lugemata sõnumite arv. Kokkuvõttes töötavad meie tarbijad kiiresti, seetõttu on jääk tavaliselt 0, kuid mõnikord võib esineda lühiajalisi piike. Kafka suudab seda standardina, aga peate määrama mingi intervalli.
On projekt , mis annab teile rohkem teavet Kafka kohta. See lihtsalt API kaudu tarbijagruppide kohta annab staatuse, kuidas selle grupi asjad on. Peale OК ja Failed on seal ka hoiatus, ja saate teada, et teie tarbijad ei suuda tootmiskiirusest sammu pidada — nad ei suuda maha lugeda seda, mis on kirjutatud. Süsteem on üsna intelligentne ja seda on mugav kasutada.

Nii näeb API vastus välja. Siin on grupp bob-live-fifa, partitsioon refund.update.v1, staatus OK, jääk 0 — viimane lõpp offset on selline.

Jälgimine updated_at SLA (takerdunud) Ma juba mainisin. Näiteks toode on läinud staatusesse, et see on tagastamiseks valmis. Seame Croni, mis ütleb, et kui see objekt 5 minuti jooksul ei lähe refund'i (me tagastame raha maksesüsteemide kaudu väga kiiresti), siis on midagi kindlasti valesti läinud, ja see on kindlasti juhtum toetuse jaoks. Seetõttu võtame lihtsalt Croni, mis loeb selliseid asju, ja kui neid on rohkem kui 0, saadab see hoiatuse.
Kokkuvõttes on ürituste kasutamine mugav, kui:
- infot vajab mitu süsteemi;
- tulemus töötlemisel ei oma tähtsust;
- üritusi on vähe või üritused on väikesed.
Tundub, et artiklil on täiesti konkreetne teema – asünkroonne API Kafka peal, kuid seoses selle ka tahaks kohe palju soovitada.
Esiteks, järgmine peab ootama novembrini, aprillis tuleb selle Peterburi versioon ja juunis räägime suurtest koormustest Novosibirskis.
Teiseks, ettekande autor Sergei Zaika kuulub meie uue konverentsi programmeerimiskomiteesse teadmiste haldamise kohta. Konverents on ühes päevane, toimub 26. aprillil, kuid programm on väga tihe.
Ja veel mais toimub ja (DevOpsCon koosseisus) – sinna saab veel pakkuda oma teemat, rääkida oma kogemusest ja kaevata oma saadud mürgisteks.
Allikas: habr.com
