{"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\/az\/blog\/administrirovanie\/povtornaya-obrabotka-sobytij-poluchennyh-iz-kafka","title":{"rendered":"Kafka-dan al\u0131nan hadis\u0259l\u0259rin t\u0259krar emal\u0131","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p><img decoding=\"async\" alt=\"Kafka-dan al\u0131nan hadis\u0259l\u0259rin t\u0259krar emal\u0131\" src=\"\/wp-content\/uploads\/2020\/02\/d04319691af5c5de40ccfe4a2268558c.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Salam, Habr.<\/p>\n<p><\/p>\n<p>Son zamanlarda <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/company\/tinkoff\/blog\/481784\/\">t\u0259cr\u00fcb\u0259mi b\u00f6l\u00fc\u015fd\u00fcm<\/a><\/noindex> Kafka Producer v\u0259 Consumer \u00fc\u00e7\u00fcn komandam\u0131z\u0131n daha \u00e7ox istifad\u0259 etdiyi parametrl\u0259r bar\u0259d\u0259. Bu m\u0259qal\u0259d\u0259, xarici sistemin m\u00fcv\u0259qq\u0259ti \u0259l\u00e7atan olmamas\u0131 n\u0259tic\u0259sind\u0259 Kafka-dan al\u0131nan hadis\u0259nin t\u0259krar emal\u0131n\u0131 nec\u0259 t\u0259\u015fkil etdiyimizi anlatmaq ist\u0259yir\u0259m.<\/p>\n<p><\/p>\n<p>M\u00fcasir t\u0259tbiql\u0259r \u00e7ox m\u00fcr\u0259kk\u0259b bir m\u00fchitd\u0259 f\u0259aliyy\u0259t g\u00f6st\u0259rir. M\u00fcasir texnoloji y\u0131\u011f\u0131nla sar\u0131lan biznes m\u0259nti\u011fi, Kubernetes v\u0259 ya OpenShift kimi orkestrator t\u0259r\u0259find\u0259n idar\u0259 olunan Docker imici i\u00e7ind\u0259dir v\u0259 dig\u0259r t\u0259tbiql\u0259rl\u0259 v\u0259 ya enterprise h\u0259ll\u0259ri il\u0259 fiziki v\u0259 virtual y\u00f6nl\u0259ndiricil\u0259r silsil\u0259si vasit\u0259sil\u0259 \u00fcnsiyy\u0259t qurur. Bel\u0259 bir m\u00fchitd\u0259 h\u0259r zaman bir \u015feyin pozulmas\u0131 m\u00fcmk\u00fcnd\u00fcr, buna g\u00f6r\u0259 d\u0259 xarici sisteml\u0259rd\u0259n birinin \u0259l\u00e7atan olmamas\u0131 hal\u0131nda hadis\u0259l\u0259rin t\u0259krar emal\u0131 bizim biznes prosesl\u0259rimizin m\u00fch\u00fcm bir hiss\u0259sidir.<\/p>\n<p><noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<h2 id=\"kak-bylo-do-kafka\">Kafka-dan \u0259vv\u0259l<\/h2>\n<p><\/p>\n<p>Layih\u0259d\u0259 \u0259vv\u0259lc\u0259 asinxron mesaj g\u00f6nd\u0259rm\u0259 \u00fc\u00e7\u00fcn IBM MQ istifad\u0259 edirdik. Xidm\u0259tin i\u015f prosesi zaman\u0131 h\u0259r hans\u0131 bir x\u0259ta ba\u015f verdikd\u0259, al\u0131nan mesaj dead-letter-queue (DLQ) daxilind\u0259 yar\u0131d\u0131l\u0131b manual t\u0259hlil \u00fc\u00e7\u00fcn g\u00f6nd\u0259ril\u0259 bil\u0259rdi. DLQ, giri\u015f qov\u015fa\u011f\u0131n\u0131n yan\u0131nda yarad\u0131l\u0131rd\u0131 v\u0259 mesaj\u0131n k\u00f6\u00e7\u00fcr\u00fclm\u0259si IBM MQ daxilind\u0259 ba\u015f verirdi. <\/p>\n<p><\/p>\n<p>\u018fg\u0259r x\u0259ta m\u00fcv\u0259qq\u0259ti xarakter da\u015f\u0131y\u0131rd\u0131sa v\u0259 biz bunu m\u00fc\u0259yy\u0259n ed\u0259 bilirdiks\u0259 (m\u0259s\u0259l\u0259n, HTTP \u00e7a\u011f\u0131r\u0131\u015f\u0131 zaman\u0131 ResourceAccessException v\u0259 ya MongoDb-y\u0259 edil\u0259n sor\u011fu zaman\u0131 MongoTimeoutException), o zaman t\u0259krar \u00e7a\u011f\u0131rmalar strategiyas\u0131 devreye girirdi. T\u0259tbiqin m\u0259ntiqinin \u015fax\u0259l\u0259nm\u0259sind\u0259n as\u0131l\u0131 olmayaraq, ilkin mesaj ya gecikdirilmi\u015f g\u00f6nd\u0259ri\u015f \u00fc\u00e7\u00fcn sistem s\u0131ra\u0131na, ya da bir zamanlar mesajlar\u0131 t\u0259krar g\u00f6nd\u0259rm\u0259k \u00fc\u00e7\u00fcn haz\u0131rlanm\u0131\u015f ayr\u0131 bir t\u0259tbiq\u0259 k\u00f6\u00e7\u00fcr\u00fcl\u00fcrd\u00fc. Bu zaman mesaj\u0131n ba\u015fl\u0131\u011f\u0131na g\u00f6nd\u0259ri\u015f say\u0131 yaz\u0131l\u0131rd\u0131 ki, bu da gecikm\u0259 interval\u0131 v\u0259 ya t\u0259tbiq s\u0259viyy\u0259sind\u0259 strategiyan\u0131n sona \u00e7atmas\u0131na ba\u011fl\u0131d\u0131r. Strategiyan\u0131n sonuna \u00e7atm\u0131\u015f\u0131qsa, lakin xarici sistem h\u0259l\u0259 d\u0259 \u0259l\u00e7atan deyils\u0259, mesaj DLQ-ya manual t\u0259hlil \u00fc\u00e7\u00fcn g\u00f6nd\u0259ril\u0259c\u0259k.<\/p>\n<p><\/p>\n<h2 id=\"poisk-resheniya\">H\u0259ll axtar\u0131\u015f\u0131<\/h2>\n<p><\/p>\n<p><noindex><a rel=\"nofollow\" href=\"https:\/\/www.google.com\/search?q=kafka+retry+message\">\u0130nternetd\u0259 axtar\u0131\u015f etdikc\u0259<\/a><\/noindex>, a\u015fa\u011f\u0131dak\u0131lar\u0131 tapa bil\u0259rsiniz <noindex><a rel=\"nofollow\" href=\"https:\/\/blog.pragmatists.com\/retrying-consumer-architecture-in-the-apache-kafka-939ac4cb851a\">h\u0259ll<\/a><\/noindex>. Q\u0131sa des\u0259k, h\u0259r gecikm\u0259 intervallar\u0131na bir m\u00f6vzu a\u00e7maq v\u0259 t\u0259tbiq t\u0259r\u0259find\u0259 m\u00fcvafiq gecikm\u0259 il\u0259 mesajlar\u0131 oxuyan Consumer-l\u0259ri h\u0259yata ke\u00e7irm\u0259k t\u0259klif olunur. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Kafka-dan al\u0131nan hadis\u0259l\u0259rin t\u0259krar emal\u0131\" src=\"\/wp-content\/uploads\/2020\/02\/718c4c3f71ccf95b5a6f60e1b2c685d2.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Bax\u0131\u015flar\u0131n \u00e7oxsayl\u0131 m\u00fcsb\u0259t olmas\u0131na baxmayaraq, bu, m\u0259n\u0259 tamamil\u0259 u\u011furlu g\u00f6r\u00fcnm\u00fcr. Birincisi, ona g\u00f6r\u0259 ki, inki\u015faf etdiricinin biznes t\u0259l\u0259bl\u0259rini yerin\u0259 yetirm\u0259kd\u0259n \u0259lav\u0259, t\u0259svir olunan mexanizmi h\u0259yata ke\u00e7irm\u0259k \u00fc\u00e7\u00fcn \u00e7ox vaxt s\u0259rf etm\u0259si laz\u0131m olacaq.<\/p>\n<p><\/p>\n<p>Bundan \u0259lav\u0259, \u0259g\u0259r Kafka klasterind\u0259 giri\u015f idar\u0259etm\u0259si aktivdirs\u0259, topikl\u0259rin yarad\u0131lmas\u0131 v\u0259 onlara laz\u0131m olan giri\u015fl\u0259rin t\u0259min edilm\u0259si \u00fc\u00e7\u00fcn bir q\u0259d\u0259r vaxt s\u0259rf olunmal\u0131d\u0131r. Bununla yana\u015f\u0131, h\u0259r bir yenid\u0259n c\u0259hd olunan topik \u00fc\u00e7\u00fcn retention.ms parametrini d\u00fczg\u00fcn se\u00e7m\u0259k laz\u0131md\u0131r ki, mesajlar t\u0259krar g\u00f6nd\u0259rilsin v\u0259 itirilm\u0259sin. Giri\u015fl\u0259ri h\u0259yata ke\u00e7irm\u0259k v\u0259 sor\u011funu h\u0259r bir m\u00f6vcud v\u0259 ya yeni xidm\u0259t \u00fc\u00e7\u00fcn t\u0259krarlamaq laz\u0131m olacaq.<\/p>\n<p><\/p>\n<p>G\u0259lin indi spring-in \u00fcmumilikd\u0259 v\u0259 spring-kafka-n\u0131n x\u00fcsusil\u0259 mesajlar\u0131n t\u0259krar emal\u0131 \u00fc\u00e7\u00fcn t\u0259qdim etdiyi mexanizml\u0259r\u0259 baxaq. Spring-kafka, m\u00fcxt\u0259lif BackOffPolicy-l\u0259ri idar\u0259 etm\u0259k \u00fc\u00e7\u00fcn abstractions t\u0259qdim ed\u0259n spring-retry-\u0259 as\u0131l\u0131l\u0131q yarad\u0131r. Bu, olduqca \u00e7evik bir al\u0259tdir, lakin onun \u0259h\u0259miyy\u0259tli bir \u00e7at\u0131\u015fmazl\u0131\u011f\u0131, t\u0259krar g\u00f6nd\u0259rilm\u0259si \u00fc\u00e7\u00fcn mesajlar\u0131n t\u0259tbiqin yadda\u015f\u0131nda saxlan\u0131lmas\u0131d\u0131r. Bu, t\u0259tbiqin yenil\u0259m\u0259si v\u0259 ya istismar zaman\u0131 bir s\u0259hv s\u0259b\u0259bind\u0259n yenid\u0259n ba\u015flamas\u0131 n\u0259tic\u0259sind\u0259 b\u00fct\u00fcn g\u00f6zl\u0259m\u0259d\u0259 olan mesajlar\u0131n itirilm\u0259sin\u0259 s\u0259b\u0259b olur. Bu m\u0259s\u0259l\u0259 bizim sistemimiz \u00fc\u00e7\u00fcn kritik oldu\u011fundan, biz onu daha da ara\u015fd\u0131rmad\u0131q.<\/p>\n<p><\/p>\n<p>K\u00f6m\u0259k\u00e7i spring-kafka bir ne\u00e7\u0259 ContainerAwareErrorHandler implementasiyas\u0131 t\u0259qdim edir, m\u0259s\u0259l\u0259n <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>, bununla, bir s\u0259hv yaranarsa offset-m\u0259 d\u0259yi\u015fm\u0259d\u0259n mesaj\u0131 sonra emal etm\u0259k m\u00fcmk\u00fcnd\u00fcr. Spring-kafka 2.3 versiyas\u0131ndan ba\u015flayaraq BackOffPolicy t\u0259yin etm\u0259k imkan\u0131 t\u0259min edilib.<\/p>\n<p><\/p>\n<p>Bu yana\u015fma, t\u0259krar emal olunan mesajlar\u0131n t\u0259tbiqin yenid\u0259n ba\u015flamas\u0131n\u0131 ya\u015famas\u0131na imkan tan\u0131y\u0131r, lakin DLQ mexanizmi h\u0259l\u0259 d\u0259 m\u00f6vcud deyil. Biz 2019-cu ilin \u0259vv\u0259lind\u0259 bu variant\u0131 se\u00e7dik, optimistc\u0259sin\u0259 DLQ-ya ehtiyac olmayaca\u011f\u0131n\u0131 d\u00fc\u015f\u00fcn\u0259r\u0259k (\u015fans\u0131m\u0131z g\u0259tirdi v\u0259 ger\u00e7\u0259kd\u0259n d\u0259 bir ne\u00e7\u0259 ayl\u0131q t\u0259tbiq istismar\u0131 \u0259rzind\u0259 DLQ-ya ehtiyac olmad\u0131). M\u00fcv\u0259qq\u0259ti s\u0259hvl\u0259r SeekToCurrentErrorHandler-in i\u015f\u0259 d\u00fc\u015fm\u0259sin\u0259 s\u0259b\u0259b oldu. Dig\u0259r s\u0259hvl\u0259r is\u0259 loga yaz\u0131l\u0131r, offset-in d\u0259yi\u015fm\u0259sin\u0259 yol a\u00e7\u0131r v\u0259 emal n\u00f6vb\u0259ti mesajla davam edir.<\/p>\n<p><\/p>\n<h2 id=\"itogovoe-reshenie\">N\u0259tic\u0259 q\u0259rar\u0131<\/h2>\n<p><\/p>\n<p>SeekToCurrentErrorHandler-a \u0259saslanan t\u0259tbiqetm\u0259nin h\u0259yata ke\u00e7irilm\u0259si, biz\u0259 \u00f6z mesajlar\u0131n yenid\u0259n g\u00f6nd\u0259rilm\u0259si mexanizmini inki\u015faf etdirm\u0259k \u00fc\u00e7\u00fcn ilham verdi.<\/p>\n<p><\/p>\n<p>\u018fvv\u0259lc\u0259 biz m\u00f6vcud t\u0259cr\u00fcb\u0259ni istifad\u0259 etm\u0259k v\u0259 onu t\u0259tbiqin m\u0259ntiqin\u0259 g\u00f6r\u0259 geni\u015fl\u0259ndirm\u0259k ist\u0259yirdik. X\u0259tti m\u0259ntiq\u0259 malik olan t\u0259tbiq \u00fc\u00e7\u00fcn yeni mesajlar\u0131n oxunmas\u0131n\u0131n dayand\u0131r\u0131lmas\u0131 \u00fc\u00e7\u00fcn ki\u00e7ik bir m\u00fcdd\u0259t t\u0259yin etm\u0259k optimal olard\u0131, bu m\u00fcdd\u0259t is\u0259 t\u0259krar \u00e7a\u011f\u0131rma strategiyas\u0131 \u00e7\u0259r\u00e7iv\u0259sind\u0259 m\u00fc\u0259yy\u0259n edilir. Dig\u0259r t\u0259tbiql\u0259r \u00fc\u00e7\u00fcn is\u0259 weblayih\u0259y\u0259 t\u0259min etm\u0259si \u00fc\u00e7\u00fcn t\u0259k bir n\u00f6qt\u0259nin olmas\u0131 arzuolunand\u0131r ki, bu, iki yana\u015fma \u00fc\u00e7\u00fcn t\u0259krar \u00e7a\u011f\u0131rma strategiyas\u0131n\u0131 h\u0259yata ke\u00e7irir. Bununla yana\u015f\u0131, bu t\u0259k n\u00f6qt\u0259 h\u0259m d\u0259 h\u0259r iki yana\u015fma \u00fc\u00e7\u00fcn DLQ funksionall\u0131\u011f\u0131na sahib olmal\u0131d\u0131r.<\/p>\n<p><\/p>\n<p>T\u0259krar \u00e7a\u011f\u0131rma strategiyas\u0131, m\u00fcv\u0259qq\u0259ti x\u0259tan\u0131n ba\u015f verm\u0259si zaman\u0131 n\u00f6vb\u0259ti intervallar\u0131 almaqdan m\u0259sul olan t\u0259tbiqin i\u00e7ind\u0259 saxlanmal\u0131d\u0131r.<\/p>\n<p><\/p>\n<h3 id=\"ostanovka-consumera-dlya-prilozheniya-s-lineynoy-logikoy\">X\u0259tti m\u0259ntiq\u0259 malik t\u0259tbiq \u00fc\u00e7\u00fcn Consumer-in dayanmas\u0131<\/h3>\n<p><\/p>\n<p>spring-kafka il\u0259 i\u015fl\u0259dikd\u0259, Consumer-in dayanma kodu t\u0259xmin\u0259n bel\u0259 g\u00f6r\u00fcn\u0259 bil\u0259r:<\/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        \/\/ DLQ-ya g\u00f6nd\u0259r<\/code><\/pre>\n<p><\/p>\n<p>M\u00fcxt\u0259lif retryAt - MessageListenerContainer-in yenid\u0259n i\u015f\u0259 sal\u0131nmas\u0131 \u00fc\u00e7\u00fcn vaxtd\u0131r, \u0259g\u0259r o, h\u0259l\u0259 d\u0259 i\u015fl\u0259yirs\u0259. Yenid\u0259n ba\u015flamas\u0131 TaskScheduler-d\u0259 ger\u00e7ekle\u015ftirilen ayr\u0131 bir ipd\u0259 ba\u015f ver\u0259c\u0259k, onun implementasiyas\u0131n\u0131 da spring t\u0259klif edir. <\/p>\n<p><\/p>\n<p>retryAt d\u0259y\u0259rini a\u015fa\u011f\u0131dak\u0131 kimi tap\u0131r\u0131q:<\/p>\n<p><\/p>\n<ol>\n<li>Yenid\u0259n \u00e7a\u011f\u0131rmalar\u0131n say\u011fac\u0131n\u0131n d\u0259y\u0259ri axtar\u0131l\u0131r.<\/li>\n<li>Say\u011fac\u0131n d\u0259y\u0259rin\u0259 uy\u011fun olaraq, t\u0259krar \u00e7a\u011f\u0131rma strategiyas\u0131nda cari gecikm\u0259 intervallar\u0131 axtar\u0131l\u0131r. Strategiyam\u0131z t\u0259tbiqin i\u00e7ind\u0259 elan edilir, onun saxlanmas\u0131 \u00fc\u00e7\u00fcn JSON format\u0131n\u0131 se\u00e7dik.<\/li>\n<li>JSON massivind\u0259 tap\u0131lan intervallar, emal\u0131n t\u0259krar\u0131 \u00fc\u00e7\u00fcn laz\u0131m olan saniy\u0259l\u0259rin say\u0131n\u0131 ehtiva edir. Bu say\u0131 cari vaxta \u0259lav\u0259 olunur, n\u0259tic\u0259d\u0259 retryAt \u00fc\u00e7\u00fcn d\u0259y\u0259r meydana g\u0259lir.<\/li>\n<li>\u018fg\u0259r interval tap\u0131lmasa, onda retryAt d\u0259y\u0259ri null olur v\u0259 mesaj DLQ-ya g\u00f6nd\u0259rilir ki, bu da \u0259l il\u0259 analiz edil\u0259c\u0259k.<\/li>\n<\/ol>\n<p><\/p>\n<p>Bu yana\u015fmada, indiki zaman \u00fc\u00e7\u00fcn emal olunan h\u0259r mesaj \u00fc\u00e7\u00fcn h\u0259r d\u0259f\u0259 \u00e7a\u011f\u0131rmalar\u0131n say\u0131n\u0131 saxlamaq laz\u0131md\u0131r, m\u0259s\u0259l\u0259n, t\u0259tbiqin yadda\u015f\u0131nda. C\u0259hd say\u0131n\u0131 yadda\u015fda saxlamaq bu yana\u015fma \u00fc\u00e7\u00fcn kritik deyil, \u00e7\u00fcnki x\u0259tti m\u0259ntiq\u0259 malik bir t\u0259tbiq \u00fcmumilikd\u0259 emal\u0131 h\u0259yata ke\u00e7ir\u0259 bilmir. Spring-retry il\u0259 f\u0259rqli olaraq, t\u0259tbiqin yenid\u0259n ba\u015flad\u0131lmas\u0131, b\u00fct\u00fcn mesajlar\u0131n t\u0259krar emal \u00fc\u00e7\u00fcn itirilm\u0259sin\u0259 s\u0259b\u0259b olmur, yaln\u0131z strategiyan\u0131n yenid\u0259n ba\u015flamas\u0131na s\u0259b\u0259b olur. <\/p>\n<p><\/p>\n<p>Bu yana\u015fma, \u00e7ox b\u00f6y\u00fck y\u00fck s\u0259b\u0259bind\u0259n m\u00f6vcud olmaya bil\u0259n xarici sistemin y\u00fck\u00fcn\u00fc azaltma\u011fa k\u00f6m\u0259k edir. Ba\u015fqa s\u00f6zl\u0259, t\u0259krar emala \u0259lav\u0259 olaraq, biz <noindex><a rel=\"nofollow\" href=\"https:\/\/microservices.io\/patterns\/reliability\/circuit-breaker.html\">circuit breaker<\/a><\/noindex>.<\/p>\n<p><\/p>\n<p>Bizim hal\u0131m\u0131zda, s\u0259hv e\u015fikl\u0259rin say\u0131 c\u0259mi 1-dir v\u0259 m\u00fcv\u0259qq\u0259ti \u015f\u0259b\u0259k\u0259 kesintisi s\u0259b\u0259biyl\u0259 sistemin dayan\u0131ql\u0131\u011f\u0131n\u0131 minimaliz\u0259 etm\u0259k \u00fc\u00e7\u00fcn, biz ki\u00e7ik gecikm\u0259 intervallar\u0131 il\u0259 \u00e7ox detalla\u015fd\u0131r\u0131lm\u0131\u015f bir t\u0259krar \u00e7a\u011f\u0131rma strategiyas\u0131 istifad\u0259 edirik. Bu, \u015firk\u0259t qrupunun b\u00fct\u00fcn t\u0259tbiql\u0259ri \u00fc\u00e7\u00fcn uy\u011fun olmaya bil\u0259r, buna g\u00f6r\u0259 d\u0259 s\u0259hv e\u015fikl\u0259ri il\u0259 interval \u00f6l\u00e7\u00fcs\u00fc aras\u0131ndak\u0131 nisb\u0259t sistemin x\u00fcsusiyy\u0259tl\u0259rin\u0259 \u0259saslanaraq t\u0259nziml\u0259nm\u0259lidir.<\/p>\n<p><\/p>\n<h3 id=\"otdelnoe-prilozhenie-dlya-obrabotki-soobscheniy-ot-prilozheniy-s-nedeterminirovannoy-logikoy\">D\u0259yi\u015fk\u0259n m\u0259ntiq\u0259 sahib t\u0259tbiql\u0259rd\u0259n mesajlar\u0131 emal etm\u0259k \u00fc\u00e7\u00fcn ayr\u0131ca bir t\u0259tbiq<\/h3>\n<p><\/p>\n<p>Bu t\u0259tbiq\u0259 (Retryer) mesaj g\u00f6nd\u0259rm\u0259k \u00fc\u00e7\u00fcn bir kod n\u00fcmun\u0259si:<\/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>N\u00fcmun\u0259d\u0259n g\u00f6r\u00fcnd\u00fcy\u00fc kimi, ba\u015fl\u0131qlarda \u00e7oxlu m\u0259lumat \u00f6t\u00fcr\u00fcl\u00fcr. RETRY_AT d\u0259y\u0259ri, istehsal\u00e7\u0131 dayand\u0131r\u0131lmas\u0131 yolu il\u0259 t\u0259krar mexanizmi \u00fc\u00e7\u00fcn oldu\u011fu kimi qal\u0131r. DESTINATION v\u0259 RETRY_AT-dan \u0259lav\u0259, biz \u00f6t\u00fcr\u00fcr\u00fck:<\/p>\n<p><\/p>\n<ul>\n<li>GROUP_ID, mesajlar\u0131 \u0259l il\u0259 analiz \u00fc\u00e7\u00fcn qrupla\u015fd\u0131rmaq v\u0259 axtar\u0131\u015f\u0131 asanla\u015fd\u0131rmaq \u00fc\u00e7\u00fcn.<\/li>\n<li>ORIGINAL_PARTITION, eyni istehsal\u00e7\u0131n\u0131 t\u0259krar emal \u00fc\u00e7\u00fcn saxlama\u011fa \u00e7al\u0131\u015fmaq \u00fc\u00e7\u00fcn. Bu parametr null ola bil\u0259r, bel\u0259 olduqda yeni parti a\u00e7\u0131q mesaj\u0131n record.key() a\u00e7ar\u0131na g\u00f6r\u0259 al\u0131nacaq.<\/li>\n<li>T\u0259krar \u00e7a\u011f\u0131rma strategiyas\u0131n\u0131 izl\u0259m\u0259k \u00fc\u00e7\u00fcn g\u00fcncellenmi\u015f COUNTER d\u0259y\u0259ri.<\/li>\n<li>SEND_TO \u2014 RETRY_AT-a \u00e7atd\u0131qda mesaj\u0131 t\u0259krar emal \u00fc\u00e7\u00fcn g\u00f6nd\u0259rm\u0259k, ya da DLQ-ya yerl\u0259\u015fdirm\u0259k \u00fc\u00e7\u00fcn olan konstant.<\/li>\n<li>REASON \u2014 mesaj\u0131n emal\u0131n\u0131n niy\u0259 dayand\u0131r\u0131ld\u0131\u011f\u0131n\u0131 bildir\u0259n s\u0259b\u0259b.<\/li>\n<\/ul>\n<p><\/p>\n<p>Retryer, PostgreSQL-d\u0259 t\u0259krar g\u00f6nd\u0259rm\u0259 v\u0259 \u0259l il\u0259 t\u0259hlil \u00fc\u00e7\u00fcn mesajlar\u0131 saxlay\u0131r. Zamanlay\u0131c\u0131ya \u0259sas\u0259n, RETRY_AT-\u0131 ke\u00e7mi\u015f mesajlar\u0131 axtar\u0131b onlar\u0131 DESTINATION topikinin ORIGINAL_PARTITION partiyas\u0131na record.key() a\u00e7ar\u0131 il\u0259 geri g\u00f6nd\u0259r\u0259n bir tap\u015f\u0131r\u0131q i\u015f\u0259 sal\u0131n\u0131r.<\/p>\n<p><\/p>\n<p>Mesaj yolland\u0131qdan sonra PostgreSQL-d\u0259n silinir. Mesajlar\u0131n \u0259l il\u0259 t\u0259hlili, Retryer il\u0259 REST API vasit\u0259sil\u0259 \u0259laq\u0259l\u0259ndirilmi\u015f sad\u0259 UI-da h\u0259yata ke\u00e7irilir. Onun \u0259sas x\u00fcsusiyy\u0259tl\u0259ri DLQ-dan mesajlar\u0131n yenid\u0259n g\u00f6nd\u0259rilm\u0259si v\u0259 ya silinm\u0259si, x\u0259ta m\u0259lumatlar\u0131n\u0131 baxmaq v\u0259 m\u0259s\u0259l\u0259n, x\u0259ta adlar\u0131 \u00fczr\u0259 mesajlar\u0131 axtarmaqd\u0131r. <\/p>\n<p><\/p>\n<p>Bizim klasterl\u0259rd\u0259 giri\u015f idar\u0259etm\u0259si aktiv oldu\u011fu \u00fc\u00e7\u00fcn, Retryer\u2019in dinl\u0259diyi topik \u00fc\u00e7\u00fcn \u0259lav\u0259 icaz\u0259l\u0259r ist\u0259m\u0259k v\u0259 Retryer\u2019in DESTINATION topikind\u0259 yazma imkan\u0131 verm\u0259k laz\u0131md\u0131r. Bu narahatd\u0131r, amma intervalla topik yana\u015fmas\u0131ndan f\u0259rqli olaraq, tam DLQ v\u0259 onunla idar\u0259 etm\u0259 \u00fc\u00e7\u00fcn bir UI \u0259ld\u0259 etmi\u015f oluruq.<\/p>\n<p><\/p>\n<p>B\u0259zi hallarda, daxil olan topik bir ne\u00e7\u0259 f\u0259rqli istehsal\u00e7\u0131 qruplar\u0131 t\u0259r\u0259find\u0259n oxunur, onlar\u0131n proqramlar\u0131 f\u0259rqli m\u0259ntiqi h\u0259yata ke\u00e7irir. Retryer vasit\u0259si il\u0259 bir proqram \u00fc\u00e7\u00fcn mesaj\u0131n t\u0259krar emal\u0131 dig\u0259r proqramda dublikat yaradacaq. Bunu qorumaq \u00fc\u00e7\u00fcn, biz bir ayr\u0131 t\u0259krar emal topiki yarad\u0131r\u0131q. Daxil olan v\u0259 t\u0259krar-emal topikl\u0259rini eyni istehsal\u00e7\u0131 h\u0259r hans\u0131 m\u0259hdudiyy\u0259t olmadan oxuya bil\u0259r. <\/p>\n<p><\/p>\n<p><img decoding=\"async\" alt=\"Kafka-dan al\u0131nan hadis\u0259l\u0259rin t\u0259krar emal\u0131\" src=\"\/wp-content\/uploads\/2020\/02\/06f2355839c6dd812ee3304bf2c72226.jpg\" style=\"display:block;margin: 0 auto;\" \/><\/p>\n<p><\/p>\n<p>Default olaraq, bu yana\u015fma circuit breaker imkan\u0131 t\u0259qdim etmir, lakin bunu t\u0259tbiq\u0259 \u0259lav\u0259 etm\u0259k m\u00fcmk\u00fcnd\u00fcr <noindex><a rel=\"nofollow\" href=\"https:\/\/spring.io\/projects\/spring-cloud-netflix\">spring-cloud-netflix<\/a><\/noindex> ya da yeni <noindex><a rel=\"nofollow\" href=\"https:\/\/spring.io\/projects\/spring-cloud-circuitbreaker\">spring cloud circuit breaker<\/a><\/noindex>, xarici xidm\u0259tl\u0259rin \u00e7a\u011f\u0131r\u0131\u015f yerl\u0259rini m\u00fcvafiq abstraksiyalara sararaq. Bundan \u0259lav\u0259, se\u00e7\u0259 bil\u0259c\u0259yiniz strategiya imkan\u0131 yaran\u0131r <noindex><a rel=\"nofollow\" href=\"https:\/\/docs.microsoft.com\/en-us\/azure\/architecture\/patterns\/bulkhead\">bulkhead<\/a><\/noindex> n\u00fcmun\u0259nin, bu da yararl\u0131 ola bil\u0259r. M\u0259s\u0259l\u0259n, spring-cloud-netflix-d\u0259 bu, thread pool v\u0259 ya semaphore ola bil\u0259r.<\/p>\n<p><\/p>\n<h2 id=\"vyvod\">\u00c7\u0131kt\u0131<\/h2>\n<p><\/p>\n<p>N\u0259tic\u0259d\u0259, vaxtil\u0259 xarici sisteml\u0259rd\u0259n birinin m\u00fcv\u0259qq\u0259ti \u0259l\u00e7atan olmamas\u0131 zaman\u0131 mesaj\u0131n emal\u0131n\u0131 t\u0259krarlama\u011fa imkan ver\u0259n ayr\u0131ca bir t\u0259tbiq \u0259ld\u0259 etdik.<\/p>\n<p><\/p>\n<p>T\u0259tbiqin \u0259sas \u00fcst\u00fcnl\u00fckl\u0259rind\u0259n biri odur ki, eyni Kafka-klasterind\u0259 i\u015fl\u0259y\u0259n xarici sisteml\u0259r ondan \u0259h\u0259miyy\u0259tli d\u0259yi\u015fiklikl\u0259r etm\u0259d\u0259n istifad\u0259 ed\u0259 bil\u0259rl\u0259r! Bu t\u0259tbiq yaln\u0131z retry-topik\u0259 giri\u015f \u0259ld\u0259 etm\u0259li, bir ne\u00e7\u0259 Kafka ba\u015fl\u0131\u011f\u0131n\u0131 doldurmal\u0131 v\u0259 mesaj\u0131 Retryer-\u0259 g\u00f6nd\u0259rm\u0259lidir. He\u00e7 bir \u0259lav\u0259 infrastruktur yaratmaq laz\u0131m deyil. Mesajlar\u0131n t\u0259tbiqd\u0259n Retryer-\u0259 v\u0259 geri \u00f6t\u00fcr\u00fclm\u0259sinin say\u0131n\u0131 azaltmaq \u00fc\u00e7\u00fcn, x\u0259tti m\u0259ntiqli t\u0259tbiql\u0259ri ay\u0131rd\u0131q v\u0259 onlarda istehlak\u00e7\u0131n\u0131n dayanmas\u0131 vasit\u0259sil\u0259 t\u0259krar emal\u0131 etdik.<\/p>\n<p>M\u0259nb\u0259: <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.0.1 - 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\/az\/blog\/administrirovanie\/povtornaya-obrabotka-sobytij-poluchennyh-iz-kafka\" \/>\n\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.0.1\" \/>\n\t\t<meta property=\"og:locale\" content=\"az_AZ\" \/>\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\/az\/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\udd47Kafka-dan al\u0131nan hadis\u0259l\u0259rin t\u0259krar\u0131 | ProHoster","description":"Salam, Habr. Yax\u0131n zamanda.","canonical_url":"https:\/\/prohoster.info\/az\/blog\/administrirovanie\/povtornaya-obrabotka-sobytij-poluchennyh-iz-kafka","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"az_AZ","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\/az\/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\/az\/wp-json\/wp\/v2\/posts\/56186","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/az\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/az\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/az\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/az\/wp-json\/wp\/v2\/comments?post=56186"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/az\/wp-json\/wp\/v2\/posts\/56186\/revisions"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/az\/wp-json\/wp\/v2\/media?parent=56186"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/az\/wp-json\/wp\/v2\/categories?post=56186"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/az\/wp-json\/wp\/v2\/tags?post=56186"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}