Esperienza in u sviluppu di u serviziu Refund Tool cù una API asincrona nantu à Kafka

Chì puderia furzà una cumpagnia cusì grande cum'è Lamoda, cù un prucessu simplificatu è decine di servizii interconnessi, à cambià significativamente u so approcciu ? A motivazione pò esse cumplitamenti sfarente: da legislativu à u desideriu di sperimentà inherente à tutti i programatori.

Ma questu ùn significa micca chì ùn pudete micca cuntà di benefici supplementari. Sergey Zaika vi dicerà esattamente ciò chì pudete vince se implementate l'API guidata da l'avvenimenti nantu à Kafka (pocuald). Ci serà ancu definitu di parlà di grandi colpi è scuperte interessanti - l'esperimentu ùn pò micca fà senza elli.

Esperienza in u sviluppu di u serviziu Refund Tool cù una API asincrona nantu à Kafka

Disclaimer: Questu articulu hè basatu annantu à i materiali di una riunione chì Sergey hà tenutu in Novembre 2018 in HighLoad++. L'esperienza in diretta di Lamoda di travaglià cù Kafka hà attiratu l'ascultori micca menu di l'altri rapporti nantu à u calendariu. Pensemu chì questu hè un esempiu eccellente di u fattu chì pudete è deve sempre truvà persone simili, è l'urganizatori di HighLoad ++ continuanu à pruvà à creà una atmosfera favurèvule à questu.

Circa u prucessu

Lamoda hè una grande plataforma di e-commerce chì hà u so propiu centru di cuntattu, serviziu di consegna (è parechji affiliati), un studio fotograficu, un magazzinu enormu, è tuttu questu funziona nantu à u so propiu software. Ci sò decine di metudi di pagamentu, partenarii b2b chì ponu aduprà alcuni o tutti issi servizii è volenu sapè infurmazione aghjurnata nantu à i so prudutti. Inoltre, Lamoda opera in trè paesi oltri a Federazione Russa è tuttu hè un pocu sfarente quì. In totale, ci sò prubabilmente più di centu manere di cunfigurà un novu ordine, chì deve esse processatu in u so modu. Tuttu chistu travaglia cù l'aiutu di decine di servizii chì qualchì volta cumunicanu in modi micca evidenti. Ci hè ancu un sistema cintrali chì a so principale rispunsabilità hè statu di ordine. A chjamemu BOB, u travagliu cun ella.

Strumentu di rimborsu cù l'API guidata da eventi

A parolla guidata da l'avvenimenti hè abbastanza manighjata; un pocu più in più, definiremu in più dettagliu ciò chì significa questu. Cumincià cù u cuntestu in quale avemu decisu di pruvà l'approcciu API guidatu da l'avvenimenti in Kafka.

Esperienza in u sviluppu di u serviziu Refund Tool cù una API asincrona nantu à Kafka

In ogni magazzini, in più di l'ordini per i quali i clienti paganu, ci sò i tempi quandu a tenda hè obligata à vultà soldi perchè u pruduttu ùn hè micca adattatu à u cliente. Questu hè un prucessu relativamente brevi: clarificà l'infurmazioni, se ne necessariu, è trasfiriu i soldi.

Ma u ritornu hè diventatu più cumplicatu per via di cambiamenti in a legislazione, è avemu avutu à implementà un microserviziu separatu per questu.

Esperienza in u sviluppu di u serviziu Refund Tool cù una API asincrona nantu à Kafka

A nostra motivazione:

  1. Legge FZ-54 - in cortu, a lege impone un rapportu à l'uffiziu di l'impositu annantu à ogni transazzione monetaria, sia un ritornu o una ricevuta, in un SLA abbastanza breve di pochi minuti. Noi, cum'è una sucietà di e-commerce, realizamu assai operazioni. Tecnicamente, questu significa una nova rispunsabilità (è dunque un novu serviziu) è migliurà in tutti i sistemi implicati.
  2. BOB split hè un prughjettu internu di a cumpagnia per allevà BOB da un gran numaru di rispunsabilità non core è riduce a so cumplessità generale.

Esperienza in u sviluppu di u serviziu Refund Tool cù una API asincrona nantu à Kafka

Stu diagramma mostra i principali sistemi Lamoda. Avà a maiò parte di elli sò più una custellazione di 5-10 microservizi attornu à un monolitu chì si riduce. Crescenu lentamente, ma avemu da pruvà à fà più chjuchi, perchè dispiegate u frammentu sceltu in u mità hè spaventosa - ùn pudemu micca permette di cascà. Semu furzati à riservà tutti i scambii (frecce) è pigliate in contu u fattu chì qualcunu di elli pò esse micca dispunibili.

