Kas varētu likt tik lielam uzņēmumam kā Lamoda ar racionalizētu procesu un desmitiem savstarpēji saistītu pakalpojumu būtiski mainīt savu pieeju? Motivācija var būt pilnīgi atšķirīga: no likumdošanas līdz vēlmei eksperimentēt, kas raksturīga visiem programmētājiem.
Bet tas nenozīmē, ka jūs nevarat rēķināties ar papildu priekšrocībām. Sergejs Zaika pastāstīs, ko tieši jūs varat laimēt, ieviešot uz notikumiem orientētu API vietnē Kafka (). Noteikti tiks runāts arī par lieliem kadriem un interesantiem atklājumiem – bez tiem eksperiments neiztikt.

Atruna: šī raksta pamatā ir materiāli no tikšanās, ko Sergejs rīkoja 2018. gada novembrī vietnē HighLoad++. Lamoda tiešraides pieredze darbā ar Kafku piesaistīja klausītājus ne mazāk kā citi ziņojumi par grafiku. Mūsuprāt, šis ir lielisks piemērs tam, ka vienmēr var un vajag atrast domubiedrus, un HighLoad++ organizatori arī turpmāk centīsies radīt tam labvēlīgu atmosfēru.
Par procesu
Lamoda ir liela e-komercijas platforma, kurai ir savs kontaktu centrs, piegādes pakalpojums (un daudzi saistītie uzņēmumi), fotostudija, milzīga noliktava, un tas viss darbojas, izmantojot savu programmatūru. Ir vairāki desmiti maksājumu metožu, B2B partneri, kuri var izmantot dažus vai visus no šiem pakalpojumiem un vēlas uzzināt jaunāko informāciju par saviem produktiem. Turklāt Lamoda darbojas trīs valstīs bez Krievijas Federācijas un tur viss ir nedaudz savādāk. Kopumā, iespējams, ir vairāk nekā simts veidu, kā konfigurēt jaunu pasūtījumu, kas ir jāapstrādā savā veidā. Tas viss darbojas, izmantojot desmitiem pakalpojumu, kas dažreiz sazinās nepārprotamā veidā. Ir arī centrālā sistēma, kuras galvenā atbildība ir pasūtījumu statusi. Mēs viņu saucam par BOB, es strādāju ar viņu.
Atmaksas rīks ar uz notikumiem balstītu API
Vārds notikumu virzīts ir diezgan izlaists; nedaudz tālāk mēs sīkāk definēsim, kas ar to tiek domāts. Sākšu ar kontekstu, kurā mēs nolēmām izmēģināt uz notikumiem balstīto API pieeju Kafkā.

Jebkurā veikalā papildus pasūtījumiem, par kuriem klienti maksā, ir reizes, kad veikalam tiek prasīts atdot naudu, jo prece klientam nav bijusi piemērota. Tas ir salīdzinoši īss process: nepieciešamības gadījumā precizējam informāciju un pārskaitām naudu.
Bet atdošana kļuva sarežģītāka sakarā ar izmaiņām likumdošanā, un mums nācās tai ieviest atsevišķu mikropakalpojumu.

Mūsu motivācija:
- Likums FZ-54 - īsi sakot, likums nosaka, ka par katru naudas darījumu, neatkarīgi no tā, vai tā ir atgriešana vai kvīts, ir jāziņo nodokļu inspekcijai diezgan īsā SLA – dažu minūšu laikā. Mēs kā e-komercijas uzņēmums veicam diezgan daudz operāciju. Tehniski tas nozīmē jaunu atbildību (un līdz ar to jaunu pakalpojumu) un uzlabojumus visās iesaistītajās sistēmās.
- BOB sadalījums ir uzņēmuma iekšējais projekts, lai atbrīvotu BOB no daudziem nesaistītiem pienākumiem un samazinātu tā vispārējo sarežģītību.

