Sperto pri evoluigado de la servo de Refund Tool kun nesinkrona API ĉe Kafka

Kio povus devigi tian grandan kompanion kiel Lamoda, kun simpligita procezo kaj dekoj da interkonektitaj servoj, signife ŝanĝi sian aliron? Instigo povas esti tute malsama: de leĝdona ĝis la deziro eksperimenti eneca en ĉiuj programistoj.

Sed ĉi tio ne signifas, ke vi ne povas fidi je pliaj avantaĝoj. Sergey Zaika diros al vi, kion precize vi povas gajni se vi efektivigas la evento-movitan API sur Kafka (fewald). Oni certe parolos ankaŭ pri grandaj pafoj kaj interesaj malkovroj - la eksperimento ne povas malhavi ilin.

Sperto pri evoluigado de la servo de Refund Tool kun nesinkrona API ĉe Kafka

Malgarantio: Ĉi tiu artikolo baziĝas sur materialoj de renkontiĝo, kiun Sergey okazigis en novembro 2018 sur HighLoad++. La viva sperto de Lamoda labori kun Kafka allogis aŭskultantojn ne malpli ol aliaj raportoj pri la horaro. Ni pensas, ke ĉi tio estas bonega ekzemplo de tio, ke vi ĉiam povas kaj devas trovi samideanojn, kaj la organizantoj de HighLoad++ daŭre provos krei etoson favoran al tio.

Pri la procezo

Lamoda estas granda retkomerca platformo, kiu havas sian propran kontaktcentron, liveran servon (kaj multajn filiojn), fotostudion, grandegan magazenon, kaj ĉio ĉi funkcias per sia propra programaro. Estas dekoj da pagmetodoj, b2b partneroj, kiuj povas uzi iujn aŭ ĉiujn ĉi tiujn servojn kaj volas scii ĝisdatajn informojn pri siaj produktoj. Krome, Lamoda funkcias en tri landoj krom la Rusa Federacio kaj ĉio estas iom malsama tie. Entute, verŝajne ekzistas pli ol cent manieroj por agordi novan ordon, kiu devas esti prilaborita laŭ sia maniero. Ĉio ĉi funkcias kun la helpo de dekoj da servoj, kiuj foje komunikas en neevidentaj manieroj. Ekzistas ankaŭ centra sistemo, kies ĉefa respondeco estas ordaj statusoj. Ni nomas ŝin BOB, mi laboras kun ŝi.

Repaga Ilo kun evento-movita API

La vorto okazaĵ-movita estas sufiĉe trudita; iom plu ni difinos pli detale, kion signifas ĉi tio. Mi komencos kun la kunteksto, en kiu ni decidis provi la API-aliron gviditan de eventoj en Kafka.

Sperto pri evoluigado de la servo de Refund Tool kun nesinkrona API ĉe Kafka

En iu ajn vendejo, krom mendoj por kiuj klientoj pagas, estas tempoj, kiam la vendejo devas redoni monon ĉar la produkto ne konvenis al la kliento. Ĉi tio estas relative mallonga procezo: ni klarigas la informojn, se necese, kaj transdonas la monon.

Sed la reveno fariĝis pli komplika pro ŝanĝoj en leĝaro, kaj ni devis efektivigi apartan mikroservon por ĝi.

Sperto pri evoluigado de la servo de Refund Tool kun nesinkrona API ĉe Kafka

Nia instigo:

  1. Leĝo FZ-54 - mallonge, la leĝo postulas raporti al la impostoficejo pri ĉiu mona transakcio, ĉu ĝi estas reveno aŭ kvitanco, ene de sufiĉe mallonga SLA de kelkaj minutoj. Ni, kiel e-komerca kompanio, faras sufiĉe multajn operaciojn. Teknike tio signifas novan respondecon (kaj do novan servon) kaj plibonigojn en ĉiuj implikitaj sistemoj.
  2. BOB disiĝis estas interna projekto de la firmao por malpezigi BOB de granda nombro da ne-kernaj respondecoj kaj redukti ĝian totalan kompleksecon.

Sperto pri evoluigado de la servo de Refund Tool kun nesinkrona API ĉe Kafka

Ĉi tiu diagramo montras la ĉefajn sistemojn de Lamoda. Nun plej multaj el ili estas pli konstelacio de 5-10 mikroservoj ĉirkaŭ ŝrumpa monolito. Ili malrapide kreskas, sed ni provas malgrandigi ilin, ĉar deploji la fragmenton elektitan en la mezo estas timiga - ni ne povas permesi ĝin fali. Ni estas devigitaj rezervi ĉiujn interŝanĝojn (sagoj) kaj konsideri la fakton, ke iu el ili povas montriĝi neatingebla.

