Experiència en el desenvolupament del servei Refund Tool amb una API asíncrona a Kafka

Què podria obligar una empresa tan gran com Lamoda, amb un procés racionalitzat i desenes de serveis interconnectats, a canviar significativament el seu enfocament? La motivació pot ser completament diferent: des del legislatiu fins al desig d'experimentació inherent a tots els programadors.

Però això no vol dir que no pugui comptar amb avantatges addicionals. Sergey Zaika us dirà què podeu guanyar exactament si implementeu l'API basada en esdeveniments a Kafka (pocsald). Definitivament també es parlarà de grans plans i descobriments interessants: l'experiment no pot prescindir d'ells.

Experiència en el desenvolupament del servei Refund Tool amb una API asíncrona a Kafka

Exempció de responsabilitat: aquest article es basa en materials d'una trobada que Sergey va celebrar el novembre de 2018 a HighLoad++. L'experiència en directe de Lamoda de treballar amb Kafka va atreure els oients no menys que altres informes de la programació. Creiem que aquest és un exemple excel·lent del fet que sempre podeu i heu de trobar persones amb idees afins, i els organitzadors de HighLoad++ continuaran intentant crear un ambient propici per a això.

Sobre el procés

Lamoda és una gran plataforma de comerç electrònic que té el seu propi centre de contacte, servei de lliurament (i molts afiliats), un estudi fotogràfic, un gran magatzem i tot això funciona amb el seu propi programari. Hi ha desenes de mètodes de pagament, socis b2b que poden utilitzar alguns o tots aquests serveis i volen conèixer informació actualitzada sobre els seus productes. A més, Lamoda opera a tres països a més de la Federació Russa i allà tot és una mica diferent. En total, probablement hi ha més d'un centenar de maneres de configurar una nova comanda, que s'ha de processar a la seva manera. Tot això funciona amb l'ajuda de desenes de serveis que de vegades es comuniquen de maneres no òbvies. També hi ha un sistema central que té com a principal responsabilitat l'estat de les comandes. La diem BOB, jo treballo amb ella.

Eina de reemborsament amb API basada en esdeveniments

La paraula impulsada per esdeveniments és força manida; una mica més enllà definirem amb més detall què vol dir això. Començaré pel context en què vam decidir provar l'enfocament de l'API basat en esdeveniments a Kafka.

Experiència en el desenvolupament del servei Refund Tool amb una API asíncrona a Kafka

A qualsevol botiga, a més de les comandes per les quals paguen els clients, hi ha moments en què la botiga està obligada a retornar diners perquè el producte no li convé al client. Aquest és un procés relativament curt: aclarim la informació, si cal, i transferim els diners.

Però la devolució es va complicar més a causa dels canvis en la legislació, i vam haver d'implementar un microservei a part.

Experiència en el desenvolupament del servei Refund Tool amb una API asíncrona a Kafka

La nostra motivació:

  1. Llei FZ-54 - En resum, la llei obliga a informar a l'oficina d'impostos sobre cada transacció monetària, ja sigui una devolució o un rebut, en un SLA força breu de pocs minuts. Nosaltres, com a empresa de comerç electrònic, realitzem un munt d'operacions. Tècnicament, això significa una nova responsabilitat (i, per tant, un nou servei) i millores en tots els sistemes implicats.
  2. BOB es va dividir és un projecte intern de l'empresa per alliberar a BOB d'un gran nombre de responsabilitats no bàsiques i reduir la seva complexitat general.

Experiència en el desenvolupament del servei Refund Tool amb una API asíncrona a Kafka

Aquest diagrama mostra els principals sistemes Lamoda. Ara la majoria són més una constel·lació de 5-10 microserveis al voltant d'un monòlit que es redueix. Estan creixent lentament, però estem intentant fer-los més petits, perquè desplegar el fragment seleccionat al mig fa por: no podem permetre que caigui. Estem obligats a reservar tots els intercanvis (fletxes) i tenir en compte que qualsevol d'ells pot resultar no disponible.

BOB també té força intercanvis: sistemes de pagament, sistemes de lliurament, sistemes de notificació, etc.