BOB hà ancu assai scambii: sistemi di pagamentu, sistemi di consegna, sistemi di notificazione, etc.

Tecnicamente BOB hè:

  • ~ 150k linee di codice + ~ 100k linee di teste;
  • php7.2 + Zend 1 & Symfony Components 3;
  • > 100 API & ~ 50 integrazioni in uscita;
  • 4 paesi cù a so propria logica cummerciale.

A implementazione di BOB hè caru è dulurosu, a quantità di codice è di prublemi chì risolve hè cusì chì nimu pò mette tuttu in a so testa. In generale, ci sò parechje ragioni per simplificà.

Prucessu di ritornu

In principiu, dui sistemi sò implicati in u prucessu: BOB è Pagamentu. Avà pareanu dui altri:

  • U serviziu di fiscalizazione, chì curarà i prublemi cù a fiscalizazione è a cumunicazione cù i servizii esterni.
  • Refund Tool, chì simpricimenti cuntene novi scambii per ùn inflate u BOB.

Avà u prucessu pare cusì:

Esperienza in u sviluppu di u serviziu Refund Tool cù una API asincrona nantu à Kafka

  1. BOB riceve una dumanda di rimborsu.
  2. BOB parla di questu Strumentu di Rimborsu.
  3. U Strumentu di rimborsu dice à Pagamentu: "Ritorna i soldi".
  4. U pagamentu torna i soldi.
  5. Refund Tool è BOB sincronizzanu i statuti cù l'altri, perchè per avà tutti dui ne anu bisognu. Ùn simu micca pronti à cambià cumplettamente à u Strumentu di rimborsu, postu chì BOB hà una UI, rapporti per a cuntabilità, è in generale assai dati chì ùn ponu esse trasferiti cusì facilmente. Avete à pusà nantu à duie sedie.
  6. A dumanda di fiscalizazione si ne va.

In u risultatu, avemu fattu un tipu d'autobus d'avvenimentu nantu à Kafka - event-bus, nantu à quale tuttu principia. Hurrah, avà avemu un unicu puntu di fallimentu (sarcasmu).

Esperienza in u sviluppu di u serviziu Refund Tool cù una API asincrona nantu à Kafka

I pro è i contra sò abbastanza evidenti. Avemu fattu un autobus, chì significa chì avà tutti i servizii dipendenu da ellu. Questu simplifica u disignu, ma introduce un unicu puntu di fallimentu in u sistema. Kafka crash, u prucessu si ferma.

Cosa hè una API guidata da eventi

Una bona risposta à sta quistione hè in u rapportu di Martin Fowler (GOTO 2017) "I tanti significati di l'architettura guidata da l'avvenimenti".

In breve ciò chì avemu fattu:

  1. Imbulighjate tutti i scambii asincroni via almacenamentu di l'avvenimenti. Invece di informà ogni cunsumadore interessatu nantu à un cambiamentu di statutu nantu à a reta, scrivimu un avvenimentu nantu à un cambiamentu di statutu à un almacenamentu centralizatu, è i cunsumatori interessati à u tema leghje tuttu ciò chì appare da quì.
  2. L'avvenimentu in questu casu hè una notificazione (notificazioni) chì qualcosa hè cambiatu in qualchì locu. Per esempiu, u statu di ordine hà cambiatu. Un cunsumadore chì hè interessatu in certi dati chì accumpagnanu u cambiamentu di statutu chì ùn hè micca inclusu in a notificazione pò scopre u so status stessu.
  3. L'opzione massima hè l'approvvigionamentu di l'avvenimenti cumpletu, trasferimentu statali, in quale avvenimentu cuntene tutte l'infurmazioni necessarii per u processu: induve hè vinutu è quale statutu hè andatu, cumu esattamente a dati cambiatu, etc. L'unica quistione hè a fattibilità è a quantità di informazioni chì pudete permette di almacenà.

Cum'è parte di u lanciamentu di u Refund Tool, avemu usatu a terza opzione. Questa trasfurmazione di l'avvenimenti simplificata postu chì ùn ci era micca bisognu di estrazione di informazioni dettagliate, in più hà eliminatu u scenariu induve ogni novu avvenimentu genera una splutazioni di clarificà e richieste da i cunsumatori.

U serviziu di Strumenta di Rimborsu micca caricatu, cusì Kafka ci hè più di un gustu di a penna chì una necessità. Ùn pensu micca chì se u serviziu di rimborsu hè diventatu un prughjettu d'alta carica, l'affari seria felice.

Scambiu Async AS IS

