Project/싹틔움

[싹틔움] 메인 μ„œλ²„μΈ‘ μ—λŸ¬λ‘œ μΈν•œ Kafka Message 전솑 μ‹€νŒ¨ μ‹œλ‚˜λ¦¬μ˜€ λŒ€λΉ„ μ•ˆμ „ μž₯치 κ³ λ―Ό

ν•œ33 2025. 4. 14. 22:35

 

πŸ’‘ κ°œμš”

 

μ•„μ›ƒλ°•μŠ€ νŒ¨ν„΄ κ΅¬ν˜„

 

κ³ λ―Ό1 : μ•„μ›ƒλ°•μŠ€ νŒ¨ν„΄μ„ μ μš©ν•˜λ©΄ Kafka λ©”μ„Έμ§€ 전솑 전에 무쑰건 DB 둜 λΆ€ν„° 쑰회λ₯Ό ν•΄μ„œ λΆˆλŸ¬μ˜€λ‹€λ³΄λ‹ˆ λ¦¬μ†ŒμŠ€κ°€ λ‚­λΉ„λ˜μ§€ μ•Šμ„κΉŒ?

κ³ λ―Ό1 ν•΄κ²°: μ•„μ›ƒλ°•μŠ€ νŒ¨ν„΄ λ³€ν˜• ꡬ쑰 κ΅¬ν˜„

 

κ³ λ―Ό2 : μž¬μ „μ†‘μ„ μ‹œλ„ν•΄λ„ κ³„μ†ν•΄μ„œ Sent 값이 False 인 κ²½μš°λŠ” μ–΄λ–»κ²Œ μ²˜λ¦¬ν•˜λ©΄ μ’‹μ„κΉŒ?

κ³ λ―Ό2 ν•΄κ²°: Redis λ„μž…μ„ 톡해 각 데이터별 Count 및 Webhook 연결을 ν†΅ν•œ 운영 처리

 

κ³ λ―Ό3 : DLQ Topic λ„μž…μ„ ν•˜λŠ” 것이 μ’‹μ„κΉŒ?


이전 κΈ€:

 

[싹틔움] API Gateway λ„μž…μ„ ν†΅ν•œ 인증 μ—­ν•  λΆ„λ‹΄

πŸ’‘ κ°œμš”μ΄μ „ κΈ€https://hanstory33.tistory.com/318 [싹틔움] 04/07 κ°œλ°œμΌμ§€ FeignClient λ„μž…μœΌλ‘œ λΆ„μ‚° μ„œλ²„μ—μ„œμ˜ 인증 문제 ν•΄κ²°πŸ’‘ κ°œμš”λ©”μΈμ„œλ²„μ™€ μ•Œλ¦Όμ„œλ²„κ°€ λΆ„λ¦¬λœ ν˜„ ꡬ쑰의 μ•Œλ¦Όμ„œλ²„λŠ” λˆ„κ΅¬λ‚˜ λ‹€λ₯Έ

hanstory33.tistory.com

 

 

 

ν˜„μž¬ κ΅¬μ‘°μ—μ„œ λ©”μΈμ„œλ²„μ™€ μ•Œλ¦Όμ„œλ²„ μ‚¬μ΄μ—μ„œ Kafka λ₯Ό μ‚¬μš©ν•΄ λ©”μ„Έμ§€λ₯Ό μ „λ‹¬ν•˜λŠ”λ°, λ‹¨μˆœν•œ λ©”μ„Έμ§€ 전달 κ΅¬ν˜„λΏλ§Œ μ•„λ‹ˆλΌ μ‹œμŠ€ν…œ μ•ˆμ •μ„ μœ„ν•΄ μ‹€νŒ¨ν•  μ‹œλ‚˜λ¦¬μ˜€λ₯Ό λŒ€λΉ„ν•  ν•„μš”κ°€ 있고 κ·Έ 방법이 많이 μžˆλ‹€λŠ” 것을 μ•Œμ•˜λ‹€. κ·Έ 쀑 Outbox νŒ¨ν„΄, retry μ‹œλ„, DLQ λ‘œμ§μ„ κ³ λ €ν•˜λ©΄μ„œ ν–ˆλ˜ 고민을 κΈ°λ‘ν•˜κ³ μž ν–ˆλ‹€.

 