Šī diagramma parāda galvenās Lamoda sistēmas. Tagad lielākā daļa no tiem ir vairāk 5-10 mikropakalpojumu konstelācija ap sarūkošu monolītu. Tie lēnām aug, bet cenšamies tos padarīt mazākus, jo vidū izvēlētā fragmenta izvietošana ir biedējoša - nevaram ļaut tam nokrist. Mēs esam spiesti rezervēt visas maiņas (bultiņas) un ņemt vērā to, ka kāda no tām var izrādīties nepieejama.
BOB ir arī diezgan daudz biržu: maksājumu sistēmas, piegādes sistēmas, paziņojumu sistēmas utt.
Tehniski BOB ir:
- ~150k koda rindiņu + ~100k rindiņu testu;
- php7.2 + Zend 1 un Symfony Components 3;
- >100 API un ~50 izejošās integrācijas;
- 4 valstis ar savu biznesa loģiku.
BOB izvietošana ir dārga un sāpīga, koda un atrisināmo problēmu daudzums ir tāds, ka neviens to visu nevar ielikt savā galvā. Kopumā ir daudz iemeslu, lai to vienkāršotu.
Atgriešanas process
Sākotnēji procesā ir iesaistītas divas sistēmas: BOB un Payment. Tagad parādās vēl divi:
- Fiskalizācijas dienests, kas parūpēsies par problēmām ar fiskalizāciju un saziņu ar ārējiem dienestiem.
- Atmaksas rīks, kas vienkārši satur jaunas maiņas, lai nepalielinātu BOB.
Tagad process izskatās šādi:

- BOB saņem atmaksas pieprasījumu.
- BOB stāsta par šo atmaksas rīku.
- Atmaksas rīks parāda maksājumam: “Atdod naudu”.
- Maksājums atdod naudu.
- Atmaksas rīks un BOB sinhronizē statusus viens ar otru, jo pagaidām abiem tas ir nepieciešams. Mēs vēl neesam gatavi pilnībā pāriet uz atmaksas rīku, jo BOB ir lietotāja saskarne, atskaites grāmatvedībai un kopumā daudz datu, kurus nevar tik vienkārši pārsūtīt. Jums jāsēž uz diviem krēsliem.
- Fiskalizācijas pieprasījums pazūd.
Rezultātā uz Kafkas uztaisījām tādu kā pasākumu autobusu - pasākums-buss, uz kura viss sākās. Urā, tagad mums ir viens neveiksmes punkts (sarkasms).