BOB ankaŭ havas sufiĉe multe da interŝanĝoj: pagsistemoj, liversistemoj, sciigaj sistemoj ktp.

Teknike BOB estas:

  • ~150k linioj de kodo + ~100k linioj de testoj;
  • php7.2 + Zend 1 & Symfony Komponantoj 3;
  • > 100 APIoj kaj ~50 elirantaj integriĝoj;
  • 4 landoj kun propra komerca logiko.

Deploji BOB estas multekosta kaj dolora, la kvanto da kodo kaj problemoj, kiujn ĝi solvas, estas tia, ke neniu povas meti ĉion en sian kapon. Ĝenerale, estas multaj kialoj por simpligi ĝin.

Revena Procezo

Komence, du sistemoj estas implikitaj en la procezo: BOB kaj Pago. Nun aperas du pliaj:

  • Fiscalization Service, kiu prizorgos problemojn pri fiskalizado kaj komunikado kun eksteraj servoj.
  • Refundilo, kiu simple enhavas novajn interŝanĝojn por ne ŝveligi la BOB.

Nun la procezo aspektas jene:

Sperto pri evoluigado de la servo de Refund Tool kun nesinkrona API ĉe Kafka

  1. BOB ricevas peton por repago.
  2. BOB parolas pri ĉi tiu Repaga Ilo.
  3. La Repaga Ilo diras al Pago: "Resendu la monon."
  4. Pago redonas la monon.
  5. Refund Tool kaj BOB sinkronigas statusojn unu kun la alia, ĉar nuntempe ili ambaŭ bezonas ĝin. Ni ankoraŭ ne pretas tute ŝanĝi al la Repaga Ilo, ĉar BOB havas UI, raportojn por kontado, kaj ĝenerale multajn datumojn, kiuj ne povas esti translokigitaj tiel facile. Vi devas sidi sur du seĝoj.
  6. La peto pri fiskalizado foriras.

Rezulte, ni faris sur Kafka ian eventobuson - event-buson, sur kiu ĉio komenciĝis. Hura, nun ni havas ununuran punkton de fiasko (sarkasmo).

Sperto pri evoluigado de la servo de Refund Tool kun nesinkrona API ĉe Kafka

La avantaĝoj kaj malavantaĝoj estas sufiĉe evidentaj. Ni faris buson, kio signifas, ke nun ĉiuj servoj dependas de ĝi. Ĉi tio simpligas la dezajnon, sed enkondukas ununuran punkton de fiasko en la sistemon. Kafka kraŝos, la procezo ĉesos.

Kio estas evento-movita API

Bona respondo al ĉi tiu demando estas en la raporto de Martin Fowler (GOTO 2017) "La Multaj Signifoj de Event-movita Arkitekturo".

Mallonge kion ni faris:

  1. Envolvu ĉiujn nesinkronajn interŝanĝojn per stokado de eventoj. Anstataŭ informi ĉiun interesatan konsumanton pri statusŝanĝo tra la reto, ni skribas eventon pri statusŝanĝo al centralizita stokado, kaj konsumantoj interesitaj pri la temo legas ĉion, kio aperas de tie.
  2. La evento en ĉi tiu kazo estas sciigo (Sciigoj) ke io ie ŝanĝiĝis. Ekzemple, la ordo statuso ŝanĝiĝis. Konsumanto, kiu interesiĝas pri iuj datumoj akompanantaj la statusŝanĝon kaj kiuj ne estas inkluzivita en la sciigo, povas mem ekscii ĝian staton.
  3. La maksimuma opcio estas plenrajta evento-provizado, ŝtata translokigo, en kiu evento enhavas ĉiujn informojn necesajn por prilaborado: de kie ĝi venis kaj al kia stato ĝi iris, kiel ĝuste la datumoj ŝanĝiĝis, ktp. La nura demando estas la farebleco kaj la kvanto da informoj, kiujn vi povas pagi konservi.

Kadre de la lanĉo de la Repaga Ilo, ni uzis la trian opcion. Ĉi tiu simpligita evento-prilaborado ĉar ne necesis ĉerpi detalajn informojn, krome ĝi forigis la scenaron, kie ĉiu nova evento generas eksplodon de klarigado de ricevi petojn de konsumantoj.

Repaga Ila Servo ne ŝarĝita, do Kafka estas pli gusto de la plumo ol neceso. Mi ne pensas, ke se la repago servo fariĝus altŝarĝa projekto, komerco estus feliĉa.

Nesinkrona interŝanĝo KIAL ESTAS