πŸ’‘ μ‹€νŒ¨ μ‹œλ‚˜λ¦¬μ˜€

- Kafka 브둜컀 λ˜λŠ” μ»¨μŠˆλ¨Έκ°€ μ‹€ν–‰ 쀑인 μ„œλ²„ κ°„ λ„€νŠΈμ›Œν¬ 연결이 λŠκΈ°κ±°λ‚˜ 지연이 λ°œμƒν•  경우, λ©”μ‹œμ§€κ°€ μ „λ‹¬λ˜μ§€ μ•Šμ„ 수 있음

- Kafka λΈŒλ‘œμ»€κ°€ λ‹€μš΄λ˜κ±°λ‚˜ μΌμ‹œμ μœΌλ‘œ μ‘λ‹΅ν•˜μ§€ μ•ŠλŠ” 경우

- μ»¨μŠˆλ¨Έκ°€ λ©”μ‹œμ§€λ₯Ό μ²˜λ¦¬ν•˜λŠ” κ³Όμ •μ—μ„œ μ˜ˆμ™Έκ°€ λ°œμƒν•˜μ—¬ λ©”μ‹œμ§€λ₯Ό μ •μƒμ μœΌλ‘œ μ²˜λ¦¬ν•˜μ§€ λͺ»ν•˜λŠ” 경우

- ν”„λ‘œλ“€μ„œμ™€ 컨슈머 κ°„ λ©”μ‹œμ§€ 포맷이 μΌμΉ˜ν•˜μ§€ μ•Šμ•„ 역직렬화에 μ‹€νŒ¨ν•˜λŠ” 경우

λ“± λ“±

 

πŸ’‘ μ•„μ›ƒλ°•μŠ€ νŒ¨ν„΄ κ΅¬ν˜„

🌱 μ•„μ›ƒλ°•μŠ€ νŒ¨ν„΄μ΄λž€?

- μ•„μ›ƒλ°•μŠ€ νŒ¨ν„΄μ€ λΆ„μ‚° μ‹œμŠ€ν…œμ—μ„œ λ°μ΄ν„°λ² μ΄μŠ€ νŠΈλžœμž­μ…˜κ³Ό λ©”μ‹œμ§€ 전솑을 일관성 있게 μ²˜λ¦¬ν•˜κΈ° μœ„ν•œ νŒ¨ν„΄μ΄λ‹€. 이 νŒ¨ν„΄μ€ λ©”μ‹œμ§€λ₯Ό Kafka와 같은 λ©”μ‹œμ§€ 브둜컀둜 직접 μ „μ†‘ν•˜μ§€ μ•Šκ³ , λ¨Όμ € 둜컬 λ°μ΄ν„°λ² μ΄μŠ€μ— μ €μž₯ν•œ ν›„ λ³„λ„μ˜ ν”„λ‘œμ„ΈμŠ€κ°€ ν•΄λ‹Ή λ©”μ‹œμ§€λ₯Ό 읽어 브둜컀둜 μ „μ†‘ν•˜λŠ” λ°©μ‹μœΌλ‘œ λ™μž‘ν•œλ‹€.

 

🌱 κ΅¬ν˜„

- ν•„μžλŠ” 기쑴에 kafka 둜 λ©”μ„Έμ§€λ₯Ό μƒμ„±ν•΄μ„œ topic 에 λ„£λŠ” 둜직 λŒ€μ‹ μ— notification Entity 에 sent Column 을 Flag λ³€μˆ˜λ‘œ μΆ”κ°€ν•΄μ„œ kafka λ©”μ„Έμ§€ 전솑 μ—¬λΆ€λ₯Ό μ²΄ν¬ν–ˆλ‹€. 기쑴에 객체 μƒμ„±μ‹œμ—λŠ” false κ°’μœΌλ‘œ λ„£μ–΄μ„œ μš°μ„  DB 에 μ €μž₯μ‹œμΌ°λ‹€.

- 이후 Scheduler λ₯Ό ν™œμš©ν•΄μ„œ μΌκ΄„μ μœΌλ‘œ sent Column 값이 false 인 λ°μ΄ν„°λ“€μ˜ kafka λ©”μ„Έμ§€λ₯Ό 생성해 topic 으둜 μ „λ‹¬μ‹œν‚¨λ‹€.

