[μΉνμ] λ©μΈ μλ²μΈ‘ μλ¬λ‘ μΈν Kafka Message μ μ‘ μ€ν¨ μλλ¦¬μ€ λλΉ μμ μ₯μΉ κ³ λ―Ό
π‘ κ°μ
μμλ°μ€ ν¨ν΄ ꡬν
κ³ λ―Ό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)