Tècnicament BOB és:

  • ~150k línies de codi + ~100k línies de proves;
  • php7.2 + Zend 1 i Symfony Components 3;
  • >100 API i ~50 integracions de sortida;
  • 4 països amb lògica empresarial pròpia.

El desplegament de BOB és costós i dolorós, la quantitat de codi i problemes que soluciona és tal que ningú s'ho pot posar tot al cap. En general, hi ha moltes raons per simplificar-ho.

Procés de devolució

Inicialment, en el procés intervenen dos sistemes: BOB i Payment. Ara apareixen dos més:

  • Servei de Fiscalització, que s'encarregarà dels problemes de fiscalització i comunicació amb serveis externs.
  • Eina de reemborsament, que simplement conté nous intercanvis per no inflar el BOB.

Ara el procés té aquest aspecte:

Experiència en el desenvolupament del servei Refund Tool amb una API asíncrona a Kafka

  1. BOB rep una sol·licitud de reemborsament.
  2. BOB parla d'aquesta eina de reemborsament.
  3. L'eina de reemborsament diu a Payment: "Retorna els diners".
  4. El pagament retorna els diners.
  5. L'eina de reemborsament i el BOB sincronitzen els estats entre ells, perquè de moment tots dos ho necessiten. Encara no estem preparats per canviar completament a l'eina de reemborsament, ja que BOB té una interfície d'usuari, informes per a la comptabilitat i, en general, moltes dades que no es poden transferir tan fàcilment. Has de seure en dues cadires.
  6. La petició de fiscalització desapareix.

Com a resultat, vam fer una mena d'autobús d'esdeveniments a Kafka - bus d'esdeveniments, en el qual va començar tot. Hura, ara tenim un únic punt de fracàs (sarcasme).

Experiència en el desenvolupament del servei Refund Tool amb una API asíncrona a Kafka

Els pros i els contres són força evidents. Hem fet un autobús, això vol dir que ara tots els serveis en depenen. Això simplifica el disseny, però introdueix un únic punt de fallada al sistema. Kafka estavellarà, el procés s'aturarà.

Què és una API basada en esdeveniments

Una bona resposta a aquesta pregunta es troba a l'informe de Martin Fowler (GOTO 2017) "Els molts significats de l'arquitectura impulsada per esdeveniments".

Breument què vam fer:

  1. Embolcalleu tots els intercanvis asíncrons mitjançant emmagatzematge d'esdeveniments. En lloc d'informar a tots els consumidors interessats sobre un canvi d'estat a la xarxa, escrivim un esdeveniment sobre un canvi d'estat a un emmagatzematge centralitzat i els consumidors interessats en el tema llegeixen tot el que apareix a partir d'aquí.
  2. L'esdeveniment en aquest cas és una notificació (notificacions) que alguna cosa ha canviat en algun lloc. Per exemple, l'estat de la comanda ha canviat. Un consumidor que estigui interessat en algunes dades que acompanyen el canvi d'estat i que no s'inclouen a la notificació pot conèixer-ne ell mateix.
  3. L'opció màxima és l'aprovisionament d'esdeveniments complet, transferència estatal, en aquest cas conté tota la informació necessària per al tractament: d'on prové i en quin estat ha anat, com han canviat exactament les dades, etc. L'única qüestió és la viabilitat i la quantitat d'informació que et pots permetre emmagatzemar.

Com a part del llançament de l'eina de reemborsament, vam utilitzar la tercera opció. Això va simplificar el processament d'esdeveniments, ja que no hi havia necessitat d'extreure informació detallada, a més d'eliminar l'escenari en què cada nou esdeveniment genera un esclat de sol·licituds aclaridores dels consumidors.

Servei d'eina de reemborsament no carregat, així que Kafka hi ha més un gust de ploma que una necessitat. No crec que si el servei de reemborsament es convertís en un projecte de gran càrrega, el negoci estaria content.

Intercanvi asíncron tal com està