- 전달이 μ™„λ£Œλœ λ°μ΄ν„°μ˜ sent 값을 true 둜 λ³€κ²½μ‹œμΌœμ£Όλ©΄ λœλ‹€.


🌱고민1 : μ•„μ›ƒλ°•μŠ€ νŒ¨ν„΄μ„ μ μš©ν•˜λ©΄ Kafka λ©”μ„Έμ§€ 전솑 전에 무쑰건 DB 둜 λΆ€ν„° 쑰회λ₯Ό ν•΄μ„œ λΆˆλŸ¬μ˜€λ‹€λ³΄λ‹ˆ λ¦¬μ†ŒμŠ€κ°€ λ‚­λΉ„λ˜μ§€ μ•Šμ„κΉŒ?

- 1차적으둜 DB 에 λ©”μ„Έμ§€λ₯Ό μ €μž₯μ‹œν‚€κ³  이후 μŠ€μΌ€μ€„λŸ¬λ₯Ό 톡해 주기적으둜 일괄 Kafka λ©”μ„Έμ§€λ₯Ό μ „μ†‘ν•˜λ‹€λ³΄λ‹ˆ μ•„λž˜ 두 κ²½μš°μ—μ„œ ν•œκ³„κ°€ μžˆμ§€ μ•Šμ„κΉŒ 생각이 λ“€μ—ˆλ‹€.

  • μ„œλ²„ 및 DB λΆ€ν•˜
  • μ‹€μ‹œκ°„ λ©”μ„Έμ§€ 전솑 λΆˆκ°€

πŸ’‘ κ³ λ―Ό1 ν•΄κ²°: μ•„μ›ƒλ°•μŠ€ νŒ¨ν„΄ λ³€ν˜• ꡬ쑰 κ΅¬ν˜„

- κ·Έλž˜μ„œ ν•„μžλŠ” μ•„μ›ƒλ°•μŠ€ νŒ¨ν„΄μ—μ„œ 쑰금 λ³€ν˜•ν•΄ 졜초 Kafka λ©”μ„Έμ§€ 생성 μ‹œ λ°”λ‘œ μ „μ†‘μ‹œν‚΄κ³Ό λ™μ‹œμ— Outbox Table 에도 μ €μž₯μ‹œν‚¨λ‹€. 이 λ•Œ Sent Flag λ³€μˆ˜λŠ” true κ°’μœΌλ‘œ μ €μž₯ν•œλ‹€.

- ν˜Ήμ‹œ Kafka λ©”μ„Έμ§€ 전솑에 μ‹€νŒ¨ν•œλ‹€λ©΄ Sent λ³€μˆ˜ 값을 false κ°’μœΌλ‘œ λ³€κ²½ν•˜κ³  이후 μŠ€μΌ€μ€„λŸ¬λ₯Ό 톡해 재처리λ₯Ό μ‹œμΌ°λ‹€.

- λ˜ν•œ DB κ³ΌλΆ€ν•˜λ₯Ό 막기 μœ„ν•΄ μƒμ„±μ‹œκ°„ κΈ°μ€€ μ˜€λ¦„μ°¨μˆœ μƒμœ„ 50 개의 데이터씩 μž¬μ „μ†‘μ„ μ‹œλ„ν•˜λ„λ‘ 섀정을 ν–ˆλ‹€.

 

- 1차적으둜 Kafka λ©”μ„Έμ§€ 전솑에 μ„±κ³΅ν•œ 데이터듀은 κ±ΈλŸ¬μ§€κΈ° λ•Œλ¬Έμ— 이후 μŠ€μΌ€μ€„λŸ¬λ₯Ό 톡해 쑰회 ν›„ μ²˜λ¦¬ν•  λ•Œμ—λ„ DB λΆ€ν•˜κ°€ 쀄고, 졜초 Kafka λ©”μ„Έμ§€ 생성 μ‹œ λ°”λ‘œ μ „μ†‘μ‹œν‚€κΈ° λ•Œλ¬Έμ— λΉ λ₯Έ λ©”μ„Έμ§€ 전솑이 κ°€λŠ₯ν•˜λ‹€.