Plusi un mīnusi ir diezgan acīmredzami. Mēs uztaisījām autobusu, kas nozīmē, ka tagad no tā ir atkarīgi visi pakalpojumi. Tas vienkāršo dizainu, bet sistēmā ievieš vienu atteices punktu. Kafka sabruks, process apstāsies.
Kas ir uz notikumiem orientēta API
Laba atbilde uz šo jautājumu ir Martina Faulera ziņojumā (GOTO 2017) .
Īsumā, ko mēs darījām:
- Aptiniet visas asinhronās apmaiņas, izmantojot notikumu krātuve. Tā vietā, lai informētu katru ieinteresēto patērētāju par statusa maiņu tīklā, mēs rakstām notikumu par statusa maiņu centralizētajā krātuvē, un patērētāji, kurus interesē šī tēma, lasa visu, kas no turienes parādās.
- Šajā gadījumā notikums ir paziņojums (paziņojumi), ka kaut kas ir mainījies. Piemēram, ir mainījies pasūtījuma statuss. Patērētājs, kuru interesē daži statusa maiņu pavadošie dati, kas nav iekļauti paziņojumā, to statusu var uzzināt pats.
- Maksimālā iespēja ir pilnvērtīga pasākumu piegāde, valsts nodošana, kurā notikumā ir visa apstrādei nepieciešamā informācija: no kurienes tā nākusi un kādā statusā tā nonākusi, kā tieši dati mainījušies utt. Jautājums ir tikai par iespējamību un informācijas apjomu, ko varat atļauties uzglabāt.
Atmaksas rīka palaišanas ietvaros mēs izmantojām trešo iespēju. Šī vienkāršota notikumu apstrāde, jo nebija nepieciešamības iegūt detalizētu informāciju, kā arī tika novērsts scenārijs, kad katrs jauns notikums rada precizējošus pieprasījumus no patērētājiem.
Atmaksas rīku pakalpojums nav ielādēts, tāpēc Kafka ir vairāk pildspalvas garša nekā nepieciešamība. Es nedomāju, ka, ja atmaksas pakalpojums kļūtu par augstas slodzes projektu, bizness būtu laimīgs.
Asinhronā apmaiņa TĀDA, KĀ IR
Asinhronai apmaiņai PHP nodaļa parasti izmanto RabbitMQ. Mēs apkopojām pieprasījuma datus, ievietojām tos rindā, un tā paša pakalpojuma patērētājs tos izlasīja un nosūtīja (vai nenosūtīja). Pašai API Lamoda aktīvi izmanto Swagger. Mēs izstrādājam API, aprakstām to programmā Swagger un ģenerējam klienta un servera kodu. Mēs izmantojam arī nedaudz uzlabotu JSON RPC 2.0.
Dažās vietās tiek izmantoti ESB autobusi, daži dzīvo uz activeMQ, bet kopumā RabbitMQ - standarta.
Asinhronā apmaiņa TO BE
Projektējot apmaiņu, izmantojot notikumu autobusu, var izsekot līdzībai. Mēs līdzīgi aprakstām turpmāko datu apmaiņu, izmantojot notikumu struktūras aprakstus. Yaml formāts, mums pašiem bija jāveic koda ģenerēšana, ģenerators izveido DTO pēc specifikācijas un iemāca ar tiem strādāt klientiem un serveriem. Paaudze pāriet divās valodās - golang un php. Tas palīdz nodrošināt bibliotēku konsekvenci. Ģenerators ir rakstīts golangā, tāpēc tas ieguva nosaukumu gogi.
Pasākumu iegūšana vietnē Kafka ir tipiska lieta. Ir risinājums no Kafka Confluent galvenās uzņēmuma versijas , risinājums no mūsu domēna brāļiem Zalando. Mūsu motivācija sākt ar vaniļas Kafku - tas nozīmē atstāt risinājumu brīvi, līdz beidzot izlemsim, vai to izmantosim visur, kā arī atstāt sev manevra un uzlabojumu iespējas: mēs vēlamies atbalstu mūsu JSON RPC 2.0, ģeneratori divām valodām un redzēsim, kas vēl.
Ironiski, ka pat tik laimīgā gadījumā, kad ir aptuveni līdzīgs bizness Zalando, kas radīja aptuveni līdzīgu risinājumu, mēs nevaram to izmantot efektīvi.
Arhitektūras modelis palaišanas brīdī ir šāds: mēs lasām tieši no Kafkas, bet rakstām tikai caur notikumu autobusu. Kafkā daudz kas ir gatavs lasīšanai: brokeri, balansieri, un tas ir vairāk vai mazāk gatavs horizontālai mērogošanai, es gribēju to paturēt. Mēs vēlējāmies pabeigt ierakstu, izmantojot vienu Gateway jeb Events-bus, un lūk, kāpēc.
Pasākumi-autobuss
Vai pasākumu autobuss. Šī ir vienkārši bezvalstnieka http vārteja, kurai ir vairākas svarīgas lomas:
- Validācijas izgatavošana — mēs pārbaudām, vai pasākumi atbilst mūsu specifikācijām.
- Pasākumu meistarsistēma, proti, šī ir galvenā un vienīgā sistēma uzņēmumā, kas atbild uz jautājumu, kādi notikumi ar kādām struktūrām tiek uzskatīti par derīgiem. Validācija vienkārši ietver datu tipus un uzskaitījumus, lai stingri norādītu saturu.
- Hash funkcija sadalīšanai - Kafka ziņojuma struktūra ir atslēgas vērtība, un, izmantojot atslēgas jaucējkodu, tiek aprēķināts, kur to ievietot.
Kāpēc
Mēs strādājam lielā uzņēmumā ar racionalizētu procesu. Kāpēc kaut ko mainīt? Šis ir eksperiments, un mēs ceram gūt vairākas priekšrocības.
1:n+1 apmaiņas (no viena līdz daudzām)
Kafka ļauj ļoti vienkārši savienot jaunus patērētājus ar API.
Pieņemsim, ka jums ir direktorijs, kas ir jāatjaunina vairākās sistēmās vienlaikus (un dažās jaunās). Iepriekš mēs izgudrojām komplektu, kas ieviesa set-API, un galvenā sistēma tika informēta par patērētāju adresēm. Tagad galvenā sistēma nosūta tēmas atjauninājumus, un visi interesenti to izlasa. Ir parādījusies jauna sistēma - pierakstījāmies par tēmu. Jā, arī komplektā, bet vienkāršāk.
Atmaksas rīka gadījumā, kas ir BOB gabals, mums ir ērti tos sinhronizēt, izmantojot Kafka. Maksājumā teikts, ka nauda tika atgriezta: BOB, RT par to uzzināja, mainīja statusus, Fiskalizācijas dienests to uzzināja un izsniedza čeku.

