{"id":56186,"date":"2020-02-06T00:00:00","date_gmt":"2020-02-05T21:00:00","guid":{"rendered":"https:\/\/prohoster.info\/blog\/blog_prohoster\/povtornaya-obrabotka-sobytij-poluchennyh-iz-kafka"},"modified":"2020-02-18T14:04:24","modified_gmt":"2020-02-18T11:04:24","slug":"povtornaya-obrabotka-sobytij-poluchennyh-iz-kafka","status":"publish","type":"post","link":"https:\/\/prohoster.info\/sq\/blog\/administrirovanie\/povtornaya-obrabotka-sobytij-poluchennyh-iz-kafka","title":{"rendered":"Rip\u00ebrpunimi i ngjarjeve t\u00eb marra nga Kafka","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p><img decoding=\"async\" alt=\"Rip\u00ebrpunimi i ngjarjeve t\u00eb marra nga Kafka\" src=\"\/wp-content\/uploads\/2020\/02\/d04319691af5c5de40ccfe4a2268558c.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>P\u00ebrsh\u00ebndetje, Habr.<\/p>\n<p><\/p>\n<p>S\u00eb fundi kam <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/tinkoff\/blog\/481784\/\">ndar\u00eb p\u00ebrvoj\u00ebn<\/a><\/noindex> n\u00eb lidhje me parametrat q\u00eb ne si ekip shpesh p\u00ebrdorim p\u00ebr Kafka Producer dhe Consumer, p\u00ebr t'u afruar me dor\u00ebzimin e garantuar. N\u00eb k\u00ebt\u00eb artikull d\u00ebshiroj t\u00eb tregoj se si organizuam riprocesimin e nj\u00eb ngjarjeje t\u00eb marr\u00eb nga Kafka, si rezultat i pap\u00ebrshtatshm\u00ebris\u00eb s\u00eb nj\u00eb sistemi t\u00eb jasht\u00ebm.<\/p>\n<p><\/p>\n<p>Aplikacionet moderne funksionojn\u00eb n\u00eb nj\u00eb mjedis shum\u00eb t\u00eb komplikuar. Logjika e biznesit, e mb\u00ebshtjell\u00eb n\u00eb nj\u00eb grumbull teknologjik modern, q\u00eb punon n\u00eb nj\u00eb imazh Docker, i menaxhuar nga nj\u00eb orkestrator si Kubernetes ose OpenShift, dhe q\u00eb komunikon me aplikacione t\u00eb tjera ose zgjidhje enterprise p\u00ebrmes nj\u00eb vargu ruterash fizik dhe virtual. N\u00eb nj\u00eb mjedis t\u00eb till\u00eb, gjithmon\u00eb mund t\u00eb ndodhin probleme, prandaj riprocesimi i ngjarjeve n\u00eb rastin e pap\u00ebrshtatshm\u00ebris\u00eb s\u00eb nj\u00eb prej sistemeve t\u00eb jashtme \u00ebsht\u00eb nj\u00eb pjes\u00eb e r\u00ebnd\u00ebsishme e proceseve tona t\u00eb biznesit.<\/p>\n<p><noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<h2 id=\"kak-bylo-do-kafka\">Si ishte para Kafka<\/h2>\n<p><\/p>\n<p>M\u00eb par\u00eb n\u00eb projekt, ne p\u00ebrdorim IBM MQ p\u00ebr dor\u00ebzimin e mesazheve n\u00eb m\u00ebnyr\u00eb asinkrone. Kur ndodhte ndonj\u00eb gabim gjat\u00eb pun\u00ebs s\u00eb sh\u00ebrbimit, mesazhi i marr\u00eb mund t\u00eb vendosej n\u00eb radh\u00ebn e mesazheve t\u00eb vdekura (DLQ) p\u00ebr shqyrtim t\u00eb m\u00ebtejsh\u00ebm. DLQ krijohej pran\u00eb radh\u00ebs hyr\u00ebse, dhe kalimi i mesazhit ndodhte brenda IBM MQ. <\/p>\n<p><\/p>\n<p>N\u00ebse gabimi kishte nj\u00eb natyr\u00eb t\u00eb p\u00ebrkohshme dhe ne mund ta p\u00ebrcaktonim k\u00ebt\u00eb (p\u00ebr shembull, ResourceAccessException gjat\u00eb nj\u00eb thirrjeje HTTP ose MongoTimeoutException gjat\u00eb nj\u00eb k\u00ebrkese n\u00eb MongoDb), at\u00ebher\u00eb strategjia e rip\u00ebrs\u00ebritjeve hynte n\u00eb fuqi. Pavar\u00ebsisht nga ndarjet e logjik\u00ebs s\u00eb aplikacionit, mesazhi i origjin\u00ebs transferohej ose n\u00eb radh\u00ebn sistemike p\u00ebr d\u00ebrgim t\u00eb vonuar, ose n\u00eb nj\u00eb aplikacion t\u00eb ve\u00e7ant\u00eb, i cili u krijua vite m\u00eb par\u00eb p\u00ebr rip\u00ebrs\u00ebritjen e mesazheve. N\u00eb k\u00ebt\u00eb rast, n\u00eb kok\u00ebn e mesazhit shkruhej numri i rip\u00ebrs\u00ebritjes, i lidhur me intervalin e vones\u00ebs ose me fundin e strategjis\u00eb n\u00eb nivelin e aplikacionit. N\u00ebse arrijm\u00eb fundin e strategjis\u00eb, por sistemi i jasht\u00ebm ende nuk \u00ebsht\u00eb i disponuesh\u00ebm, at\u00ebher\u00eb mesazhi do t\u00eb vendoset n\u00eb DLQ p\u00ebr shqyrtim manual.<\/p>\n<p><\/p>\n<h2 id=\"poisk-resheniya\">K\u00ebrkimi i zgjidhjes<\/h2>\n<p><\/p>\n<p><noindex><a rel=\"nofollow\" href=\"https:\/\/www.google.com\/search?q=kafka+retry+message\">Duke k\u00ebrkuar n\u00eb internet<\/a><\/noindex>, mund t\u00eb gjejm\u00eb k\u00ebt\u00eb <noindex><a rel=\"nofollow\" href=\"https:\/\/blog.pragmatists.com\/retrying-consumer-architecture-in-the-apache-kafka-939ac4cb851a\">vendim<\/a><\/noindex>. N\u00ebse e shkurtojm\u00eb, propozohet t\u00eb krijohet nj\u00eb tem\u00eb p\u00ebr \u00e7do interval vonese dhe t\u00eb implementohen n\u00eb an\u00ebn e aplikacionit Consumer q\u00eb do t\u00eb lexojn\u00eb mesazhet me vones\u00ebn e nevojshme. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Rip\u00ebrpunimi i ngjarjeve t\u00eb marra nga Kafka\" src=\"\/wp-content\/uploads\/2020\/02\/718c4c3f71ccf95b5a6f60e1b2c685d2.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Megjith\u00ebse ka nj\u00eb num\u00ebr t\u00eb madh komentesh pozitive, m\u00eb duket se nuk \u00ebsht\u00eb krejt\u00ebsisht e suksesshme. S\u00eb pari, sepse zhvilluesi, p\u00ebrve\u00e7 realizimit t\u00eb k\u00ebrkesave t\u00eb biznesit, do t\u00eb duhet t\u00eb shpenzoj\u00eb shum\u00eb koh\u00eb p\u00ebr t\u00eb realizuar mekanizmin e p\u00ebrshkruar.<\/p>\n<p><\/p>\n<p>P\u00ebr m\u00eb tep\u00ebr, n\u00ebse menaxhimi i qasjes \u00ebsht\u00eb i aktivizuar n\u00eb klasterin Kafka, do t'i duhet t\u00eb investoj\u00eb nj\u00eb koh\u00eb p\u00ebr t\u00eb krijuar temat dhe p\u00ebr t\u00eb siguruar qasjet e nevojshme p\u00ebr to. N\u00eb p\u00ebrve\u00e7im t\u00eb k\u00ebsaj, do t\u00eb duhet t\u00eb zgjidhni parametrin e duhur retention.ms p\u00ebr \u00e7do nga temat e riprovimit, n\u00eb m\u00ebnyr\u00eb q\u00eb mesazhet t\u00eb d\u00ebrgohen p\u00ebrs\u00ebri dhe t\u00eb mos humbasin. Zbatimi dhe k\u00ebrkesa e qasjeve do t\u00eb duhet t\u00eb p\u00ebrs\u00ebritet p\u00ebr \u00e7do sh\u00ebrbim ekzistues ose t\u00eb ri.<\/p>\n<p><\/p>\n<p>Tani le t\u00eb shohim se cilat mekanizma p\u00ebr p\u00ebrpunimin e p\u00ebrs\u00ebritur t\u00eb mesazheve na ofron spring-i n\u00eb p\u00ebrgjith\u00ebsi dhe spring-kafka n\u00eb ve\u00e7anti. Spring-kafka ka nj\u00eb var\u00ebsi tranzitive mbi spring-retry, i cili ofron abstraksione p\u00ebr menaxhimin e politikat e BackOff. Kjo \u00ebsht\u00eb nj\u00eb mjet mjaft fleksib\u00ebl, por nj\u00eb nga disavantazhet e tij t\u00eb r\u00ebnd\u00ebsishme \u00ebsht\u00eb ruajtja e mesazheve p\u00ebr rip\u00ebrpunim n\u00eb memorjen e aplikacionit. Kjo do t\u00eb thot\u00eb se rinisja e aplikacionit p\u00ebr shkak t\u00eb azhurnimit ose gabimeve gjat\u00eb p\u00ebrdorimit do t\u00eb \u00e7oj\u00eb n\u00eb humbjen e t\u00eb gjith\u00eb mesazheve q\u00eb presin p\u00ebr rip\u00ebrpunim. Duke qen\u00eb se ky pik\u00eb \u00ebsht\u00eb kritik p\u00ebr sistemin ton\u00eb, ne nuk e konsideruam m\u00eb tej.<\/p>\n<p><\/p>\n<p>Vet\u00eb spring-kafka ofron disa zbatime t\u00eb ContainerAwareErrorHandler, p\u00ebr shembull, <noindex><a rel=\"nofollow\" href=\"https:\/\/github.com\/spring-projects\/spring-kafka\/blob\/master\/spring-kafka\/src\/main\/java\/org\/springframework\/kafka\/listener\/SeekToCurrentErrorHandler.java\">SeekToCurrentErrorHandler<\/a><\/noindex>, me ndihm\u00ebn e s\u00eb cil\u00ebs mund t\u00eb p\u00ebrpunoni nj\u00eb mesazh m\u00eb von\u00eb pa nd\u00ebrruar offset n\u00eb rast gabimi. Prej versionit spring-kafka 2.3, \u00ebsht\u00eb b\u00ebr\u00eb e mundur t\u00eb p\u00ebrcaktojn\u00eb BackOffPolicy.<\/p>\n<p><\/p>\n<p>Ky qasje lejon q\u00eb mesazhet q\u00eb rip\u00ebrpunohen t\u00eb p\u00ebrjetojn\u00eb rinisjen e aplikacionit, por mekanizmi DLQ ende mungon. Ky variant ishte ai q\u00eb ne zgjodh\u00ebm n\u00eb fillim t\u00eb vitit 2019, duke qen\u00eb optimist se DLQ nuk do t\u00eb ishte e nevojshme (na ndihmoi dhe me t\u00eb v\u00ebrtet\u00eb nuk u nevojit p\u00ebr disa muaj shfryt\u00ebzimi t\u00eb aplikacionit me nj\u00eb sistem t\u00eb till\u00eb t\u00eb rip\u00ebrpunimit). Gabimet temporale \u00e7onin n\u00eb aktivizimin e SeekToCurrentErrorHandler. Gabimet e tjera shfaqeshin n\u00eb log, \u00e7onin n\u00eb nd\u00ebrrimin e offset, dhe p\u00ebrpunimi vazhdonte me mesazhin tjet\u00ebr.<\/p>\n<p><\/p>\n<h2 id=\"itogovoe-reshenie\">Zgjidhja p\u00ebrfundimtare<\/h2>\n<p><\/p>\n<p>Implementimi i bazuar n\u00eb SeekToCurrentErrorHandler na shtyu t\u00eb zhvillonim nj\u00eb mekaniz\u00ebm t\u00eb vetin p\u00ebr ri-d\u00ebrgimin e mesazheve.<\/p>\n<p><\/p>\n<p>S\u00eb pari, ne doja t\u00eb shfryt\u00ebzojm\u00eb p\u00ebrvoj\u00ebn ekzistuese dhe ta zgjeronim at\u00eb n\u00eb var\u00ebsi t\u00eb logjik\u00ebs s\u00eb aplikacionit. P\u00ebr nj\u00eb aplikacion me logjik\u00eb lineare, optimale do t\u00eb ishte t\u00eb ndalosh leximin e mesazheve t\u00eb reja p\u00ebr nj\u00eb periudh\u00eb t\u00eb vog\u00ebl kohore, t\u00eb caktuar n\u00eb kuad\u00ebr t\u00eb strategjis\u00eb s\u00eb ri-thirrjeve. P\u00ebr aplikacionet e tjera, do t\u00eb d\u00ebshironim t\u00eb kishim nj\u00eb pik\u00eb t\u00eb vetme q\u00eb do t\u00eb garantonte p\u00ebrmbushjen e strategjis\u00eb s\u00eb ri-thirrjeve. P\u00ebrve\u00e7 k\u00ebsaj, kjo pik\u00eb e vetme duhet t\u00eb ket\u00eb funksionalitetin e DLQ p\u00ebr t\u00eb dyja qasjet.<\/p>\n<p><\/p>\n<p>Strategjia e ri-thirrjeve duhet t\u00eb ruhet n\u00eb aplikacionin q\u00eb p\u00ebrgjigjet p\u00ebr t\u00eb marr\u00eb intervalin e ardhsh\u00ebm n\u00eb rast t\u00eb nj\u00eb gabimi t\u00eb p\u00ebrkohsh\u00ebm.<\/p>\n<p><\/p>\n<h3 id=\"ostanovka-consumera-dlya-prilozheniya-s-lineynoy-logikoy\">Ndalesa e Consumer-it p\u00ebr nj\u00eb aplikacion me logjik\u00eb lineare<\/h3>\n<p><\/p>\n<p>Kur punoni me spring-kafka, kodi p\u00ebr ndalimin e Consumer-it mund t\u00eb duket di\u00e7ka si kjo:<\/p>\n<p><\/p>\n<pre><code class=\"java\">public void pauseListenerContainer(MessageListenerContainer listenerContainer, \n                                   Instant retryAt) {\n        if (nonNull(retryAt) &amp;&amp; listenerContainer.isRunning()) {\n            listenerContainer.stop();\n            taskScheduler.schedule(() -&gt; listenerContainer.start(), retryAt);\n            return;\n        }\n        \/\/ n\u00eb DLQ\n    }<\/code><\/pre>\n<p><\/p>\n<p>N\u00eb shembullin e m\u00ebsip\u00ebrm, retryAt \u00ebsht\u00eb koha kur duhet t\u00eb rifilloni MessageListenerContainer-n, n\u00ebse ai \u00ebsht\u00eb ende duke punuar. Rihapja do t\u00eb ndodh\u00eb n\u00eb nj\u00eb thread t\u00eb ve\u00e7ant\u00eb, i nisur n\u00eb TaskScheduler, implementimin e t\u00eb cilit gjithashtu e ofron spring. <\/p>\n<p><\/p>\n<p>Vlera retryAt ne e gjejm\u00eb n\u00eb k\u00ebt\u00eb m\u00ebnyr\u00eb:<\/p>\n<p><\/p>\n<ol>\n<li>K\u00ebrkohet vlera e num\u00ebruesit t\u00eb ri-thirrjeve.<\/li>\n<li>N\u00eb p\u00ebrputhje me vler\u00ebn e num\u00ebruesit, k\u00ebrkohet intervali aktual i vones\u00ebs n\u00eb strategjin\u00eb e ri-thirrjeve. Strategjia shpallet brenda aplikacionit, p\u00ebr ruajtjen e saj ne zgjodh\u00ebm formatin JSON.<\/li>\n<li>Intervali i gjetur n\u00eb masivin JSON p\u00ebrmban numrin e sekondave, pas t\u00eb cilave do t\u00eb duhet t\u00eb p\u00ebrs\u00ebritet p\u00ebrpunimi. Ky num\u00ebr sekondash shtohet n\u00eb koh\u00ebn aktuale, duke formuar vler\u00ebn p\u00ebr retryAt.<\/li>\n<li>N\u00ebse intervali nuk gjendet, at\u00ebher\u00eb vlera retryAt \u00ebsht\u00eb null dhe mesazhi do t\u00eb d\u00ebrgohet n\u00eb DLQ p\u00ebr shqyrtim manual.<\/li>\n<\/ol>\n<p><\/p>\n<p>Me k\u00ebtij qasje, mbetet vet\u00ebm t\u00eb ruhet numri i p\u00ebrpjekjeve p\u00ebr \u00e7do mesazh q\u00eb \u00ebsht\u00eb tani n\u00eb procesim, p\u00ebr shembull n\u00eb memorien e aplikacionit. Ruajtja e numrit t\u00eb p\u00ebrpjekjeve n\u00eb memorien e aplikacionit nuk \u00ebsht\u00eb kritike p\u00ebr k\u00ebt\u00eb qasje, pasi aplikacioni me logjik\u00eb lineare nuk mund t\u00eb p\u00ebrpunoj\u00eb gjith\u00e7ka. N\u00eb krahasim me spring-retry, riparagjykimi i aplikacionit nuk do t\u00eb \u00e7oj\u00eb n\u00eb humbjen e t\u00eb gjitha mesazheve p\u00ebr rip\u00ebrpunim, por thjesht n\u00eb rinisjen e strategjis\u00eb. <\/p>\n<p><\/p>\n<p>Kjo qasje ndihmon n\u00eb leht\u00ebsimin e ngarkes\u00ebs nga sistemi i jasht\u00ebm, i cili mund t\u00eb jet\u00eb i paaksesuesh\u00ebm p\u00ebr shkak t\u00eb ngarkes\u00ebs shum\u00eb t\u00eb madhe. N\u00eb fjal\u00eb t\u00eb tjera, p\u00ebrve\u00e7 rip\u00ebrpunimit, kemi arritur n\u00eb implementimin e modelit <noindex><a rel=\"nofollow\" href=\"https:\/\/microservices.io\/patterns\/reliability\/circuit-breaker.html\">circuit breaker<\/a><\/noindex>.<\/p>\n<p><\/p>\n<p>N\u00eb rastin ton\u00eb, pragu i gabimit \u00ebsht\u00eb vet\u00ebm 1, dhe p\u00ebr t\u00eb minimizuar koh\u00ebn e vones\u00ebs s\u00eb sistemit p\u00ebr shkak t\u00eb nj\u00eb nd\u00ebrprerjeje t\u00eb p\u00ebrkohshme rrjetore, ne p\u00ebrdorim nj\u00eb strategji shum\u00eb granulare t\u00eb p\u00ebrpjekjeve t\u00eb rip\u00ebrs\u00ebritura me intervale t\u00eb vogla vonese. Kjo mund t\u00eb mos jet\u00eb e p\u00ebrshtatshme p\u00ebr t\u00eb gjitha aplikacionet e grupit, prandaj raporti midis pragut t\u00eb gabimit dhe madh\u00ebsis\u00eb s\u00eb intervalit duhet t\u00eb p\u00ebrcaktohet duke u bazuar n\u00eb karakteristikat e sistemit.<\/p>\n<p><\/p>\n<h3 id=\"otdelnoe-prilozhenie-dlya-obrabotki-soobscheniy-ot-prilozheniy-s-nedeterminirovannoy-logikoy\">Nj\u00eb aplikacion t\u00eb ve\u00e7ant\u00eb p\u00ebr t\u00eb p\u00ebrpunuar mesazhet nga aplikacionet me logjik\u00eb t\u00eb pabesueshme<\/h3>\n<p><\/p>\n<p>Ja nj\u00eb shembull kodi q\u00eb d\u00ebrgon nj\u00eb mesazh n\u00eb nj\u00eb aplikacion t\u00eb till\u00eb (Retryer), i cili do t\u00eb kryej\u00eb rip\u00ebrs\u00ebritjen n\u00eb tem\u00ebn DESTINATION kur t\u00eb arrij\u00eb koha RETRY_AT:<\/p>\n<p><\/p>\n<pre><code class=\"java\">\npublic  void retry(ConsumerRecord record, String retryToTopic, \n                         Instant retryAt, String counter, String groupId, Exception e) {\n        Headers headers = ofNullable(record.headers()).orElse(new RecordHeaders());\n        List<Header> arrayOfHeaders = \n            new ArrayList(Arrays.asList(headers.toArray()));\n        updateHeader(arrayOfHeaders, GROUP_ID, groupId::getBytes);\n        updateHeader(arrayOfHeaders, DESTINATION, retryToTopic::getBytes);\n        updateHeader(arrayOfHeaders, ORIGINAL_PARTITION, \n                     () -&gt; Integer.toString(record.partition()).getBytes());\n        if (nonNull(retryAt)) {\n            updateHeader(arrayOfHeaders, COUNTER, counter::getBytes);\n            updateHeader(arrayOfHeaders, SEND_TO, \"retry\"::getBytes);\n            updateHeader(arrayOfHeaders, RETRY_AT, retryAt.toString()::getBytes);\n        } else {\n            updateHeader(arrayOfHeaders, REASON, \n                         ExceptionUtils.getStackTrace(e)::getBytes);\n            updateHeader(arrayOfHeaders, SEND_TO, \"backout\"::getBytes);\n        }\n        ProducerRecord messageToSend =\n            new ProducerRecord(retryTopic, null, null, record.key(), record.value(), arrayOfHeaders);\n        kafkaTemplate.send(messageToSend);\n    }<\/code><\/pre>\n<p><\/p>\n<p>Nga shembulli duket se shum\u00eb informacion p\u00ebrcillet n\u00eb header. Vlera RETRY_AT \u00ebsht\u00eb e nj\u00ebjt\u00eb si p\u00ebr mekanizmin e p\u00ebrs\u00ebritjes p\u00ebrmes ndalimit t\u00eb Consumer\u2019it. P\u00ebrve\u00e7 DESTINATION dhe RETRY_AT, ne kalojm\u00eb:<\/p>\n<p><\/p>\n<ul>\n<li>GROUP_ID, p\u00ebr t\u00eb cilin grupohen mesazhet p\u00ebr analiz\u00eb manuale dhe thjeshtim t\u00eb k\u00ebrkimit.<\/li>\n<li>ORIGINAL_PARTITION, p\u00ebr t\u00eb ruajtur t\u00eb nj\u00ebjtin Consumer p\u00ebr rip\u00ebrpunim. Ky parametr mund t\u00eb jet\u00eb null, n\u00eb k\u00ebt\u00eb rast particion i ri do t\u00eb merret nga \u00e7el\u00ebsi record.key() i mesazhit origjinal.<\/li>\n<li>Vlera e p\u00ebrdit\u00ebsuar COUNTER, p\u00ebr t\u00eb ndjekur strategjin\u00eb e rip\u00ebrs\u00ebritjeve.<\/li>\n<li>SEND_TO \u2014 konstant, q\u00eb tregon n\u00ebse mesazhi duhet t\u00eb d\u00ebrgohet p\u00ebr rip\u00ebrpunim kur arrihet RETRY_AT ose t\u00eb vendoset n\u00eb DLQ.<\/li>\n<li>REASON \u2014 arsyeja p\u00ebr t\u00eb cil\u00ebn p\u00ebrpunimi i mesazhit u nd\u00ebrpre.<\/li>\n<\/ul>\n<p><\/p>\n<p>Retryer ruan mesazhet p\u00ebr d\u00ebrgim t\u00eb rip\u00ebrs\u00ebritur dhe analiz\u00eb manuale n\u00eb PostgreSQL. Nj\u00eb detyr\u00eb aktivizohet sipas orarit q\u00eb gjen mesazhet me RETRY_AT t\u00eb kaluar dhe i d\u00ebrgon ato p\u00ebrs\u00ebri n\u00eb particionin ORIGINAL_PARTITION t\u00eb tem\u00ebs DESTINATION me \u00e7el\u00ebsin record.key().<\/p>\n<p><\/p>\n<p>Pas d\u00ebrgimit t\u00eb mesazheve, ato fshihen nga PostgreSQL. Analiza manuale e mesazheve ndodh n\u00eb nj\u00eb UI t\u00eb thjesht\u00eb, e cila nd\u00ebrvepron me Retryer p\u00ebrmes REST API. Karakteristikat e tij kryesore jan\u00eb d\u00ebrgimi p\u00ebrs\u00ebri ose fshirja e mesazheve nga DLQ, shikimi i informacionit p\u00ebr gabimin dhe k\u00ebrkimi i mesazheve, p\u00ebr shembull, sipas emrit t\u00eb gabimit. <\/p>\n<p><\/p>\n<p>Duke qen\u00eb se n\u00eb klasteret tona \u00ebsht\u00eb aktivizuar menaxhimi i qasjes, \u00ebsht\u00eb e nevojshme q\u00eb t\u00eb k\u00ebrkohet qasje shtes\u00eb n\u00eb tem\u00ebn q\u00eb d\u00ebgjon Retryer, dhe t'i jepet mund\u00ebsia Retryer t\u00eb shkruaj\u00eb n\u00eb tem\u00ebn DESTINATION. Kjo \u00ebsht\u00eb e pak\u00ebndshme, por, ndryshe nga qasja me tem\u00ebn n\u00eb interval, ne kemi nj\u00eb DLQ t\u00eb plot\u00eb dhe nj\u00eb UI p\u00ebr menaxhimin e saj.<\/p>\n<p><\/p>\n<p>Ka raste kur tema hyr\u00ebse lexohet nga disa grupe t\u00eb ndryshme konsumatore, aplikacionet e t\u00eb cilave zbatojn\u00eb logjik\u00eb t\u00eb ndryshme. Rip\u00ebrpunimi i mesazhit p\u00ebrmes Retryer p\u00ebr nj\u00eb nga k\u00ebto aplikacione do t\u00eb \u00e7oj\u00eb n\u00eb nj\u00eb kopje tjet\u00ebr n\u00eb tjetrin. P\u00ebr t'u mbrojtur nga kjo, krijojm\u00eb nj\u00eb tem\u00eb t\u00eb ve\u00e7ant\u00eb p\u00ebr rip\u00ebrpunim. Tema hyr\u00ebse dhe retry-t\u00ebma mund t\u00eb lexohen nga e nj\u00ebjta Consumer pa ndonj\u00eb kufizim. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Rip\u00ebrpunimi i ngjarjeve t\u00eb marra nga Kafka\" src=\"\/wp-content\/uploads\/2020\/02\/06f2355839c6dd812ee3304bf2c72226.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>N\u00eb m\u00ebnyr\u00eb t\u00eb parazgjedhur, kjo qasje nuk ofron mund\u00ebsi p\u00ebr nj\u00eb circuit breaker, megjithat\u00eb mund t\u00eb shtohet n\u00eb aplikacion p\u00ebrmes <noindex><a rel=\"nofollow\" href=\"https:\/\/spring.io\/projects\/spring-cloud-netflix\">spring-cloud-netflix<\/a><\/noindex> ose t\u00eb riut <noindex><a rel=\"nofollow\" href=\"https:\/\/spring.io\/projects\/spring-cloud-circuitbreaker\">spring cloud circuit breaker<\/a><\/noindex>, duke mb\u00ebshtjell\u00eb vendet e thirrjeve t\u00eb sh\u00ebrbimeve t\u00eb jashtme n\u00eb p\u00ebrkat\u00ebsit\u00eb p\u00ebrkat\u00ebse. P\u00ebr m\u00eb tep\u00ebr, shfaqet mund\u00ebsia e zgjedhjes s\u00eb strategjis\u00eb p\u00ebr <noindex><a rel=\"nofollow\" href=\"https:\/\/docs.microsoft.com\/en-us\/azure\/architecture\/patterns\/bulkhead\">bulkhead<\/a><\/noindex> paterni, q\u00eb gjithashtu mund t\u00eb jet\u00eb e dobishme. P\u00ebr shembull, n\u00eb spring-cloud-netflix kjo mund t\u00eb jet\u00eb pool me tela ose semafor.<\/p>\n<p><\/p>\n<h2 id=\"vyvod\">P\u00ebrfundimi<\/h2>\n<p><\/p>\n<p>Si p\u00ebrfundim, ne kemi nj\u00eb aplikacion t\u00eb ve\u00e7ant\u00eb q\u00eb lejon p\u00ebrs\u00ebritjen e p\u00ebrpunimit t\u00eb mesazheve gjat\u00eb munges\u00ebs s\u00eb p\u00ebrkohshme t\u00eb ndonj\u00eb sistemi t\u00eb jasht\u00ebm.<\/p>\n<p><\/p>\n<p>Nj\u00eb nga p\u00ebrfitimet kryesore t\u00eb aplikacionit \u00ebsht\u00eb se ai mund t\u00eb p\u00ebrdoret nga sistemet e jashtme q\u00eb funksionojn\u00eb n\u00eb t\u00eb nj\u00ebjtin klaster Kafka, pa pasur nevoj\u00eb p\u00ebr ndryshime t\u00eb r\u00ebnd\u00ebsishme nga ana e tyre! Ky aplikacion do t\u00eb ket\u00eb nevoj\u00eb vet\u00ebm p\u00ebr t\u00eb marr\u00eb qasje n\u00eb tem\u00ebn e retry-it, p\u00ebr t\u00eb plot\u00ebsuar disa k\u00ebshilla Kafka dhe p\u00ebr t\u00eb d\u00ebrguar mesazhin n\u00eb Retryer. Nuk ka nevoj\u00eb t\u00eb ngritet ndonj\u00eb infrastruktur\u00eb shtes\u00eb. Dhe p\u00ebr t\u00eb reduktuar numrin e mesazheve q\u00eb kalohen nga aplikacioni n\u00eb Retryer dhe prap\u00eb, ne kemi ve\u00e7uar aplikacione me logjik\u00eb linjare dhe kemi realizuar p\u00ebrs\u00ebritjen n\u00eb to p\u00ebrmes ndalimit t\u00eb Consumer.<\/p>\n<p>Burimi: <a content=\"nofollow\" rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/tinkoff\/blog\/487094\/\">habr.com<\/a><\/p>","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"excerpt":{"rendered":"<p>\u041f\u0440\u0438\u0432\u0435\u0442, \u0425\u0430\u0431\u0440. \u041d\u0435\u0434\u0430\u0432\u043d\u043e \u044f \u043f\u043e\u0434\u0435\u043b\u0438\u043b\u0441\u044f \u043e\u043f\u044b\u0442\u043e\u043c \u043e \u0442\u043e\u043c, \u043a\u0430\u043a\u0438\u0435 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u044b \u043c\u044b \u0432 \u043a\u043e\u043c\u0430\u043d\u0434\u0435 \u0447\u0430\u0449\u0435 \u0432\u0441\u0435\u0433\u043e \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u0434\u043b\u044f Kafka Producer \u0438 Consumer, \u0447\u0442\u043e\u0431\u044b \u043f\u0440\u0438\u0431\u043b\u0438\u0437\u0438\u0442\u044c\u0441\u044f \u043a \u0433\u0430\u0440\u0430\u043d\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u043e\u0439 \u0434\u043e\u0441\u0442\u0430\u0432\u043a\u0435. \u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u0445\u043e\u0447\u0443 \u0440\u0430\u0441\u0441\u043a\u0430\u0437\u0430\u0442\u044c, \u043a\u0430\u043a \u043c\u044b \u043e\u0440\u0433\u0430\u043d\u0438\u0437\u043e\u0432\u0430\u043b\u0438 \u043f\u043e\u0432\u0442\u043e\u0440\u043d\u0443\u044e \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0443 \u0441\u043e\u0431\u044b\u0442\u0438\u044f, \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u043e\u0433\u043e \u0438\u0437 Kafka, \u0432 \u0440\u0435\u0437\u0443\u043b\u044c\u0442\u0430\u0442\u0435 \u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e\u0439 \u043d\u0435\u0434\u043e\u0441\u0442\u0443\u043f\u043d\u043e\u0441\u0442\u0438 \u0432\u043d\u0435\u0448\u043d\u0435\u0439 \u0441\u0438\u0441\u0442\u0435\u043c\u044b. \u0421\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0442 \u0432 \u043e\u0447\u0435\u043d\u044c \u0441\u043b\u043e\u0436\u043d\u043e\u0439 \u0441\u0440\u0435\u0434\u0435. \u0411\u0438\u0437\u043d\u0435\u0441-\u043b\u043e\u0433\u0438\u043a\u0430, \u043e\u0431\u0435\u0440\u043d\u0443\u0442\u0430\u044f [&hellip;]<\/p>\n","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[688],"tags":[],"class_list":["post-56186","post","type-post","status-publish","format-standard","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=\"\u041f\u0440\u0438\u0432\u0435\u0442, \u0425\u0430\u0431\u0440. \u041d\u0435\u0434\u0430\u0432\u043d\u043e.\" \/>\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\/povtornaya-obrabotka-sobytij-poluchennyh-iz-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\u041f\u043e\u0432\u0442\u043e\u0440\u043d\u0430\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u0441\u043e\u0431\u044b\u0442\u0438\u0439, \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u044b\u0445 \u0438\u0437 Kafka | ProHoster\" \/>\n\t\t<meta property=\"og:description\" content=\"\u041f\u0440\u0438\u0432\u0435\u0442, \u0425\u0430\u0431\u0440. \u041d\u0435\u0434\u0430\u0432\u043d\u043e.\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/prohoster.info\/sq\/blog\/administrirovanie\/povtornaya-obrabotka-sobytij-poluchennyh-iz-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=\"2020-02-05T21:00:00+00:00\" \/>\n\t\t<meta property=\"article:modified_time\" content=\"2020-02-18T11:04:24+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\u00ebrs\u00ebritja e p\u00ebrpunimit t\u00eb ngjarjeve t\u00eb marr\u00eb nga Kafka | ProHoster","description":"P\u00ebrsh\u00ebndetje, Habr. S\u00eb fundmi.","canonical_url":"https:\/\/prohoster.info\/sq\/blog\/administrirovanie\/povtornaya-obrabotka-sobytij-poluchennyh-iz-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\u041f\u043e\u0432\u0442\u043e\u0440\u043d\u0430\u044f \u043e\u0431\u0440\u0430\u0431\u043e\u0442\u043a\u0430 \u0441\u043e\u0431\u044b\u0442\u0438\u0439, \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u043d\u044b\u0445 \u0438\u0437 Kafka | ProHoster","og:description":"\u041f\u0440\u0438\u0432\u0435\u0442, \u0425\u0430\u0431\u0440. \u041d\u0435\u0434\u0430\u0432\u043d\u043e.","og:url":"https:\/\/prohoster.info\/sq\/blog\/administrirovanie\/povtornaya-obrabotka-sobytij-poluchennyh-iz-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":"2020-02-05T21:00:00+00:00","article:modified_time":"2020-02-18T11:04:24+00:00","article:publisher":"https:\/\/www.facebook.com\/prohoster","article:author":"https:\/\/www.facebook.com\/prohoster"},"aioseo_meta_data":{"post_id":"56186","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":null,"breadcrumb_settings":null,"limit_modified_date":false,"reviewed_by":null,"ai":null,"created":"2021-02-28 19:29:19","updated":"2022-10-02 15:56:10","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\/56186","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=56186"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/sq\/wp-json\/wp\/v2\/posts\/56186\/revisions"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/sq\/wp-json\/wp\/v2\/media?parent=56186"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/sq\/wp-json\/wp\/v2\/categories?post=56186"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/sq\/wp-json\/wp\/v2\/tags?post=56186"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}