Por nesinkronaj interŝanĝoj, la PHP-sekcio kutime uzas RabbitMQ. Ni kolektis la datumojn por la peto, metis ĝin en atendovico, kaj la konsumanto de la sama servo legis ĝin kaj sendis ĝin (aŭ ne sendis ĝin). Por la API mem, Lamoda aktive uzas Swagger. Ni desegnas API, priskribas ĝin en Swagger kaj generas klientan kaj servilan kodon. Ni ankaŭ uzas iomete plibonigitan JSON RPC 2.0.

En kelkaj lokoj ESB-busoj estas uzataj, kelkaj vivas sur activeMQ, sed, ĝenerale, RabbitMQ - normo.

Nesinkrona interŝanĝo ESTI

Dum desegnado de interŝanĝo per evento-buso, analogio povas esti spurita. Ni simile priskribas estontan interŝanĝon de datumoj per priskriboj pri eventostrukturo. La yaml-formato, ni mem devis fari la kodon-generadon, la generatoro kreas DTO-ojn laŭ la specifo kaj instruas klientojn kaj servilojn labori kun ili. Generacio eniras du lingvojn - golang kaj php. Ĉi tio helpas konservi bibliotekojn konsekvencaj. La generatoro estas skribita en golang, tial ĝi ricevis la nomon gogi.

Event-fontado ĉe Kafka estas tipa afero. Estas solvo de la ĉefa entreprena versio de Kafka Confluent, ekzistas nakadi, solvo de niaj domajnaj fratoj Zalando. Nia instigo komenci kun vanilo Kafka - tio signifas lasi la solvon libera ĝis ni finfine decidos ĉu ni uzos ĝin ĉie, kaj ankaŭ lasi al ni spacon por manovro kaj plibonigoj: ni volas subtenon por niaj. JSON RPC 2.0, generatoroj por du lingvoj kaj ni vidu kion alian.

Estas ironie, ke eĉ en tia feliĉa kazo, kiam ekzistas proksimume simila komerco, Zalando, kiu faris proksimume similan solvon, ni ne povas uzi ĝin efike.

La arkitektura ŝablono ĉe lanĉo estas jena: ni legas rekte el Kafka, sed skribas nur per evento-buso. Estas multo preta por legi en Kafka: makleristoj, ekvilibristoj, kaj ĝi estas pli-malpli preta por horizontala skalo, mi volis konservi ĉi tion. Ni volis kompletigi la registradon per unu Enirejo alinome Event-buso, kaj jen kial.

Eventoj-buso

Aŭ eventobuso. Ĉi tio estas simple sennacia http-enirejo, kiu prenas plurajn gravajn rolojn:

  • Produktanta Validumadon — ni kontrolas, ke la eventoj plenumas niajn specifojn.
  • Eventa majstra sistemo, tio estas, ĉi tiu estas la ĉefa kaj nura sistemo en la kompanio, kiu respondas la demandon pri kiuj eventoj, kun kiuj strukturoj estas konsiderataj validaj. Valumado simple implikas datumtipojn kaj enumojn por strikte specifi enhavon.
  • Hash-funkcio por sharding - la Kafka mesaĝstrukturo estas ŝlosilvalora kaj uzante la hash de ŝlosilo estas kalkulita kie meti ĝin.

kial

Ni laboras en granda kompanio kun simpligita procezo. Kial ŝanĝi ion? Ĉi tio estas eksperimento, kaj ni atendas rikolti plurajn avantaĝojn.

1:n+1 interŝanĝoj (unu al multaj)

Kafka tre facilas konekti novajn konsumantojn al la API.

Ni diru, ke vi havas dosierujon, kiun vi bezonas ĝisdatigi en pluraj sistemoj samtempe (kaj en iuj novaj). Antaŭe, ni inventis pakaĵon, kiu efektivigis set-API, kaj la majstra sistemo estis informita pri konsumantaj adresoj. Nun la majstra sistemo sendas ĝisdatigojn al la temo, kaj ĉiu, kiu interesiĝas, legas ĝin. Aperis nova sistemo - ni subskribis ĝin por la temo. Jes, ankaŭ pakaĵo, sed pli simpla.

En la kazo de repago-ilo, kiu estas peco de BOB, estas oportune por ni konservi ilin sinkronigitaj per Kafka. Pago diras, ke la mono estis redonita: BOB, RT eksciis pri tio, ŝanĝis siajn statusojn, Fiscalization Service eksciis pri tio kaj eldonis ĉekon.

Sperto pri evoluigado de la servo de Refund Tool kun nesinkrona API ĉe Kafka

Ni havas planojn krei unuigitan Sciigan Servon, kiu sciigus la klienton pri novaĵoj pri lia mendo/revenoj. Nun ĉi tiu respondeco estas disvastigita inter sistemoj. Sufiĉos por ni instrui la Servon pri Sciigoj kapti koncernajn informojn de Kafka kaj respondi al ĝi (kaj malŝalti ĉi tiujn sciigojn en aliaj sistemoj). Neniuj novaj rektaj interŝanĝoj estos postulataj.