🌱고민2 : μž¬μ „μ†‘μ„ μ‹œλ„ν•΄λ„ κ³„μ†ν•΄μ„œ Sent 값이 False 인 κ²½μš°λŠ” μ–΄λ–»κ²Œ μ²˜λ¦¬ν•˜λ©΄ μ’‹μ„κΉŒ?

- μΌμ‹œμ μΈ λ„€νŠΈμ›Œν¬ 였λ₯˜ λ“±μœΌλ‘œ Kafka λ©”μ„Έμ§€ 전솑에 μ‹€νŒ¨ν–ˆμ„ λ•Œλ₯Ό λŒ€λΉ„ν•΄ μ•„μ›ƒλ°•μŠ€ νŒ¨ν„΄μ„ ν•„μžμ˜ μ„œλΉ„μŠ€μ— 맞게 μˆ˜μ •μ„ ν–ˆλ‹€.

- ν•˜μ§€λ§Œ μΌμ‹œμ μΈ λ„€νŠΈμ›Œν¬κ°€ μ•„λ‹ˆλΌ Kafka 연결이 λŠμ–΄μ‘Œλ“  μ–΄λ– ν•œ 치λͺ…적인 상황 λ•Œλ¬Έμ— μ§€μ†μ μœΌλ‘œ μž¬μ „μ†‘μ„ μ‹œλ„ν•΄λ„ Kafka λ©”μ„Έμ§€ 전솑에 μ‹€νŒ¨λ₯Ό ν•˜λŠ” 경우, Outbox DB μ—λŠ” 데이터가 계속 μŒ“μΌ 것이닀.

List<NotificationOutbox> findTop50BySentFalseAndDlqFalseOrderByCreatedAtAsc();

 

- λ˜ν•œ μœ„μ²˜λŸΌ μƒμ„±μ‹œκ°„ κΈ°μ€€ μ˜€λ¦„μ°¨μˆœμœΌλ‘œ μƒμœ„ 50개λ₯Ό κ°€μ Έμ˜€λ‹€λ³΄λ‹ˆ, 계속 같은 λ°μ΄ν„°λ§Œ 반볡적으둜 Kafka λ©”μ„Έμ§€ 전솑 μ‹œλ„λ₯Ό ν•˜κ²Œ 될 것이닀.


πŸ’‘ κ³ λ―Ό2 ν•΄κ²°: Redis λ„μž…μ„ 톡해 각 데이터별 Count 및 Webhook 연결을 ν†΅ν•œ 운영 처리

- λ•Œλ¬Έμ— 각 데이터별 μž¬μ „μ†‘ 횟수의 ν•œκ³„λ₯Ό λ‘μ—ˆμ–΄μ•Όν–ˆκ³ , λ‹¨μˆœ 카운트이기 λ•Œλ¬Έμ— DB λΆ€ν•˜λ₯Ό 쀄이고 TTL λ“± 섀정을 톡해 κ΄€λ¦¬ν•˜κΈ° μš©μ΄ν•œ redis λ₯Ό μ΄μš©ν•΄ count λ₯Ό ν–ˆλ‹€.

 

- 각 Outbox Id 별 μž¬μ „μ†‘ 3회 μ œν•œμ„ κ±Έκ³ , λ§Œμ•½ 3회 초과둜 μž¬μ „μ†‘ μ‹€νŒ¨ μ‹œ 이λ₯Ό 치λͺ…적인 μ—λŸ¬ λ°œμƒμœΌλ‘œ λΆ„λ₯˜ν•œλ‹€.

 

- 이λ₯Ό 운영적인 μΈ‘λ©΄μ—μ„œ κ°œλ°œμžκ°€ 쑰치λ₯Ό ν•  수 μžˆλ„λ‘ ν•΄λ‹Ή Outbox λ°μ΄ν„°μ˜ errored Column 값을 true 둜 λ³€κ²½ν•˜κ³ ,

데이터 정보와 ν•¨κ»˜ Discord Webhook λ₯Ό μ—°κ²°ν•΄ 곡유 κ°€λŠ₯ν•˜λ„λ‘ ν–ˆλ‹€.

 

