{"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\/sq\/blog\/administrirovanie\/opyt-razrabotki-servisa-refund-tool-s-asinhronnym-api-na-kafka","title":{"rendered":"P\u00ebrvoja e zhvillimit t\u00eb sh\u00ebrbimit Refund Tool me API asinkron mbi Kafka","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p>\u00c7far\u00eb mund ta b\u00ebj\u00eb nj\u00eb kompani kaq t\u00eb madhe si Lamoda, me nj\u00eb proces t\u00eb p\u00ebrsosur dhe qindra sh\u00ebrbime t\u00eb lidhura, t\u00eb ndryshoj\u00eb ndjesh\u00ebm qasjen e saj? Motivimi mund t\u00eb jet\u00eb krejt\u00ebsisht i ndrysh\u00ebm: nga legjislacioni deri te d\u00ebshira e natyrshme e \u00e7do programuesi p\u00ebr t\u00eb eksperimentuar.<\/p>\n<p>Por kjo nuk do t\u00eb thot\u00eb se nuk mund t\u00eb pritet nj\u00eb p\u00ebrfitim shtes\u00eb. N\u00eb \u00e7far\u00eb m\u00ebnyre mund t\u00eb fitohet, n\u00ebse zbatohet API i orientuar nga ngjarjet n\u00eb Kafka, do t\u00eb tregoj\u00eb Sergey Zaika (<noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/users\/fewald\/\" class=\"user_link\">fewald<\/a><\/noindex>). Mbi t\u00eb gjitha sfidat dhe zbulimet interesante do t\u00eb flasim gjithashtu \u2013 eksperimentet nuk mund t\u00eb kalojn\u00eb pa to.<\/p>\n<p><img decoding=\"async\" alt=\"P\u00ebrvoja e zhvillimit t\u00eb sh\u00ebrbimit Refund Tool me API asinkron mbi Kafka\" src=\"\/wp-content\/uploads\/2019\/04\/7ab959ab45ec5c6565b35b18b361c0ea.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\n<em>Disclaimer: Ky artikull \u00ebsht\u00eb i bazuar n\u00eb materialet e mitapit q\u00eb Sergey mbajti n\u00eb n\u00ebntor t\u00eb vitit 2018 n\u00eb HighLoad++. P\u00ebrvoja e drejtp\u00ebrdrejt\u00eb e pun\u00ebs s\u00eb Lamoda me Kafka t\u00ebrhoqi d\u00ebgjuesit po aq sa dokime t\u00eb tjera nga programi. Na duket se \u00ebsht\u00eb nj\u00eb shembull i shk\u00eblqyer se gjithmon\u00eb mund dhe duhet t\u00eb gjejm\u00eb aleat\u00eb, nd\u00ebrsa organizator\u00ebt e HighLoad++ do t\u00eb vazhdojn\u00eb t\u00eb p\u00ebrpiqen t\u00eb krijojn\u00eb nj\u00eb atmosfer\u00eb miq\u00ebsore p\u00ebr k\u00ebt\u00eb.<\/em><br \/>\n<noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<h2>P\u00ebr procesin<\/h2>\n<p>\nLamoda \u00ebsht\u00eb nj\u00eb platform\u00eb e madhe e-commerce, e cila ka qendr\u00ebn e saj t\u00eb kontaktit, sh\u00ebrbimin e d\u00ebrges\u00ebs (dhe shum\u00eb partner\u00eb), studio fotografike, nj\u00eb depo t\u00eb madhe dhe gjith\u00e7ka funksionon me softin e saj. Ka dhjet\u00ebra m\u00ebnyra pagesash, partner\u00eb b2b q\u00eb mund t\u00eb p\u00ebrdorin nj\u00eb pjes\u00eb ose t\u00eb gjitha k\u00ebto sh\u00ebrbime dhe duan t\u00eb din\u00eb informacionin e sakt\u00eb p\u00ebr produktet e tyre. P\u00ebr m\u00eb tep\u00ebr, Lamoda punon n\u00eb tri vende p\u00ebrve\u00e7 RF dhe atje gjith\u00e7ka \u00ebsht\u00eb paksa ndryshe. N\u00eb total, ndoshta ekzistojn\u00eb m\u00eb shum\u00eb se nj\u00ebqind m\u00ebnyra p\u00ebr t\u00eb konfigurimin e nj\u00eb porosie t\u00eb re, e cila duhet t\u00eb trajtohet n\u00eb m\u00ebnyr\u00ebn e vet. T\u00eb gjitha k\u00ebto funksionojn\u00eb me ndihm\u00ebn e dhjet\u00ebra sh\u00ebrbimeve, t\u00eb cilat komunikojn\u00eb ndonj\u00ebher\u00eb n\u00eb m\u00ebnyra jo t\u00eb qarta. Ka gjithashtu nj\u00eb sistem qendror, p\u00ebrgjegj\u00ebsia kryesore e t\u00eb cilit \u00ebsht\u00eb statusi i porosive. Ne e quajm\u00eb at\u00eb BOB, un\u00eb punoj me t\u00eb.<\/p>\n<h2>Refund Tool me API t\u00eb orientuar ndaj ngjarjeve <\/h2>\n<p>\nFjala e orientuar nga ngjarjet \u00ebsht\u00eb p\u00ebrdorur shum\u00eb, m\u00eb von\u00eb do t\u00eb p\u00ebrcaktojm\u00eb sakt\u00ebsisht se \u00e7far\u00eb n\u00ebnkupton kjo. Do t\u00eb fillojm\u00eb me kontekstin n\u00eb t\u00eb cilin ne vendos\u00ebm t\u00eb provonim qasjen e API-s\u00eb t\u00eb orientuar nga ngjarjet n\u00eb Kafka. <\/p>\n<p><img decoding=\"async\" alt=\"P\u00ebrvoja e zhvillimit t\u00eb sh\u00ebrbimit Refund Tool me API asinkron mbi Kafka\" src=\"\/wp-content\/uploads\/2019\/04\/3bfdce47dd8420fc63d84645e76de647.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nN\u00eb \u00e7do dyqan, p\u00ebrve\u00e7 porosive p\u00ebr t\u00eb cilat bler\u00ebsit paguajn\u00eb, ka raste kur dyqani k\u00ebrkohet t\u00eb kthej\u00eb para, sepse produkti nuk i p\u00ebrshtatet klientit. Ky proces relativisht i shkurt\u00ebr: sqarojm\u00eb informacionin, n\u00ebse \u00ebsht\u00eb e nevojshme, dhe transferojm\u00eb parat\u00eb. <\/p>\n<p>Por nja udh\u00ebzimi u b\u00eb m\u00eb i komplikuar p\u00ebr shkak t\u00eb ndryshimeve n\u00eb legjislacion, dhe na duhet t\u00eb realizojm\u00eb nj\u00eb mikrosh\u00ebrbim t\u00eb ve\u00e7ant\u00eb p\u00ebr k\u00ebt\u00eb.<\/p>\n<p><img decoding=\"async\" alt=\"P\u00ebrvoja e zhvillimit t\u00eb sh\u00ebrbimit Refund Tool me API asinkron mbi Kafka\" src=\"\/wp-content\/uploads\/2019\/04\/0e358df5476e7448976e0f1147a103fb.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nMotivacioni yn\u00eb:<\/p>\n<ol>\n<li><strong>Ligji FZ-54<\/strong>\u00a0\u2014 n\u00eb p\u00ebrmbledhje, ligji k\u00ebrkon t\u00eb raportojm\u00eb n\u00eb administrat\u00ebn tatimore p\u00ebr \u00e7do transaksion financiar, qoft\u00eb kthim apo ardhje, me nj\u00eb SLA mjaft t\u00eb shkurt\u00ebr prej disa minutash. Ne, si e-commerce, kryejm\u00eb nj\u00eb num\u00ebr t\u00eb konsideruesh\u00ebm transaksionesh. Teknikisht, kjo do t\u00eb thot\u00eb nj\u00eb p\u00ebrgjegj\u00ebsi t\u00eb re (pra nj\u00eb sh\u00ebrbim t\u00eb ri) dhe p\u00ebrmir\u00ebsime n\u00eb t\u00eb gjitha sistemet e p\u00ebrfshira.<\/li>\n<li><strong>BOB split<\/strong>\u00a0\u2014 nj\u00eb projekt i brendsh\u00ebm i kompanis\u00eb p\u00ebr t\u00eb eliminuar numrin e madh t\u00eb p\u00ebrgjegj\u00ebsive jo-profesionale nga BOB dhe p\u00ebr t\u00eb reduktuar kompleksitetin e tij t\u00eb p\u00ebrgjithsh\u00ebm.<\/li>\n<\/ol>\n<p>\n<img decoding=\"async\" alt=\"P\u00ebrvoja e zhvillimit t\u00eb sh\u00ebrbimit Refund Tool me API asinkron mbi Kafka\" src=\"\/wp-content\/uploads\/2019\/04\/d3ecf9961bdb372fc5f84ee9389f73ef.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nN\u00eb k\u00ebt\u00eb skem\u00eb jan\u00eb paraqitur sistemet kryesore t\u00eb Lamoda. Tani shumica e tyre p\u00ebrb\u00ebjn\u00eb m\u00eb shum\u00eb <strong>nj\u00eb grup prej 5-10 mikrosh\u00ebrbimesh rreth nj\u00eb monoliti n\u00eb zvog\u00eblim<\/strong>. Ato po rriten, por ne p\u00ebrpiqemi t'i b\u00ebjm\u00eb m\u00eb t\u00eb vogla, sepse \u00ebsht\u00eb e frikshme t\u00eb vendos\u00ebsh nj\u00eb fragment t\u00eb dedikuar n\u00eb mes \u2014 nuk duhet lejuar q\u00eb ai t\u00eb bie. T\u00eb gjitha shk\u00ebmbimet (arrows) ne jemi t\u00eb detyruar t'i rezervojm\u00eb dhe t\u00eb supozojm\u00eb se ndonj\u00ebra prej tyre mund t\u00eb b\u00ebhet e paaksesueshme.<\/p>\n<p>N\u00eb BOB gjithashtu ka shum\u00eb shk\u00ebmbime: sisteme pagese, d\u00ebrgimi, njoftime etj. <\/p>\n<p>Teknikisht BOB \u00ebsht\u00eb:<\/p>\n<ul>\n<li>~150k rreshta kodi + ~100k rreshta testesh;<\/li>\n<li>php7.2 + Zend 1 &amp; Komponent\u00ebt Symfony 3;<\/li>\n<li>&gt;100 API &amp; ~50 integrime dal\u00ebse;<\/li>\n<li>4 vende me logjik\u00ebn e tyre t\u00eb biznesit. <\/li>\n<\/ul>\n<p>\nT\u00eb implementosh BOB \u00ebsht\u00eb e shtrenjt\u00eb dhe e dhimbshme, numri i kodit dhe detyrat q\u00eb ai zgjidh jan\u00eb t\u00eb tilla sa askush nuk mund ta mbaj\u00eb at\u00eb n\u00eb mendje n\u00eb t\u00ebr\u00ebsi. N\u00eb thelb, ka shum\u00eb arsye p\u00ebr ta thjeshtuar.<\/p>\n<h2>Procesi i kthimit<\/h2>\n<p>\nFillimisht n\u00eb proces p\u00ebrfshihen dy sisteme: BOB dhe Pagesa. Tani po shfaqen edhe dy t\u00eb tjera:<\/p>\n<ul>\n<li>Sh\u00ebrbimi i Fiskalizimit, i cili do t\u00eb marr\u00eb p\u00ebrsip\u00ebr problemet me fiskalizimin dhe komunikimin me sh\u00ebrbimet e jashtme.<\/li>\n<li>Mjeti i Kthimit, n\u00eb t\u00eb cilin thjesht transferohen shk\u00ebmbimet e reja, p\u00ebr t\u00eb mos rritur BOB-n\u00eb.<\/li>\n<\/ul>\n<p>\nTani procesi duket k\u00ebshtu:<\/p>\n<p><img decoding=\"async\" alt=\"P\u00ebrvoja e zhvillimit t\u00eb sh\u00ebrbimit Refund Tool me API asinkron mbi Kafka\" src=\"\/wp-content\/uploads\/2019\/04\/13c02975881ad35c61304053c604cda3.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<\/p>\n<ol>\n<li>BOB merr nj\u00eb k\u00ebrkes\u00eb p\u00ebr kthimin e parave.<\/li>\n<li>BOB e informon k\u00ebt\u00eb Mjet Kthimi.<\/li>\n<li>Mjeti i Kthimit i thot\u00eb Pages\u00ebs: \"Kthe parat\u00eb\".<\/li>\n<li>Pagesa kthen parat\u00eb.<\/li>\n<li>Mjeti i Kthimit dhe BOB sinjalizojn\u00eb nj\u00ebri-tjetrin p\u00ebr statuset, sepse tani t\u00eb dyve u nevojitet. Ne ende nuk jemi gati t\u00eb kalojm\u00eb plot\u00ebsisht n\u00eb Mjetin Kthimi, sepse n\u00eb BOB ka UI, raporte p\u00ebr kontabilitetin, dhe n\u00eb p\u00ebrgjith\u00ebsi shum\u00eb t\u00eb dh\u00ebna q\u00eb nuk mund t\u00eb transferohen aq leht\u00ebsisht. Na duhet t\u00eb rrim\u00eb n\u00eb dy karrige.<\/li>\n<li>Shkarkohet k\u00ebrkesa p\u00ebr fiskalizim.<\/li>\n<\/ol>\n<p>\nK\u00ebshtu, ne krijuam nj\u00eb autobus ngjarjesh p\u00ebrmes Kafka, ku gjith\u00e7ka \u00ebsht\u00eb lidhur. Hurra, tani kemi nj\u00eb pik\u00eb t\u00eb vetme t\u00eb d\u00ebshtimit (sarkaz\u00ebm).<\/p>\n<p><img decoding=\"async\" alt=\"P\u00ebrvoja e zhvillimit t\u00eb sh\u00ebrbimit Refund Tool me API asinkron mbi Kafka\" src=\"\/wp-content\/uploads\/2019\/04\/674edd7972998b4985071f5250612c7e.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nPikat e forta dhe t\u00eb dob\u00ebta jan\u00eb mjaft evidente. Krijuam autobus, q\u00eb do t\u00eb thot\u00eb se tani t\u00eb gjitha sh\u00ebrbimet varen nga ai. Kjo e thjeshton projektimin, por sjell nj\u00eb pik\u00eb t\u00eb vetme t\u00eb d\u00ebshtimit n\u00eb sistem. N\u00ebse Kafka bie, procesi do t\u00eb ndaloj\u00eb.<\/p>\n<h2>\u00c7far\u00eb \u00ebsht\u00eb API me ngjarje? <\/h2>\n<p>\nNj\u00eb p\u00ebrgjigje e mir\u00eb p\u00ebr k\u00ebt\u00eb pyetje ndodhet n\u00eb raportin e Martin Fowler (GOTO 2017). <noindex><a rel=\"nofollow\" href=\"https:\/\/youtu.be\/STKCRSUsyPO\">\u00abShum\u00eb Kuptime t\u00eb Arkitektur\u00ebs me Ngjarje\u00bb<\/a><\/noindex>. <\/p>\n<p>P\u00ebrmbledhja e asaj q\u00eb ne b\u00ebm\u00eb:<\/p>\n<ol>\n<li>Ne p\u00ebrfshim\u00eb t\u00eb gjitha shk\u00ebmbimet asinkrone p\u00ebrmes <strong>ruajtjes s\u00eb ngjarjeve.<\/strong>N\u00eb vend q\u00eb t\u00eb lajm\u00ebrojm\u00eb \u00e7do konsumator t\u00eb interesuar p\u00ebrmes rrjetit n\u00eb lidhje me ndryshimin e statusit, ne shkruajm\u00eb nj\u00eb ngjarje n\u00eb nj\u00eb depo t\u00eb centralizuar mbi ndryshimin e statusit, dhe konsumator\u00ebt e interesuar n\u00eb tem\u00eb lexojn\u00eb prej aty gjith\u00e7ka q\u00eb shfaqet.<\/li>\n<li>Ngjarja (event) n\u00eb k\u00ebt\u00eb rast \u00ebsht\u00eb nj\u00eb njoftim (<strong>notifications<\/strong>) p\u00ebr at\u00eb q\u00eb di\u00e7ka ka ndryshuar diku. P\u00ebr shembull, statusi i porosis\u00eb \u00ebsht\u00eb ndryshuar. Konsumatori, i cili k\u00ebrkon disa t\u00eb dh\u00ebna p\u00ebrcjell\u00ebse t\u00eb r\u00ebnd\u00ebsishme p\u00ebr ndryshimin e statusit dhe q\u00eb nuk jan\u00eb n\u00eb njoftim, mund t\u00eb m\u00ebsoj\u00eb gjendjen e tyre vet\u00eb.<\/li>\n<li>Varianti maksimal \u00ebsht\u00eb sourcing i plot\u00eb t\u00eb ngjarjeve, <strong>transferi i gjendjes<\/strong>, n\u00eb t\u00eb cilin ngjarja p\u00ebrmban t\u00eb gjitha informacionet e nevojshme p\u00ebr p\u00ebrpunim: nga erdhi dhe n\u00eb \u00e7far\u00eb statusi kaloi, si ndryshuan t\u00eb dh\u00ebnat etj. Pyetje \u00ebsht\u00eb vet\u00ebm sa e arsyeshme \u00ebsht\u00eb dhe sa informacion mund t\u00eb lejoni t\u00eb ruhet.<\/li>\n<\/ol>\n<p>\nN\u00eb kuad\u00ebr t\u00eb lan\u00e7imit t\u00eb Refund Tool, ne p\u00ebrdor\u00ebm variantin e tret\u00eb. Kjo e thjeshtoi p\u00ebrpunimin e ngjarjeve, pasi nuk \u00ebsht\u00eb e nevojshme t\u00eb nxjerrim informata t\u00eb detajuara, plus p\u00ebrjashtoi skenarin kur \u00e7do ngjarje e re shkakton nj\u00eb shp\u00ebrthim t\u00eb k\u00ebrkesave t\u00eb qarta nga konsumator\u00ebt.<\/p>\n<p>Sh\u00ebrbimi Refund Tool <strong>nuk \u00ebsht\u00eb i ngarkuar<\/strong>, prandaj Kafka aty \u00ebsht\u00eb m\u00eb shum\u00eb nj\u00eb prov\u00eb sesa nj\u00eb nevoj\u00eb. Nuk mendoj se, n\u00ebse sh\u00ebrbimi i kthimit t\u00eb parave do t\u00eb b\u00ebhej nj\u00eb projekt me ngarkes\u00eb t\u00eb lart\u00eb, biznesi do t\u00eb ishte i k\u00ebnaqur.<\/p>\n<h4>Shk\u00ebmbimi asinkron AS IS<\/h4>\n<p>\nP\u00ebr shk\u00ebmbimet asinkrone, departamenti i PHP zakonisht p\u00ebrdor RabbitMQ. Grumbullojm\u00eb t\u00eb dh\u00ebnat p\u00ebr k\u00ebrkes\u00ebn, i vendosim n\u00eb radh\u00eb, dhe konsumatori i t\u00eb nj\u00ebjtit sh\u00ebrbim e lexon dhe d\u00ebrgon (ose jo). P\u00ebr API-n\u00eb vet\u00eb, Lamoda e p\u00ebrdor aktivisht Swagger. E projektojm\u00eb API-n\u00eb, e p\u00ebrshkruajm\u00eb n\u00eb Swagger, gjenerojm\u00eb kodin klient dhe server. Gjithashtu, ne p\u00ebrdorim nj\u00eb JSON RPC 2.0 pak m\u00eb t\u00eb zgjeruar. <\/p>\n<p>Disa vende p\u00ebrdorin autobus\u00eb esb, disa jetojn\u00eb n\u00eb activeMQ, por, n\u00eb p\u00ebrgjith\u00ebsi, <strong>RabbitMQ \u2014 standard<\/strong>.<\/p>\n<h4>Async exchange TO BE<\/h4>\n<p>\nDuke nj\u00eb analogji kur projektojm\u00eb shk\u00ebmbimin p\u00ebrmes events-bus. Ne e p\u00ebrshkruajm\u00eb shk\u00ebmbimin e t\u00eb dh\u00ebnave n\u00eb t\u00eb ardhmen n\u00eb nj\u00eb m\u00ebnyr\u00eb t\u00eb ngjashme p\u00ebrmes p\u00ebrshkrimeve t\u00eb struktur\u00ebs s\u00eb event-it. Formati yaml, ne duhej t\u00eb b\u00ebnim vet\u00eb kodin e gjenerimit, gjeneratori sipas specifikacionit krijon DTO dhe m\u00ebson klient\u00ebt dhe server\u00ebt t\u00eb punojn\u00eb me ta. Gjenerimi b\u00ebhet n\u00eb dy gjuh\u00eb \u2014 <strong>golang dhe php<\/strong>. Kjo lejon q\u00eb bibliotekat t\u00eb jen\u00eb t\u00eb sinkronizuara. Gjeneratori \u00ebsht\u00eb shkruar n\u00eb golang, ndaj mori emrin gogi.<\/p>\n<p>Event-sourcing n\u00eb Kafka \u00ebsht\u00eb di\u00e7ka tipike. Ka nj\u00eb zgjidhje nga versioni kryesor enterprise i Kafka Confluent, ka <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/zalando\/nakadi\">nakadi<\/a><\/noindex>, nj\u00eb zgjidhje nga \"v\u00ebllez\u00ebrit\" tan\u00eb n\u00eb fush\u00ebn e domenit Zalando. Motivacioni yn\u00eb p\u00ebr t\u00eb filluar me vanilla Kafka <strong>\u00ebsht\u00eb q\u00eb t\u00eb mbajm\u00eb zgjidhjen falas, derisa t\u00eb vendosim n\u00ebse do ta p\u00ebrdorim at\u00eb n\u00eb mas\u00eb, si dhe t\u00eb ruajm\u00eb hap\u00ebsir\u00eb p\u00ebr manovrim dhe p\u00ebrmir\u00ebsime: ne duam mb\u00ebshtetje p\u00ebr<\/strong>\u00a0JSON RPC 2.0 <strong>, gjenerator\u00ebt p\u00ebr dy gjuh\u00eb dhe t\u00eb shohim \u00e7far\u00eb tjet\u00ebr.<\/strong>Ironikisht, q\u00eb edhe n\u00eb nj\u00eb rast t\u00eb till\u00eb t\u00eb lumtur, kur ekziston nj\u00eb biznes mjaft analog si Zalando, i cili b\u00ebri nj\u00eb zgjidhje t\u00eb ngjashme, ne nuk mund ta p\u00ebrdorim at\u00eb efektivisht. <\/p>\n<p>Arkitektursh\u00ebm, n\u00eb fillim, modeli \u00ebsht\u00eb i till\u00eb: lexojm\u00eb direkt nga Kafka, por shkruajm\u00eb vet\u00ebm p\u00ebrmes events-bus. P\u00ebr leximin n\u00eb Kafka ka shum\u00eb t\u00eb gatshme: broker\u00eb, balancues dhe ajo \u00ebsht\u00eb m\u00eb shum\u00eb-m\u00eb pak e gatshme p\u00ebr shkall\u00ebzim horizontal, k\u00ebt\u00eb d\u00ebshironim ta ruanim. Megjithat\u00eb, p\u00ebr shkrimin, ne d\u00ebshiruam ta mb\u00ebshtjellim p\u00ebrmes nj\u00eb Gateway aka Events-bus, dhe ja pse. <\/p>\n<p>Events-bus<\/p>\n<h3>Ose autobusi i ngjarjeve. Ky \u00ebsht\u00eb thjesht nj\u00eb gateway http stateless, q\u00eb merr p\u00ebr vete disa role t\u00eb r\u00ebnd\u00ebsishme:<\/h3>\n<p>\nValidimi i produkteve<\/p>\n<ul>\n<li><strong>\u2014 kontrollojm\u00eb q\u00eb ngjarjet p\u00ebrputhen me specifikimin ton\u00eb.<\/strong>\u00a0Sistemi kryesor p\u00ebr ngjarjet<\/li>\n<li><strong>, dometh\u00ebn\u00eb kjo \u00ebsht\u00eb sistemi kryesor dhe i vet\u00ebm n\u00eb kompani, q\u00eb p\u00ebrgjigjet n\u00eb pyetjen, se cilat ngjarje me cilat struktura konsiderohen p\u00ebrshtat\u00ebse. N\u00eb validim p\u00ebrfshihen thjesht llojet e t\u00eb dh\u00ebnave dhe enums p\u00ebr specifikimin e fort\u00eb t\u00eb p\u00ebrmbajtjes.<\/strong>Funksioni Hash <\/li>\n<li><strong>p\u00ebr shardimin \u2014 struktura e mesazhit Kafka \u00ebsht\u00eb key-value dhe sipas hashes nga key llogaritet se ku do ta vendosim.<\/strong> Pse<\/li>\n<\/ul>\n<p><\/p>\n<h3>Ne punojm\u00eb n\u00eb nj\u00eb kompani t\u00eb madhe me nj\u00eb proces t\u00eb vendosur. Pse t\u00eb ndryshojm\u00eb di\u00e7ka?<\/h3>\n<p>\nKy \u00ebsht\u00eb nj\u00eb eksperiment <strong>, dhe ne presim t\u00eb fitojm\u00eb disa p\u00ebrfitime.<\/strong>1:n+1 shk\u00ebmbime (nj\u00eb me shum\u00eb)<\/p>\n<h4>Me Kafka \u00ebsht\u00eb shum\u00eb e leht\u00eb t\u00eb lidheni me API t\u00eb konsumator\u00ebve t\u00eb rinj.<\/h4>\n<p>\nMe\u00a0Kafka \u00ebsht\u00eb shum\u00eb e leht\u00eb t\u00eb lidheni me\u00a0API-t\u00eb e konsumator\u00ebve t\u00eb rinj. <\/p>\n<p>Supozoni se keni nj\u00eb regjist\u00ebr q\u00eb duhet ta mbani t\u00eb azhurnuar n\u00eb disa sisteme nj\u00ebkoh\u00ebsisht (edhe n\u00eb t\u00eb reja). M\u00eb par\u00eb ne krijonim nj\u00eb bundle q\u00eb implementonte set-API, dhe sistemit master i raportonim adresat e konsumator\u00ebve. Tani sistemi master d\u00ebrgon p\u00ebrdit\u00ebsime n\u00eb nj\u00eb topic, dhe t\u00eb gjith\u00eb ata q\u00eb jan\u00eb t\u00eb interesuar lexojn\u00eb. Pati nj\u00eb sistem t\u00eb ri \u2014 e regjistruam at\u00eb n\u00eb topic. Po, gjithashtu nj\u00eb bundle, por m\u00eb t\u00eb thjesht\u00eb.<\/p>\n<p>N\u00eb rastin e refund-tool, i cili \u00ebsht\u00eb nj\u00eb pjes\u00eb e BOB, \u00ebsht\u00eb e leht\u00eb p\u00ebr ne t\u00eb mbajm\u00eb ato t\u00eb sinkronizuara p\u00ebrmes Kafka. Pagimi thot\u00eb se parat\u00eb u kthyen: BOB, RT e mor\u00ebn vesh k\u00ebt\u00eb, nd\u00ebrruan statuset e tyre, Sh\u00ebrbimi i Fiskalizimit mori vesh p\u00ebr k\u00ebt\u00eb dhe nxori nj\u00eb \u00e7ek.<\/p>\n<p><img decoding=\"async\" alt=\"P\u00ebrvoja e zhvillimit t\u00eb sh\u00ebrbimit Refund Tool me API asinkron mbi Kafka\" src=\"\/wp-content\/uploads\/2019\/04\/b01b22a333b58e87aeef0c52d40e6960.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nNe kemi plane p\u00ebr t\u00eb b\u00ebr\u00eb nj\u00eb Sh\u00ebrbim t\u00eb P\u00ebrcjelljes s\u00eb Njoftimeve i cili do t\u00eb informonte klientin p\u00ebr lajmet n\u00eb lidhje me porosin\u00eb e tij\/p\u00ebr kthimet. Aktualisht kjo p\u00ebrgjegj\u00ebsi \u00ebsht\u00eb shp\u00ebrndar\u00eb midis sistemeve. Na mjafton t\u00eb m\u00ebsojm\u00eb Sh\u00ebrbimin e Njoftimeve t\u00eb kap\u00eb informacionin p\u00ebrkat\u00ebs nga Kafka dhe t\u00eb reagoj\u00eb ndaj tij (dhe t\u00eb \u00e7aktivizojm\u00eb k\u00ebto njoftime n\u00eb sistemet e tjera). Nuk do t\u00eb nevojiten shk\u00ebmbime t\u00eb reja t\u00eb drejtp\u00ebrdrejta.<\/p>\n<h4>Data-driven<\/h4>\n<p>\nInformacioni midis sistemeve b\u00ebhet i transparenc\u00ebs \u2014 sado \"enterprise\" t\u00eb jet\u00eb i nd\u00ebrlikuar dhe sa i madh t\u00eb jet\u00eb backlog-u juaj. N\u00eb Lamoda ka nj\u00eb departament t\u00eb Analiz\u00ebs s\u00eb T\u00eb Dh\u00ebnave q\u00eb mbledh t\u00eb dh\u00ebnat nga sistemet dhe i transformon ato n\u00eb nj\u00eb form\u00eb t\u00eb rip\u00ebrdorueshme, si p\u00ebr biznesin ashtu edhe p\u00ebr sistemet inteligjente. Kafka lejon q\u00eb t\u2019ju ofroj\u00eb atyre shum\u00eb t\u00eb dh\u00ebna shpejt dhe t\u00eb mbaj\u00eb k\u00ebt\u00eb rrjedh\u00eb informacioni t\u00eb azhurnuar.<\/p>\n<h4>Replication log<\/h4>\n<p>\nMesazhet nuk humbasin pas leximit, si n\u00eb RabbitMQ. Kur nj\u00eb event p\u00ebrmban informacion t\u00eb mjaftuesh\u00ebm p\u00ebr p\u00ebrpunim, ne kemi nj\u00eb histori t\u00eb ndryshimeve t\u00eb fundit mbi objektin, dhe, n\u00ebse d\u00ebshirojm\u00eb, mund\u00ebsin\u00eb p\u00ebr t\u00eb aplikuar k\u00ebto ndryshime.<\/p>\n<p>Koha e ruajtjes s\u00eb replication log varet nga intensiteti i shkrimeve n\u00eb k\u00ebt\u00eb topic, Kafka lejon q\u00eb t\u00eb konfigurohen fleksib\u00ebl kufijt\u00eb p\u00ebr sa i p\u00ebrket koh\u00ebs s\u00eb ruajtjes dhe p\u00ebrmasat e t\u00eb dh\u00ebnave. P\u00ebr topicet intensive \u00ebsht\u00eb e r\u00ebnd\u00ebsishme q\u00eb t\u00eb gjith\u00eb konsumator\u00ebt t\u00eb arrijn\u00eb t\u00eb lexojn\u00eb informacionin p\u00ebrpara se ai t\u00eb zhduket, edhe n\u00eb rast t\u00eb nj\u00eb mosfunksionimi t\u00eb p\u00ebrkohsh\u00ebm. Zakonisht arrihet t\u00eb ruhet informacioni p\u00ebr\u00a0<strong>nj\u00ebsi dit\u00ebsh<\/strong>, q\u00eb \u00ebsht\u00eb mjaft e mjaftueshme p\u00ebr mb\u00ebshtetje. <\/p>\n<p><img decoding=\"async\" alt=\"P\u00ebrvoja e zhvillimit t\u00eb sh\u00ebrbimit Refund Tool me API asinkron mbi Kafka\" src=\"\/wp-content\/uploads\/2019\/04\/0e08dd384155289123ebee96430c2370.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nM\u00eb pas pak p\u00ebrmbledhje e dokumentacionit, p\u00ebr ata q\u00eb nuk jan\u00eb t\u00eb njohur me Kafka (imazhi gjithashtu \u00ebsht\u00eb nga dokumentacioni)<\/p>\n<p>N\u00eb AMQP ka radh\u00eb: shkruajm\u00eb mesazhe n\u00eb radh\u00eb p\u00ebr konsumatorin. Zakonisht, nj\u00eb radh\u00eb trajtohet nga nj\u00eb sistem me t\u00eb nj\u00ebjt\u00ebn logjik\u00eb biznesi. N\u00ebse nevojitet q\u00eb t\u00eb njoftohen disa sisteme, mund t\u00eb m\u00ebsojm\u00eb aplikacionin t\u00eb shkruaj\u00eb n\u00eb disa radh\u00eb ose t\u00eb konfigurojm\u00eb nj\u00eb exchange me nj\u00eb mekaniz\u00ebm fanout, i cili i kopjon ato vet\u00eb.<\/p>\n<p>N\u00eb Kafka ka nj\u00eb abstraksion t\u00eb ngjash\u00ebm <em>topic<\/em>, ku shkruani mesazhe, por ato nuk zhduken pas leximit. N\u00eb m\u00ebnyr\u00eb t\u00eb parazgjedhur, kur lidheni me Kafka, merrni t\u00eb gjitha mesazhet, dhe ka mund\u00ebsin\u00eb t\u00eb ruani vendin ku jeni ndalur. K\u00ebshtu q\u00eb lexoni sequentially, mund t\u00eb mos sh\u00ebnoni mesazhin si t\u00eb lexuar, por t\u00eb ruani id, nga i cili pastaj do t\u00eb vazhdoni leximin. Id, ku jeni ndalur, quhet offset (shk\u00ebputje), dhe mekanizmi \u00ebsht\u00eb commit offset. <\/p>\n<p>P\u00ebr rrjedhoj\u00eb, mund t\u00eb implementoni logjik\u00eb t\u00eb ndryshme. P\u00ebr shembull, BOB ekziston n\u00eb 4 instanca p\u00ebr vende t\u00eb ndryshme - Lamoda \u00ebsht\u00eb n\u00eb Rusi, Kazakistan, Ukrain\u00eb, Bjellorusi. Duke qen\u00eb se ato deploy-ohen ve\u00e7mas, ato kan\u00eb pak m\u00eb shum\u00eb konfigurime dhe logjik\u00eb biznesi t\u00eb ve\u00e7ant\u00eb. Ne tregojm\u00eb n\u00eb mesazh se p\u00ebr cilin vend \u00ebsht\u00eb. \u00c7do konsumator BOB n\u00eb \u00e7do vend lexon me groupId t\u00eb ndryshme, dhe n\u00ebse mesazhi nuk i p\u00ebrket atij, e kalon at\u00eb, dmth. menj\u00ebher\u00eb komiton offset +1. N\u00ebse po aq topic lexon Sh\u00ebrbimi Yn\u00eb t\u00eb Pagesave, at\u00ebher\u00eb ai e b\u00ebn k\u00ebt\u00eb me nj\u00eb grup t\u00eb ve\u00e7ant\u00eb, dhe p\u00ebr k\u00ebt\u00eb arsye offset-et nuk p\u00ebrputhen.<\/p>\n<p><b>K\u00ebrkesat p\u00ebr ngjarjet:<\/b><\/p>\n<ul>\n<li><strong>Plot\u00ebsia e t\u00eb dh\u00ebnave. <\/strong>Do t\u00eb donim q\u00eb n\u00eb ngjarje t\u00eb kishte t\u00eb dh\u00ebna t\u00eb mjaftueshme p\u00ebr ta trajtuar at\u00eb. <\/li>\n<\/ul>\n<p><\/p>\n<ul>\n<li><strong>Integriteti. <\/strong>Ne e delegojm\u00eb Events-bus kontrollin se ngjarja \u00ebsht\u00eb e q\u00ebndrueshme dhe ai mund ta trajtoj\u00eb at\u00eb.<\/li>\n<li><strong>Rendi \u00ebsht\u00eb i r\u00ebnd\u00ebsish\u00ebm. <\/strong>N\u00eb rastin e kthimit, ne jemi t\u00eb detyruar t\u00eb punojm\u00eb me historin\u00eb. Me njoftimet, rendi nuk ka r\u00ebnd\u00ebsi, n\u00ebse jan\u00eb njoftime homogjene, email-i do t\u00eb jet\u00eb i nj\u00ebjt\u00eb pavar\u00ebsisht se cili porosi mb\u00ebrriti i pari. N\u00eb rastin e kthimit ka nj\u00eb proces t\u00eb qart\u00eb, n\u00ebse e ndryshojm\u00eb rendin, do t\u00eb ket\u00eb p\u00ebrjashtime, rimbursimi nuk do t\u00eb krijohet apo nuk do t\u00eb p\u00ebrpunoj\u00eb - ne do t\u00eb p\u00ebrfundojm\u00eb n\u00eb nj\u00eb status tjet\u00ebr.<\/li>\n<li><strong>Koherenca. <\/strong>Ne kemi nj\u00eb repository dhe tani po krijojm\u00eb ngjarje n\u00eb vend t\u00eb API. Na nevojitet nj\u00eb m\u00ebnyr\u00eb p\u00ebr t\u00eb transmetuar shpejt dhe n\u00eb m\u00ebnyr\u00eb t\u00eb lir\u00eb informacionin p\u00ebr ngjarjet e reja dhe p\u00ebr ndryshimet n\u00eb ato ekzistuese n\u00eb sh\u00ebrbimet tona. Kjo arrihet p\u00ebrmes nj\u00eb specifikimi t\u00eb p\u00ebrbashk\u00ebt n\u00eb nj\u00eb depozit\u00eb git t\u00eb ndar\u00eb dhe gjenerator\u00ebve t\u00eb kodit. Prandaj, klient\u00ebt dhe server\u00ebt n\u00eb sh\u00ebrbime t\u00eb ndryshme jan\u00eb t\u00eb pajtuar.<\/li>\n<\/ul>\n<p><\/p>\n<h2>Kafka n\u00eb Lamoda<\/h2>\n<p>\nKemi tri instalime Kafka: <\/p>\n<ol>\n<li>Logs;<\/li>\n<li>R&amp;D;<\/li>\n<li>Events-bus.<\/li>\n<\/ol>\n<p>\nSot po flasim vet\u00ebm p\u00ebr pik\u00ebn e fundit. N\u00eb events-bus, ne kemi instalime t\u00eb vogla - 3 broker\u00eb (server\u00eb) dhe gjithsej 27 tema. Zakonisht, nj\u00eb tem\u00eb \u00ebsht\u00eb nj\u00eb proces. Por kjo \u00ebsht\u00eb nj\u00eb \u00e7\u00ebshtje delikate dhe tani do ta trajtojm\u00eb at\u00eb.<\/p>\n<p><img decoding=\"async\" alt=\"P\u00ebrvoja e zhvillimit t\u00eb sh\u00ebrbimit Refund Tool me API asinkron mbi Kafka\" src=\"\/wp-content\/uploads\/2019\/04\/f398852689b31429cc97b4cbffcabab5.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nM\u00eb sip\u00ebr \u00ebsht\u00eb grafiku rps. Procesi i kthimeve sh\u00ebnohet me nj\u00eb vij\u00eb turchize (po, po, ajo q\u00eb \u00ebsht\u00eb n\u00eb boshtin X), dhe me pink procesi i p\u00ebrdit\u00ebsimit t\u00eb p\u00ebrmbajtjes. <\/p>\n<p>Katalogu Lamoda p\u00ebrmban miliona produkte, dhe t\u00eb dh\u00ebnat p\u00ebrdit\u00ebsohen vazhdimisht. Disa koleksione dalin nga moda, n\u00eb vend t\u00eb tyre lan\u00e7ohen t\u00eb reja, dhe n\u00eb katalog n\u00eb vazhdim\u00ebsi shfaqen modele t\u00eb reja. Ne p\u00ebrpiqemi t\u00eb parashikojm\u00eb se \u00e7far\u00eb do t\u00eb jet\u00eb interesante p\u00ebr klient\u00ebt tan\u00eb nes\u00ebr, prandaj vazhdimisht blejm\u00eb gj\u00ebra t\u00eb reja, i fotografojm\u00eb dhe p\u00ebrdit\u00ebsojm\u00eb vitrin\u00ebn. <\/p>\n<p>Pikat roz\u00eb jan\u00eb p\u00ebrdit\u00ebsime produktesh, dmth ndryshime p\u00ebr produktet. \u00cbsht\u00eb e dukshme se djemt\u00eb po fotografonin, fotografonin, dhe pastaj papritur! - ngarkuan nj\u00eb grup ngjarjesh.<\/p>\n<h2>Rastet e p\u00ebrdorimit t\u00eb Lamoda Events<\/h2>\n<p>\nArkitektura e nd\u00ebrtuar p\u00ebrdoret p\u00ebr operacione t\u00eb tilla:<\/p>\n<ul>\n<li><strong>Ndjekja e statusve t\u00eb kthimeve<\/strong>: thirrje p\u00ebr veprim dhe ndjekja e statusve nga t\u00eb gjitha sistemet e p\u00ebrfshira. Pagesa, statuset, fiskalizimi, njoftimet. K\u00ebtu kemi provuar qasje, krijuar mjete, mbledhur t\u00eb gjitha gabimet, shkruar dokumentacionin dhe u kemi treguar koleg\u00ebve se si ta p\u00ebrdorin k\u00ebt\u00eb.<\/li>\n<li><strong>P\u00ebrdit\u00ebsimi i kartelave t\u00eb produkteve: <\/strong>konfigurimi, meta-t\u00eb dh\u00ebnat, karakteristikat. Lexohet nga nj\u00eb sistem (i cili shfaq), nd\u00ebrsa shkruhet nga disa.<\/li>\n<li><strong>Email, push dhe sms<\/strong>: porosia u mblodh, porosia arriti, kthimi u pranua etj., shum\u00eb prej tyre. <\/li>\n<li><strong>Stoku, p\u00ebrdit\u00ebsimi i magazin\u00ebs<\/strong>\u00a0\u2014 p\u00ebrdit\u00ebsim sasi i emrave, thjesht numra: ardhja n\u00eb magazin\u00eb, kthimi. Nevojitet q\u00eb t\u00eb gjitha sistemet e lidhura me rezervimin e produkteve t\u00eb operojn\u00eb me t\u00eb dh\u00ebna sa m\u00eb t\u00eb sakta. Tani sistemi i p\u00ebrdit\u00ebsimit t\u00eb stokut \u00ebsht\u00eb mjaft kompleks, Kafka do ta leht\u00ebsoj\u00eb at\u00eb.<\/li>\n<li><strong>Analiza e t\u00eb dh\u00ebnave<\/strong> (R&amp;D-nd\u90e8\u95e8), mjetet ML, analiza, statistika. Ne duam q\u00eb informacioni t\u00eb jet\u00eb transparent \u2013 p\u00ebr k\u00ebt\u00eb Kafka \u00ebsht\u00eb shum\u00eb i p\u00ebrshtatsh\u00ebm.<\/li>\n<\/ul>\n<p>\nTani \u00ebsht\u00eb pjesa m\u00eb interesante p\u00ebr dhimbjet e p\u00ebrvoja dhe zbulimet interesante q\u00eb ndodh\u00ebn gjat\u00eb gjasht\u00eb muajve.<\/p>\n<h2>Problemet e dizajnit<\/h2>\n<p>\nSupozoni se duam t\u00eb b\u00ebjm\u00eb nj\u00eb gj\u00eb t\u00eb re \u2013 p\u00ebr shembull, t\u00eb transferojm\u00eb t\u00ebr\u00eb procesin e dor\u00ebzimit n\u00eb Kafka. Tani, nj\u00eb pjes\u00eb e procesit realizohet n\u00eb Procesimin e Porosive n\u00eb BOB. Pas kalimit t\u00eb porosis\u00eb n\u00eb sh\u00ebrbimin e dor\u00ebzimit, pozita n\u00eb magazin\u00eb nd\u00ebrmjet\u00ebse dhe gj\u00ebrat e tjera kan\u00eb nj\u00eb model statusi. Ka nj\u00eb monolit t\u00eb t\u00ebr\u00eb, madje dy, plus nj\u00eb grumbull API-sh t\u00eb dedikuara p\u00ebr dor\u00ebzimin. Ata din\u00eb shum\u00eb m\u00eb tep\u00ebr p\u00ebr dor\u00ebzimin. <\/p>\n<p>Duket se k\u00ebto jan\u00eb fusha t\u00eb ngjashme, por p\u00ebr Procesimin e Porosive n\u00eb BOB dhe p\u00ebr sistemin e dor\u00ebzimit statuset ndryshojn\u00eb. P\u00ebr shembull, disa sh\u00ebrbime kurierike nuk d\u00ebrgojn\u00eb statuset nd\u00ebrmjet\u00ebse, por vet\u00ebm ato p\u00ebrfundimtare: \"u dor\u00ebzua\" ose \"u humb\". T\u00eb tjer\u00ebt, p\u00ebrkundrazi, raportojn\u00eb shum\u00eb holl\u00ebsisht p\u00ebr l\u00ebvizjen e produktit. T\u00eb gjith\u00eb kan\u00eb rregullat e tyre t\u00eb validimit: p\u00ebr dik\u00eb, nj\u00eb email valid \u00ebsht\u00eb i mjaftuesh\u00ebm p\u00ebr ta procesuar; p\u00ebr t\u00eb tjer\u00eb, \u00ebsht\u00eb jo valid, por porosia gjithsesi do t\u00eb procesuar, sepse ka telefon p\u00ebr kontakt, nd\u00ebrsa dikush tjet\u00ebr do t\u00eb thot\u00eb se nj\u00eb porosi e till\u00eb nuk do t\u00eb procesuar fare.<\/p>\n<h3>Rrjedha e t\u00eb dh\u00ebnave<\/h3>\n<p>\nN\u00eb rastin e Kafka, lind pyetja e organizimit t\u00eb rrjedh\u00ebs s\u00eb t\u00eb dh\u00ebnave. Kjo detyr\u00eb \u00ebsht\u00eb e lidhur me zgjedhjen e strategjis\u00eb n\u00eb disa pik\u00eb, le t\u00eb kalojm\u00eb p\u00ebrmes tyre t\u00eb gjitha.<\/p>\n<h4>N\u00eb nj\u00eb tem\u00eb apo n\u00eb t\u00eb ndryshme?<\/h4>\n<p>\nNe kemi nj\u00eb specifikim t\u00eb ngjarjes. N\u00eb BOB shkruajm\u00eb se nj\u00eb porosi e caktuar duhet t\u00eb dor\u00ebzohet, dhe p\u00ebrcaktojm\u00eb: numri i porosis\u00eb, p\u00ebrb\u00ebrja e saj, disa SKU dhe kodet bar etj. Kur produkti t\u00eb arrij\u00eb n\u00eb magazin\u00eb, dor\u00ebzimi do t\u00eb mund t\u00eb marr\u00eb statuset, timestamps dhe gjith\u00e7ka tjet\u00ebr q\u00eb nevojitet. Por m\u00eb pas duam t\u00eb marrim azhurnime p\u00ebr k\u00ebto t\u00eb dh\u00ebna n\u00eb BOB. Ne kemi nj\u00eb proces t\u00eb kund\u00ebrt p\u00ebr marrjen e t\u00eb dh\u00ebnave nga dor\u00ebzimi. A \u00ebsht\u00eb kjo e nj\u00ebjta ngjarje? Apo \u00ebsht\u00eb nj\u00eb shk\u00ebmbim i ve\u00e7ant\u00eb q\u00eb meriton nj\u00eb tem\u00eb t\u00eb ve\u00e7ant\u00eb?<\/p>\n<p>Me sa duket, ato do t\u00eb jen\u00eb shum\u00eb t\u00eb ngjashme, dhe tundimi p\u00ebr t\u00eb b\u00ebr\u00eb nj\u00eb tem\u00eb \u00ebsht\u00eb i justifikuesh\u00ebm, sepse nj\u00eb tem\u00eb e ve\u00e7ant\u00eb \u2013 \u00ebsht\u00eb konsumator\u00eb t\u00eb ve\u00e7ant\u00eb, konfigurime t\u00eb ve\u00e7anta, gjenerim t\u00eb ve\u00e7ant\u00eb t\u00eb gjith\u00e7kaje. Por nuk \u00ebsht\u00eb fakt.<\/p>\n<h4>Fusha e re apo ngjarje e re?<\/h4>\n<p>\nPor shkak se ndodhin ato ngjarje, ka nj\u00eb problem tjet\u00ebr. P\u00ebr shembull, jo t\u00eb gjitha sistemet e d\u00ebrgimit mund t\u00eb gjenerojn\u00eb nj\u00eb DTO t\u00eb till\u00eb, q\u00eb mund t\u00eb gjeneroj\u00eb BOB. Ne i d\u00ebrgojm\u00eb atyre ID-t\u00eb, por ata nuk i ruajn\u00eb, sepse atyre nuk u nevojiten, nd\u00ebrsa nga pik\u00ebpamja e fillimit t\u00eb procesit event-bus, ky fush\u00eb \u00ebsht\u00eb e domosdoshme. <\/p>\n<p>N\u00ebse ne vendosim nj\u00eb rregull p\u00ebr event-bus q\u00eb ky fush\u00eb \u00ebsht\u00eb e domosdoshme, at\u00ebher\u00eb jemi t\u00eb detyruar n\u00eb BOB ose n\u00eb trajtuesin e ngjarjeve fillestare t\u00eb vendosim rregulla t\u00eb tjera verifikimi. Verifikimi fillon t\u00eb p\u00ebrhapet n\u00eb sh\u00ebrbim \u2014 kjo nuk \u00ebsht\u00eb shum\u00eb e p\u00ebrshtatshme.<\/p>\n<p>Nj\u00eb problem tjet\u00ebr \u00ebsht\u00eb komoditeti i zhvillimit inkremental. Na thon\u00eb se duhet t\u00eb shtojm\u00eb di\u00e7ka n\u00eb ngjarje, dhe, ndoshta, n\u00ebse e mendojm\u00eb mir\u00eb, duhet t\u00eb kishte qen\u00eb nj\u00eb ngjarje e ve\u00e7ant\u00eb. Por n\u00eb skem\u00ebn ton\u00eb, nj\u00eb ngjarje e ve\u00e7ant\u00eb \u00ebsht\u00eb nj\u00eb tem\u00eb e ve\u00e7ant\u00eb. Nj\u00eb tem\u00eb e ve\u00e7ant\u00eb \u00ebsht\u00eb t\u00ebr\u00eb procesi q\u00eb p\u00ebrshkrova m\u00eb lart. Zhvilluesi ndjen lidhjen t\u00eb thjesht\u00eb t\u00eb shtoj\u00eb nj\u00eb fush\u00eb tjet\u00ebr n\u00eb skem\u00ebn JSON dhe ta ri-gjeneroj\u00eb.<\/p>\n<p>N\u00eb rastin e refunds, ne n\u00eb k\u00ebt\u00eb m\u00ebnyr\u00eb arrit\u00ebm n\u00eb nj\u00eb ngjarje ngjarjesh pas gjasht\u00eb muajsh. Kishim nj\u00eb meta-ngjarje, e cila quhej refund update, n\u00eb t\u00eb cil\u00ebn kishte nj\u00eb fush\u00eb tipe, e cila p\u00ebrshkruante se \u00e7far\u00eb p\u00ebrfshin ky update. Nga kjo kishim \"fantastike\" switch-e me verifikuesit, q\u00eb thoshin se si duhet verifikuar kjo ngjarje me k\u00ebt\u00eb tip.<\/p>\n<h4>Versionimi i ngjarjeve<\/h4>\n<p>\nP\u00ebr verifikimin e mesazheve n\u00eb Kafka, mund t\u00eb p\u00ebrdoren <noindex><a rel=\"nofollow\" href=\"https:\/\/docs.confluent.io\/current\/schema-registry\/docs\/index.html\">Avro<\/a><\/noindex>, por duhet t\u00eb kemi parasysh q\u00eb t\u00eb p\u00ebrdorim Confluent. N\u00eb rastin ton\u00eb me versionimin, duhet t\u00eb jemi t\u00eb kujdessh\u00ebm. Nuk do t\u00eb jet\u00eb gjithmon\u00eb e mundur t\u00eb ritheksojm\u00eb mesazhet nga replication log, sepse modeli \u00ebsht\u00eb \"larguar\". Kryesisht, b\u00ebhet q\u00eb t\u00eb nd\u00ebrtojm\u00eb versione n\u00eb at\u00eb m\u00ebnyr\u00eb q\u00eb modeli t\u00eb jet\u00eb backward-compatible: p\u00ebr shembull, ta b\u00ebjm\u00eb nj\u00eb fush\u00eb p\u00ebrkoh\u00ebsisht t\u00eb pavlefshme. N\u00ebse ndryshimet jan\u00eb shum\u00eb t\u00eb forta, fillojm\u00eb t\u00eb shkruajm\u00eb n\u00eb nj\u00eb tem\u00eb t\u00eb re, dhe klient\u00ebt e kalojm\u00eb kur ata e p\u00ebrfundojn\u00eb t\u00eb vjetrin.<\/p>\n<h4>Garancia e rendit t\u00eb leximit t\u00eb partitions<\/h4>\n<p>\nTemat brenda Kafka jan\u00eb t\u00eb ndara n\u00eb partitions. Kjo nuk \u00ebsht\u00eb shum\u00eb e r\u00ebnd\u00ebsishme derisa ne projektuojm\u00eb entitetet dhe shk\u00ebmbimet, por \u00ebsht\u00eb e r\u00ebnd\u00ebsishme kur vendosim se si do ta konsumojm\u00eb dhe do ta shkall\u00ebzojm\u00eb.<\/p>\n<p>N\u00eb rrethanat normale, ju shkruani n\u00eb Kafka nj\u00eb tem\u00eb. Fallback, p\u00ebrdoret nj\u00eb ndar\u00ebs, dhe t\u00eb gjith\u00eb mesazhet e k\u00ebsaj teme bien n\u00eb t\u00eb. Nd\u00ebrsa konsumatori lexon k\u00ebto mesazhe n\u00eb m\u00ebnyr\u00eb t\u00eb nj\u00ebpasnj\u00ebshme. Le t\u00eb themi tani, q\u00eb na duhet t\u00eb zgjeronim sistemin q\u00eb mesazhet t\u00eb lexohet nga dy konsumator\u00eb t\u00eb ndrysh\u00ebm. N\u00ebse, p\u00ebr shembull, d\u00ebrgoni nj\u00eb SMS, mund t\u00eb themi q\u00eb Kafka t\u00eb krijoj\u00eb nj\u00eb ndarje t\u00eb shtes\u00eb, dhe Kafka do t\u00eb filloj\u00eb t\u00eb ndaj\u00eb mesazhet n\u00eb dy pjes\u00eb - gjysm\u00ebn aty, gjysm\u00ebn k\u00ebtu. <\/p>\n<p>Si i ndan Kafka? \u00c7do mesazh ka nj\u00eb trup (ku ruajm\u00eb JSON) dhe ka nj\u00eb \u00e7el\u00ebs. M\u00eb k\u00ebtij \u00e7el\u00ebsi mund t\u00eb aplikoni nj\u00eb funksion hash, i cili do t\u00eb p\u00ebrcaktoj\u00eb n\u00eb cil\u00ebn ndarje do t\u00eb shkoj\u00eb mesazhi.<\/p>\n<p>N\u00eb rastin ton\u00eb me rikthimet, kjo \u00ebsht\u00eb e r\u00ebnd\u00ebsishme, n\u00ebse marrim dy ndar\u00ebs, ka mund\u00ebsi q\u00eb konsumatori paralel t\u00eb trajtoj\u00eb ngjarjen e dyt\u00eb p\u00ebrpara asaj t\u00eb par\u00eb dhe do t\u00eb ket\u00eb probleme. Funksioni hash garanton q\u00eb mesazhet me t\u00eb nj\u00ebjtin \u00e7el\u00ebs do t\u00eb shkojn\u00eb n\u00eb t\u00eb nj\u00ebjt\u00ebn ndarje. <\/p>\n<h4>Ngjarjet vs urdhrat<\/h4>\n<p>\nKjo \u00ebsht\u00eb nj\u00eb tjet\u00ebr problem me t\u00eb cilin u p\u00ebrball\u00ebm. Ngjarja \u00ebsht\u00eb nj\u00eb ngjarje: ne themi q\u00eb di\u00e7ka ndodhi (something_happened), p\u00ebr shembull, nj\u00eb artikull u anulua ose u b\u00eb rikthimi. N\u00ebse k\u00ebto ngjarje dikush i d\u00ebgjon, at\u00ebher\u00eb n\u00eb \"artikulli u anulua\" entiteti i rikthimit do t\u00eb krijohet dhe \"u b\u00eb rikthimi\" do t\u00eb regjistrohet diku n\u00eb konfigurime.<\/p>\n<p>Por zakonisht, kur projektoni ngjarje, nuk d\u00ebshironi t\u00eb shkruani ato kot - parashikoni q\u00eb dikush do t'i lexoj\u00eb. Niveli i joshjes \u00ebsht\u00eb i lart\u00eb p\u00ebr t\u00eb shkruar jo something_happened (item_canceled, refund_refunded), por something_should_be_done. P\u00ebr shembull, artikulli \u00ebsht\u00eb gati p\u00ebr kthim.<\/p>\n<p>Nga nj\u00ebra an\u00eb, kjo sugjeron se si do t\u00eb p\u00ebrdoret ngjarja. Nga ana tjet\u00ebr, kjo duket shum\u00eb m\u00eb pak si emri normal i nj\u00eb ngjarjeje. Po ashtu, nga kjo nuk \u00ebsht\u00eb shum\u00eb larg deri te urdhri do_something. Por nuk keni garanci q\u00eb kjo ngjarje \u00ebsht\u00eb lexuar nga dikush; dhe n\u00ebse \u00ebsht\u00eb lexuar, at\u00ebher\u00eb \u00ebsht\u00eb lexuar me sukses; dhe n\u00ebse \u00ebsht\u00eb lexuar me sukses, at\u00ebher\u00eb b\u00ebri di\u00e7ka, dhe kjo di\u00e7ka kaloi me sukses. N\u00eb momentin q\u00eb ngjarja b\u00ebhet do_something, b\u00ebhet e nevojshme t\u00eb keni feedback dhe kjo \u00ebsht\u00eb problem.<\/p>\n<p><img decoding=\"async\" alt=\"P\u00ebrvoja e zhvillimit t\u00eb sh\u00ebrbimit Refund Tool me API asinkron mbi Kafka\" src=\"\/wp-content\/uploads\/2019\/04\/b755d91208092bd9791a41ce4633fb48.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nN\u00eb shk\u00ebmbimin asinkron n\u00eb RabbitMQ, kur lexoni nj\u00eb mesazh, shkoni te http, keni nj\u00eb p\u00ebrgjigje - t\u00eb pakt\u00ebn, q\u00eb mesazhi u pranua. Kur shkruani n\u00eb Kafka, keni nj\u00eb mesazh q\u00eb ju keni shkruar n\u00eb Kafka, por p\u00ebr m\u00ebnyr\u00ebn si \u00ebsht\u00eb trajtuar, nuk dini asgj\u00eb. <\/p>\n<p>Prandaj, n\u00eb rastin ton\u00eb, duhej t\u00eb merrnim nj\u00eb ngjarje p\u00ebrgjegj\u00ebse dhe t\u00eb vendosnim monitorimin q\u00eb, n\u00ebse ndodhin kaq shum\u00eb ngjarje, pas nj\u00eb periudhe kohore duhet t\u00eb ndodhin kaq shum\u00eb ngjarje p\u00ebrgjegj\u00ebse. N\u00ebse kjo nuk ndodh, duket se di\u00e7ka ka shkuar keq. P\u00ebr shembull, n\u00ebse d\u00ebrgojm\u00eb ngjarjen \"item_ready_to_refund\", presim q\u00eb refundi t\u00eb krijohet, klientit t'i kthehen parat\u00eb, dhe ne t\u00eb marrim ngjarjen \"money_refunded\". Por kjo nuk \u00ebsht\u00eb e sigurt, prandaj nevojitet monitorimi.<\/p>\n<h3>Nuancat<\/h3>\n<p>\nKa nj\u00eb problem mjaft t\u00eb qart\u00eb: n\u00ebse lexoni nga t\u00f3piku n\u00eb m\u00ebnyr\u00eb t\u00eb vazhdueshme, dhe keni ndonj\u00eb mesazh t\u00eb keq, konsumatori bie dhe m\u00eb tej nuk mund t\u00eb vazhdoni. Ju nevojitet <strong>t\u00eb ndaloni t\u00eb gjith\u00eb konsumator\u00ebt<\/strong>, t\u00eb komitoni offset-in m\u00eb tej, p\u00ebr t\u00eb vazhduar leximin.<\/p>\n<p>Ne e dinim k\u00ebt\u00eb, e kishim parashikuar, dhe megjithat\u00eb ndodhi. Ndodhi sepse ngjarja ishte e vlefshme nga pik\u00ebpamja e events-bus, ngjarja ishte e vlefshme nga pik\u00ebpamja e validuesit t\u00eb aplikacionit, por nuk ishte e vlefshme nga pik\u00ebpamja e PostgreSQL, sepse n\u00eb nj\u00eb sistem MySQL kishim UNISIGNED INT, nd\u00ebrsa n\u00eb sistemin e sapo shkruar ishte PostgreSQL thjesht me INT. Ai ka nj\u00eb madh\u00ebsi pak m\u00eb t\u00eb vog\u00ebl dhe Id nuk u p\u00ebrshtat. Symfony vdiq me nj\u00eb p\u00ebrjashtim. Ne, natyrisht, e kap\u00ebm p\u00ebrjashtimin, sepse e kishim parashikuar at\u00eb, dhe planifikuam t\u00eb komitonim k\u00ebt\u00eb offset, por para k\u00ebsaj donim t\u00eb rritnim num\u00ebruesin e problemeve, duke qen\u00eb se mesazhi u p\u00ebrpunua me d\u00ebshtim. Num\u00ebruesit n\u00eb k\u00ebt\u00eb projekt gjithashtu ndodhen n\u00eb baz\u00eb, dhe Symfony tashm\u00eb kishte mbyllur komunikimin me baz\u00ebn, dhe nj\u00eb p\u00ebrjashtim tjet\u00ebr vrau t\u00eb gjith\u00eb procesin pa shanse p\u00ebr t\u00eb komituar offset-in.<\/p>\n<p>P\u00ebr nj\u00eb koh\u00eb, sh\u00ebrbimi q\u00ebndroi i pal\u00ebvizur - p\u00ebr fat, me Kafka kjo nuk \u00ebsht\u00eb aq e frikshme, sepse mesazhet mbeten. Kur puna rikthehet, do t\u00eb jet\u00eb e mundur t'i lexoni ato. Kjo \u00ebsht\u00eb e dobishme.<\/p>\n<p>Kafka ka mund\u00ebsin\u00eb p\u00ebrmes tooling t\u00eb vendos\u00eb nj\u00eb offset t\u00eb \u00e7far\u00ebdo. Por p\u00ebr ta b\u00ebr\u00eb k\u00ebt\u00eb, duhet t\u00eb ndaloni t\u00eb gjith\u00eb konsumator\u00ebt - n\u00eb rastin ton\u00eb, t\u00eb p\u00ebrgatisni nj\u00eb version t\u00eb ve\u00e7ant\u00eb, n\u00eb t\u00eb cilin nuk do t\u00eb ket\u00eb konsumator\u00ebsh, redeployments. At\u00ebher\u00eb me an\u00eb t\u00eb tooling n\u00eb Kafka \u00ebsht\u00eb e mundur t\u00eb l\u00ebvizni offset-in dhe mesazhi do t\u00eb kaloj\u00eb.<\/p>\n<p>Nj\u00eb nuanc\u00eb tjet\u00ebr - <strong>replication log vs rdkafka.so<\/strong>\u00a0\u2014 \u00ebsht\u00eb e lidhur me specifikat e projektit ton\u00eb. Ne kemi PHP, dhe n\u00eb PHP, zakonisht t\u00eb gjitha bibliotekat komunikojn\u00eb me Kafka p\u00ebrmes depozit\u00ebs rdkafka.so, dhe m\u00eb pas ka nj\u00eb lloj mbulese. Mund t\u00eb jet\u00eb se k\u00ebto jan\u00eb v\u00ebshtir\u00ebsi t\u00eb veta, por rezultoi se thjesht rileximi i nj\u00eb pjese t\u00eb lexuar m\u00eb par\u00eb nuk \u00ebsht\u00eb aq i leht\u00eb. N\u00eb p\u00ebrgjith\u00ebsi, pati probleme programe.<\/p>\n<p>Duke u kthyer te ve\u00e7orit\u00eb e pun\u00ebs me partitions, n\u00eb dokumentacion \u00ebsht\u00eb shkruar n\u00eb m\u00ebnyr\u00eb t\u00eb drejtp\u00ebrdrejt\u00eb <strong>consumers &gt;= topic partitions<\/strong>. Por e m\u00ebsova k\u00ebt\u00eb shum\u00eb m\u00eb von\u00eb se sa do t\u00eb d\u00ebshiroja. N\u00ebse d\u00ebshironi t\u00eb shkall\u00ebzoni dhe t\u00eb keni dy konsumator\u00eb, ju nevojiten t\u00eb pakt\u00ebn dy partitions. K\u00ebshtu, n\u00ebse keni pasur nj\u00eb partition, n\u00eb t\u00eb cilin ishte grumbulluar 20,000 mesazhe, dhe krijuat nj\u00eb t\u00eb ri, numri i mesazheve nuk do t\u00eb p\u00ebrputhet shpejt. Prandaj, p\u00ebr t\u00eb pasur dy konsumator\u00eb paralel\u00eb, duhet t\u00eb merresh me partitions.<\/p>\n<h2>Monitorimi<\/h2>\n<p>\nMendoj se, sipas monitorimeve, do t\u00eb jet\u00eb akoma m\u00eb e qart\u00eb se cilat probleme ka qasja aktuale.<\/p>\n<p>P\u00ebr shembull, num\u00ebrojm\u00eb sa produkte n\u00eb baz\u00eb sapo kan\u00eb ndryshuar statusin, dhe p\u00ebr pasoj\u00eb, p\u00ebr k\u00ebto ndryshime duhet t\u00eb ndodhin ngjarje, dhe e d\u00ebrgojm\u00eb k\u00ebt\u00eb num\u00ebr n\u00eb sistemin ton\u00eb t\u00eb monitorimit. M\u00eb pas nga Kafka marrim numrin e dyt\u00eb, sa n\u00eb t\u00eb v\u00ebrtet\u00eb jan\u00eb regjistruar ngjarje. \u00cbsht\u00eb e qart\u00eb, diferenca midis k\u00ebtyre dy numrave gjithmon\u00eb duhet t\u00eb jet\u00eb zero.<\/p>\n<p><img decoding=\"async\" alt=\"P\u00ebrvoja e zhvillimit t\u00eb sh\u00ebrbimit Refund Tool me API asinkron mbi Kafka\" src=\"\/wp-content\/uploads\/2019\/04\/07d8ed08514f2fb97d9019466b96342c.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nP\u00ebr m\u00eb tep\u00ebr, duhet t\u00eb monitorojm\u00eb si shkon prodhuesi, n\u00ebse events-bus ka pranuar mesazhet, dhe si shkon konsumatori. P\u00ebr shembull, n\u00eb grafik\u00ebt m\u00eb posht\u00eb, Refund Tool \u00ebsht\u00eb mir\u00eb, nd\u00ebrsa BOB ka duksh\u00ebm disa probleme (pikat blu).<\/p>\n<p><img decoding=\"async\" alt=\"P\u00ebrvoja e zhvillimit t\u00eb sh\u00ebrbimit Refund Tool me API asinkron mbi Kafka\" src=\"\/wp-content\/uploads\/2019\/04\/57112dbe70d2b388c53f19c34cca6f63.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nKisha p\u00ebrmendur tashm\u00eb vones\u00ebn e grupit t\u00eb konsumator\u00ebve. N\u00eb thelb, kjo \u00ebsht\u00eb sasia e mesazheve t\u00eb pa lexuara. N\u00eb t\u00ebr\u00ebsi, konsumator\u00ebt tan\u00eb punojn\u00eb shpejt, prandaj vonesa zakonisht \u00ebsht\u00eb 0, por ndonj\u00ebher\u00eb mund t\u00eb ket\u00eb nj\u00eb kulm t\u00eb shkurt\u00ebr. Kafka e b\u00ebn k\u00ebt\u00eb nga kutia, por duhet t\u00eb caktohet nj\u00eb interval i caktuar. <\/p>\n<p>Ka nj\u00eb projekt <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/linkedin\/Burrow\">Burrow<\/a><\/noindex>, i cili do t'ju jap\u00eb m\u00eb shum\u00eb informacion p\u00ebr Kafka. Ai thjesht ofron statusin e grupit t\u00eb konsumator\u00ebve p\u00ebrmes API-s\u00eb, si\u00e7 \u00ebsht\u00eb statusi i grupit t\u00eb konsumator\u00ebve. P\u00ebrve\u00e7 OK dhe Failed, aty ka edhe warning, dhe do t\u00eb mund t\u00eb m\u00ebsoni se konsumator\u00ebt tuaj nuk po arrijn\u00eb ritmin e prodhimit - nuk po arrijn\u00eb t\u00eb lexojn\u00eb at\u00eb q\u00eb shkruhet. Sistemi \u00ebsht\u00eb mjaft i zgjuar, \u00ebsht\u00eb komod p\u00ebr t'u p\u00ebrdorur. <\/p>\n<p><img decoding=\"async\" alt=\"P\u00ebrvoja e zhvillimit t\u00eb sh\u00ebrbimit Refund Tool me API asinkron mbi Kafka\" src=\"\/wp-content\/uploads\/2019\/04\/cece8495801e187b155487a802e1a35a.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nK\u00ebshtu duket p\u00ebrgjigja p\u00ebrmes API-s\u00eb. K\u00ebtu \u00ebsht\u00eb grupi bob-live-fifa, partition refund.update.v1, statusi OK, lag 0 - offseti i fundit i p\u00ebrfunduar \u00ebsht\u00eb ky.<\/p>\n<p><img decoding=\"async\" alt=\"P\u00ebrvoja e zhvillimit t\u00eb sh\u00ebrbimit Refund Tool me API asinkron mbi Kafka\" src=\"\/wp-content\/uploads\/2019\/04\/1538b2ccc390e9b83075f54566f1039b.png\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<br \/>\nMonitorimi <strong>updated_at SLA (e bllokuar)<\/strong> Un\u00eb tashm\u00eb kam p\u00ebrmendur. P\u00ebr shembull, artikulli kaloi n\u00eb statusin q\u00eb \u00ebsht\u00eb gati p\u00ebr kthim. Ne vendosim Cron, i cili thot\u00eb se n\u00ebse brenda 5 minutash ky objekt nuk kalon n\u00eb refund (ne kthejm\u00eb parat\u00eb p\u00ebrmes sistemit t\u00eb pagesave shum\u00eb shpejt), at\u00ebher\u00eb di\u00e7ka sigurisht ka shkuar keq, dhe ky \u00ebsht\u00eb nj\u00eb rast p\u00ebr suportin. Prandaj merrni thjesht Cron, i cili lexon k\u00ebto gj\u00ebra, dhe n\u00ebse jan\u00eb m\u00eb shum\u00eb se 0, at\u00ebher\u00eb d\u00ebrgon nj\u00eb alarm.<\/p>\n<p><b>P\u00ebrmbledhja, p\u00ebrdorimi i ngjarjeve \u00ebsht\u00eb i p\u00ebrshtatsh\u00ebm kur<\/b>:<\/p>\n<ul>\n<li>informacioni i nevojitet disa sistemeve;<\/li>\n<li>rezultati i p\u00ebrpunimit nuk ka r\u00ebnd\u00ebsi;<\/li>\n<li>ka pak ngjarje ose ngjarjet jan\u00eb t\u00eb vogla. <\/li>\n<\/ul>\n<blockquote><p>Duket se artikulli ka nj\u00eb tem\u00eb mjaft specifike - API asinkron mbi Kafka, por p\u00ebr t\u00eb lidhur me t\u00eb, dua menj\u00ebher\u00eb t\u00eb rekomandoj shum\u00eb cosa.<br \/>\nS\u00eb pari, e ardhmja <noindex><a rel=\"nofollow\" href=\"https:\/\/www.highload.ru\/\">HighLoad++<\/a><\/noindex> duhet t\u00eb presim deri n\u00eb n\u00ebntor, por tashm\u00eb n\u00eb prill do t\u00eb ket\u00eb versionin e tij n\u00eb Sh\u00ebn Petersburg, nd\u00ebrsa n\u00eb qershor do t\u00eb flasim p\u00ebr ngarkesa t\u00eb larta n\u00eb Novosibirsk.<br \/>\nS\u00eb dyti, autori i raportit, Sergey Zaika, \u00ebsht\u00eb pjes\u00eb e Komitetit Programor t\u00eb konferenc\u00ebs son\u00eb t\u00eb re mbi menaxhimin e njohurive. <noindex><a rel=\"nofollow\" href=\"https:\/\/knowledgeconf.ru\/2019\">KnowledgeConf<\/a><\/noindex>. Konferenca \u00ebsht\u00eb nj\u00eb ditore, do t\u00eb mbahet m\u00eb 26 prill, por programi \u00ebsht\u00eb shum\u00eb i ngjeshur.<br \/>\nDhe gjithashtu n\u00eb maj do t\u00eb ket\u00eb <noindex><a rel=\"nofollow\" href=\"https:\/\/phprussia.ru\/2019\">PHP Rusia<\/a><\/noindex> dhe\u00a0<noindex><a rel=\"nofollow\" href=\"https:\/\/ritfest.ru\/2019\">RIT++<\/a><\/noindex> (me DevOpsConf n\u00eb p\u00ebrb\u00ebrje) - atje gjithashtu mund t\u00eb ofroni tem\u00ebn tuaj, t\u00eb flisni p\u00ebr p\u00ebrvoj\u00ebn tuaj dhe t\u00eb ankohemi p\u00ebr goditjet tuaja t\u00eb papritura.<\/p><\/blockquote>\n<p>Burimi: <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.2 - 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\/sq\/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.2\" \/>\n\t\t<meta property=\"og:locale\" content=\"sq_AL\" \/>\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\/sq\/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\udd47P\u00ebrvoja e zhvillimit t\u00eb sh\u00ebrbimit Refund Tool me API asinkron mbi Kafka | ProHoster","description":"\u00c7far\u00eb mund ta b\u00ebj\u00eb nj\u00eb kompani kaq t\u00eb madhe si Lamoda, me nj\u00eb proces t\u00eb rregullt dhe dhjet\u00ebra sh\u00ebrbime t\u00eb lidhura, t\u00eb ndryshoj\u00eb duksh\u00ebm qasjen?","canonical_url":"https:\/\/prohoster.info\/sq\/blog\/administrirovanie\/opyt-razrabotki-servisa-refund-tool-s-asinhronnym-api-na-kafka","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"sq_AL","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\/sq\/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\/sq\/wp-json\/wp\/v2\/posts\/30778","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/sq\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/sq\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/sq\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/sq\/wp-json\/wp\/v2\/comments?post=30778"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/sq\/wp-json\/wp\/v2\/posts\/30778\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/prohoster.info\/sq\/wp-json\/wp\/v2\/media\/22763"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/sq\/wp-json\/wp\/v2\/media?parent=30778"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/sq\/wp-json\/wp\/v2\/categories?post=30778"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/sq\/wp-json\/wp\/v2\/tags?post=30778"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}