Datum-pelita

Informoj inter sistemoj iĝas travideblaj - negrave kian "sangan entreprenon" vi havas kaj kiom ajn dika estas via restarigo. Lamoda havas fakon de Data Analytics, kiu kolektas datumojn de sistemoj kaj metas ĝin en reuzeblan formon, kaj por komerco kaj por inteligentaj sistemoj. Kafka permesas vin rapide doni al ili multajn datumojn kaj konservi tiun informan fluon ĝisdatigita.

Replika protokolo

Mesaĝoj ne malaperas post legi, kiel en RabbitMQ. Kiam okazaĵo enhavas sufiĉe da informoj por prilaborado, ni havas historion de lastatempaj ŝanĝoj al la objekto, kaj, se dezirite, la kapablon apliki ĉi tiujn ŝanĝojn.

La konserva periodo de la reprodukta protokolo dependas de la intenseco de skribado al ĉi tiu temo; Kafka permesas al vi flekseble fiksi limojn pri stokado kaj datumvolumo. Por intensaj temoj, estas grave ke ĉiuj konsumantoj havu tempon por legi la informojn antaŭ ol ĝi malaperas, eĉ en la kazo de mallongdaŭra nefunkciebleco. Kutime eblas konservi datumojn por unuoj de tagoj, kio sufiĉas por subteno.

Sperto pri evoluigado de la servo de Refund Tool kun nesinkrona API ĉe Kafka

Poste, iom rerakonto de la dokumentaro, por tiuj, kiuj ne konas Kafka (la bildo estas ankaŭ el la dokumentaro)

AMQP havas vostojn: ni skribas mesaĝojn al vosto por la konsumanto. Tipe, unu atendovico estas prilaborita per unu sistemo kun la sama komerca logiko. Se vi bezonas sciigi plurajn sistemojn, vi povas instrui la aplikaĵon skribi al pluraj atendovicoj aŭ agordi interŝanĝon per la fanout-mekanismo, kiu klonas ilin mem.

Kafka havas similan abstraktadon temo, en kiuj oni skribas mesaĝojn, sed ili ne malaperas post legado. Defaŭlte, kiam vi konektas al Kafka, vi ricevas ĉiujn mesaĝojn kaj havas la eblon konservi kie vi lasis. Tio estas, ke vi legas sinsekve, vi eble ne markas la mesaĝon kiel legita, sed konservu la identigilon de kiu vi povas tiam daŭrigi legi. La Idaĵo, pri kiu vi fiksis, nomiĝas ofseto, kaj la mekanismo estas commit offset.

Sekve, malsama logiko povas esti efektivigita. Ekzemple, ni havas BOB en 4 okazoj por malsamaj landoj - Lamoda estas en Rusio, Kazaĥio, Ukrainio, Belorusio. Ĉar ili estas deplojitaj aparte, ili havas iomete malsamajn agordojn kaj sian propran komercan logikon. Ni indikas en la mesaĝo al kiu lando ĝi rilatas. Ĉiu BOB-konsumanto en ĉiu lando legas kun malsama groupId, kaj se la mesaĝo ne validas por ili, ili preterlasas ĝin, t.e. tuj faras ofseton +1. Se la sama temo estas legata de nia Paga Servo, tiam ĝi faras tion kun aparta grupo, kaj tial kompensoj ne intersekcas.

Postuloj pri Evento:

  • Kompleteco de datumoj. Mi ŝatus, ke la evento havu sufiĉe da datumoj por ke ĝi estu prilaborita.

  • Integreco. Ni delegas al Events-bus la konfirmon, ke la evento estas konsekvenca kaj ĝi povas prilabori ĝin.
  • Gravas la ordo. En la kazo de reveno, ni estas devigitaj labori kun historio. Kun sciigoj, la ordo ne gravas, se ili estas homogenaj sciigoj, la retpoŝto estos la sama sendepende de kiu ordo alvenis unue. En la kazo de repago, estas klara procezo; se ni ŝanĝas la ordon, aperos esceptoj, la repago ne estos kreita aŭ procesita - ni finiĝos en malsama stato.
  • Kohereco. Ni havas vendejon, kaj nun ni kreas eventojn anstataŭ API. Ni bezonas manieron rapide kaj malmultekoste transdoni informojn pri novaj eventoj kaj ŝanĝoj al ekzistantaj al niaj servoj. Ĉi tio estas atingita per komuna specifo en aparta git-deponejo kaj kodgeneratoroj. Tial, klientoj kaj serviloj en malsamaj servoj estas kunordigitaj.

Kafka en Lamoda