Per als intercanvis asíncrons, el departament de PHP sol utilitzar RabbitMQ. Vam recollir les dades de la sol·licitud, la vam posar en cua i el consumidor del mateix servei les va llegir i enviar (o no enviar-la). Per a la pròpia API, Lamoda utilitza activament Swagger. Dissenyem una API, la descrivim a Swagger i generem codi de client i servidor. També fem servir un JSON RPC 2.0 lleugerament millorat.

En alguns llocs s'utilitzen autobusos ESB, alguns viuen a activeMQ, però, en general, RabbitMQ - estàndard.

Intercanvi asíncron TO BE

Quan es dissenya l'intercanvi mitjançant el bus d'esdeveniments, es pot rastrejar una analogia. De manera similar, descriurem l'intercanvi de dades futur mitjançant descripcions d'estructura d'esdeveniments. El format yaml, havíem de fer la generació de codi nosaltres mateixos, el generador crea DTO segons l'especificació i ensenya als clients i servidors a treballar-hi. La generació va en dos idiomes - golang i php. Això ajuda a mantenir les biblioteques coherents. El generador està escrit en golang, per això va rebre el nom de gogi.

L'obtenció d'esdeveniments a Kafka és una cosa típica. Hi ha una solució de la versió empresarial principal de Kafka Confluent, hi ha nakadi, una solució dels nostres germans de domini Zalando. El nostre motivació per començar amb vainilla Kafka - això vol dir deixar la solució lliure fins que finalment decidim si la farem servir a tot arreu, i també deixar-nos marge de maniobra i millores: volem suport per als nostres JSON RPC 2.0, generadors per a dos idiomes i a veure què més.

És irònic que fins i tot en un cas tan feliç, quan hi ha un negoci aproximadament similar, Zalando, que va fer una solució aproximadament similar, no la podem utilitzar de manera eficaç.

El patró arquitectònic al llançament és el següent: llegim directament de Kafka, però escrivim només a través d'un bus d'esdeveniments. Hi ha molt a punt per llegir a Kafka: corredors, equilibradors, i està més o menys llest per a l'escala horitzontal, volia mantenir això. Volíem completar l'enregistrament a través d'un Gateway, també conegut com Events-bus, i aquí teniu el perquè.

Esdeveniments-autobús

O un autobús d'esdeveniments. Aquesta és simplement una passarel·la http sense estat, que assumeix diverses funcions importants:

  • Producció de validació — comprovem que els actes compleixen les nostres especificacions.
  • Sistema mestre d'esdeveniments, és a dir, aquest és el principal i únic sistema de l'empresa que respon a la pregunta de quins esdeveniments amb quines estructures es consideren vàlids. La validació només implica tipus de dades i enumeracions per especificar estrictament el contingut.
  • Funció hash per a la fragmentació: l'estructura del missatge de Kafka és clau-valor i utilitzant el hash de la clau es calcula on posar-la.

Per què

Treballem en una gran empresa amb un procés simplificat. Per què canviar res? Això és un experiment, i esperem obtenir diversos beneficis.

intercanvis 1:n+1 (un a molts)

Kafka fa que sigui molt fàcil connectar nous consumidors a l'API.

Suposem que teniu un directori que heu de mantenir actualitzat en diversos sistemes alhora (i en alguns de nous). Anteriorment, vam inventar un paquet que implementava set-API i el sistema mestre es va informar de les adreces dels consumidors. Ara el sistema mestre envia actualitzacions del tema i tothom que estigui interessat el llegeix. Ha aparegut un nou sistema: el vam apuntar al tema. Sí, també paquet, però més senzill.

En el cas de refund-tool, que és una peça de BOB, ens convé mantenir-los sincronitzats a través de Kafka. El pagament diu que els diners van ser retornats: BOB, RT es van assabentar d'això, van canviar els seus estats, el Servei de Fiscalització es va assabentar d'això i va emetre un xec.

Experiència en el desenvolupament del servei Refund Tool amb una API asíncrona a Kafka

Tenim plans per crear un servei de notificacions unificat que avisi el client sobre les notícies relacionades amb la seva comanda/devolucions. Ara aquesta responsabilitat es reparteix entre sistemes. Ens n'hi haurà prou amb ensenyar al Servei de Notificacions a captar informació rellevant de Kafka i respondre-hi (i a desactivar aquestes notificacions en altres sistemes). No es requeriran nous intercanvis directes.