Esam plānojuši izveidot vienotu Paziņojumu servisu, kas informētu klientu par jaunumiem saistībā ar viņa pasūtījumu/atgriešanu. Tagad šī atbildība ir sadalīta starp sistēmām. Pietiks, ja mēs iemācīsim Paziņojumu dienestam noķert no Kafkas būtisku informāciju un uz to reaģēt (un atspējot šos paziņojumus citās sistēmās). Jaunas tiešās apmaiņas nebūs vajadzīgas.
Datu vadīts
Informācija starp sistēmām kļūst caurspīdīga — neatkarīgi no tā, kāds jums ir "asiņains uzņēmums", un neatkarīgi no tā, cik liels ir jūsu neatmaksātais apjoms. Lamoda ir Datu analīzes nodaļa, kas apkopo datus no sistēmām un ievieto tos atkārtoti lietojamā formā gan biznesam, gan viedajām sistēmām. Kafka ļauj ātri sniegt viņiem daudz datu un atjaunināt šo informācijas plūsmu.
Replikācijas žurnāls
Ziņojumi pēc lasīšanas nepazūd, kā tas ir RabbitMQ. Ja notikums satur pietiekami daudz informācijas apstrādei, mums ir nesen veikto izmaiņu vēsture objektā un, ja vēlaties, iespēja piemērot šīs izmaiņas.
Replikācijas žurnāla glabāšanas periods ir atkarīgs no rakstīšanas intensitātes šajā tēmā; Kafka ļauj elastīgi iestatīt uzglabāšanas laika un datu apjoma ierobežojumus. Intensīvām tēmām ir svarīgi, lai visiem patērētājiem būtu laiks izlasīt informāciju, pirms tā pazūd, pat īslaicīgas nedarbošanās gadījumā. Parasti ir iespējams saglabāt datus par dienu vienības, kas ir pilnīgi pietiekami atbalstam.

Tālāk neliels dokumentācijas pārstāsts, tiem, kam Kafka nav pazīstama (bilde arī no dokumentācijas)
AMQP ir rindas: mēs rakstām ziņojumus uz rindu patērētājam. Parasti vienu rindu apstrādā viena sistēma ar tādu pašu biznesa loģiku. Ja jums ir jāinformē vairākas sistēmas, varat iemācīt lietojumprogrammai rakstīt vairākās rindās vai konfigurēt apmaiņu ar fanout mehānismu, kas pats tās klonē.
Kafkam ir līdzīga abstrakcija temats, kurā rakstāt ziņas, taču tās pēc izlasīšanas nepazūd. Pēc noklusējuma, kad izveidojat savienojumu ar Kafka, jūs saņemat visus ziņojumus un jums ir iespēja saglabāt no vietas, kur pārtraucāt. Tas ir, jūs lasāt secīgi, varat neatzīmēt ziņojumu kā lasītu, bet saglabāt id, no kura varat turpināt lasīt. Id, kuru izmantojāt, sauc par nobīdi, un mehānisms ir nobīde.
Attiecīgi var īstenot dažādu loģiku. Piemēram, mums ir BOB 4 gadījumos dažādām valstīm - Lamoda ir Krievijā, Kazahstānā, Ukrainā, Baltkrievijā. Tā kā tie tiek izvietoti atsevišķi, tiem ir nedaudz atšķirīgas konfigurācijas un sava biznesa loģika. Mēs ziņojumā norādām, uz kuru valsti tas attiecas. Katrs BOB patērētājs katrā valstī lasa ar atšķirīgu groupId, un, ja ziņojums uz viņu neattiecas, viņi to izlaiž, t.i. nekavējoties veic nobīdi +1. Ja to pašu tēmu lasa mūsu Maksājumu dienests, tas to dara ar atsevišķu grupu, un tāpēc ieskaiti nekrustojas.
Pasākuma prasības:
- Datu pilnīgums. Es vēlētos, lai pasākumam būtu pietiekami daudz datu, lai to varētu apstrādāt.
- Integritāte. Mēs deleģējam Events-bus pārbaudi, vai notikums ir konsekvents un var to apstrādāt.
- Kārtība ir svarīga. Atgriešanās gadījumā esam spiesti strādāt ar vēsturi. Ar paziņojumiem pasūtījums nav svarīgs, ja tie ir viendabīgi paziņojumi, e-pasts būs vienāds neatkarīgi no tā, kurš pasūtījums ieradās pirmais. Naudas atmaksas gadījumā ir skaidrs process, ja mainīsim pasūtījumu, radīsies izņēmumi, atmaksa netiks izveidota vai apstrādāta - mēs nonāksim citā statusā.
- Konsekvence. Mums ir veikals, un tagad mēs veidojam notikumus, nevis API. Mums ir nepieciešams veids, kā ātri un lēti pārsūtīt mūsu pakalpojumos informāciju par jauniem notikumiem un izmaiņām esošajos. Tas tiek panākts, izmantojot kopīgu specifikāciju atsevišķā git repozitorijā un kodu ģeneratoros. Tāpēc klienti un serveri dažādos servisos tiek saskaņoti.
Kafka Lamodā
Mums ir trīs Kafka instalācijas:
- Baļķi;
- R&D;
- Pasākumi-autobuss.
Šodien mēs runājam tikai par pēdējo punktu. Pasākumos-busā mums nav īpaši lielas instalācijas - 3 brokeri (serveri) un tikai 27 tēmas. Parasti viena tēma ir viens process. Bet tas ir smalks punkts, un mēs to tagad pieskarsim.