Ni havas tri instalaĵojn de Kafka:

  1. Ŝtipoj;
  2. R&D;
  3. Eventoj-buso.

Hodiaŭ ni parolas nur pri la lasta punkto. Ĉe evento-buso, ni ne havas tre grandajn instalaĵojn - 3 makleristoj (serviloj) kaj nur 27 temoj. Kiel regulo, unu temo estas unu procezo. Sed ĉi tio estas subtila punkto, kaj ni tuŝos ĝin nun.

Sperto pri evoluigado de la servo de Refund Tool kun nesinkrona API ĉe Kafka

Supre estas la rps-grafo. La procezo de repago estas markita per turkisa linio (jes, tiu sur la X-akso), kaj la rozkolora linio estas la procezo de ĝisdatigo de enhavo.

La katalogo de Lamoda enhavas milionojn da produktoj, kaj la datumoj estas ĉiam ĝisdatigitaj. Iuj kolektoj malmodiĝas, novaj estas liberigitaj por anstataŭigi ilin, kaj novaj modeloj konstante aperas en la katalogo. Ni provas antaŭdiri, kio estos interesa por niaj klientoj morgaŭ, do ni konstante aĉetas novajn aferojn, fotas ilin kaj ĝisdatigas la ekranujon.

Rozkoloraj pintoj estas produktaj ĝisdatigoj, tio estas, ŝanĝoj en produktoj. Videblas, ke la uloj fotis, fotis, kaj poste denove! — ŝargis pakon da eventoj.

Lamoda Eventoj uzkazoj

Ni uzas la konstruitan arkitekturon por la sekvaj operacioj:

  • Revena statospurado: alvoko kaj statospurado de ĉiuj implikitaj sistemoj. Pago, statusoj, fiskalizado, sciigoj. Ĉi tie ni provis la aliron, faris ilojn, kolektis ĉiujn cimojn, skribis dokumentadon kaj diris al niaj kolegoj kiel uzi ĝin.
  • Ĝisdatigante produktkartojn: agordo, metadatenoj, karakterizaĵoj. Unu sistemo legas (kiu montriĝas), kaj pluraj skribas.
  • Retpoŝto, puŝo kaj sms: la mendo estas kolektita, la mendo alvenis, la reveno estis akceptita, ktp., estas multaj.
  • Stock, magazeno renovigo — kvanta ĝisdatigo de aĵoj, nur nombroj: alveno al la magazeno, reveno. Necesas, ke ĉiuj sistemoj asociitaj kun rezervado de varoj funkcias kun la plej aktualaj datumoj. Nuntempe, la akcia ĝisdatiga sistemo estas sufiĉe kompleksa; Kafka simpligos ĝin.
  • datumoj Analizo (R&D-sekcio), ML-iloj, analitiko, statistiko. Ni volas ke informoj estu travideblaj - Kafka bone taŭgas por tio.

Nun la pli interesa parto pri la grandaj ŝvelaĵoj kaj interesaj malkovroj, kiuj okazis dum la pasintaj ses monatoj.

Dezajnaj problemoj

Ni diru, ke ni volas fari novan aferon - ekzemple translokigi la tutan liveran procezon al Kafka. Nun parto de la procezo estas efektivigita en Ordo-Pretigo en BOB. Estas statusa modelo malantaŭ la translokigo de mendo al la liverservo, movado al meza magazeno, ktp. Estas tuta monolito, eĉ du, plus amaso da APIoj dediĉitaj al livero. Ili scias multe pli pri livero.

Ĉi tiuj ŝajnas esti similaj areoj, sed la Ordo-Pretigo en BOB kaj la Sendado-Sistemo havas malsamajn statusojn. Ekzemple, iuj kurierservoj ne sendas mezajn statusojn, sed nur la finajn: "liverita" aŭ "perdita". Aliaj, male, raportas tre detale pri la movo de varoj. Ĉiu havas siajn proprajn validigajn regulojn: por iuj, la retpoŝto validas, kio signifas, ke ĝi estos prilaborita; por aliaj ĝi ne validas, sed la mendo ankoraŭ estos procesita ĉar ekzistas telefonnumero por kontakto, kaj iu diros, ke tia mendo tute ne estos procesita.

Fluo de datumoj

En la kazo de Kafka, ŝprucas la demando pri organizado de la datumfluo. Ĉi tiu tasko implicas elekti strategion bazitan sur pluraj punktoj; ni trarigardu ilin ĉiujn.

En unu temo aŭ en malsamaj?