Basat en dades

La informació entre sistemes es fa transparent, independentment de quina "empresa sagnant" tingueu i per molt que sigui la vostra cartera de retard. Lamoda disposa d'un departament d'anàlisi de dades que recull dades dels sistemes i les posa en un format reutilitzable, tant per a empreses com per a sistemes intel·ligents. Kafka us permet donar-los ràpidament moltes dades i mantenir aquest flux d'informació actualitzat.

Registre de replicació

Els missatges no desapareixen després de ser llegits, com a RabbitMQ. Quan un esdeveniment conté informació suficient per processar-lo, tenim un historial dels canvis recents a l'objecte i, si ho desitja, la possibilitat d'aplicar aquests canvis.

El període d'emmagatzematge del registre de rèplica depèn de la intensitat d'escriptura d'aquest tema; Kafka us permet establir de manera flexible límits de temps d'emmagatzematge i volum de dades. Per a temes intensius, és important que tots els consumidors tinguin temps per llegir la informació abans que desaparegui, fins i tot en el cas d'inoperabilitat a curt termini. Normalment és possible emmagatzemar dades per unitats de dies, que és prou per a suport.

Experiència en el desenvolupament del servei Refund Tool amb una API asíncrona a Kafka

A continuació, un petit relat de la documentació, per a aquells que no estiguin familiaritzats amb Kafka (la imatge també és de la documentació)

AMQP té cues: escrivim missatges a una cua per al consumidor. Normalment, un sistema processa una cua amb la mateixa lògica empresarial. Si necessiteu notificar diversos sistemes, podeu ensenyar a l'aplicació a escriure en diverses cues o configurar l'intercanvi amb el mecanisme de distribució, que els clona ell mateix.

Kafka té una abstracció semblant tema, en què escrius missatges, però no desapareixen després de llegir-los. De manera predeterminada, quan us connecteu a Kafka, rebeu tots els missatges i teniu l'opció de desar-los on ho heu deixat. És a dir, si llegeixes seqüencialment, no pots marcar el missatge com a llegit, sinó que deseu l'identificador des del qual podreu continuar llegint. L'identificador que heu establert s'anomena offset i el mecanisme és commit offset.

En conseqüència, es poden implementar diferents lògiques. Per exemple, tenim BOB en 4 casos per a diferents països: Lamoda es troba a Rússia, Kazakhstan, Ucraïna i Bielorússia. Com que es despleguen per separat, tenen configuracions lleugerament diferents i la seva pròpia lògica empresarial. Indiquem al missatge a quin país fa referència. Cada consumidor BOB de cada país llegeix amb un groupId diferent, i si el missatge no s'aplica a ells, se'l salten, és a dir. immediatament comet compensació +1. Si el nostre Servei de pagament llegeix el mateix tema, ho fa amb un grup separat i, per tant, les compensacions no s'entrecreuen.

Requisits de l'esdeveniment:

  • Completitud de les dades. M'agradaria que l'esdeveniment tingués dades suficients perquè es pugui processar.

  • Integritat Deleguem a Events-bus la verificació que l'esdeveniment sigui coherent i pugui processar-lo.
  • L'ordre és important. En el cas d'un retorn, ens veiem obligats a treballar amb la història. Amb les notificacions, la comanda no és important, si es tracta de notificacions homogènies, el correu electrònic serà el mateix independentment de la comanda que hagi arribat primer. En el cas d'un reemborsament, hi ha un procés clar; si canviem la comanda, es produiran excepcions, la devolució no es crearà ni es processarà; acabarem en un estat diferent.
  • Coherència. Tenim una botiga i ara creem esdeveniments en lloc d'una API. Necessitem una manera de transmetre de manera ràpida i econòmica informació sobre nous esdeveniments i canvis als existents als nostres serveis. Això s'aconsegueix mitjançant una especificació comuna en un repositori git i generadors de codi separats. Per tant, es coordinen clients i servidors en diferents serveis.