Augšpusē ir rps grafiks. Atmaksas process ir atzīmēts ar tirkīza līniju (jā, uz X ass), un rozā līnija ir satura atjaunināšanas process.
Lamoda katalogā ir miljoniem produktu, un dati tiek pastāvīgi atjaunināti. Dažas kolekcijas iziet no modes, to vietā tiek izlaistas jaunas, un katalogā pastāvīgi parādās jauni modeļi. Mēs cenšamies paredzēt, kas mūsu klientiem būs interesants rīt, tāpēc pastāvīgi iegādājamies jaunas lietas, fotografējam tās un atjaunojam vitrīnu.
Rozā virsotnes ir produktu atjauninājumi, tas ir, produktu izmaiņas. Redzams, ka puiši bildēja, bildēja, un tad atkal! — ielādēja pasākumu paku.
Lamoda Events lietošanas gadījumi
Mēs izmantojam konstruēto arhitektūru šādām darbībām:
- Atgriešanas statusa izsekošana: aicinājums uz darbību un statusa izsekošana no visām iesaistītajām sistēmām. Maksājums, statusi, fiskalizācija, paziņojumi. Šeit mēs pārbaudījām pieeju, izveidojām rīkus, savācām visas kļūdas, rakstījām dokumentāciju un stāstījām saviem kolēģiem, kā to izmantot.
- Produktu karšu atjaunināšana: konfigurācija, metadati, raksturlielumi. Viena sistēma lasa (kas tiek parādīta) un vairākas raksta.
- E-pasts, push un sms: pasūtījums ir savākts, pasūtījums ir pienācis, atgriešana ir pieņemta utt., to ir daudz.
- Krājumu, noliktavas atjaunošana — preču kvantitatīvs atjauninājums, tikai skaitļi: ierašanās noliktavā, atgriešana. Ir nepieciešams, lai visas sistēmas, kas saistītas ar preču rezervēšanu, darbotos ar jaunākajiem datiem. Pašlaik krājumu atjaunināšanas sistēma ir diezgan sarežģīta, Kafka to vienkāršos.
- Datu analīze (R&D nodaļa), ML rīki, analītika, statistika. Mēs vēlamies, lai informācija būtu caurspīdīga – Kafka tam ir labi piemērots.
Tagad interesantākā daļa par lielajiem izciļņiem un interesantiem atklājumiem, kas notikuši pēdējā pusgada laikā.
Dizaina problēmas
Pieņemsim, ka vēlamies veikt jaunu lietu – piemēram, nodot visu piegādes procesu Kafkai. Tagad daļa no procesa ir ieviesta pasūtījumu apstrādē BOB. Pasūtījuma nodošanas piegādes dienestam, pārvietošanas uz starpnoliktavu un tā tālāk ir statusa modelis. Ir vesels monolīts, pat divi, kā arī daudz API, kas paredzēti piegādei. Viņi zina daudz vairāk par piegādi.
Šķiet, ka šīs jomas ir līdzīgas, taču pasūtījumu apstrādei BOB un piegādes sistēmai ir atšķirīgi statusi. Piemēram, daži kurjerpakalpojumi nesūta starpposma statusus, bet tikai galīgos: “piegādāts” vai “pazaudēts”. Citi, gluži pretēji, ļoti detalizēti ziņo par preču apriti. Katram ir savi validācijas noteikumi: dažiem e-pasts ir derīgs, kas nozīmē, ka tas tiks apstrādāts; citiem tas nav derīgs, bet pasūtījums tik un tā tiks apstrādāts, jo ir telefona numurs saziņai, un kāds teiks, ka šāds pasūtījums netiks apstrādāts vispār.
Datu straume
Kafkas gadījumā rodas jautājums par datu plūsmas organizēšanu. Šis uzdevums ietver stratēģijas izvēli, pamatojoties uz vairākiem punktiem; apskatīsim tos visus.
Vienā tēmā vai dažādās?
Mums ir pasākuma specifikācija. BOB ierakstām, ka jāpiegādā tāds un tāds pasūtījums, un norādām: pasūtījuma numuru, tā sastāvu, dažus SKU un svītrkodus utt. Precēm nonākot noliktavā, piegāde varēs saņemt statusus, laika zīmogus un visu nepieciešamo. Bet tad mēs vēlamies saņemt atjauninājumus par šiem datiem BOB. Mums ir apgriezts datu saņemšanas process no piegādes. Vai tas ir tas pats pasākums? Vai arī šī ir atsevišķa apmaiņa, kas ir pelnījusi savu tēmu?
Visticamāk, tie būs ļoti līdzīgi, un kārdinājums taisīt vienu tēmu nav nepamatots, jo atsevišķa tēma nozīmē atsevišķus patērētājus, atsevišķas konfigurācijas, atsevišķu ģenerēšanu tam visam. Bet ne fakts.
Jauns lauks vai jauns pasākums?
Bet, ja izmantojat tos pašus notikumus, rodas cita problēma. Piemēram, ne visas piegādes sistēmas var ģenerēt tādu DTO, kādu var ģenerēt BOB. Mēs viņiem nosūtām ID, bet viņi to nesaglabā, jo viņiem tas nav vajadzīgs, un no notikumu kopnes procesa sākšanas viedokļa šis lauks ir obligāts.
Ja mēs ieviešam notikumu kopnes noteikumu, ka šis lauks ir obligāts, mēs esam spiesti iestatīt papildu validācijas noteikumus BOB vai sākuma notikumu apdarinātājā. Validācija sāk izplatīties visā pakalpojumā - tas nav ļoti ērti.
Vēl viena problēma ir kārdinājums pakāpeniski attīstīties. Mums saka, ka kaut kas ir jāpapildina ar pasākumu, un varbūt, ja tā padomājam, tam vajadzēja būt atsevišķam pasākumam. Bet mūsu shēmā atsevišķs pasākums ir atsevišķa tēma. Atsevišķa tēma ir viss iepriekš aprakstītais process. Izstrādātājam ir kārdinājums vienkārši pievienot citu lauku JSON shēmai un to atjaunot.
Naudas atmaksas gadījumā notikumu pasākumā ieradāmies pusgada laikā. Mums bija viens meta-notikums, ko sauc par atmaksas atjauninājumu, kurā bija tipa lauks, kurā aprakstīts, kas patiesībā ir šis atjauninājums. Tāpēc mums bija “brīnišķīgi” slēdži ar pārbaudītājiem, kuri mums pastāstīja, kā apstiprināt šo notikumu ar šāda veida palīdzību.
Notikuma versiju veidošana
Lai apstiprinātu ziņojumus Kafkā, varat izmantot , bet vajadzēja uzreiz uz tā likt un lietot Confluent. Mūsu gadījumā mums jābūt uzmanīgiem ar versiju veidošanu. Ne vienmēr būs iespējams atkārtoti nolasīt ziņojumus no replikācijas žurnāla, jo modelis ir “palicis”. Būtībā izrādās, ka versijas ir jāveido tā, lai modelis būtu saderīgs ar atpakaļejošu spēku: piemēram, uz laiku padariet lauku neobligātu. Ja atšķirības ir pārāk lielas, mēs sākam rakstīt jaunā tēmā un nododam klientus, kad viņi pabeidz lasīt veco.
Garantēta nodalījumu lasīšanas secība
Tēmas Kafkas iekšienē ir sadalītas nodalījumos. Tas nav īpaši svarīgi, kamēr mēs veidojam entītijas un biržas, taču tas ir svarīgi, lemjot, kā to patērēt un mērogot.
Parastā gadījumā tu raksti vienu tēmu Kafkā. Pēc noklusējuma tiek izmantots viens nodalījums, un visi ziņojumi šajā tēmā tiek novirzīti uz to. Līdz ar to patērētājs šos ziņojumus lasa secīgi. Teiksim, tagad sistēma ir jāpaplašina, lai ziņojumus lasītu divi dažādi patērētāji. Ja, piemēram, sūtāt SMS, varat likt Kafkai izveidot papildu nodalījumu, un Kafka sāks sadalīt ziņojumus divās daļās - puse šeit, puse šeit.
Kā Kafka tos sadala? Katram ziņojumam ir pamatteksts (kurā mēs glabājam JSON) un atslēga. Šai atslēgai varat pievienot jaucējfunkciju, kas noteiks, kurā nodalījumā ziņojums tiks nosūtīts.
Mūsu gadījumā ar atmaksām tas ir svarīgi, ja ņemam divus nodalījumus, tad pastāv iespēja, ka paralēlais patērētājs apstrādās otro notikumu pirms pirmā un būs nepatikšanas. Jaukšanas funkcija nodrošina, ka ziņojumi ar vienu un to pašu atslēgu nonāk tajā pašā nodalījumā.
Notikumi vs komandas
Šī ir vēl viena problēma, ar kuru mēs saskārāmies. Notikums ir noteikts notikums: mēs sakām, ka kaut kur kaut kas noticis (something_nopped), piemēram, prece tika atcelta vai atmaksāta nauda. Ja kāds klausās šos notikumus, saskaņā ar “prece cancelled” tiks izveidota atmaksas vienība un kaut kur iestatījumos tiks ierakstīts “atmaksa notikusi”.
Bet parasti, plānojot pasākumus, jūs nevēlaties tos rakstīt velti - jūs paļaujaties uz to, ka kāds tos izlasīs. Pastāv liels kārdinājums rakstīt nevis kaut ko_noticis (prece_canceled, refund_refunded), bet kaut ko_vajadzētu_izdarīt. Piemēram, prece ir gatava atgriešanai.
No vienas puses, tas liecina, kā pasākums tiks izmantots. No otras puses, tas daudz mazāk izklausās pēc parasta notikuma nosaukuma. Turklāt tas nav tālu līdz komandai do_something. Bet jums nav garantijas, ka kāds izlasīs šo notikumu; un ja izlasi, tad veiksmīgi izlasīji; un ja tu to veiksmīgi izlasīji, tad kaut ko izdarīji, un tas kaut kas izdevās. Brīdī, kad notikums kļūst par kaut ko darīt, ir nepieciešama atgriezeniskā saite, un tā ir problēma.