Ni havas evento-specifon. En BOB ni skribas, ke tia kaj tia mendo devas esti liverita, kaj indikas: la mendnumeron, ĝian konsiston, kelkajn SKU-ojn kaj strekkodojn, ktp. Kiam la varoj alvenos al la magazeno, la livero povos ricevi statusojn, tempomarkojn kaj ĉion necesan. Sed tiam ni volas ricevi ĝisdatigojn pri ĉi tiuj datumoj en BOB. Ni havas inversan procezon ricevi datumojn de livero. Ĉu ĉi tio estas la sama evento? Aŭ ĉu ĉi tio estas aparta interŝanĝo, kiu meritas sian propran temon?

Plej verŝajne, ili estos tre similaj, kaj la tento fari unu temon ne estas senbaza, ĉar aparta temo signifas apartajn konsumantojn, apartajn agordojn, apartan generacion de ĉio ĉi. Sed ne fakto.

Nova kampo aŭ nova evento?

Sed se vi uzas la samajn eventojn, tiam aperas alia problemo. Ekzemple, ne ĉiuj liversistemoj povas generi la specon de DTO kiun BOB povas generi. Ni sendas al ili la identigilon, sed ili ne konservas ĝin ĉar ili ne bezonas ĝin, kaj el la vidpunkto de komenci la evento-busan procezon, ĉi tiu kampo estas postulata.

Se ni enkondukas regulon por event-buso, ke ĉi tiu kampo estas postulata, tiam ni estas devigitaj agordi pliajn validigajn regulojn en la BOB aŭ en la starta evento-traktilo. Validiĝo komencas disvastiĝi tra la servo - ĉi tio ne estas tre oportuna.

Alia problemo estas la tento al pliiga evoluo. Oni diras al ni, ke io necesas aldoni al la evento, kaj eble, se ni pripensas, ĝi devus esti aparta evento. Sed en nia skemo, aparta evento estas aparta temo. Aparta temo estas la tuta procezo, kiun mi priskribis supre. La programisto estas tentata simple aldoni alian kampon al la JSON-skemo kaj regeneri ĝin.

En la kazo de repagoj, ni alvenis al la evento de eventoj en duonjaro. Ni havis unu meta-okazaĵon nomitan repago ĝisdatigo, kiu havis tipkampon priskribantan kio ĉi tiu ĝisdatigo fakte estis. Pro tio, ni havis "mirindajn" ŝaltilojn kun validigiloj, kiuj diris al ni kiel validigi ĉi tiun eventon per ĉi tiu tipo.

Eventa versio

Por validigi mesaĝojn en Kafka vi povas uzi Avro, sed necesis tuj kuŝi sur ĝi kaj uzi Confluent. En nia kazo, ni devas esti singardaj kun versio. Ne ĉiam eblos relegi mesaĝojn el la replika protokolo ĉar la modelo "foriris". Esence, ĝi rezultas konstrui versiojn tiel ke la modelo estas malantaŭen kongrua: ekzemple, faru kampon provizore laŭvola. Se la diferencoj estas tro fortaj, ni komencas skribi en nova temo, kaj transdonas klientojn kiam ili finas legi la malnovan.

Garantiita legado ordo de vadoj

Temoj ene de Kafka estas dividitaj en sekciojn. Ĉi tio ne estas tre grava dum ni desegnas entojn kaj interŝanĝojn, sed gravas kiam ni decidas kiel konsumi kaj skali ĝin.

En la kutima kazo, vi skribas unu temon en Kafka. Defaŭlte, unu sekcio estas uzata, kaj ĉiuj mesaĝoj en ĉi tiu temo iras al ĝi. Kaj la konsumanto sekve legas ĉi tiujn mesaĝojn sinsekve. Ni diru nun, ke ni devas vastigi la sistemon por ke mesaĝoj estu legitaj de du malsamaj konsumantoj. Se, ekzemple, vi sendas SMS, tiam vi povas diri al Kafka fari plian sekcion, kaj Kafka komencos dividi la mesaĝojn en du partojn - duono ĉi tie, duono ĉi tie.

Kiel Kafka dividas ilin? Ĉiu mesaĝo havas korpon (en kiu ni konservas JSON) kaj ŝlosilon. Vi povas alfiksi hash-funkcion al ĉi tiu ŝlosilo, kiu determinos en kiun sekcion la mesaĝo eniros.

En nia kazo kun repagoj, ĉi tio estas grava, se ni prenas du sekciojn, tiam ekzistas ŝanco, ke paralela konsumanto prilaboros la duan eventon antaŭ la unua kaj estos problemo. La hashfunkcio certigas, ke mesaĝoj kun la sama ŝlosilo finiĝas en la sama sekcio.

Eventoj kontraŭ komandoj

Ĉi tio estas alia problemo, kiun ni renkontis. Okazaĵo estas certa evento: ni diras, ke io okazis ie (io_okazis), ekzemple, ero estis nuligita aŭ repago okazis. Se iu aŭskultas ĉi tiujn eventojn, tiam laŭ "ero nuligita", la repago ento estos kreita, kaj "repago okazis" estos skribita ie en la aranĝoj.

