๐ก ๊ฐ์
์์๋ฐ์ค ํจํด ๊ตฌํ
๊ณ ๋ฏผ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)