RabbitMQ asinhronajā apmaiņā, izlasot ziņojumu, dodieties uz http, jums ir atbilde - vismaz, ka ziņojums tika saņemts. Kad tu raksti Kafkai, parādās ziņa, ko tu rakstīji Kafkai, bet tu neko nezini par to, kā tas tika apstrādāts.
Līdz ar to mūsu gadījumā nācās ieviest atbildes notikumu un izveidot monitoringu, lai, ja tiktu nosūtīts tik daudz notikumu, pēc tāda un tāda laika pienāktu tikpat daudz atbildes notikumu. Ja tas nenotiek, tad šķiet, ka kaut kas ir nogājis greizi. Piemēram, ja mēs nosūtījām notikumu “item_ready_to_refund”, mēs sagaidām, ka tiks izveidota atmaksa, nauda tiks atgriezta klientam un mums tiks nosūtīts pasākums “money_refunded”. Bet tas nav droši, tāpēc ir nepieciešama uzraudzība.
Nianses
Pastāv diezgan acīmredzama problēma: ja jūs lasāt no tēmas secīgi un jums ir slikta ziņa, patērētājs kritīs, un jūs netiksit tālāk. Tev vajag apturēt visus patērētājus, veiciet nobīdi tālāk, lai turpinātu lasīt.
Mēs par to zinājām, ar to rēķinājāmies, un tomēr tas notika. Un tas notika tāpēc, ka notikums bija derīgs no notikumu-bus viedokļa, notikums bija derīgs no lietojumprogrammu validatora viedokļa, bet tas nebija derīgs no PostgreSQL viedokļa, jo mūsu sistēmā MySQL ar UNSIGNED INT sistēmā bija PostgreSQL tikai ar INT. Viņa izmērs ir nedaudz mazāks, un ID nederēja. Simfonijs nomira ar izņēmumu. Mēs, protams, uztvērām izņēmumu, jo paļāvāmies uz to un gatavojāmies veikt šo nobīdi, taču pirms tam mēs vēlējāmies palielināt problēmu skaitītāju, jo ziņojums tika apstrādāts neveiksmīgi. Arī šī projekta skaitītāji ir datu bāzē, un Symfony jau ir slēdzis saziņu ar datu bāzi, un otrais izņēmums nogalināja visu procesu bez iespējas veikt kompensāciju.
Serviss kādu laiku nogulēja - par laimi ar Kafku nav tik slikti, jo ziņas paliek. Kad darbs ir atjaunots, varat pabeigt to lasīšanu. Tas ir ērti.
Kafka spēj iestatīt patvaļīgu nobīdi, izmantojot instrumentus. Bet, lai to izdarītu, jums ir jāaptur visi patērētāji - mūsu gadījumā sagatavojiet atsevišķu laidienu, kurā nebūs patērētāju, pārdalīšanas. Pēc tam programmā Kafka varat novirzīt nobīdi, izmantojot instrumentus, un ziņojums tiks nosūtīts.
Vēl viena nianse - replikācijas žurnāls vs rdkafka.so - ir saistīts ar mūsu projekta specifiku. Mēs izmantojam PHP, un PHP, kā likums, visas bibliotēkas sazinās ar Kafku caur rdkafka.so repozitoriju, un tad ir kaut kāds iesaiņojums. Varbūt tās ir mūsu personīgās grūtības, bet izrādījās, ka vienkārši pārlasīt kādu gabalu no jau izlasītā nav nemaz tik viegli. Kopumā bija programmatūras problēmas.
Atgriežoties pie darba ar starpsienām specifikas, tas ir rakstīts tieši dokumentācijā patērētāji >= tēmu nodalījumi. Bet es par to uzzināju daudz vēlāk, nekā es vēlētos. Ja vēlaties mērogot un jums ir divi patērētāji, jums ir nepieciešami vismaz divi nodalījumi. Tas ir, ja jums bija viens nodalījums, kurā bija uzkrājušies 20 tūkstoši ziņojumu, un jūs izveidojāt jaunu, ziņojumu skaits drīz netiks izlīdzināts. Tāpēc, lai būtu divi paralēli patērētāji, jums jārīkojas ar starpsienām.
Uzraudzība
Es domāju, ka tas, kā mēs to uzraudzīsim, būs vēl skaidrāks, kādas problēmas ir esošajā pieejā.
Piemēram, mēs aprēķinām, cik produktu datubāzē nesen ir mainījuši statusu, un attiecīgi notikumiem, pamatojoties uz šīm izmaiņām, bija jānotiek, un mēs nosūtām šo numuru mūsu uzraudzības sistēmai. Tad no Kafkas mēs iegūstam otro numuru, cik notikumu faktiski tika ierakstīti. Acīmredzot atšķirībai starp šiem diviem skaitļiem vienmēr jābūt nullei.