Sed kutime, kiam vi desegnas eventojn, vi ne volas skribi ilin vane - vi fidas je tio, ke iu legos ilin. Estas alta tento skribi ne io_okazinta (ero_nuligita, repago_repagita), sed io_devus_esti_farita. Ekzemple, ero estas preta por esti resendita.

Unuflanke, ĝi sugestas kiel la evento estos uzata. Aliflanke, ĝi sonas multe malpli kiel normala okazaĵonomo. Krome, ĝi ne estas malproksime de ĉi tie al la ordono fari_ion. Sed vi ne havas garantion, ke iu legas ĉi tiun eventon; kaj se vi legas ĝin, tiam vi legis ĝin sukcese; kaj se vi legis ĝin sukcese, tiam vi faris ion, kaj tiu io sukcesis. En la momento, kiam evento fariĝas fari_io, retrosciigo fariĝas necesa, kaj tio estas problemo.

Sperto pri evoluigado de la servo de Refund Tool kun nesinkrona API ĉe Kafka

En nesinkrona interŝanĝo en RabbitMQ, kiam vi legas la mesaĝon, iru al http, vi havas respondon - almenaŭ ke la mesaĝo estis ricevita. Kiam vi skribas al Kafka, estas mesaĝo, kiun vi skribis al Kafka, sed vi nenion scias pri kiel ĝi estis prilaborita.

Tial, en nia kazo, ni devis enkonduki respondan eventon kaj agordi monitoradon, por ke se tiom da eventoj estus senditaj, post tia kaj tia tempo alvenu la sama nombro da respondaj eventoj. Se ĉi tio ne okazas, tiam io ŝajnas esti misfunkciinta. Ekzemple, se ni sendis la eventon "item_ready_to_refund", ni atendas, ke repago estos kreita, la mono estos resendita al la kliento, kaj la evento "money_refunded" estos sendita al ni. Sed ĉi tio ne estas certa, do necesas monitorado.

Nuancoj

Estas sufiĉe evidenta problemo: se vi legas el temo sinsekve, kaj vi havas iun malbonan mesaĝon, la konsumanto falos, kaj vi ne iros plu. Vi bezonas haltigu ĉiujn konsumantojn, faru ofseton plu por daŭrigi legi.

Ni sciis pri ĝi, ni kalkulis je ĝi, kaj tamen ĝi okazis. Kaj ĉi tio okazis ĉar la evento validis el la vidpunkto de events-bus, la evento validis el la vidpunkto de la aplikaĵo validator, sed ĝi ne validis el la vidpunkto de PostgreSQL, ĉar en nia unu sistemo. MySQL kun UNSIGNED INT, kaj en la nove skribita la sistemo havis PostgreSQL nur kun INT. Lia grandeco estas iom pli malgranda, kaj la Id ne konvenis. Symfony mortis kun escepto. Ni, kompreneble, kaptis la escepton ĉar ni fidis je ĝi, kaj estis fari ĉi tiun ofseton, sed antaŭ tio ni volis pligrandigi la problemon nombrilon, ĉar la mesaĝo estis procesita malsukcese. La nombriloj en ĉi tiu projekto ankaŭ estas en la datumbazo, kaj Symfony jam fermis komunikadon kun la datumbazo, kaj la dua escepto mortigis la tutan procezon sen ŝanco fari kompenson.

La servo kuŝis iom da tempo - feliĉe, ĉe Kafka tio ne estas tiel malbona, ĉar la mesaĝoj restas. Kiam laboro estas restarigita, vi povas fini legi ilin. Estas komforta.

Kafka havas la kapablon agordi arbitran ofseton per ilado. Sed por fari tion, vi devas haltigi ĉiujn konsumantojn - en nia kazo, preparu apartan eldonon, en kiu ne estos konsumantoj, redeplojoj. Tiam en Kafka vi povas ŝanĝi la ofseton per ilado, kaj la mesaĝo trairos.

Alia nuanco - replika protokolo kontraŭ rdkafka.so - rilatas al la specifaĵoj de nia projekto. Ni uzas PHP, kaj en PHP, kiel regulo, ĉiuj bibliotekoj komunikas kun Kafka per la deponejo rdkafka.so, kaj tiam ekzistas ia envolvaĵo. Eble ĉi tiuj estas niaj personaj malfacilaĵoj, sed montriĝis, ke simple relegi pecon de tio, kion ni jam legis, ne estas tiel facila. Ĝenerale, estis programaraj problemoj.