Per i scambii asincroni, u dipartimentu PHP generalmente usa RabbitMQ. Avemu cullatu i dati per a dumanda, mette in una fila, è u cunsumadore di u stessu serviziu leghjite è mandatu (o ùn l'hà micca mandatu). Per l'API stessu, Lamoda usa attivamente Swagger. Cuncepemu una API, a descrivamu in Swagger, è generà u codice cliente è servitore. Avemu ancu aduprà un JSON RPC 2.0 ligeramente rinfurzatu.

In certi lochi l'autobus ESB sò usati, alcuni campanu nantu à activeMQ, ma, in generale, RabbitMQ - standard.

Scambiu Async TO BE

Quandu u cuncepimentu di scambiu via events-bus, una analogia pò esse tracciata. Descrivemu in modu simile u scambiu di dati futuru attraversu e descrizzioni di a struttura di l'avvenimenti. U formatu yaml, avemu avutu per fà a generazione di codice noi stessi, u generatore crea DTO secondu a specificazione è insegna à i clienti è i servitori à travaglià cun elli. A generazione passa in duie lingue - golang è php. Questu aiuta à mantene e biblioteche coerenti. U generatore hè scrittu in golang, chì hè per quessa chì hà ricevutu u nome gogi.

Event-sourcing in Kafka hè una cosa tipica. Ci hè una suluzione da a versione principale di l'impresa di Kafka Confluent, ci hè nakadi, una suluzione da i nostri fratelli di duminiu Zalando. I nostri mutivazione per principià cù vaniglia Kafka - questu significa lascià a suluzione libera finu à chì finalmente decidemu s'ellu l'avemu aduprà in ogni locu, è ancu lascià à noi stessi un spaziu di manovra è di migliuramentu : vulemu sustegnu à i nostri JSON RPC 2.0, generatori per duie lingue è vedemu chì altru.

Hè ironicu chì ancu in un casu cusì felice, quandu ci hè un affari quasi simili, Zalando, chì hà fattu una suluzione quasi simile, ùn pudemu micca aduprà in modu efficace.

U mudellu architetturale à u lanciu hè u seguitu: leghjemu direttamente da Kafka, ma scrivite solu per l'avvenimenti-bus. Ci hè assai prontu per leghje in Kafka: brokers, balancers, è hè più o menu prontu per a scala horizontale, vulia mantene questu. Vulemu compie a registrazione attraversu un Gateway aka Events-bus, è eccu perchè.

Avvenimenti-bus

O un autobus d'avvenimentu. Il s'agit simplement d'une passerelle http sans état, qui assume plusieurs rôles importants :

  • Pruduzzione di Validazione - cuntrollemu chì l'avvenimenti scontranu e nostre specificazioni.
  • Sistema maestru di l'avvenimentu, vale à dì, questu hè u sistema principalu è solu in a cumpagnia chì risponde à a quistione di quale avvenimenti cù quale strutture sò cunsiderate valide. A validazione implica solu tipi di dati è enumerazioni per specificà strettamente u cuntenutu.
  • Funzione Hash per sharding - a struttura di missaghju Kafka hè chjave-valore è utilizendu l'hash of key hè calculatu induve mette.

Perchè

Travagliemu in una grande cumpagnia cù un prucessu simplificatu. Perchè cambià qualcosa? Questu hè un esperimentu, è s'aspittamu à cugliera parechji benefici.

1: n + 1 scambii (unu à parechji)

Kafka rende assai faciule per cunnette novi cunsumatori à l'API.

Diciamu chì avete un repertoriu chì avete bisognu di mantene a data in parechji sistemi à una volta (è in certi novi). Nanzu, avemu inventatu un bundle chì implementava set-API, è u sistema maestru era infurmatu di l'indirizzi di i cunsumatori. Avà u sistema maestru manda l'aghjurnamenti à u tema, è tutti quelli chì anu interessatu leghjenu. Un novu sistema hè apparsu - avemu firmatu per u tema. Iè, ancu bundle, ma più simplice.

In u casu di rimborsu-tool, chì hè un pezzu di BOB, hè cunvenutu per noi di mantenenu sincronizati attraversu Kafka. Pagamentu dice chì i soldi sò stati rimbursati: BOB, RT hà sappiutu di questu, cambiatu u so status, u serviziu di Fiscalization hà scupertu questu è emessu un verificatu.

Esperienza in u sviluppu di u serviziu Refund Tool cù una API asincrona nantu à Kafka

Avemu prughjetti di creà un Serviziu di Notificazioni unificatu chì avvisà u cliente nantu à e nutizie riguardanti u so ordine / ritorni. Avà sta rispunsabilità hè sparghje trà i sistemi. Serà abbastanza per noi d'insignà à u Serviziu di Notificazioni per catturà l'infurmazioni pertinenti da Kafka è risponde à questu (è disattivà sti notificazioni in altri sistemi). Ùn serà micca necessariu novi scambii diretti.

Basatu nantu à i dati

L'infurmazioni trà i sistemi diventanu trasparenti - ùn importa ciò chì "impresa sanguinosa" avete è ùn importa quant'ellu hè u vostru backlog. Lamoda hà un dipartimentu di Data Analytics chì raccoglie e dati da i sistemi è a mette in una forma riutilizabile, sia per l'affari sia per i sistemi intelligenti. Kafka vi permette di dà rapidamente assai dati è mantene quellu flussu di informazioni à ghjornu.

Log di replicazione

I missaghji ùn spariscenu micca dopu avè lettu, cum'è in RabbitMQ. Quandu un avvenimentu cuntene abbastanza infurmazione per u prucessu, avemu una storia di cambiamenti recenti à l'ughjettu, è, se vulete, a capacità di applicà sti cambiamenti.

U periodu di almacenamentu di u logu di replicazione dipende da l'intensità di scrittura à questu tema; Kafka permette di stabilisce limiti in u tempu di almacenamentu è u voluminu di dati. Per i temi intensivi, hè impurtante chì tutti i cunsumatori anu u tempu di leghje l'infurmazioni prima di sparisce, ancu in u casu di inoperabilità di corta durazione. Di solitu hè pussibule di almacenà dati per unità di ghjorni, chì hè abbastanza per u sustegnu.

Esperienza in u sviluppu di u serviziu Refund Tool cù una API asincrona nantu à Kafka

In seguitu, un pocu di ricunniscenza di a documentazione, per quelli chì ùn sò micca familiarizati cù Kafka (a stampa hè ancu da a documentazione)

AMQP hà fila: scrivemu missaghji à una fila per u cunsumadore. Di genere, una fila hè trattata da un sistema cù a listessa logica cummerciale. Sè avete bisognu di notificà parechji sistemi, pudete insignà l'applicazione à scrive à parechje fila o cunfigurà u scambiu cù u mecanismu di fanout, chì clone elli stessu.

Kafka hà una astrazione simili Topic, in quale scrivite missaghji, ma ùn spariscenu micca dopu a lettura. Per automaticamente, quandu vi cunnettate à Kafka, ricevete tutti i missaghji è avete l'opzione di salvà induve avete lasciatu. Questu hè, leghjite in sequenza, ùn pudete micca marcà u missaghju cum'è lettu, ma salvà l'id da quale pudete cuntinuà a lettura. L'ID chì avete stabilitu hè chjamatu offset, è u mecanismu hè commit offset.

In cunsiquenza, pò esse implementatu diverse logiche. Per esempiu, avemu BOB in 4 casi per diversi paesi - Lamoda hè in Russia, Kazakhstan, Ucraina, Bielorussia. Siccomu sò disposti separatamente, anu cunfigurazione ligeramente sfarente è a so propria logica cummerciale. Indichemu in u missaghju à quale paese si riferisce. Ogni cunsumu BOB in ogni paese leghje cù un differente groupId, è se u messagiu ùn hè micca appiicatu à elli, saltate, i.e. cummette immediatamente offset +1. Se u stessu tema hè lettu da u nostru Serviziu di Pagamentu, allora u face cù un gruppu separatu, è per quessa chì i offsets ùn si intersecanu micca.

Requisiti di l'avvenimentu:

  • Completezza di dati. Mi piacerebbe chì l'avvenimentu hà abbastanza dati per pudè esse trattatu.

  • Integrità. Deleghemu à Events-bus a verificazione chì l'avvenimentu hè coherente è pò processà.
  • L'ordine hè impurtante. In u casu di un ritornu, simu furzati à travaglià cù a storia. Cù notificazioni, l'ordine ùn hè micca impurtante, s'ellu sò notificazioni homogenee, l'email serà u listessu, indipendentemente da quale ordine hè ghjuntu prima. In u casu di un rimborsu, ci hè un prucessu chjaru; se cambiamu l'ordine, l'eccezzioni saranu, u rimborsu ùn serà micca creatu o processatu - finiremu in un statu diversu.
  • Cuerenza. Avemu una tenda, è avà creemu avvenimenti invece di una API. Avemu bisognu di un modu per trasmette rapidamente è à pocu pressu infurmazione nantu à novi avvenimenti è cambiamenti à quelli esistenti à i nostri servizii. Questu hè ottenutu per mezu di una specificazione cumuni in un repository git separatu è generatori di codice. Dunque, i clienti è i servitori in diversi servizii sò coordinati.

Kafka in Lamoda

Avemu trè installazioni Kafka:

  1. Logs;
  2. R&D;
  3. Avvenimenti-bus.

Oghje parlemu solu di l'ultimu puntu. À l'avvenimenti-bus, ùn avemu micca installazioni assai grande - 3 brokers (servitori) è solu 27 temi. In regula, un tema hè un prucessu. Ma questu hè un puntu sottile, è avemu da tuccà avà.

Esperienza in u sviluppu di u serviziu Refund Tool cù una API asincrona nantu à Kafka

Sopra hè u graficu rps. U prucessu di rimborsu hè marcatu cù una linea turchese (sì, quella nantu à l'assi X), è a linea rosa hè u prucessu d'aghjurnamentu di cuntenutu.

U catalogu Lamoda cuntene milioni di prudutti, è i dati sò aghjurnati in tuttu u tempu. Certi cullezzione sò fora di moda, novi sò liberati per rimpiazzà, è novi mudelli sò sempre in u catalogu. Pruvemu di predichendu ciò chì serà interessante per i nostri clienti dumane, cusì compru constantemente cose novi, fotografiali è aghjurnà a vitrina.

I picchi rosati sò l'aghjurnamenti di u produttu, vale à dì cambiamenti in i prudutti. Si pò vede chì i picciotti piglianu ritratti, piglianu ritratti, è poi torna ! - hà caricatu un pacchettu di avvenimenti.

Casi d'usu Lamoda Events

Utilizemu l'architettura custruita per e seguenti operazioni:

  • Segui u statutu di ritornu: call-to-action è seguimentu di statutu da tutti i sistemi implicati. Pagamentu, statuti, fiscalizazione, notificazioni. Quì avemu pruvatu l'approcciu, fattu arnesi, cullucatu tutti i bug, hà scrittu documentazione è hà dettu à i nostri culleghi cumu l'utilizanu.
  • Aghjurnà e carte di u produttu: cunfigurazione, meta-dati, caratteristiche. Un sistema leghje (chì mostra), è parechji scrive.
  • E-mail, push è sms: l'ordine hè statu cullatu, l'ordine hè ghjuntu, u ritornu hè statu accettatu, etc., ci sò assai.
  • Stock, rinnuvamentu di magazzinu - aghjurnamentu quantitatiu di l'articuli, solu numeri: ghjunta à u magazzinu, ritornu. Hè necessariu chì tutti i sistemi assuciati cù a riservazione di merchenzie operanu cù i dati più attuali. Attualmente, u sistema di aghjurnamentu di u stock hè abbastanza cumplessu; Kafka simplificà.
  • Analisi di Dati (dipartimentu R&D), strumenti ML, analitiche, statistiche. Vulemu chì l'infurmazione sia trasparente - Kafka hè bè adattatu per questu.

Avà a parte più interessante nantu à i grandi bumps è i scuperti interessanti chì sò accaduti in l'ultimi sei mesi.

Problemi di disignu

Diciamu chì vulemu fà una cosa nova - per esempiu, trasferisce tuttu u prucessu di consegna à Kafka. Avà una parte di u prucessu hè implementata in u Processu di l'Ordine in BOB. Ci hè un mudellu di statutu daretu à u trasferimentu di un ordine à u serviziu di consegna, u muvimentu in un magazzinu intermediu, etc. Ci hè un monolitu sanu, ancu dui, più una mansa di API dedicate à a consegna. Sapenu assai di più nantu à a consegna.

Queste parenu esse zoni simili, ma u Trattamentu di l'Ordine in BOB è u Sistema di Spedizioni sò stati diversi. Per esempiu, certi servizii di messageria ùn mandanu micca stati intermedii, ma solu quelli finali: "consegna" o "perdu". L'altri, à u cuntrariu, informanu in grande dettagliu nantu à u muvimentu di e merchenzie. Ognunu hà e so regule di validazione: per certi, l'email hè validu, chì significa chì serà trattatu; per altri ùn hè micca validu, ma l'ordine serà sempre trattatu perchè ci hè un numeru di telefunu per u cuntattu, è qualchissia dicerà chì un tali ordine ùn serà micca trattatu in tuttu.

Flussu di dati

In u casu di Kafka, a quistione di urganizà u flussu di dati si pone. Stu compitu implica a scelta di una strategia basatu annantu à parechji punti; andemu per tutti.

In un tema o in altri ?

Avemu una specificazione di l'avvenimentu. In BOB scrivimu chì un tali ordine deve esse mandatu, è indicà: u numeru d'ordine, a so cumpusizioni, qualchi SKU è codici di barre, etc. Quandu e merchenzie ghjunghjenu à u magazzinu, a consegna serà capace di riceve status, timestamps è tuttu ciò chì hè necessariu. Ma allora vulemu riceve l'aghjurnamenti nantu à sta dati in BOB. Avemu un prucessu inversu di riceve dati da a consegna. Hè u listessu avvenimentu? O hè questu un scambiu separatu chì meriteghja u so propiu tema?

Probabilmente, seranu assai simili, è a tentazione di fà un tema ùn hè micca infundatu, perchè un tema separatu significa cunsumatori separati, cunfigurazioni separati, una generazione separata di tuttu questu. Ma micca un fattu.

Novu campu o novu avvenimentu?

Ma s'è vo aduprate u listessu evenimenti, allura un altru prublema nasce. Per esempiu, micca tutti i sistemi di consegna ponu generà u tipu di DTO chì BOB pò generà. Mandemu l'id, ma ùn salvanu micca perchè ùn anu micca bisognu, è da u puntu di vista di inizià u prucessu di l'avvenimentu-bus, stu campu hè necessariu.

Se introducemu una regula per l'eventu-bus chì stu campu hè necessariu, allora simu furzati à stabilisce reguli di validazione supplementari in u BOB o in u gestore di l'avvenimentu iniziale. A validazione cumencia à sparghje in tuttu u serviziu - questu ùn hè micca assai còmuda.

Un altru prublema hè a tentazione di u sviluppu incrementale. Ci hè dettu chì qualcosa deve esse aghjuntu à l'avvenimentu, è forsi, se pensemu, duverebbe esse un avvenimentu separatu. Ma in u nostru schema, un avvenimentu separatu hè un tema separatu. Un tema separatu hè u prucessu tutale chì aghju descrittu sopra. U sviluppatore hè tentatu à aghjunghje un altru campu à u schema JSON è rigenerate.

In u casu di rimborsi, simu ghjunti à l'eventuali di l'avvenimenti in mezzu annu. Avemu avutu un meta-avvenimentu chjamatu aghjurnamentu di rimborsu, chì avia un campu di tipu chì descriva ciò chì sta aghjurnazione era in realtà. Per via di questu, avemu avutu switch "meravigliosi" cù validatori chì ci anu dettu cumu per cunvalidà stu avvenimentu cù stu tipu.

Versione di l'avvenimentu

Per cunvalidà i missaghji in Kafka pudete aduprà Avro, ma era necessariu di mette immediatamente nantu à questu è aduprà Confluent. In u nostru casu, avemu da esse attenti à a versione. Ùn serà micca sempre pussibule di rileghje i missaghji da u logu di replicazione perchè u mudellu hà "lasciatu". In fondu, si trova à custruisce versioni in modu chì u mudellu hè retrocompatibile: per esempiu, fate un campu temporaneamente opcional. Sì i diffirenzii sò troppu forti, cuminciamu à scrive in un novu tema, è trasfiriu i clienti quandu finiscinu di leghje u vechju.

Ordine di lettura garantitu di partizioni

I temi in Kafka sò divisi in partizioni. Questu ùn hè micca assai impurtante mentre cuncepemu entità è scambii, ma hè impurtante quandu decide cumu cunsumà è scala.

In u solitu, scrive un tema in Kafka. Per automaticamente, una partizione hè aduprata, è tutti i missaghji in questu tema vanu à questu. È u cunsumu cunsiquenza leghje sti missaghji sequentially. Dicemu chì avà avemu bisognu di espansione u sistema per chì i missaghji sò letti da dui cunsumatori diffirenti. Sè, per esempiu, invià SMS, pudete dì à Kafka di fà una partizione supplementaria, è Kafka hà da cumincià à sparte i missaghji in dui parti - a mità quì, a mità quì.

Cumu Kafka li divide ? Ogni missaghju hà un corpu (in quale guardamu JSON) è una chjave. Pudete aghjunghje una funzione hash à sta chjave, chì determinarà in quale partizione andrà u messagiu.

In u nostru casu cù rimborsi, questu hè impurtante, se pigghiamu dui partizioni, allora ci hè una chance chì un cunsumadore parallelu prucessa u sicondu avvenimentu prima di u primu è ci sarà prublemi. A funzione hash assicura chì i missaghji cù a listessa chjave finiscinu in a listessa partizione.

Avvenimenti vs cumandamenti

Questu hè un altru prublema chì avemu scontru. L'avvenimentu hè un certu avvenimentu: dicemu chì qualcosa hè accadutu in un locu (something_happened), per esempiu, un articulu hè statu annullatu o un rimborsu hè accadutu. Se qualchissia sente questi avvenimenti, allora secondu "elementu annullatu", l'entità di rimborsu serà creata, è "rimbursamentu hè accadutu" serà scrittu in qualchì locu in i setups.

Ma di solitu, quandu cuncepisce l'avvenimenti, ùn vulete micca scrivite in vain - cunfidate di u fattu chì qualchissia li leghje. Ci hè una alta tentazione di scrive micca qualcosa_successu (item_canceled, refund_refunded), ma qualcosa_sould_be_done. Per esempiu, l'articulu hè prontu per esse tornatu.

Da una banda, suggerisce cumu l'avvenimentu serà utilizatu. Per d 'altra banda, sona assai menu cum'è un nome di avvenimentu normale. Inoltre, ùn hè micca luntanu da quì à l'ordine di fà_qualcosa. Ma ùn avete micca guarantisci chì qualchissia leghje stu avvenimentu; è s'è vo leghjite, allura vi leghje bè; è s'è vo leghjite bè, allora avete fattu qualcosa, è chì qualcosa era successu. U mumentu chì un avvenimentu diventa fà_qualcosa, u feedback diventa necessariu, è questu hè un prublema.

Esperienza in u sviluppu di u serviziu Refund Tool cù una API asincrona nantu à Kafka

In u scambiu asincronu in RabbitMQ, quandu avete lettu u missaghju, andate à http, avete una risposta - almenu chì u messagiu hè statu ricevutu. Quandu scrivite à Kafka, ci hè un missaghju chì avete scrittu à Kafka, ma ùn sapete nunda di cumu hè statu trattatu.

Per quessa, in u nostru casu, avemu avutu à intruduce un avvenimentu di risposta è stallà u monitoraghju in modu chì si sò stati mandati tanti avvenimenti, dopu à un tali tempu, u listessu numeru di eventi di risposta duveria ghjunghje. S'ellu ùn succede micca, allora qualcosa pare avè sbagliatu. Per esempiu, se avemu mandatu l'avvenimentu "item_ready_to_refund", aspittemu chì un rimborsu serà creatu, i soldi seranu tornati à u cliente, è l'avvenimentu "money_refunded" serà mandatu à noi. Ma questu ùn hè micca sicuru, cusì u monitoraghju hè necessariu.

Nuances

Ci hè un prublema abbastanza evidenti: se leghjite da un tema in sequenza, è avete qualchì missaghju cattivu, u cunsumadore cascarà, è ùn andarè più. Avete bisognu ferma tutti i cunsumatori, impegnate più offset per cuntinuà a lettura.

L'avemu saputu, l'avemu cuntatu, è ancu hè accadutu. È questu hè accadutu perchè l'avvenimentu era validu da u puntu di vista di l'avvenimenti-bus, l'avvenimentu era validu da u puntu di vista di u validatore di l'applicazione, ma ùn era micca validu da u puntu di vista di PostgreSQL, perchè in u nostru sistema unicu. MySQL cun INT UNSIGNED, è in u novu scrittu u sistema avia PostgreSQL solu cù INT. A so taglia hè un pocu più chjuca, è l'Id ùn hè micca adattatu. Symfony hè mortu cù una eccezzioni. Avemu, sicuru, chjappà l'eccezzioni perchè avemu cunfidendu nantu à questu, è andavanu à cummettenu questu offset, ma prima di questu avemu vulutu incrementà u contatore di prublema, postu chì u missaghju hè statu processatu senza successu. I cuntatori in stu prughjettu sò ancu in a basa di dati, è Symfony hà digià chjusu a cumunicazione cù a basa di dati, è a seconda eccezzioni hà uccisu tuttu u prucessu senza una chance di cumpensà offset.

U serviziu dispostu per qualchì tempu - per furtuna, cù Kafka ùn hè micca cusì male, perchè i missaghji restanu. Quandu u travagliu hè restauratu, pudete finisce di leghje. Hè còmode.

Kafka hà a capacità di stabilisce un offset arbitrariu per l'uttellu. Ma per fà questu, avete bisognu di piantà tutti i cunsumatori - in u nostru casu, preparanu una liberazione separata in quale ùn ci sarà micca cunsumatori, redistribuzioni. Allora in Kafka pudete cambià l'offset à traversu l'utensili, è u missaghju passerà.

Un'altra sfumatura - log di replicazione vs rdkafka.so - hè in relazione cù e specificità di u nostru prughjettu. Utilizemu PHP, è in PHP, per regula, tutte e biblioteche cumunicanu cù Kafka attraversu u repository rdkafka.so, è dopu ci hè un tipu di wrapper. Forse queste sò e nostre difficultà persunali, ma hè risultatu chì simpricimenti rileghje un pezzu di ciò chì avemu digià lettu ùn hè micca cusì faciule. In generale, ci sò stati prublemi di software.

Riturnà à i specifichi di travaglià cù partizioni, hè scrittu ghjustu in a documentazione cunsumatori >= partizioni tematiche. Ma aghju scupertu questu assai più tardi di ciò chì mi vulia. Se vulete scala è avè dui cunsumatori, avete bisognu di almenu duie partizioni. Questu hè, s'è vo avete una particione in quale 20 mila missaghji avianu accumulatu, è avete fattu un novu, u numeru di missaghji ùn sarà equalized prestu. Dunque, per avè dui cunsumatori paralleli, avete bisognu di trattà cù partizioni.

Monitoramentu

Pensu chì a manera di monitorà serà ancu più chjaru chì prublemi ci sò in l'approcciu esistenti.

Per esempiu, calculemu quanti prudutti in a basa di dati anu cambiatu recentemente u so statutu, è, per quessa, l'avvenimenti duveranu esse accaduti in basa di sti cambiamenti, è mandemu stu numeru à u nostru sistema di surviglianza. Allora da Kafka avemu u sicondu numeru, quanti avvenimenti sò stati registrati. Ovviamente, a diffarenza trà sti dui numeri deve esse sempre zero.

Esperienza in u sviluppu di u serviziu Refund Tool cù una API asincrona nantu à Kafka

In più, avete bisognu di monitorà cumu u pruduttore hè fattu, s'ellu eventi-bus ricevutu missaghji, è cumu si face u cunsumadore. Per esempiu, in i charts quì sottu, Refund Tool hè bè, ma BOB hà chjaramente alcuni prublemi (picchi blu).

Esperienza in u sviluppu di u serviziu Refund Tool cù una API asincrona nantu à Kafka

Aghju digià citatu u lag di u gruppu di cunsumatori. À pocu pressu, questu hè u numeru di missaghji micca letti. In generale, i nostri cunsumatori travaglianu rapidamente, cusì u lag hè di solitu 0, ma qualchì volta pò esse un piccu à cortu termini. Kafka pò fà questu fora di a scatula, ma avete bisognu di stabilisce un certu intervallu.

Ci hè un prughjettu Burrowchì vi darà più infurmazione nantu à Kafka. Simply usa l'API di u gruppu di cunsumatori per dà u statutu di cumu si face stu gruppu. In più di OK and Failed, ci hè un avvirtimentu, è pudete scopre chì i vostri cunsumatori ùn ponu micca affruntà u ritmu di produzzione - ùn anu micca tempu per correghje ciò chì hè scrittu. U sistema hè abbastanza intelligente è faciule d'utilizà.

Esperienza in u sviluppu di u serviziu Refund Tool cù una API asincrona nantu à Kafka

Questu hè ciò chì pare a risposta API. Eccu u gruppu bob-live-fifa, partition refund.update.v1, status OK, lag 0 - l'ultimu offset finali tali è cusì.

Esperienza in u sviluppu di u serviziu Refund Tool cù una API asincrona nantu à Kafka

Monitoramentu updated_at SLA (bloccatu) Aghju digià citatu. Per esempiu, u pruduttu hà cambiatu à u statutu chì hè prestu per u ritornu. Installemu Cron, chì dice chì, se in 5 minuti, questu ughjettu ùn hè micca andatu à rimborsu (returnemu soldi per i sistemi di pagamentu assai rapidamente), allora qualcosa certamente andò male, è questu hè definitu un casu per supportu. Dunque, avemu solu piglià Cron, chì leghje tali cose, è s'ellu sò più grande di 0, allora manda una alerta.

Per riassume, l'usu di l'avvenimenti hè cunvenutu quandu:

  • infurmazione hè necessaria da parechji sistemi;
  • u risultatu di u prucessu ùn hè micca impurtante;
  • ci sò pochi avvenimenti o picculi avvenimenti.

Sembra chì l'articulu hà un tema assai specificu - API asincrona nantu à Kafka, ma in cunnessione cù questu mi piacerebbe ricumandemu assai cose à una volta.
Prima, dopu HighLoad ++ ci vole à aspittà finu à nuvembre, in April ci sarà una versione di San Petruburgu, è in ghjugnu parlemu di carichi elevati in Novosibirsk.
Siconda, l'autore di u rapportu, Sergei Zaika, hè un membru di u Cumitatu di u prugramma di a nostra nova cunferenza nantu à a gestione di a cunniscenza. CunniscenzaConf. A cunferenza hè di un ghjornu, si farà u 26 d'aprile, ma u so prugramma hè assai intensu.
È serà in maghju PHP Russia и RIT++ (cù DevOpsConf inclusu) - pudete ancu prupone u vostru tema quì, parlà di a vostra sperienza è lagnate di i vostri coni ripieni.

Source: www.habr.com

Add a comment