Turklāt jums ir jāuzrauga, kā klājas ražotājam, vai notikumi-bus saņemtie ziņojumi un kā klājas patērētājam. Piemēram, zemāk redzamajās diagrammās Atmaksas rīks darbojas labi, bet BOB acīmredzami ir dažas problēmas (zilas virsotnes).

Es jau minēju patērētāju grupas nobīdi. Aptuveni runājot, tas ir nelasīto ziņojumu skaits. Kopumā mūsu patērētāji strādā ātri, tāpēc nobīde parasti ir 0, bet dažreiz var būt īslaicīgs maksimums. Kafka to var izdarīt no kastes, taču jums ir jāiestata noteikts intervāls.
Ir projekts kas sniegs jums vairāk informācijas par Kafku. Tā vienkārši izmanto patērētāju grupas API, lai sniegtu statusu, kā šai grupai veicas. Papildus OK un Failed ir brīdinājums, un jūs varat uzzināt, ka jūsu patērētāji nevar tikt galā ar ražošanas tempu - viņiem nav laika rakstītā korektūru. Sistēma ir diezgan gudra un viegli lietojama.

Šādi izskatās API atbilde. Šeit ir grupa bob-live-fifa, partition refund.update.v1, statuss OK, lag 0 - pēdējā gala nobīde tāda un tāda.