🚨 ν…ŒμŠ€νŠΈ

try {
    if (true) {
        throw new RuntimeException("πŸ’₯ 고의둜 λ°œμƒμ‹œν‚¨ Kafka μ˜ˆμ™Έ");
    }
    kafkaTemplate.send("notifications", message);
    log.info("βœ… Kafka 전솑 성곡");
}

 

μ˜λ„μ μœΌλ‘œ Error 에 걸리게 ν•˜κΈ° μœ„ν•΄μ„œ Kafka message λ₯Ό μƒμ„±ν•˜λŠ” try 문에 RuntimeException μ—λŸ¬κ°€ λ‚˜μ˜€κ²Œ ν–ˆλ‹€.

 

λ°˜λ³΅λ¬Έμ„ 3번 λŒλ©΄μ„œ Redis μ—μ„œ count λ₯Ό ν•˜κ³  count μ œν•œμ΄ λλ‚˜λ©΄ ν•΄λ‹Ή log 와 ν•¨κ»˜ Discord μ•Œλ¦Ό 전솑을 보내며 errored 값을 true 둜 μˆ˜μ •ν•œλ‹€.


🌱고민3 : DLQ Topic λ„μž…μ„ ν•˜λŠ” 것이 μ’‹μ„κΉŒ?

- Kafka 의 DLQ κΈ°λŠ₯을 κ³ λ―Όν•΄λ³΄μ•˜λ‹€. 

 

DLQ ( Dead Letter Queue ) λž€ ?

λ©”μ‹œμ§€ μ†ŒλΉ„(Consumer) 쀑 μ²˜λ¦¬μ— μ‹€νŒ¨ν•œ λ©”μ‹œμ§€λ₯Ό λ”°λ‘œ μ €μž₯ν•˜λŠ” Kafka의 νŠΉμˆ˜ν•œ ν† ν”½(Queue)

 

- λ‹€μ–‘ν•œ 문제둜 Kafka Message μƒμ„±μ˜ μ‹€νŒ¨ μΌ€μ΄μŠ€κ°€ μžˆκ² μ§€λ§Œ, κ·Έ 쀑 Kafka μ„œλ²„ μžμ²΄μ— λ¬Έμ œκ°€ μžˆλŠ” μ‹œλ‚˜λ¦¬μ˜€λ₯Ό λŒ€λΉ„ν•΄λ³΄μžλ©΄ κ²°κ΅­ Kafka μ„œλ²„μ— λ¬Έμ œκ°€ 있기 λ•Œλ¬Έμ— Kafka DLQ Topic 에 μ €μž₯을 μ‹œλ„ν•΄λ„ λ˜‘κ°™μ΄ λ¬Έμ œκ°€ 생길 κ²ƒμœΌλ‘œ νŒλ‹¨ν–ˆλ‹€.

 

- ν˜„μž¬ Redis λ₯Ό ν™œμš©ν•œ 3회 μž¬μ‹œλ„ 및 Discord μ•Œλ¦Ό 전솑을 톡해 운영적인 μΈ‘λ©΄μ—μ„œ λŒ€μ‘μ΄ κ°€λŠ₯ν•˜λ„λ‘ 섀계λ₯Ό ν–ˆκΈ° λ•Œλ¬Έμ—, DLQ 둜 λ©”μ„Έμ§€ 전솑은 Producer 츑이 μ•„λ‹Œ 이미 Kafka 둜 λ©”μ„Έμ§€κ°€ μ €μž₯이 λ˜μ—ˆμ§€λ§Œ Consumer 츑인 μ•Œλ¦Όμ„œλ²„μ—μ„œ 이 λ©”μ„Έμ§€λ₯Ό μˆ˜μ‹ ν•˜μ§€ λͺ»ν•œ μ‹œλ‚˜λ¦¬μ˜€λ₯Ό λŒ€λΉ„ν•΄ μ•Œλ¦Όμ„œλ²„μ—μ„œ DLQ 둜 μ „μ†‘ν•˜λŠ” ꡬ쑰λ₯Ό μ„ νƒν•΄λ³΄μ•˜λ‹€.

(https://hanstory33.tistory.com/321)