Kafka a Lamoda

Tenim tres instal·lacions de Kafka:

  1. Registres;
  2. R+D;
  3. Esdeveniments-autobús.

Avui només parlem de l'últim punt. A events-bus, no tenim instal·lacions molt grans: 3 corredors (servidors) i només 27 temes. Per regla general, un tema és un procés. Però aquest és un punt subtil i ara el tocarem.

Experiència en el desenvolupament del servei Refund Tool amb una API asíncrona a Kafka

A dalt hi ha el gràfic rps. El procés de reemborsament està marcat amb una línia turquesa (sí, la de l'eix X) i la línia rosa és el procés d'actualització del contingut.

El catàleg de Lamoda conté milions de productes i les dades s'actualitzen constantment. Algunes col·leccions passen de moda, se n'estrenen de noves per substituir-les i constantment apareixen nous models al catàleg. Intentem predir què serà interessant per als nostres clients demà, així que comprem coses noves constantment, les fotografiem i actualitzem la vitrina.

Els pics rosats són actualitzacions de productes, és a dir, canvis en els productes. Es pot veure que els nois van fer fotos, van fer fotos, i després de nou! — va carregar un paquet d'esdeveniments.

Casos d'ús de Lamoda Events

Utilitzem l'arquitectura construïda per a les operacions següents:

  • Seguiment de l'estat de retorn: crida a l'acció i seguiment de l'estat de tots els sistemes implicats. Pagament, estats, fiscalització, notificacions. Aquí vam provar l'enfocament, vam fer eines, vam recopilar tots els errors, vam escriure documentació i vam dir als nostres companys com utilitzar-la.
  • Actualització de les targetes de producte: configuració, metadades, característiques. Un sistema llegeix (que es mostra) i diversos escriuen.
  • Correu electrònic, push i sms: s'ha recollit la comanda, ha arribat la comanda, s'ha acceptat la devolució, etc., n'hi ha molts.
  • Stock, renovació de magatzem — actualització quantitativa d'articles, només números: arribada al magatzem, devolució. Cal que tots els sistemes associats a la reserva de mercaderies funcionin amb les dades més actuals. Actualment, el sistema d'actualització d'estocs és força complex; Kafka el simplificarà.
  • Anàlisi de Dades (Departament d'R+D), eines de ML, analítiques, estadístiques. Volem que la informació sigui transparent; Kafka és molt adequat per a això.

Ara la part més interessant sobre els grans cops i els descobriments interessants que s'han produït durant els últims sis mesos.

Problemes de disseny

Suposem que volem fer una cosa nova, per exemple, transferir tot el procés de lliurament a Kafka. Ara part del procés s'implementa en Processament de comandes a BOB. Hi ha un model d'estat darrere de la transferència d'una comanda al servei de lliurament, el moviment a un magatzem intermedi, etc. Hi ha tot un monòlit, fins i tot dos, més un munt d'API dedicades al lliurament. Saben molt més sobre el lliurament.

Sembla que són àrees semblants, però el processament de comandes a BOB i el sistema d'enviament tenen estats diferents. Per exemple, alguns serveis de missatgeria no envien estats intermedis, sinó només els finals: "entregat" o "perdut". Altres, per contra, informen amb gran detall sobre el moviment de mercaderies. Cadascú té les seves pròpies regles de validació: per a alguns, el correu electrònic és vàlid, la qual cosa significa que es processarà; per a altres no és vàlid, però la comanda encara es processarà perquè hi ha un número de telèfon de contacte, i algú dirà que aquesta comanda no es processarà en absolut.

Flux de dades

En el cas de Kafka, es planteja la qüestió de l'organització del flux de dades. Aquesta tasca consisteix a escollir una estratègia a partir de diversos punts; repassem-los tots.

En un tema o en diferents?

Tenim una especificació de l'esdeveniment. A BOB escrivim que cal lliurar tal o tal comanda, i indiquem: el número de comanda, la seva composició, alguns SKU i codis de barres, etc. Quan la mercaderia arribi al magatzem, el lliurament podrà rebre estats, segells de temps i tot el que sigui necessari. Però després volem rebre actualitzacions sobre aquestes dades a BOB. Tenim un procés invers de recepció de dades des del lliurament. És aquest el mateix esdeveniment? O és un intercanvi a part que mereix un tema propi?

El més probable és que siguin molt semblants, i la temptació de fer un tema no és infundada, perquè un tema separat significa consumidors separats, configuracions separades, una generació separada de tot això. Però no és un fet.

Nou camp o nou esdeveniment?

Però si utilitzeu els mateixos esdeveniments, sorgeix un altre problema. Per exemple, no tots els sistemes de lliurament poden generar el tipus de DTO que pot generar BOB. Els enviem l'identificador, però no el guarden perquè no el necessiten, i des del punt de vista d'iniciar el procés del bus d'esdeveniments, aquest camp és obligatori.

Si introduïm una regla per al bus d'esdeveniments que aquest camp és obligatori, ens veiem obligats a establir regles de validació addicionals al BOB o al gestor d'esdeveniments d'inici. La validació comença a estendre's per tot el servei, això no és molt convenient.

Un altre problema és la temptació del desenvolupament incremental. Ens diuen que cal afegir alguna cosa a l'esdeveniment, i potser, si hi pensem bé, hauria d'haver estat un esdeveniment a part. Però en el nostre esquema, un esdeveniment separat és un tema a part. Un tema a part és tot el procés que he descrit anteriorment. El desenvolupador té la temptació d'afegir un altre camp a l'esquema JSON i regenerar-lo.

En el cas de les devolucions, vam arribar en cas d'esdeveniments en mig any. Vam tenir un meta-esdeveniment anomenat actualització de reemborsament, que tenia un camp de tipus que descrivia què era realment aquesta actualització. Per això, vam tenir interruptors "meravellosos" amb validadors que ens van dir com validar aquest esdeveniment amb aquest tipus.

Versions d'esdeveniments

Per validar missatges a Kafka podeu utilitzar Avro, però calia posar-hi immediatament i utilitzar Confluent. En el nostre cas, hem d'anar amb compte amb la versió. No sempre serà possible tornar a llegir els missatges del registre de rèplica perquè el model ha "sort". Bàsicament, resulta construir versions perquè el model sigui compatible cap enrere: per exemple, fer que un camp sigui temporalment opcional. Si les diferències són massa fortes, comencem a escriure en un tema nou i transferim els clients quan acabin de llegir l'antic.

Ordre de lectura garantit de les particions

Els temes dins de Kafka es divideixen en particions. Això no és molt important mentre estem dissenyant entitats i intercanvis, però sí a l'hora de decidir com consumir-lo i escalar-lo.

En el cas habitual, escrius un tema a Kafka. Per defecte, s'utilitza una partició i tots els missatges d'aquest tema hi van. I, en conseqüència, el consumidor llegeix aquests missatges seqüencialment. Suposem que ara hem d'ampliar el sistema perquè els missatges siguin llegits per dos consumidors diferents. Si, per exemple, esteu enviant SMS, podeu dir-li a Kafka que faci una partició addicional i Kafka començarà a dividir els missatges en dues parts: la meitat aquí, la meitat aquí.

Com els divideix Kafka? Cada missatge té un cos (en el qual emmagatzemem JSON) i una clau. Podeu adjuntar una funció hash a aquesta clau, que determinarà a quina partició anirà el missatge.

En el nostre cas de reemborsaments, això és important, si prenem dues particions, hi ha la possibilitat que un consumidor paral·lel processi el segon esdeveniment abans que el primer i hi hagi problemes. La funció hash garanteix que els missatges amb la mateixa clau acabin a la mateixa partició.

Esdeveniments vs ordres

Aquest és un altre problema que hem trobat. L'esdeveniment és un esdeveniment determinat: diem que alguna cosa ha passat en algun lloc (alguna cosa ha passat), per exemple, s'ha cancel·lat un article o s'ha produït un reemborsament. Si algú escolta aquests esdeveniments, segons "element cancel·lat", es crearà l'entitat de reemborsament i "s'ha produït el reemborsament" s'escriurà en algun lloc de la configuració.

Però normalment, quan dissenyeu esdeveniments, no voleu escriure'ls en va: confieu en el fet que algú els llegirà. Hi ha una gran temptació d'escriure no alguna cosa_happened (element_cancel·lat, refund_refunded), sinó alguna cosa_ha de_fer_se. Per exemple, l'article està llest per ser retornat.

D'una banda, suggereix com s'utilitzarà l'esdeveniment. D'altra banda, sona molt menys com un nom d'esdeveniment normal. A més, no està lluny d'aquí l'ordre do_something. Però no teniu cap garantia que algú llegeixi aquest esdeveniment; i si el llegiu, aleshores el llegiu amb èxit; i si l'heu llegit amb èxit, aleshores vau fer alguna cosa, i això va tenir èxit. En el moment en què un esdeveniment es converteix en do_something, el feedback es fa necessari, i això és un problema.

Experiència en el desenvolupament del servei Refund Tool amb una API asíncrona a Kafka

En l'intercanvi asíncron a RabbitMQ, quan llegiu el missatge, aneu a http, teniu una resposta, almenys que s'ha rebut el missatge. Quan escrius a Kafka, hi ha un missatge que has escrit a Kafka, però no saps res sobre com es va processar.

Per tant, en el nostre cas, hem hagut d'introduir un esdeveniment de resposta i configurar un seguiment de manera que si s'envien tants esdeveniments, després de tal o tal hora arribessin el mateix nombre d'esdeveniments de resposta. Si això no passa, sembla que alguna cosa ha anat malament. Per exemple, si hem enviat l'esdeveniment "item_ready_to_refund", esperem que es crearà un reemborsament, es retornaran els diners al client i se'ns enviarà l'esdeveniment "money_refunded". Però això no és segur, de manera que cal fer un seguiment.

Matisos

Hi ha un problema força evident: si llegeixes d'un tema seqüencialment i tens algun missatge dolent, el consumidor caurà i no aniràs més enllà. Necessites aturar tots els consumidors, compromeu la compensació encara més per continuar llegint.

Ho sabíem, comptàvem amb això i, tanmateix, va passar. I això va passar perquè l'esdeveniment era vàlid des del punt de vista de events-bus, l'esdeveniment era vàlid des del punt de vista del validador d'aplicacions, però no era vàlid des del punt de vista de PostgreSQL, perquè en el nostre sistema únic. MySQL amb UNSIGNED INT, i al nou escrit el sistema tenia PostgreSQL només amb INT. La seva mida és una mica més petita i l'identificador no encaixava. Symfony va morir amb una excepció. Per descomptat, vam agafar l'excepció perquè confiàvem en ella i anàvem a cometre aquest desplaçament, però abans volíem augmentar el comptador de problemes, ja que el missatge es va processar sense èxit. Els comptadors d'aquest projecte també es troben a la base de dades, i Symfony ja ha tancat la comunicació amb la base de dades, i la segona excepció va matar tot el procés sense possibilitat de cometre compensació.

El servei es va estirar durant un temps; afortunadament, amb Kafka això no està tan malament, perquè els missatges es mantenen. Quan es recuperi el treball, podeu acabar de llegir-los. És còmode.

Kafka té la capacitat d'establir un desplaçament arbitrari mitjançant eines. Però per fer-ho, cal aturar tots els consumidors; en el nostre cas, prepareu un llançament separat en el qual no hi haurà consumidors, redistribucions. Aleshores, a Kafka, podeu canviar el desplaçament mitjançant eines i el missatge passarà.

Un altre matís - registre de rèplica vs rdkafka.so - està relacionat amb les especificitats del nostre projecte. Utilitzem PHP, i en PHP, per regla general, totes les biblioteques es comuniquen amb Kafka a través del dipòsit rdkafka.so, i després hi ha algun tipus d'embolcall. Potser aquestes són les nostres dificultats personals, però va resultar que simplement rellegir un fragment del que ja havíem llegit no és tan fàcil. En general, hi havia problemes de programari.

Tornant als detalls del treball amb particions, està escrit directament a la documentació consumidors >= particions de tema. Però em vaig assabentar d'això molt més tard del que m'hagués agradat. Si voleu escalar i tenir dos consumidors, necessiteu almenys dues particions. És a dir, si teníeu una partició en la qual s'havien acumulat 20 mil missatges i n'heu fet una de nova, el nombre de missatges no s'igualarà aviat. Per tant, per tenir dos consumidors paral·lels, cal tractar amb particions.

Seguiment

Crec que de la manera com ho farem el seguiment serà encara més clar quins problemes hi ha en l'enfocament existent.

Per exemple, calculem quants productes de la base de dades han canviat recentment el seu estat i, en conseqüència, s'haurien d'haver produït esdeveniments en funció d'aquests canvis, i enviem aquest número al nostre sistema de seguiment. Aleshores de Kafka obtenim el segon número, quants esdeveniments es van gravar realment. Òbviament, la diferència entre aquests dos nombres ha de ser sempre zero.

Experiència en el desenvolupament del servei Refund Tool amb una API asíncrona a Kafka

A més, cal controlar com està el productor, si el bus d'esdeveniments ha rebut missatges i com ho està fent el consumidor. Per exemple, als gràfics següents, l'eina de reemborsament funciona bé, però BOB té clarament alguns problemes (pics blaus).

Experiència en el desenvolupament del servei Refund Tool amb una API asíncrona a Kafka

Ja he esmentat el retard del grup de consumidors. A grans trets, aquest és el nombre de missatges no llegits. En general, els nostres consumidors treballen ràpidament, de manera que el retard sol ser 0, però de vegades pot haver-hi un pic a curt termini. Kafka pot fer-ho fora de la caixa, però cal establir un interval determinat.

Hi ha un projecte cauque us donarà més informació sobre Kafka. Simplement utilitza l'API del grup de consumidors per donar l'estat de com està aquest grup. A més d'OK i Failed, hi ha un avís i podeu descobrir que els vostres consumidors no poden fer front al ritme de producció: no tenen temps per revisar el que està escrit. El sistema és bastant intel·ligent i fàcil d'utilitzar.

Experiència en el desenvolupament del servei Refund Tool amb una API asíncrona a Kafka

Així es veu la resposta de l'API. Aquí hi ha el grup bob-live-fifa, partició refund.update.v1, estat OK, retard 0: l'últim desplaçament final tal i tal.

Experiència en el desenvolupament del servei Refund Tool amb una API asíncrona a Kafka

Seguiment updated_at SLA (encallat) Ja he comentat. Per exemple, el producte ha canviat a l'estat que està llest per a la devolució. Instal·lem Cron, que diu que si en 5 minuts aquest objecte no s'ha reemborsat (tornem els diners a través dels sistemes de pagament molt ràpidament), alguna cosa definitivament va sortir malament, i aquest és definitivament un cas de suport. Per tant, simplement prenem Cron, que llegeix aquestes coses, i si són superiors a 0, envia una alerta.

En resum, utilitzar esdeveniments és convenient quan:

  • La informació la necessiten diversos sistemes;
  • el resultat del processament no és important;
  • hi ha pocs esdeveniments o petits esdeveniments.

Sembla que l'article té un tema molt específic: API asíncrona a Kafka, però en relació amb això m'agradaria recomanar moltes coses alhora.
Primer, següent HighLoad ++ Cal esperar fins al novembre, a l'abril hi haurà una versió de Sant Petersburg, i al juny parlarem de les càrregues altes a Novosibirsk.
En segon lloc, l'autor de l'informe, Sergei Zaika, és membre del Comitè del Programa de la nostra nova conferència sobre gestió del coneixement. KnowledgeConf. La jornada és d'un dia, tindrà lloc el 26 d'abril, però el seu programa és molt intens.
I serà al maig PHP Rússia и RIT++ (amb DevOpsConf inclòs): també podeu suggerir-hi el vostre tema, parlar de la vostra experiència i queixar-vos dels vostres cons farcits.

Font: www.habr.com

Afegeix comentari