Upgrade to Pro — share decks privately, control downloads, hide ads and more …

지연이체 서비스 개발기: 은행 점검 시간 끝나면 송금해 드릴게요!

kakao
November 01, 2024

지연이체 서비스 개발기: 은행 점검 시간 끝나면 송금해 드릴게요!

#아키텍처 #Kafka

Kafka 기반 지연이체 서비스를 재설계하고 개발한 경험을 공유합니다.
아키텍처 설계부터 릴리즈하며 마주한 문제와 해결 에피소드까지, 저와 같은 고민을 마주한 분들이라면 이 세션을 추천합니다.

발표자 : elmo.wiz
카카오페이 송금 서비스를 개발하는 엘모입니다.

kakao

November 01, 2024
Tweet

More Decks by kakao

Other Decks in Programming

Transcript

  1. ਷೯ ਷೯੼Ѩदр ۄ੉঱਷೯ _ যೖ஖਷೯ ҕా੼Ѩ ભܰ٣਷೯ _ ೐۽ب਷೯ ҕా੼Ѩ

    ઁ੉૑਷೯ ҕా੼Ѩ ௑਷೯ _ ֎য়਷೯ ҕా੼Ѩ   ׮নೠ਷೯ ׮নೠ੼Ѩदр ҕా੼Ѩदр _
  2. 6TFS "1*TFSWFS ૑ো੉୓١۾ %# ੷੢ ੼Ѩ৮ܐदрઑഥ ਷೯ಐ ਷೯੼Ѩઙܐറ ࣠Әغب۾ ૑ো੉୓١۾ೡөਃ

     ૑ো੉୓١۾"1*ѐߊ ↟ ࣠Ә੿ࠁ ↟ ࣠Әप೯৘੿दр ↟ ࢚క%&-":
  3. ૑ো੉୓प೯ҳഅ 1SJWBUF "1*TFSWFS ࣠Әप೯ਃ୒ 4DIFEVMFS ↟ ࣠Әप೯ %# ↟ ࣠Ә੿ࠁ

    ↟ ࣠Әप೯৘੿दр ↟ ࢚క%&-": ↟ ࠙݃׮ࣻ೯ ↟ ࢚క%&-": 
 ࣠Әप೯৘੿दрب׳ೠѪٜ3FBE
  4. ↟ ࠙݃׮ࣻ೯ ↟ ࢚క%&-": 
 ࣠Әप೯৘੿दрب׳ೠѪٜ3FBE 1SJWBUF "1*TFSWFS ࣠Әप೯ਃ୒ 4DIFEVMFS

    ↟ ࣠Әप೯ %# ↟ ࣠Ә੿ࠁ ↟ ࣠Әप೯৘੿दр ↟ ࢚క%&-": ૑ো੉୓प೯ҳഅ ҷ۞тѪэ਷ؘ՘ੋо GFBUѤߑ૓ࢤп
  5. ૑ো੉୓प೯ҳഅ 1SJWBUF "1*TFSWFS ࣠Әप೯ਃ୒ 4DIFEVMFS ↟ ࣠Әप೯ %# ↟ ࣠Ә੿ࠁ

    ↟ ࣠Әप೯৘੿दр ↟ ࢚క%&-": ↟ ࠙݃׮ࣻ೯ ↟ ࢚క%&-": 
 ࣠Әप೯৘੿दрب׳ೠѪٜ3FBE
  6. ૑ো੉୓प೯ҳഅ 1SJWBUF "1*TFSWFS ࣠Әप೯ਃ୒ 4DIFEVMFS ↟ ࣠Әप೯ %# ↟ ࣠Ә੿ࠁ

    ↟ ࣠Әप೯৘੿दр ↟ ࢚క%&-": ↟ ࠙݃׮ࣻ೯ ↟ ࢚క%&-": 
 ࣠Әप೯৘੿दрب׳ೠѪٜ3FBE  ࣻୌѤ
  7. ↟ ࠙݃׮ࣻ೯ ↟ ࢚క%&-": 
 ࣠Әप೯৘੿दрب׳ೠѪٜ3FBE 1SJWBUF "1*TFSWFS ࣠Әप೯ਃ୒ 4DIFEVMFS

    ↟ ࣠Әप೯ %# ↟ ࣠Ә੿ࠁ ↟ ࣠Әप೯৘੿दр ↟ ࢚క%&-": ૑ো੉୓प೯ҳഅ ࠙উীࣻୌѤ࣠Ә৮ܐޅೠ׮
  8. ↟ ࠙݃׮ࣻ೯ ↟ ࢚క%&-": 
 ࣠Әप೯৘੿दрب׳ೠѪٜ3FBE 1SJWBUF "1*TFSWFS ࣠Әप೯ਃ୒ 4DIFEVMFS

    ↟ ࣠Әप೯ %# ↟ ࣠Ә੿ࠁ ↟ ࣠Әप೯৘੿दр ↟ ࢚క%&-": ૑ো੉୓प೯ҳഅ झா઴۞ܳט۰ࠅө
  9. 1SJWBUF "1*TFSWFS ↟ ࣠Әप೯ %# ↟ ࣠Ә੿ࠁ ↟ ࣠Әप೯৘੿दр ↟

    ࢚క%&-":  झா઴۞ܳט۰ࠅө ࣠Әप೯ࢲߡীࠗ׸ ݫद૑௸ف੗
  10. 1SJWBUF "1*TFSWFS ↟ ࣠Әप೯ %# ↟ ࣠Ә੿ࠁ ↟ ࣠Әप೯৘੿दр ↟

    ࢚క%&-":  झா઴۞ܳט۰ࠅө ࣠Әप೯ࢲߡীࠗ׸ ࢎղҕਊݫद૑௸,BGLB۽
  11. ,BGLBӝ߈૑ো੉୓प೯ ,BGLB 1SPEVDF $POTVNFS 1SJWBUF "1*TFSWFS ࣠Әप೯ਃ୒ $POTVNF %# ↟

    ࣠Ә੿ࠁ ↟ ࣠Әप೯৘੿दр ↟ ࢚క%&-": 4DIFEVMFS ↟ ࠙݃׮ࣻ೯
  12. ,BGLB 1SPEVDF $POTVNFS 1SJWBUF "1*TFSWFS ࣠Әप೯ਃ୒ $POTVNF 5PQJDUSBOTGFS - EFMBZ

    1BSUJUJPO $POTVNFS؀ࣻ ,BGLBӝ߈૑ো੉୓प೯ %# ↟ ࣠Ә੿ࠁ ↟ ࣠Әप೯৘੿दр ↟ ࢚క%&-": 4DIFEVMFS ↟ ࠙݃׮ࣻ೯
  13. ,BGLBӝ߈૑ো੉୓प೯ ,BGLB 1SPEVDF $POTVNFS 1SJWBUF "1*TFSWFS ࣠Әप೯ਃ୒ $POTVNF 5PQJDUSBOTGFS -

    EFMBZ 1BSUJUJPO $POTVNFS؀ࣻ %# ↟ ࣠Ә੿ࠁ ↟ ࣠Әप೯৘੿दр ↟ ࢚క%&-": 4DIFEVMFS ↟ ࠙݃׮ࣻ೯ ,BGLBӝ߈ইఃఫ୊ীࢲب ೨बӝמ੘زػ׮
  14. ,BGLBӝ߈૑ো੉୓प೯ ,BGLB 1SPEVDF $POTVNFS 1SJWBUF "1*TFSWFS ࣠Әप೯ਃ୒ $POTVNF 5PQJDUSBOTGFS -

    EFMBZ 1BSUJUJPO $POTVNFS؀ࣻ %# ↟ ࣠Ә੿ࠁ ↟ ࣠Әप೯৘੿दр ↟ ࢚క%&-": 4DIFEVMFS ↟ ࠙݃׮ࣻ೯
  15. ,BGLB 1SPEVDF $POTVNFS 1SJWBUF "1*TFSWFS ࣠Әप೯ਃ୒ $POTVNF 5PQJDUSBOTGFS - EFMBZ

    1BSUJUJPO $POTVNFS؀ࣻ %# ↟ ࣠Ә੿ࠁ ↟ ࣠Әप೯৘੿दр ↟ ࢚క%&-": 4DIFEVMFS ↟ ࠙݃׮ࣻ೯ ,BGLBӝ߈૑ো੉୓प೯ ష೗ীэ਷࣠ӘѤ੉ऺੌࣻ੓׮
  16. 4,*1 ,BGLB 1SPEVDF $POTVNFS 1SJWBUF "1*TFSWFS ࣠Әप೯ਃ୒ $POTVNF %# 4DIFEVMFS

    ઺ࠂ࣠Әߑ૑ ӝࠄ੸ੋ࢚క୓ఊ۽૒୶о അ੤ஶगݠ؀
  17. 4,*1 ,BGLB 1SPEVDF $POTVNFS 1SJWBUF "1*TFSWFS ࣠Әप೯ਃ୒ $POTVNF %# 4DIFEVMFS

    ઺ࠂ࣠Әߑ૑ ӝࠄ੸ੋ࢚క୓ఊ۽૒୶о ஶगݠ؀ীࢲزदীஶचೡࣻ੓׮
  18. Ҋ޹ ౵౭࣌ ஶगݠטܻӝ ,BGLB 5PQJDUSBOTGFS - EFMBZ QBSUJUJPO QBSUJUJPO QBSUJUJPO

    QBSUJUJPO QBSUJUJPO $POTVNFS ౵౭࣌ࣻೠߣטܻݶ׮द઴੉ӝ൨ٜ׮ *OWBMJE1BSUJUJPOT&YDFQUJPO
  19. Ҋ޹ $POTVNFSীDPODVSSFODZࢸ੿ @KafkaListener( topics = ["transfer-delay"], groupId = "kafka-consumer", concurrency

    = "3" ) fun listen( @Headers headers: MessageHeaders, @Payload delayMessage: TransferDelayMessage ): ConsumerResult { delaySend(headers, delayMessage) ConsumerResult.success() }
  20. Ҋ޹ $POTVNFSীࢲ࠺زӝ۽प೯ private val executor = Executors.newFixedThreadPool(4) @KafkaListener( topics =

    ["transfer-delay"], groupId = "kafka-consumer" ) fun listen( @Headers headers: MessageHeaders, @Payload delayMessage: TransferDelayMessage ): ConsumerResult { CompletableFuture.runAsync({ delaySend(headers, delayMessage) }, executor).join() ConsumerResult.success() }
  21. ೧Ѿ ׮Ѥݫद૑ஶच @KafkaListener( topics = ["transfer-delay"], containerFactory = "batchKafkaListenerContainerFactory", groupId

    = "kafka-consumer", properties = [ "max.poll.records:20" ] ) fun listen( @Headers headers: MessageHeaders, @Payload delayMessages: List<TransferDelayMessage> ): ConsumerResult { return try { delaySend(headers, delayMessages) ConsumerResult.success() } catch (ex: Exception) { log.error { "error:$ex" } ConsumerResult.fail() } } $POTVNFSীࢲ#BUDI3FBE۽ࢸ੿
  22. ೧Ѿ ׮Ѥݫद૑ஶच @KafkaListener( topics = ["transfer-delay"], containerFactory = "batchKafkaListenerContainerFactory", groupId

    = "kafka-consumer", properties = [ "max.poll.records:20" ] ) fun listen( @Headers headers: MessageHeaders, @Payload delayMessages: List<TransferDelayMessage> ): ConsumerResult { return try { delaySend(headers, delayMessages) ConsumerResult.success() } catch (ex: Exception) { log.error { "error:$ex" } ConsumerResult.fail() } } $POTVNFSীࢲ#BUDI3FBE۽ࢸ੿ GBDUPSZJT#BUDI-JTUFOFSUSVF GBDUPSZDPOUBJOFS1SPQFSUJFTBDL.PEF$POUBJOFS1SPQFSUJFT"DL.PEF#"5$)
  23. ೧Ѿ ׮Ѥݫद૑ஶच @KafkaListener( topics = ["transfer-delay"], containerFactory = "batchKafkaListenerContainerFactory", groupId

    = "kafka-consumer", properties = [ "max.poll.records:20" ] ) fun listen( @Headers headers: MessageHeaders, @Payload delayMessages: List<TransferDelayMessage> ): ConsumerResult { return try { delaySend(headers, delayMessages) ConsumerResult.success() } catch (ex: Exception) { log.error { "error:$ex" } ConsumerResult.fail() } } $POTVNFSীࢲ#BUDI3FBE۽ࢸ੿
  24. ೧Ѿ ׮Ѥݫद૑ஶच @KafkaListener( topics = ["transfer-delay"], containerFactory = "batchKafkaListenerContainerFactory", groupId

    = "kafka-consumer", properties = [ "max.poll.records:20" ] ) fun listen( @Headers headers: MessageHeaders, @Payload delayMessages: List<TransferDelayMessage> ): ConsumerResult { return try { delaySend(headers, delayMessages) ConsumerResult.success() } catch (ex: Exception) { log.error { "error:$ex" } ConsumerResult.fail() } } 3FDPSETࣻࢸ੿
  25. ೧Ѿ .VMUJUISFBE੸ਊ private val forkJoinPool: ForkJoinPool = ForkJoinPool(10) @KafkaListener( topics

    = ["transfer-delay"], containerFactory = "batchKafkaListenerContainerFactory", groupId = "kafka-consumer", properties = [ "max.poll.records:20" ] ) fun listen(@Headers headers: MessageHeaders, @Payload delayMessages: List<TransferDelayMessage>): ConsumerResult { return try { val groupedMessages = delayMessages.groupBy { it.payAccountId } forkJoinPool.submit { groupedMessages.values.parallelStream().forEach { messages -> delaySend(headers, messages) } }.join() ConsumerResult.success() } catch (ex: Exception) { log.error { "[ForkJoinPool Exception]. error:$ex" } ConsumerResult.fail() } }
  26. ѐࢶ੹റप೯दр࠺Ү ѐࢶ੹ ѐࢶറ $POTVNFS؀ࣻ   3FBE3FDPSETࣻ   5ISFBEࣻ

      ࠙׼୊ܻѤࣻ Ѥ Ѥ प೯दр ࠙ ࠙ ਷೯ҕా੼Ѩदрӝળ
  27. 2"