Revenante al la specifaĵoj pri laboro kun sekcioj, ĝi estas skribita ĝuste en la dokumentado konsumantoj >= temaj sekcioj. Sed mi eksciis pri tio multe pli malfrue ol mi dezirus. Se vi volas grimpi kaj havi du konsumantojn, vi bezonas almenaŭ du sekciojn. Tio estas, se vi havis unu sekcion, en kiu amasiĝis 20 mil mesaĝoj, kaj vi faris novan, la nombro da mesaĝoj ne estos egaligita baldaŭ. Tial, por havi du paralelajn konsumantojn, vi devas trakti sekciojn.

Monitorado

Mi pensas, ke la maniero kiel ni kontrolas ĝin estos eĉ pli klara, kiaj problemoj estas en la ekzistanta aliro.

Ekzemple, ni kalkulas kiom da produktoj en la datumbazo lastatempe ŝanĝis sian statuson, kaj sekve, eventoj devus okazi surbaze de ĉi tiuj ŝanĝoj, kaj ni sendas ĉi tiun numeron al nia monitora sistemo. Tiam de Kafka ni ricevas la duan numeron, kiom da eventoj estis efektive registritaj. Evidente, la diferenco inter ĉi tiuj du nombroj ĉiam estu nulo.

Sperto pri evoluigado de la servo de Refund Tool kun nesinkrona API ĉe Kafka

Krome, vi devas kontroli kiel fartas la produktanto, ĉu evento-buso ricevis mesaĝojn, kaj kiel fartas la konsumanto. Ekzemple, en la malsupraj leteroj, Refund Tool faras bone, sed BOB klare havas iujn problemojn (bluaj pintoj).

Sperto pri evoluigado de la servo de Refund Tool kun nesinkrona API ĉe Kafka

Mi jam menciis konsumgrupon malfruon. Malglate parolante, ĉi tio estas la nombro da nelegitaj mesaĝoj. Ĝenerale, niaj konsumantoj laboras rapide, do la malfruo estas kutime 0, sed foje povas esti mallongdaŭra pinto. Kafka povas fari tion el la skatolo, sed vi devas agordi certan intervalon.

Estas projekto Burrowkiu donos al vi pliajn informojn pri Kafka. Ĝi simple uzas la konsumantgrupon API por doni la statuson de kiel ĉi tiu grupo fartas. Krom Bone kaj Malsukcesa, estas averto, kaj vi povas ekscii, ke viaj konsumantoj ne povas elteni la ritmon de produktado - ili ne havas tempon por provlegi tion, kio estas skribita. La sistemo estas sufiĉe inteligenta kaj facile uzebla.

Sperto pri evoluigado de la servo de Refund Tool kun nesinkrona API ĉe Kafka

Jen kiel aspektas la API-respondo. Jen la grupo bob-live-fifa, dispartigo refund.update.v1, statuso OK, lag 0 - la lasta fina kompenso tia kaj tia.

Sperto pri evoluigado de la servo de Refund Tool kun nesinkrona API ĉe Kafka

Monitorado ĝisdatigita_ĉe SLA (blokita) Mi jam menciis. Ekzemple, la produkto ŝanĝiĝis al la statuso, ke ĝi estas preta por reveno. Ni instalas Cron, kiu diras, ke se en 5 minutoj ĉi tiu objekto ne iris al repago (ni resendas monon per pagsistemoj tre rapide), tiam io certe misfunkciis, kaj ĉi tio certe estas kazo por subteno. Tial ni simple prenas Cron, kiu legas tiajn aferojn, kaj se ili estas pli grandaj ol 0, tiam ĝi sendas alarmon.

Por resumi, uzi eventojn estas oportuna kiam:

  • informoj estas bezonataj de pluraj sistemoj;
  • la rezulto de prilaborado ne gravas;
  • estas malmultaj eventoj aŭ malgrandaj eventoj.

Ŝajnus, ke la artikolo havas tre specifan temon - nesinkrona API pri Kafka, sed lige kun ĝi mi ŝatus rekomendi multajn aferojn samtempe.
Unue, poste HighLoad++ ni devas atendi ĝis novembro, en aprilo estos Sankt-Peterburga versio, kaj en junio ni parolos pri altaj ŝarĝoj en Novosibirsk.
Due, la aŭtoro de la raporto, Sergej Zaika, estas membro de la Programa Komitato de nia nova konferenco pri scio-administrado. KnowledgeConf. La konferenco estas unutaga, okazos la 26-an de aprilo, sed ĝia programo estas tre intensa.
Kaj estos en majo PHP Rusio и RIT++ (kun DevOpsConf inkluzivita) - vi ankaŭ povas sugesti vian temon tie, paroli pri via sperto kaj plendi pri viaj plenigitaj konusoj.

fonto: www.habr.com

Aldoni komenton