Uzraudzība updated_at SLA (iestrēdzis) Es jau minēju. Piemēram, prece ir mainījusies uz statusu, ka tā ir gatava atgriešanai. Instalējam Cron, kas saka, ja 5 minūšu laikā šis objekts nav aizgājis uz atmaksu (ļoti ātri atdodam naudu caur maksājumu sistēmām), tad kaut kas noteikti nogāja greizi, un šis noteikti ir atbalsta gadījums. Tāpēc mēs vienkārši ņemam Cron, kas nolasa šādas lietas, un, ja tās ir lielākas par 0, tad tas nosūta brīdinājumu.
Rezumējot, notikumu izmantošana ir ērta, kad:
- informācija ir nepieciešama vairākām sistēmām;
- apstrādes rezultāts nav svarīgs;
- ir maz pasākumu vai nelielu notikumu.
Šķiet, ka rakstam ir ļoti specifiska tēma - asinhronā API uz Kafka, bet saistībā ar to es gribētu ieteikt daudzas lietas uzreiz.
Pirmkārt, nākamais jāgaida līdz novembrim, aprīlī būs Sanktpēterburgas versija, un jūnijā runāsim par lielām slodzēm Novosibirskā.
Otrkārt, ziņojuma autors Sergejs Zaika ir mūsu jaunās zināšanu pārvaldības konferences programmu komitejas loceklis. . Konference ir vienas dienas, notiks 26.aprīlī, bet tās programma ir ļoti spraiga.
Un tas būs maijā и (ar iekļautu DevOpsConf) - jūs varat arī ieteikt savu tēmu tur, runāt par savu pieredzi un sūdzēties par saviem pildītajiem čiekuriem.
Avots: www.habr.com
