{"id":30778,"date":"2019-10-31T21:37:23","date_gmt":"2019-10-31T18:37:23","guid":{"rendered":"https:\/\/prohoster.info\/blog\/opyt-razrabotki-servisa-refund-tool-s-asinhronnym-api-na-kafka\/"},"modified":"2019-10-31T21:37:23","modified_gmt":"2019-10-31T18:37:23","slug":"opyt-razrabotki-servisa-refund-tool-s-asinhronnym-api-na-kafka","status":"publish","type":"post","link":"https:\/\/prohoster.info\/et\/blog\/administrirovanie\/opyt-razrabotki-servisa-refund-tool-s-asinhronnym-api-na-kafka","title":{"rendered":"Kogemus Refund Tool teenuse arendamisest as\u00fcnkroonse API-ga Kafka-l","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p>Mis v\u00f5ib sundida nii suurt ettev\u00f5tet nagu Lamoda, kellel on sujuv protsess ja k\u00fcmneid omavahel seotud teenuseid, oluliselt oma l\u00e4henemist muutma? Motivatsioon v\u00f5ib olla t\u00e4iesti erinev: seadusandlikest p\u00f5hjustest kuni k\u00f5igile arendajatele omase katsetussoovini.<\/p>\n<p>Kuid see ei t\u00e4henda sugugi, et ei saa loota lisakasu peale. Mida konkreetselt v\u00f5ib v\u00f5ita, kui rakendada events-driven API-d Kafka peal, selgitab Sergei Zaika (<noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/users\/fewald\/\" class=\"user_link\">fewald<\/a><\/noindex>). Ka kepiga k\u00e4idud teed ja huvitavad avastused tulevad kindlasti juttu \u2013 eks katse ei saa ilma nendeta olla.<\/p>\n<p><img decoding=\"async\" alt=\"Kogemus Refund Tool teenuse arendamisest as\u00fcnkroonse API-ga Kafka-l\" src=\"\/wp-content\/uploads\/2019\/04\/7ab959ab45ec5c6565b35b18b361c0ea.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\n<em>Ees\u00f5igus: See artikkel p\u00f5hineb materjalidel, mis tulenesid meetapist, mille Sergei viis l\u00e4bi novembris 2018 HighLoad++-il. Lamoda elukogemus Kafka kasutamisest t\u00f5mbas kuulajate t\u00e4helepanu mitte v\u00e4hem kui teised ettekanded ajakavas. Me arvame, et see on suurep\u00e4rane n\u00e4ide sellest, kuidas alati ja tuleb leida \u00fcksteisem\u00f5istvaid inimesi, ning HighLoad++ korraldajad j\u00e4tkavad p\u00fc\u00fcdlust luua sellele soodsa atmosf\u00e4\u00e4ri.<\/em><br \/>\n<noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<h2>Protsessist<\/h2>\n<p>\nLamoda on suur e-kaubanduse platvorm, millel on oma kontaktikeskus, kohaletoimetamisteenused (ja palju partnerite teenuseid), fotostuudio, suur ladu ja k\u00f5ik see t\u00f6\u00f6tab oma tarkvaral. On k\u00fcmneid makseviise, b2b-partnereid, kes saavad kasutada osa v\u00f5i k\u00f5iki neid teenuseid ja tahavad teada oma toodete kohta jooksvalt teavet. Lisaks tegutseb Lamoda kolmes riigis v\u00e4ljaspool Venemaad, kus k\u00f5ik on veidi teistsugune. Seega on t\u00f5en\u00e4oliselt olemas rohkem kui sada viisi, kuidas uut tellimust konfigureerida, mida tuleb eraldi t\u00f6\u00f6delda. K\u00f5ik see toimib k\u00fcmnete teenuste abil, mis suhtlevad kohati mitte\u00fcheselt. On ka keskne s\u00fcsteem, mille peamine vastutus on tellimuste staatused. Me nimetame seda BOB-iks, mina t\u00f6\u00f6tan selle nimel.<\/p>\n<h2>Refund Tool with events-driven API <\/h2>\n<p>\nS\u00f5na events-driven on \u00fcsna kasutatud, veidi hiljem m\u00e4\u00e4ratleme, mida selle all m\u00f5istetakse. Alustan kontekstiga, milles otsustasime events-driven API-d Kafka peal proovida. <\/p>\n<p><img decoding=\"async\" alt=\"Kogemus Refund Tool teenuse arendamisest as\u00fcnkroonse API-ga Kafka-l\" src=\"\/wp-content\/uploads\/2019\/04\/3bfdce47dd8420fc63d84645e76de647.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nIgas poes, peale tellimuste, mille eest kliendid maksavad, on hetki, kus poelt oodatakse raha tagastamist, kuna toode ei sobinud kliendile. See suhteliselt l\u00fchike protsess: t\u00e4psustame teavet, kui see on vajalik, ja kanname raha tagasi. <\/p>\n<p>Kuid tagastamise protsess on muutunud keeruliseks seadusandlikest muudatustest tulenevalt ja me pidime selle jaoks rakendama eraldi mikroteenuse.<\/p>\n<p><img decoding=\"async\" alt=\"Kogemus Refund Tool teenuse arendamisest as\u00fcnkroonse API-ga Kafka-l\" src=\"\/wp-content\/uploads\/2019\/04\/0e358df5476e7448976e0f1147a103fb.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nMeie motivatsioon:<\/p>\n<ol>\n<li><strong>Seadus FZ-54<\/strong>\u00a0\u2014 l\u00fchidalt, seadus n\u00f5uab igast rahalisest tehingust, olgu see tagastus v\u00f5i sisse tulek, teavitamist maksuhaldurile \u00fcsna l\u00fchikese SLAga, m\u00f5ne minuti jooksul. Meie, kui e-kaubandus, teeme \u00fcsna palju tehinguid. Tehniliselt t\u00e4hendab see uut vastutust (ehk siis uut teenust) ja t\u00e4iustusi k\u00f5igis seotud s\u00fcsteemides.<\/li>\n<li><strong>BOB split<\/strong>\u00a0\u2014 ettev\u00f5tte sisemine projekt, et vabaneda BOBist suurest hulgast mitteprofiilsest vastutusest ja v\u00e4hendada selle \u00fcldist keerukust.<\/li>\n<\/ol>\n<p>\n<img decoding=\"async\" alt=\"Kogemus Refund Tool teenuse arendamisest as\u00fcnkroonse API-ga Kafka-l\" src=\"\/wp-content\/uploads\/2019\/04\/d3ecf9961bdb372fc5f84ee9389f73ef.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nSellel skeemil on kujutatud Lamoda p\u00f5hitehnoloogiaid. Praegu esindavad enamik neist pigem <strong>5-10 mikroteenuse t\u00e4htkuju, mis keerleb v\u00e4heneva monoliidi \u00fcmber.<\/strong>Need kasvavad tasapisi, kuid p\u00fc\u00fcame neid v\u00e4hendada, sest keskmise osa v\u00e4lja andmine on hirmutav \u2014 ei tohi lubada, et see kukub. K\u00f5ik vahetused (nooled) peame varundama ja arvestama, et \u00fcks neist v\u00f5ib olla k\u00e4ttesaamatu.<\/p>\n<p>BOB-is on samuti palju vahetusi: makses\u00fcsteemid, tarne, teavitused jne. <\/p>\n<p>Tehniliselt on BOB:<\/p>\n<ul>\n<li>~150k koodirida + ~100k testide rida;<\/li>\n<li>php7.2 + Zend 1 &amp; Symfony Components 3;<\/li>\n<li>&gt;100 API &amp; ~50 v\u00e4ljuvat integratsiooni;<\/li>\n<li>4 riiki oma \u00e4riloogikaga. <\/li>\n<\/ul>\n<p>\nBOB-i rakendamine on kulukas ja valus, koodihulk ja sellega lahendatavad \u00fclesanded on nii suured, et keegi ei saa seda t\u00e4ielikult oma peasse paigutada. \u00dcldiselt on palju p\u00f5hjuseid selle lihtsustamiseks.<\/p>\n<h2>Tagastamisprotsess<\/h2>\n<p>\nAlguses on protsessis kaasatud kaks s\u00fcsteemi: BOB ja Maksmine. N\u00fc\u00fcd lisanduvad veel kaks:<\/p>\n<ul>\n<li>Fiskalisatsiooni teenus, mis v\u00f5tab enda kanda fiskaliseerimise probleemid ja suhtlemise v\u00e4listest teenustest.<\/li>\n<li>Tagastamise t\u00f6\u00f6riist, kuhu lihtsalt viidatakse uued vahetused, et mitte paisutada BOB-i.<\/li>\n<\/ul>\n<p>\nN\u00fc\u00fcd n\u00e4eb protsess v\u00e4lja nii:<\/p>\n<p><img decoding=\"async\" alt=\"Kogemus Refund Tool teenuse arendamisest as\u00fcnkroonse API-ga Kafka-l\" src=\"\/wp-content\/uploads\/2019\/04\/13c02975881ad35c61304053c604cda3.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<\/p>\n<ol>\n<li>BOB saab raha tagastamise taotluse.<\/li>\n<li>BOB teavitab sellest Tagastamise t\u00f6\u00f6riista.<\/li>\n<li>Tagastamise t\u00f6\u00f6riist \u00fctleb Maksmisele: \u201eTagasta raha.\u201d<\/li>\n<li>Maksmine tagastab raha.<\/li>\n<li>Tagastamise t\u00f6\u00f6riist ja BOB s\u00fcnkroniseerivad omavahel staatuseid, sest see on neile m\u00f5lemale endiselt vajalik. Me pole veel valmis t\u00e4ielikult \u00fcle minema Tagastamise t\u00f6\u00f6riistale, kuna BOB-is on kasutajaliides, raamatupidamisteatised ja \u00fcldiselt palju andmeid, mida ei saa nii lihtsalt \u00fcle viia. Peame istuma kahel toolil.<\/li>\n<li>Teave saadetakse fiskaliseerimiseks.<\/li>\n<\/ol>\n<p>\nL\u00f5puks tegime me Kafka p\u00f5hjal mingi \u00fcrituste buss - event-bus, millele k\u00f5ik tuginevad. Hooray, n\u00fc\u00fcd on meil \u00fcksik t\u00f5rkepunkt (sarcasm).<\/p>\n<p><img decoding=\"async\" alt=\"Kogemus Refund Tool teenuse arendamisest as\u00fcnkroonse API-ga Kafka-l\" src=\"\/wp-content\/uploads\/2019\/04\/674edd7972998b4985071f5250612c7e.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nPlussid ja miinused on \u00fcsna ilmsed. Me tegime bussi, seega s\u00f5ltuvad k\u00f5ik teenused sellest. See lihtsustab projekteerimist, kuid toob s\u00fcsteemi \u00fche t\u00f5rkepunkti. Kui Kafka seab end, siis protsess peatub.<\/p>\n<h2>Mis on events-driven API <\/h2>\n<p>\nHea vastus sellele k\u00fcsimusele on Martin Fowler'i ettekandes (GOTO 2017) <noindex><a rel=\"nofollow\" href=\"https:\/\/youtu.be\/STKCRSUsyPO\">\u00abThe Many Meanings of Event-Driven Architecture\u00bb<\/a><\/noindex>. <\/p>\n<p>L\u00fchidalt, mida me tegime:<\/p>\n<ol>\n<li>K\u00e4ppisime k\u00f5ik as\u00fcnkroonsed vahetused l\u00e4bi <strong>events storage<\/strong>. Selle asemel, et teavitada iga huvitatud tarbijat v\u00f5rgu kaudu staatuse muutumisest, kirjutame me tsentraliseeritud salvestusse s\u00fcndmuse staatuse muutumisest, ja teemaga huvitatud tarbijad loevad sealt k\u00f5ik, mis ilmub.<\/li>\n<li>S\u00fcndmus (event) antud juhul on teade (<strong>notifications<\/strong>) selle kohta, et midagi kuskil on muutunud. N\u00e4iteks, tellimuse staatust on muudetud. Tarbija, kellele on olulised teatud saatemuutuste andmed, mida teates ei ole, saab nende seisundit ise teada.<\/li>\n<li>Maksimaalne variant on t\u00e4ielik event sourcing, <strong>state transfer<\/strong>, kus s\u00fcndmus sisaldab kogu vajalikku teavet t\u00f6\u00f6tlemiseks: kust ja millisesse staatusesse liikusid, kuidas andmed t\u00e4pselt muutusid jne. K\u00fcsimus on ainult otstarbekuses ja teabe mahus, mida saate endale lubada salvestada.<\/li>\n<\/ol>\n<p>\nRefund Tool'i k\u00e4ivitamise raames kasutasime me kolmandat varianti. See lihtsustas s\u00fcndmuste t\u00f6\u00f6tlemist, kuna pole vaja hankida detailselt teavet, pluss v\u00e4listas stsenaariumi, kus iga uus s\u00fcndmus tekitab tarbijatelt hulgaliselt t\u00e4psustavaid get-p\u00e4ringuid.<\/p>\n<p>Refund Tool teenus <strong>ei ole koormatud<\/strong>, seega on Kafka seal pigem katse kui vajadus. Ei arva, et kui tagastusteenus muutuks suure koormuse projektiks, oleks \u00e4ri sellega rahul.<\/p>\n<h4>Async exchange AS IS<\/h4>\n<p>\nAs\u00fcnkroonsete vahetuste jaoks kasutab PHP osakond tavaliselt RabbitMQ. Koondame andmed p\u00e4ringu jaoks, paneme j\u00e4rjekorda ja selle sama teenuse tarbija loeb need ja saadab (v\u00f5i ei saada). Lamoda kasutab API jaoks aktiivselt Swaggerit. Projekteerime API, kirjeldame seda Swaggeris, genereerime kliendi- ja serverikoodi. Veel kasutame me veidi laiemat JSON RPC 2.0. <\/p>\n<p>Kohati kasutatakse esb-busse, keegi elab activeMQ peal, kuid \u00fcldiselt, <strong>RabbitMQ - standard<\/strong>.<\/p>\n<h4>Async exchange TO BE<\/h4>\n<p>\nProjekteerides vahetust events-bus kaudu, v\u00f5ib m\u00e4rgata sarnast mustrit. Me kirjeldame sarnasel viisil tulevast andmevahetust event'i struktuuri kirjeldustega. YAML-formaat, koodigeneratsiooni pidime tegema ise, generaator vastavalt spetsifikatsioonile loob DTO ja \u00f5petab kliente ja servereid nendega t\u00f6\u00f6tama. Generatsioon toimub kahes keeles - <strong>golang ja php<\/strong>. See v\u00f5imaldab hoida raamatukogud koosk\u00f5las. Generaator on kirjutatud golang'is, mille t\u00f5ttu sai ta nimeks gogi.<\/p>\n<p>Event-sourcing Kafka peal on t\u00fc\u00fcpiline. On lahendus peamisest ettev\u00f5tte versioonist Kafka Confluent, on <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/zalando\/nakadi\">nakadi<\/a><\/noindex>, lahendus meie \"vendadelt\" valdkonna alal Zalando. Meie <strong>motivation alustada vanilla Kafka'ga<\/strong>\u00a0on see, et j\u00e4tta lahendus tasuta, kuni me l\u00f5puks ei otsusta, kas me kavatseme seda laialdaselt kasutada, ning j\u00e4tta endale ruumi man\u00f6\u00f6verdamiseks ja t\u00e4iustamiseks: me tahame toetada <strong>JSON RPC 2.0<\/strong>, generaatorid kahes keeles ja vaatame, mis veel. <\/p>\n<p>Ironiline on see, et isegi sellises \u00f5nnelikus olukorras, kus on umbes sarnane \u00e4ri nagu Zalando, mis on teinud umbes sarnase lahenduse, ei saa me seda t\u00f5husalt kasutada. <\/p>\n<p>Arhitektuuriliselt on k\u00e4ivitamise mustern\u00e4ide j\u00e4rgmine: loeme otse Kafka'st, kuid kirjutame ainult l\u00e4bi events-bus'i. Kafka lugemiseks on palju valmis lahendusi: broker'id, tasakaalustajad ja see on enam-v\u00e4hem valmis horisontaalseks skaleerimiseks, seda soovisime s\u00e4ilitada. Kirjutamine, soovisime aga m\u00e4hkida \u00fche Gateway aka Events-bus'i kaudu ja just sellep\u00e4rast.<\/p>\n<h3>Events-bus<\/h3>\n<p>\nV\u00f5i s\u00fcndmuste buss. See on lihtsalt stateless http gateway, mis v\u00f5tab endale mitu olulist rolli:<\/p>\n<ul>\n<li><strong>Tootmise valideerimine<\/strong>\u00a0kontrollime, et s\u00fcndmused vastavad meie spetsifikatsioonile.<\/li>\n<li><strong>S\u00fcndmuste meistris\u00fcsteem<\/strong>, see t\u00e4hendab, et see on ainus ja peamine s\u00fcsteem ettev\u00f5ttes, mis vastab k\u00fcsimusele, millised s\u00fcndmused milliste struktuuridega loetakse kehtivaks. Valideerimisse kuuluvad lihtsalt andmet\u00fc\u00fcbid ja enums sisu range spetsifikatsiooni jaoks. <\/li>\n<li><strong>Hash-funktsioon<\/strong> shardimise jaoks - Kafka s\u00f5numite struktuur on key-value ja just key hash'i j\u00e4rgi arvutame, kuhu see panna.<\/li>\n<\/ul>\n<p><\/p>\n<h3>Miks<\/h3>\n<p>\nMe t\u00f6\u00f6tame suures ettev\u00f5ttes, kus on v\u00e4lja t\u00f6\u00f6tatud protsess. Miks midagi muuta? <strong>See on eksperiment<\/strong>, ja me loodame saada mitmeid eeliseid.<\/p>\n<h4>1:n+1 vahetused (\u00fcks-mitmele)<\/h4>\n<p>\nKafka'ga on v\u00e4ga lihtne \u00fchendada uusi tarbijaid API-le. <\/p>\n<p>Oletame, et teil on kataloog, mida tuleb \u00fcheaegselt mitmes s\u00fcsteemis ajakohasena hoida (ja mingites uutes s\u00fcsteemides samuti). Varem koostasime kimbu, mis rakendas set-API-d, ning master-s\u00fcsteemile edastasime tarbijate aadressid. N\u00fc\u00fcd saadab master-s\u00fcsteem v\u00e4rskendusi teema, mida k\u00f5ik huvilised loevad. Ilmus uus s\u00fcsteem \u2013 registreerisime selle teemale. Jah, samuti kimp, kuid lihtsam.<\/p>\n<p>Refund-tool'i puhul, mis on osa BOB-ist, on meil mugav hoida neid Kafka kaudu s\u00fcnkroonitud. Maksmine \u00fctleb, et raha on tagastatud: BOB ja RT said sellest teada, muutsid oma staatuseid ning Fiskalitise teenus sai sellest teada ja v\u00e4ljastas t\u0161eki.<\/p>\n<p><img decoding=\"async\" alt=\"Kogemus Refund Tool teenuse arendamisest as\u00fcnkroonse API-ga Kafka-l\" src=\"\/wp-content\/uploads\/2019\/04\/b01b22a333b58e87aeef0c52d40e6960.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nMeil on plaanis luua \u00fchtne Teavitusteenus, mis teavitaks klienti tema tellimuste\/tagastuste uudistest. Praegu on see vastutus jaotatud s\u00fcsteemide vahel. Meil piisab, kui \u00f5petame Teavitusteenusele v\u00e4lja p\u00fc\u00fcda Kafka-st asjakohast teavet ning sellele reageerida (ja v\u00e4lja l\u00fclitada teiste s\u00fcsteemide teavitused). Uusi vahetusi ei ole vaja.<\/p>\n<h4>Andmep\u00f5hine<\/h4>\n<p>\nTeave s\u00fcsteemide vahel muutub l\u00e4bipaistvaks \u2013 olenemata sellest, kui \u201everine\u201d ettev\u00f5te teil parasjagu on ja kui mahukas on teie backlog. Lamodas on andmeanal\u00fc\u00fcsi osakond, mis kogub s\u00fcsteemidest andmeid ja viib need taassendrisse kasutatavasse vormi, nii \u00e4ri kui ka intellektuaalsete s\u00fcsteemide jaoks. Kafka v\u00f5imaldab kiiresti anda neile palju andmeid ja hoida seda infovoogu ajakohasena.<\/p>\n<h4>Replikatsiooni ajalugu<\/h4>\n<p>\nS\u00f5numid ei kao p\u00e4rast lugemist, nagu RabbitMQ-s. Kui s\u00fcndmus sisaldab piisavalt teavet t\u00f6\u00f6tlemiseks, siis meil on viimaste muudatuste ajalugu objekti kohta ja vajadusel v\u00f5imalus neid muudatusi rakendada.<\/p>\n<p>Replikatsiooni ajaloos s\u00e4ilitamise t\u00e4htaeg s\u00f5ltub selle teema kirjutamisintensiivsusest, Kafka v\u00f5imaldab paindlikult seadistada s\u00e4ilitamise ajapiiranguid ja andmemahtusid. Intensiivsete teemade puhul on oluline, et k\u00f5ik tarbijad j\u00f5uaksid teavet lugeda enne, kui see kaob, isegi l\u00fchiajalise t\u00f6\u00f6katkestuse korral. Tavaliselt \u00f5nnestub andmeid hoida\u00a0<strong>p\u00e4evade kaupa<\/strong>, mis on piisav toetuse jaoks. <\/p>\n<p><img decoding=\"async\" alt=\"Kogemus Refund Tool teenuse arendamisest as\u00fcnkroonse API-ga Kafka-l\" src=\"\/wp-content\/uploads\/2019\/04\/0e08dd384155289123ebee96430c2370.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nEdasi l\u00e4heb veidi dokumentatsiooni r\u00e4\u00e4kimist nendele, kes ei tunne Kafka't (pilt on samuti dokumentatsioonist)<\/p>\n<p>AMQP'is on j\u00e4rjekorrad: kirjutame s\u00f5numeid tarbija j\u00e4rjekorda. \u00dcldjuhul t\u00f6\u00f6tlebs \u00fcks s\u00fcsteem sama \u00e4ri-logikaga \u00fchte j\u00e4rjekorda. Kui on vaja teavitada mitmeid s\u00fcsteeme, saab rakendust \u00f5petada kirjutama mitmesse j\u00e4rjekorda v\u00f5i seadistada exchange f\u00e4nnideadme s\u00fcsteemiga, mis kloonib neid.<\/p>\n<p>Kafkas on sarnane abstraktsioon <em>teema<\/em>, kuhu kirjutate s\u00f5numeid, kuid need ei kao p\u00e4rast lugemist. Vaikes\u00e4tte j\u00e4rgi, kui \u00fchendate Kafkasse, saate k\u00f5ik s\u00f5numid, ja samas on v\u00f5imalus salvestada koht, kus te l\u00f5petasite. See t\u00e4hendab, et loete j\u00e4rjestikku, ei pea s\u00f5numit loetuks m\u00e4rgima, kuid saate salvestada id, kust hiljem lugemisega j\u00e4tkata. Id, kus te l\u00f5petasite, nimetatakse offset'iks (nihe), ja mehhanismiks on commit offset. <\/p>\n<p>Seega saab rakendada erinevat loogikat. N\u00e4iteks BOB eksisteerib neljas instantsis erinevates riikides \u2013 Lamoda on Venemaal, Kasahstanis, Ukrainas, Valgevenes. Kuna neid rakendatakse eraldi, on neil natuke erinevad konfiguratsioonid ja \u00e4ri-loogika. Me m\u00e4rgime s\u00f5numis, millisele riigile see kuulub. Iga BOB tarbija igas riigis loeb erineva groupId'ga ja kui s\u00f5num ei kuulu neile, siis nad j\u00e4tavad selle vahele, st nad kommitivad kohe offset +1. Kui sama teema loeb meie Makseteenus, siis teeb ta seda eraldi grupiga ja seega offset'id ei ristile.<\/p>\n<p><b>N\u00f5uded s\u00fcndmustele:<\/b><\/p>\n<ul>\n<li><strong>Andmete t\u00e4ielikkus. <\/strong>Sooviks, et s\u00fcndmuses oleks piisavalt andmeid, et seda saaks t\u00f6\u00f6delda. <\/li>\n<\/ul>\n<p><\/p>\n<ul>\n<li><strong>Terviklikkus. <\/strong>Delegeerime Events-bus'ile kontrolli, et s\u00fcndmus oleks j\u00e4rjekindel ja ta saaks selle t\u00f6\u00f6delda.<\/li>\n<li><strong>J\u00e4rjekord on oluline. <\/strong>Tagastamise korral peame t\u00f6\u00f6tama ajaloo baasil. Teavituste puhul ei ole j\u00e4rjekord t\u00e4htis, kui need on \u00fchtsed teavitused, e-kiri on sama, olenemata sellest, milline tellimus saabus esimesena. Tagastamise korral on selge protsess, kui j\u00e4rjekorda muuta, siis v\u00f5ivad tekkida erandid, tagasimakset ei luu v\u00f5i ei t\u00f6\u00f6delda \u2013 satume teise olekusse.<\/li>\n<li><strong>Sisukaal. <\/strong>Meil on salvestusruum ja n\u00fc\u00fcd loome s\u00fcndmusi, mitte API-d. Me vajame kiiret ja odavat viisi, et edastada teenustele teavet uutest s\u00fcndmustest ja juba olemasolevate muutustest. Selle saavutame \u00fchiselt m\u00e4\u00e4ratletud spetsifikatsiooni ja koodigeneraatoreid kasutades eraldi git-repositooriumis. Seet\u00f5ttu on meie kliendid ja serverid erinevates teenustes koosk\u00f5lastatud.<\/li>\n<\/ul>\n<p><\/p>\n<h2>Kafka Lamodas<\/h2>\n<p>\nMeil on kolm Kafka installeerimist: <\/p>\n<ol>\n<li>Logs;<\/li>\n<li>R&amp;D;<\/li>\n<li>Events-buss.<\/li>\n<\/ol>\n<p>\nT\u00e4na r\u00e4\u00e4gime ainult viimase punktist. Events-bussis ei ole meil v\u00e4ga suuri installeerimisi \u2013 3 pakkujat (serverit) ja kokku 27 teemat. Reeglina on \u00fcks teema \u00fcks protsess. Kuid see on delikaatne teema, ja me k\u00e4sitleme seda kohe.<\/p>\n<p><img decoding=\"async\" alt=\"Kogemus Refund Tool teenuse arendamisest as\u00fcnkroonse API-ga Kafka-l\" src=\"\/wp-content\/uploads\/2019\/04\/f398852689b31429cc97b4cbffcabab5.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\n\u00dclal on rps graafik. Tagasimaksete protsess on m\u00e4rgitud t\u00fcrkiissinise joonega (jah, jah, see, mis asub X-teljel), ja roosa on sisu uuendamise protsess. <\/p>\n<p>Lamoda kataloogis on miljoneid tooteid, ja andmeid uuendatakse pidevalt. \u00dched kollektsioonid kaovad moest, nende asemele tulevad uued, ning kataloogis tekivad pidevalt uued mudelid. P\u00fc\u00fcame ennustada, mis v\u00f5iks meie klientidele homseks huvi pakkuda, seet\u00f5ttu ostame pidevalt uusi asju, pildistame neid ja uuendame v\u00e4ljapanekut. <\/p>\n<p>Roosad tipud on tooteuuenduse, see t\u00e4hendab muudatusi toodetes. N\u00e4ha on, et meie mehed pildistasid, pildistasid, ja siis j\u00e4rsku! \u2014 laadisid \u00fcles hulga s\u00fcndmusi.<\/p>\n<h2>Lamoda s\u00fcndmuste kasutusjuhtumid<\/h2>\n<p>\nEhitatud arhitektuuri kasutame selliste toimingute jaoks:<\/p>\n<ul>\n<li><strong>Tagasimaksete staatuste j\u00e4lgimine<\/strong>: \u00fcleskutse ja staatuste j\u00e4lgimine k\u00f5igilt osalevatelt s\u00fcsteemidelt. Maksmine, staatused, maksustamine, teavitamine. Siin katsetasime l\u00e4henemist, tegime t\u00f6\u00f6riistad, kogusime k\u00f5ik vead, kirjutasime dokumentatsiooni ja r\u00e4\u00e4kisime kolleegidele, kuidas seda kasutada.<\/li>\n<li><strong>Tooteinfo uuendamine: <\/strong>konfiguratsioon, metaandmed, omadused. \u00dcks s\u00fcsteem loeb (mis kuvab), ja mitu kirjutab.<\/li>\n<li><strong>Email, push ja sms<\/strong>: tellimus on kokku pandud, tellimus on kohal, tagasimakse on vastu v\u00f5etud jne, neid on palju. <\/li>\n<li><strong>Laoseis, laouuendus<\/strong>\u00a0\u2014 kvantitatiivne uuendus nimedele, lihtsalt numbrid: lao saabumine, tagastamine. Vajame, et k\u00f5ik toote reserveerimisega seotud s\u00fcsteemid t\u00f6\u00f6taksid v\u00f5imalikult v\u00e4rskete andmete alusel. Praegu on laouuendamise s\u00fcsteem \u00fcsna keeruline, Kafka lihtsustab seda.<\/li>\n<li><strong>Andmeanal\u00fc\u00fcs<\/strong> (R&amp;D-osakond), ML-t\u00f6\u00f6riistad, anal\u00fc\u00fctika, statistika. Me soovime, et teave oleks l\u00e4bipaistev - selleks sobib Kafka h\u00e4sti.<\/li>\n<\/ul>\n<p>\nN\u00fc\u00fcd huvitavam osa kogemustest ja huvitavatest avastustest, mis on toimunud poole aasta jooksul.<\/p>\n<h2>Projekteerimise probleemid<\/h2>\n<p>\nOletame, et soovime teha midagi uut - n\u00e4iteks viia kogu tarneprotsessi \u00fcle Kafka peale. Praegu on osa protsessist ellu viidud Order Processing'is BOB-is. Tellimuse edastamise, vahehoidlasse liikumise ja muude asjade jaoks on olemas staatuse mudel. Seal on \u00fcks korralik monoliit, isegi kaks, pluss hulk API-sid, mis on seotud tarnega. Need teavad tarne kohta palju rohkem. <\/p>\n<p>Tundub, et need on sarnased valdkonnad, kuid Order Processing BOB-is ja tarne s\u00fcsteemi staatused erinevad. N\u00e4iteks m\u00f5ne kullerteenuse puhul ei saadeta vahepealseid staatuseid, vaid ainult l\u00f5ppsidet: 'toimetatud' v\u00f5i 'kadunud'. Teised, vastupidi, annavad v\u00e4ga detailset teavet kauba liikumise kohta. K\u00f5igil on oma valideerimisreeglid: kellegi jaoks on e-post kehtiv, seega t\u00f6\u00f6tlevad nad seda; teiste jaoks on e-post kehtetu, kuid tellimus t\u00f6\u00f6deldakse ikkagi, kuna kontaktiks on telefon, ja m\u00f5ned \u00fctlevad, et sellist tellimust ei hakata \u00fcldse t\u00f6\u00f6tlema.<\/p>\n<h3>Andmevoog<\/h3>\n<p>\nKafka puhul tekib andmevoo korraldamise k\u00fcsimus. See \u00fclesanne on seotud strateegia valikuga mitmel korral, liigume nende k\u00f5igi kaudu.<\/p>\n<h4>Kas \u00fchte teemasse v\u00f5i erinevatesse?<\/h4>\n<p>\nMeil on s\u00fcndmuse spetsifikatsioon. BOB-is kirjutame, et seda ja seda tellimust tuleb toimetada, ning m\u00e4rkime: tellimuse number, selle koosseis, m\u00f5ned SKU-d ja bar-koodid jne. Kui kaup j\u00f5uab hoiukohta, suudab tarne saada staatuseid, ajatempleid ja k\u00f5ike vajalikku. Kuid edaspidi soovime BOB-is saada neid andmeid uuendustena. Meil tekib tagasisuunaline protsess andmete hankimiseks tarne kaudu. Kas see on sama s\u00fcndmus? V\u00f5i on tegemist eraldi vahetusega, mis v\u00e4\u00e4rib eraldi teemat?<\/p>\n<p>T\u00f5en\u00e4oliselt on nad v\u00e4ga sarnased, ja ahvatlus teha \u00fcks teema on p\u00f5hjendatud, kuna eraldi teema t\u00e4hendab eraldi tarbijaid, eraldi konfiguratsioone, selle k\u00f5ik eraldi genereerimist. Kuid see pole kindlasti kindel.<\/p>\n<h4>Uus v\u00e4li v\u00f5i uus s\u00fcndmus?<\/h4>\n<p>\nKuid kui kasutada samu s\u00fcndmusi, siis tekib teine probleem. N\u00e4iteks ei suuda k\u00f5ik kohaletoimetamiss\u00fcsteemid genereerida sellist DTO-d, mida suudab genereerida BOB. Saadame neile id, kuid nad ei salvesta neid, kuna need neile ei ole vajalikud, ning protsessi event-bus alustamise seisukohalt on see v\u00e4li kohustuslik. <\/p>\n<p>Kui me kehtestame event-bus\u2019i jaoks reegli, et see v\u00e4li on kohustuslik, peame lisama BOB-is v\u00f5i start-s\u00fcndmuse t\u00f6\u00f6tlejas t\u00e4iendavad valideerimise reeglid. Valideerimine hakkab teenuse peale laiali valguma \u2014 see ei ole v\u00e4ga mugav.<\/p>\n<p>Veel \u00fcks probleem on inkrementaalse arenduse k\u00fclget\u00f5mme. Meile \u00f6eldakse, et peaksime s\u00fcndmusele midagi lisama ja v\u00f5ib-olla, kui korralikult m\u00f5elda, oleks see pidanud olema eraldi s\u00fcndmus. Kuid meie skeemis on eraldi s\u00fcndmus eraldi teema. Eraldi teema on k\u00f5ik see protsess, mida ma \u00fclal kirjeldasin. Arendajal tekib kiusatus lihtsalt lisada JSON skeemi veel \u00fcks v\u00e4li ja regenererida.<\/p>\n<p>Refundide puhul j\u00f5udsime kuue kuu jooksul s\u00fcndmuste s\u00fcndmuseni. Meil oli \u00fcks meta-s\u00fcndmus, mida nimetatakse refund update, milles oli v\u00e4li type, mis kirjeldas, milles see uuendus seisneb. Selle t\u00f5ttu olid meil \"suurep\u00e4rased\" l\u00fclitid valideerijatega, mis \u00fctlesid, kuidas seda s\u00fcndmust selle type-ga valideerida.<\/p>\n<h4>S\u00fcndmuste versioonimine<\/h4>\n<p>\nKafka s\u00f5numite valideerimiseks saab kasutada <noindex><a rel=\"nofollow\" href=\"https:\/\/docs.confluent.io\/current\/schema-registry\/docs\/index.html\">Avro<\/a><\/noindex>, kuid seda tuli kohe ette n\u00e4ha ja kasutada Confluent'i. Meie puhul tuleb versioonimisega ettevaatlik olla. Mitte alati ei pruugi olla v\u00f5imalik s\u00f5numeid lugeda replication log'ist, kuna mudel on \"lahkunud\". \u00dcldiselt tuleb luua versioone nii, et mudel oleks tagurpidi \u00fchilduv: n\u00e4iteks teha v\u00e4li ajutiselt mitte-kohustuslikuks. Kui erinevused on liiga suured, hakkame kirjutama uude teema ja liigume klientidega \u00fcle, kui nad on vana lugenud.<\/p>\n<h4>Lugemise j\u00e4rjekorra garantii jagunemistes<\/h4>\n<p>\nTeemad Kafka-s on jagatud partitsioonideks. See ei ole v\u00e4ga t\u00e4htis, kuna projekteerime entiteete ja vahetusi, kuid on oluline, kui otsustame, kuidas seda tarbida ja skaleerida.<\/p>\n<p>Tavaliselt kirjutate Kafka-sse \u00fche teema. Vaikimisi kasutatakse \u00fchte partitsiooni, kuhu k\u00f5ik selle teema s\u00f5numid satuvad. Ja tarbija loeb vastavalt j\u00e4rjestikku neid s\u00f5numeid. Oletame, et n\u00fc\u00fcd tuleb s\u00fcsteemi laiendada nii, et s\u00f5numeid loeks kaks erinevat tarbijat. Kui te n\u00e4iteks saadate SMS-i, saab \u00f6elda, et Kafka loob t\u00e4iendava partitsiooni, ja Kafka hakkab s\u00f5numeid jagama kahe osa vahel \u2013 pooled siia, pooled sinna. <\/p>\n<p>Kuidas Kafka need jagab? Igal s\u00f5numil on sisu (kus me hoiame JSON-i) ja klahv. Sellele klahvile v\u00f5ib rakendada hash-funktsiooni, mis m\u00e4\u00e4rab, millisesse partitsiooni s\u00f5num satub.<\/p>\n<p>Meie tagastuste juhtumiga on see oluline; kui v\u00f5tame kaks partitsiooni, on v\u00f5imalus, et paralleelne tarbija t\u00f6\u00f6tleb teist s\u00fcndmust enne esimest ja see toob kaasa probleeme. Hash-funktsioon tagab, et sama klahviga s\u00f5numid satuvad samasse partitsioon. <\/p>\n<h4>S\u00fcndmused vs k\u00e4sud<\/h4>\n<p>\nSee on veel \u00fcks probleem, millega kokku puutusime. S\u00fcndmus on mingisugune juhtum: me \u00fctleme, et midagi juhtus kuskil (something_happened), n\u00e4iteks, ese t\u00fchistati v\u00f5i toimus tagastamine. Kui neid s\u00fcndmusi keegi kuulab, siis \u00abese t\u00fchistati\u00bb toob endaga kaasa tagastuse loomise, ja \u00abtoimus tagastamine\u00bb salvestatakse kuskil seadistustes.<\/p>\n<p>Kuid tavaliselt, kui te projekteerite s\u00fcndmusi, ei soovi te neid asjata kirjutada \u2013 te loote seda, et keegi neid loeb. Suur kiusatus on kirjutada mitte something_happened (item_canceled, refund_refunded), vaid something_should_be_done. N\u00e4iteks, ese on tagastamiseks valmis.<\/p>\n<p>\u00dchelt poolt viitab see, kuidas s\u00fcndmust kasutatakse. Teiselt poolt, see ei sarnane tavalise s\u00fcndmuse nimetusega. Lisaks sellele ei ole siin kaugel k\u00e4sust do_something. Kuid teil ei ole garantiid, et keegi selle s\u00fcndmuse l\u00f5i; ja kui keegi seda luges, siis kas ta luges selle edukalt; ja kui ta luges edukalt, siis ta tegi midagi, ja see midagi l\u00e4ks edukalt l\u00e4bi. Hetkel, kui s\u00fcndmus muutub do_something-iks, on vajalik tagasiside ning see on probleem.<\/p>\n<p><img decoding=\"async\" alt=\"Kogemus Refund Tool teenuse arendamisest as\u00fcnkroonse API-ga Kafka-l\" src=\"\/wp-content\/uploads\/2019\/04\/b755d91208092bd9791a41ce4633fb48.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nAs\u00fcnkroonse vahetuse korral RabbitMQ-s, kui olete s\u00f5numi lugenud, l\u00e4inud http-sse, on teil vastus \u2013 v\u00e4hemalt, et s\u00f5num oli vastu v\u00f5etud. Kui te kirjutate Kafka-sse, on teade, et olete kirjutanud Kafka-sse, kuid te ei tea, kuidas see t\u00f6\u00f6deldi. <\/p>\n<p>Seega meie puhul pidime sisse viima vastus\u00fcrituse ja seadistama j\u00e4lgimise sellele, et kui on juhtunud nii palju s\u00fcndmusi, peaks teatud aja p\u00e4rast saabuma sama palju vastus\u00fcritusi. Kui seda ei toimu, siis tundub, et midagi on valesti l\u00e4inud. N\u00e4iteks, kui me saatsime s\u00fcndmuse \u201eitem_ready_to_refund\u201c, ootame, et tagasimakse luuakse, klient saab raha tagasi ja me saame s\u00fcndmuse \u201emoney_refunded\u201c. Kuid see ei ole t\u00e4pne, seega on j\u00e4lgimine vajalik.<\/p>\n<h3>N\u00fcansid<\/h3>\n<p>\nOn \u00fcsna ilmne probleem: kui loete teemadelt j\u00e4rjestikku ja teil on mingi halb s\u00f5num, l\u00f5ppeb tarbija t\u00f6\u00f6 ja edasi ei saa minna. Teil on vaja <strong>peatada k\u00f5ik tarbijad<\/strong>, salvestada offset edasi, et j\u00e4tkata lugemist.<\/p>\n<p>Me teadsime sellest, olime sellele seadnud reservi ja see juhtus ikkagi. Ja see juhtus, kuna s\u00fcndmus oli kehtiv events-busi vaatenurgast, s\u00fcndmus oli kehtiv rakenduse valideerija vaatenurgast, kuid see ei olnud kehtiv PostgreSQL vaatenurgast, sest \u00fches s\u00fcsteemis oli meil MySQL UNSIGNED INT ja uues s\u00fcsteemis oli PostgreSQL lihtsalt INT. Selle suurus on veidi v\u00e4iksem ja ID ei mahuks sisse. Symfony jooksis v\u00e4lja erandi t\u00f5ttu. Loomulikult p\u00fc\u00fcdsime me erandi kinni, sest olime selle peale ette valmistanud ja plaanisime seda offsetit salvestada, kuid tahtsime enne seda probleemide arvu suurendada, kuna s\u00f5numi t\u00f6\u00f6tlemine eba\u00f5nnestus. Arvutid on selles projektis samuti andmebaasis, ja Symfony on juba l\u00f5petanud \u00fchenduse andmebaasiga ning teine erand h\u00e4vitas kogu protsessi ilma v\u00f5imaluseta offseti salvestada.<\/p>\n<p>M\u00f5nda aega t\u00f6\u00f6tas teenus \u2013 \u00f5nneks ei ole Kafka puhul see nii hirmus, kuna s\u00f5numid p\u00fcsivad. Kui t\u00f6\u00f6 taastub, siis saab need l\u00e4bi lugeda. See on mugav.<\/p>\n<p>Kafkal on v\u00f5imalik t\u00f6\u00f6riistade kaudu seada suvaline offset. Kuid selleks tuleb peatada k\u00f5ik tarbijad \u2013 meie puhul valmistada eraldi versioon, kus tarbijaid ei ole, uue juurutamise puudumisel. Siis saab Kafkas t\u00f6\u00f6riistade kaudu offseti nihutada ja s\u00f5num l\u00e4bib.<\/p>\n<p>Teine n\u00fcanss - <strong>replication log vs rdkafka.so<\/strong>\u00a0\u2014 on seotud meie projekti spetsiifikaga. Meil on PHP, ja PHP-s suhtlevad k\u00f5ik raamatukogud tavaliselt Kafka'ga l\u00e4bi rdkafka.so reposte, millele j\u00e4rgneb mingi \u00fcmberm\u00f5testamine. V\u00f5ib-olla on need meie isiklikud raskused, aga selgus, et lihtsalt uuesti lugeda varem loetud teksti ei ole sugugi lihtne. \u00dches\u00f5naga, olid tarkvaraprobleemid.<\/p>\n<p>Naastes partitsioonide t\u00f6\u00f6tamise erip\u00e4rade juurde, on otse dokumentatsioonis kirjutatud <strong>tarbijad &gt;= teema partitsioonid<\/strong>. Aga ma sain sellest teada palju hiljem, kui oleks soovinud. Kui soovite skaleeruda ja omada kahte tarbijat, vajate v\u00e4hemalt kahte partitsiooni. See t\u00e4hendab, et kui teil oli \u00fcks partitsioon, kuhu oli kogunend 20 tuhat s\u00f5numit, ja l\u00f5ite uue, siis s\u00f5numite arv ei tasandu varsti. Seet\u00f5ttu, et saada kaks paralleelset tarbijat, tuleb osata partitsioonidega t\u00f6\u00f6tada.<\/p>\n<h2>J\u00e4lgimine<\/h2>\n<p>\nMa arvan, et meie j\u00e4lgimise p\u00f5hjal on veel selgem, millised probleemid on olemasolevas l\u00e4henemises.<\/p>\n<p>N\u00e4iteks loeme, kui palju tooteid andmebaasis on hiljuti staatust muutnud, ja vastavalt sellele peaksid olema toimunud s\u00fcndmused, ning saadame selle arvu oma j\u00e4lgimiss\u00fcsteemi. Hiljem saame Kafka'st teise arvu, kui palju tegelikult s\u00fcndmusi registreeriti. Ilmselgelt peaks nende kahe arvu vahe alati olema null.<\/p>\n<p><img decoding=\"async\" alt=\"Kogemus Refund Tool teenuse arendamisest as\u00fcnkroonse API-ga Kafka-l\" src=\"\/wp-content\/uploads\/2019\/04\/07d8ed08514f2fb97d9019466b96342c.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nLisaks tuleb j\u00e4lgida, kuidas on producer'i asjad, kas events-bus on s\u00f5numid vastu v\u00f5tnud, ja kuidas on tarbijaga. N\u00e4iteks allolevatel graafikutel on Refund Tool'il k\u00f5ik korras, aga BOB'il on selgelt mingid probleemid (sinised tipud).<\/p>\n<p><img decoding=\"async\" alt=\"Kogemus Refund Tool teenuse arendamisest as\u00fcnkroonse API-ga Kafka-l\" src=\"\/wp-content\/uploads\/2019\/04\/57112dbe70d2b388c53f19c34cca6f63.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nOlen juba maininud tarbijagruppi j\u00e4\u00e4ki. \u00dcldiselt on see lugemata s\u00f5numite arv. Kokkuv\u00f5ttes t\u00f6\u00f6tavad meie tarbijad kiiresti, seet\u00f5ttu on j\u00e4\u00e4k tavaliselt 0, kuid m\u00f5nikord v\u00f5ib esineda l\u00fchiajalisi piike. Kafka suudab seda standardina, aga peate m\u00e4\u00e4rama mingi intervalli. <\/p>\n<p>On projekt <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/linkedin\/Burrow\">Burrow<\/a><\/noindex>, mis annab teile rohkem teavet Kafka kohta. See lihtsalt API kaudu tarbijagruppide kohta annab staatuse, kuidas selle grupi asjad on. Peale O\u041a ja Failed on seal ka hoiatus, ja saate teada, et teie tarbijad ei suuda tootmiskiirusest sammu pidada \u2014 nad ei suuda maha lugeda seda, mis on kirjutatud. S\u00fcsteem on \u00fcsna intelligentne ja seda on mugav kasutada. <\/p>\n<p><img decoding=\"async\" alt=\"Kogemus Refund Tool teenuse arendamisest as\u00fcnkroonse API-ga Kafka-l\" src=\"\/wp-content\/uploads\/2019\/04\/cece8495801e187b155487a802e1a35a.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nNii n\u00e4eb API vastus v\u00e4lja. Siin on grupp bob-live-fifa, partitsioon refund.update.v1, staatus OK, j\u00e4\u00e4k 0 \u2014 viimane l\u00f5pp offset on selline.<\/p>\n<p><img decoding=\"async\" alt=\"Kogemus Refund Tool teenuse arendamisest as\u00fcnkroonse API-ga Kafka-l\" src=\"\/wp-content\/uploads\/2019\/04\/1538b2ccc390e9b83075f54566f1039b.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nJ\u00e4lgimine <strong>updated_at SLA (takerdunud)<\/strong> Ma juba mainisin. N\u00e4iteks toode on l\u00e4inud staatusesse, et see on tagastamiseks valmis. Seame Croni, mis \u00fctleb, et kui see objekt 5 minuti jooksul ei l\u00e4he refund'i (me tagastame raha makses\u00fcsteemide kaudu v\u00e4ga kiiresti), siis on midagi kindlasti valesti l\u00e4inud, ja see on kindlasti juhtum toetuse jaoks. Seet\u00f5ttu v\u00f5tame lihtsalt Croni, mis loeb selliseid asju, ja kui neid on rohkem kui 0, saadab see hoiatuse.<\/p>\n<p><b>Kokkuv\u00f5ttes on \u00fcrituste kasutamine mugav, kui<\/b>:<\/p>\n<ul>\n<li>infot vajab mitu s\u00fcsteemi;<\/li>\n<li>tulemus t\u00f6\u00f6tlemisel ei oma t\u00e4htsust;<\/li>\n<li>\u00fcritusi on v\u00e4he v\u00f5i \u00fcritused on v\u00e4ikesed. <\/li>\n<\/ul>\n<blockquote><p>Tundub, et artiklil on t\u00e4iesti konkreetne teema \u2013 as\u00fcnkroonne API Kafka peal, kuid seoses selle ka tahaks kohe palju soovitada.<br \/>\nEsiteks, j\u00e4rgmine <noindex><a rel=\"nofollow\" href=\"https:\/\/www.highload.ru\/\">HighLoad++<\/a><\/noindex> peab ootama novembrini, aprillis tuleb selle Peterburi versioon ja juunis r\u00e4\u00e4gime suurtest koormustest Novosibirskis.<br \/>\nTeiseks, ettekande autor Sergei Zaika kuulub meie uue konverentsi programmeerimiskomiteesse teadmiste haldamise kohta. <noindex><a rel=\"nofollow\" href=\"https:\/\/knowledgeconf.ru\/2019\">KnowledgeConf<\/a><\/noindex>Konverents on \u00fches p\u00e4evane, toimub 26. aprillil, kuid programm on v\u00e4ga tihe.<br \/>\nJa veel mais toimub <noindex><a rel=\"nofollow\" href=\"https:\/\/phprussia.ru\/2019\">PHP Russia<\/a><\/noindex> ja\u00a0<noindex><a rel=\"nofollow\" href=\"https:\/\/ritfest.ru\/2019\">RIT++<\/a><\/noindex> (DevOpsCon koosseisus) \u2013 sinna saab veel pakkuda oma teemat, r\u00e4\u00e4kida oma kogemusest ja kaevata oma saadud m\u00fcrgisteks.<\/p><\/blockquote>\n<p>Allikas: <a content=\"nofollow\" rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/oleg-bunin\/blog\/445424\/\">habr.com<\/a><\/p>","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"excerpt":{"rendered":"<p>\u0427\u0442\u043e \u043c\u043e\u0436\u0435\u0442 \u0437\u0430\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0442\u0430\u043a\u0443\u044e \u0431\u043e\u043b\u044c\u0448\u0443\u044e \u043a\u043e\u043c\u043f\u0430\u043d\u0438\u044e \u043a\u0430\u043a Lamoda \u0441\u00a0\u043e\u0442\u043b\u0430\u0436\u0435\u043d\u043d\u044b\u043c \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u043e\u043c \u0438\u00a0\u0434\u0435\u0441\u044f\u0442\u043a\u0430\u043c\u0438 \u0432\u0437\u0430\u0438\u043c\u043e\u0441\u0432\u044f\u0437\u0430\u043d\u043d\u044b\u0445 \u0441\u0435\u0440\u0432\u0438\u0441\u043e\u0432 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u043c\u0435\u043d\u044f\u0442\u044c \u043f\u043e\u0434\u0445\u043e\u0434? \u041c\u043e\u0442\u0438\u0432\u0430\u0446\u0438\u044f \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u0441\u043e\u0432\u0435\u0440\u0448\u0435\u043d\u043d\u043e \u0440\u0430\u0437\u043d\u0430\u044f: \u043e\u0442\u00a0\u0437\u0430\u043a\u043e\u043d\u043e\u0434\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0439 \u0434\u043e\u00a0\u043f\u0440\u0438\u0441\u0443\u0449\u0435\u0433\u043e \u0432\u0441\u0435\u043c \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0441\u0442\u0430\u043c \u0436\u0435\u043b\u0430\u043d\u0438\u044f \u044d\u043a\u0441\u043f\u0435\u0440\u0438\u043c\u0435\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c. \u041d\u043e\u00a0\u044d\u0442\u043e \u0432\u043e\u0432\u0441\u0435 \u043d\u0435\u00a0\u0437\u043d\u0430\u0447\u0438\u0442, \u0447\u0442\u043e \u043d\u0435\u043b\u044c\u0437\u044f \u0440\u0430\u0441\u0441\u0447\u0438\u0442\u044b\u0432\u0430\u0442\u044c \u043d\u0430\u00a0\u0434\u043e\u043f\u043e\u043b\u043d\u0438\u0442\u0435\u043b\u044c\u043d\u0443\u044e \u0432\u044b\u0433\u043e\u0434\u0443. \u0412\u00a0\u0447\u0435\u043c \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u043e \u043c\u043e\u0436\u043d\u043e \u0432\u044b\u0438\u0433\u0440\u0430\u0442\u044c, \u0435\u0441\u043b\u0438 \u0432\u043d\u0435\u0434\u0440\u0438\u0442\u044c events-driven API \u043d\u0430\u00a0Kafka, \u0440\u0430\u0441\u0441\u043a\u0430\u0436\u0435\u0442 \u0421\u0435\u0440\u0433\u0435\u0439 \u0417\u0430\u0438\u043a\u0430 (fewald). \u041f\u0440\u043e \u043d\u0430\u0431\u0438\u0442\u044b\u0435 \u0448\u0438\u0448\u043a\u0438 \u0438\u00a0\u0438\u043d\u0442\u0435\u0440\u0435\u0441\u043d\u044b\u0435 \u043e\u0442\u043a\u0440\u044b\u0442\u0438\u044f \u0442\u043e\u0436\u0435 \u043e\u0431\u044f\u0437\u0430\u0442\u0435\u043b\u044c\u043d\u043e [&hellip;]<\/p>\n","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"author":1,"featured_media":22763,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[688],"tags":[],"class_list":["post-30778","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-administrirovanie"],"aioseo_notices":[],"aioseo_head":"\n\t\t<!-- All in One SEO 5.0.1.1 - aioseo.com -->\n\t<meta name=\"description\" content=\"\u0427\u0442\u043e \u043c\u043e\u0436\u0435\u0442 \u0437\u0430\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0442\u0430\u043a\u0443\u044e \u0431\u043e\u043b\u044c\u0448\u0443\u044e \u043a\u043e\u043c\u043f\u0430\u043d\u0438\u044e \u043a\u0430\u043a Lamoda \u0441 \u043e\u0442\u043b\u0430\u0436\u0435\u043d\u043d\u044b\u043c \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u043e\u043c \u0438 \u0434\u0435\u0441\u044f\u0442\u043a\u0430\u043c\u0438 \u0432\u0437\u0430\u0438\u043c\u043e\u0441\u0432\u044f\u0437\u0430\u043d\u043d\u044b\u0445 \u0441\u0435\u0440\u0432\u0438\u0441\u043e\u0432 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u043c\u0435\u043d\u044f\u0442\u044c \u043f\u043e\u0434\u0445\u043e\u0434?\" \/>\n\t<meta name=\"robots\" content=\"max-image-preview:large\" \/>\n\t<meta name=\"author\" content=\"Yuri Gagarin\"\/>\n\t<link rel=\"canonical\" href=\"https:\/\/prohoster.info\/et\/blog\/administrirovanie\/opyt-razrabotki-servisa-refund-tool-s-asinhronnym-api-na-kafka\" \/>\n\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.1.1\" \/>\n\t\t<meta property=\"og:locale\" content=\"et_EE\" \/>\n\t\t<meta property=\"og:site_name\" content=\"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b\" \/>\n\t\t<meta property=\"og:type\" content=\"article\" \/>\n\t\t<meta property=\"og:title\" content=\"\ud83e\udd47\u041e\u043f\u044b\u0442 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0441\u0435\u0440\u0432\u0438\u0441\u0430 Refund Tool \u0441 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u043c API \u043d\u0430 Kafka | ProHoster\" \/>\n\t\t<meta property=\"og:description\" content=\"\u0427\u0442\u043e \u043c\u043e\u0436\u0435\u0442 \u0437\u0430\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0442\u0430\u043a\u0443\u044e \u0431\u043e\u043b\u044c\u0448\u0443\u044e \u043a\u043e\u043c\u043f\u0430\u043d\u0438\u044e \u043a\u0430\u043a Lamoda \u0441 \u043e\u0442\u043b\u0430\u0436\u0435\u043d\u043d\u044b\u043c \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u043e\u043c \u0438 \u0434\u0435\u0441\u044f\u0442\u043a\u0430\u043c\u0438 \u0432\u0437\u0430\u0438\u043c\u043e\u0441\u0432\u044f\u0437\u0430\u043d\u043d\u044b\u0445 \u0441\u0435\u0440\u0432\u0438\u0441\u043e\u0432 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u043c\u0435\u043d\u044f\u0442\u044c \u043f\u043e\u0434\u0445\u043e\u0434?\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/prohoster.info\/et\/blog\/administrirovanie\/opyt-razrabotki-servisa-refund-tool-s-asinhronnym-api-na-kafka\" \/>\n\t\t<meta property=\"og:image\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:secure_url\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:width\" content=\"350\" \/>\n\t\t<meta property=\"og:image:height\" content=\"350\" \/>\n\t\t<meta property=\"article:published_time\" content=\"2019-10-31T18:37:23+00:00\" \/>\n\t\t<meta property=\"article:modified_time\" content=\"2019-10-31T18:37:23+00:00\" \/>\n\t\t<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<meta property=\"article:author\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<!-- All in One SEO -->\n\n","aioseo_head_json":{"title":"\ud83e\udd47Kogemused Refund Tool teenuse arendamisest as\u00fcnkroonses API-s Kafka | ProHoster","description":"Mis v\u00f5ib sundida nii suurt ettev\u00f5tet nagu Lamoda, kellel on h\u00e4sti organiseeritud protsess ja k\u00fcmneid omavahel seotud teenuseid, oma l\u00e4henemist oluliselt muutma?","canonical_url":"https:\/\/prohoster.info\/et\/blog\/administrirovanie\/opyt-razrabotki-servisa-refund-tool-s-asinhronnym-api-na-kafka","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"et_EE","og:site_name":"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b","og:type":"article","og:title":"\ud83e\udd47\u041e\u043f\u044b\u0442 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0438 \u0441\u0435\u0440\u0432\u0438\u0441\u0430 Refund Tool \u0441 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u043c API \u043d\u0430 Kafka | ProHoster","og:description":"\u0427\u0442\u043e \u043c\u043e\u0436\u0435\u0442 \u0437\u0430\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0442\u0430\u043a\u0443\u044e \u0431\u043e\u043b\u044c\u0448\u0443\u044e \u043a\u043e\u043c\u043f\u0430\u043d\u0438\u044e \u043a\u0430\u043a Lamoda \u0441 \u043e\u0442\u043b\u0430\u0436\u0435\u043d\u043d\u044b\u043c \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u043e\u043c \u0438 \u0434\u0435\u0441\u044f\u0442\u043a\u0430\u043c\u0438 \u0432\u0437\u0430\u0438\u043c\u043e\u0441\u0432\u044f\u0437\u0430\u043d\u043d\u044b\u0445 \u0441\u0435\u0440\u0432\u0438\u0441\u043e\u0432 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u043c\u0435\u043d\u044f\u0442\u044c \u043f\u043e\u0434\u0445\u043e\u0434?","og:url":"https:\/\/prohoster.info\/et\/blog\/administrirovanie\/opyt-razrabotki-servisa-refund-tool-s-asinhronnym-api-na-kafka","og:image":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:secure_url":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:width":350,"og:image:height":350,"article:published_time":"2019-10-31T18:37:23+00:00","article:modified_time":"2019-10-31T18:37:23+00:00","article:publisher":"https:\/\/www.facebook.com\/prohoster","article:author":"https:\/\/www.facebook.com\/prohoster"},"aioseo_meta_data":{"post_id":"30778","title":null,"description":null,"keywords":null,"keyphrases":null,"primary_term":null,"canonical_url":null,"og_title":null,"og_description":null,"og_object_type":"default","og_image_type":"default","og_image_url":null,"og_image_width":null,"og_image_height":null,"og_image_custom_url":null,"og_image_custom_fields":null,"og_video":null,"og_custom_url":null,"og_article_section":null,"og_article_tags":null,"twitter_use_og":false,"twitter_card":"default","twitter_image_type":"default","twitter_image_url":null,"twitter_image_custom_url":null,"twitter_image_custom_fields":null,"twitter_title":null,"twitter_description":null,"schema":{"blockGraphs":[],"customGraphs":[],"default":{"data":{"Article":[],"Course":[],"Dataset":[],"FAQPage":[],"Movie":[],"Person":[],"Product":[],"ProductReview":[],"Car":[],"Recipe":[],"Service":[],"SoftwareApplication":[],"WebPage":[]},"graphName":"","isEnabled":true},"graphs":[]},"schema_type":null,"schema_type_options":null,"pillar_content":false,"robots_default":true,"robots_noindex":false,"robots_noarchive":false,"robots_nosnippet":false,"robots_nofollow":false,"robots_noimageindex":false,"robots_noodp":false,"robots_notranslate":false,"robots_max_snippet":null,"robots_max_videopreview":null,"robots_max_imagepreview":"large","priority":null,"frequency":null,"local_seo":null,"seo_analyzer_scan_date":"2026-01-21 02:58:19","breadcrumb_settings":null,"limit_modified_date":false,"reviewed_by":null,"ai":null,"created":"2021-03-01 03:29:56","updated":"2026-01-21 02:58:19","focus_keyword":null,"additional_keywords":null,"truseo_locale":null},"gt_translate_keys":[{"key":"link","format":"url"}],"_links":{"self":[{"href":"https:\/\/prohoster.info\/et\/wp-json\/wp\/v2\/posts\/30778","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/et\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/et\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/et\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/et\/wp-json\/wp\/v2\/comments?post=30778"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/et\/wp-json\/wp\/v2\/posts\/30778\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/et\/wp-json\/wp\/v2\/media\/22763"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/et\/wp-json\/wp\/v2\/media?parent=30778"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/et\/wp-json\/wp\/v2\/categories?post=30778"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/et\/wp-json\/wp\/v2\/tags?post=30778"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}