CompensaTX๋ ์์ ํ ๋ถ๋ฆฌ๋ ์ํ/์ธํ ๊ณ์ข ์์คํ
(๊ฐ๊ธฐ ๋ค๋ฅธ DB, ์๋ฒ) ํ๊ฒฝ์์
์์ ํ๊ณ ๊ฐ์ธํ๊ฒ ํ์ ยท์ด์ฒด๋ฅผ ์ฒ๋ฆฌํ ์ ์๋ Saga(๋ณด์ ํธ๋์ญ์
) ํจํด ๊ธฐ๋ฐ ๋ถ์ฐ ํธ๋์ญ์
์์คํ
์
๋๋ค.
- ์ฅ์ /๋คํธ์ํฌ ์ค๋ฅ ๋ฐ์ ์์๋ ๋ฐ์ดํฐ ์ ํฉ์ฑ์ ๋ณด์ฅ
- ์๋ ๋ณต๊ตฌ ๋ฐ ์๋ ๊ฐ์ ๋ชจ๋ ์ง์
- ์ค์ ํ ์ค๋ฑ ํฌ์ ๋ถ์ฐ ํ์ ๊ตฌ์กฐ๋ฅผ ๋ฒค์น๋งํนํ์ฌ ์ค๊ณ
| ๊ณ ํ์ฐ | ์ด์ ํ | ์ด์ฉํ | ์ฅ์กํ |
| @kohtaewoo | @lyjh98 | @dldydgns | @songhajang |
| Kafka consumer | ์ธํ(OEHWA) ๊ณ์ข API ์๋ฒ | ์ค์ผ์คํธ๋ ์ด์ API ์๋ฒ | ํ๋ก ํธ์๋ UI ์ํ(KRW) ๊ณ์ข API ์๋ฒ |
| ๋ ํฌ | ์ค๋ช | ๋งํฌ |
|---|---|---|
| compensaTX-BE | Backend API ์๋ฒ (์ค์ผ์คํธ๋ ์ด์ , ํธ๋์ญ์ ํ๋ฆ ์ ์ด) | ๐ ๋ฐ๋ก๊ฐ๊ธฐ |
| compensaTX-FE | Frontend (Vue.js ๊ธฐ๋ฐ UI) | ๐ ๋ฐ๋ก๊ฐ๊ธฐ |
| compensaTX-api-krw | ์ํ(KRW) ๊ณ์ข API ์๋ฒ (Oracle ๊ธฐ๋ฐ) | ๐ ๋ฐ๋ก๊ฐ๊ธฐ |
| compensaTX-api-oehwa | ์ธํ(OEHW) ๊ณ์ข API ์๋ฒ (MySQL ๊ธฐ๋ฐ) | ๐ ๋ฐ๋ก๊ฐ๊ธฐ |
| compensaTX-consumer-krw | ์ํ(KRW) Kafka ์ปจ์๋จธ (๊ณ ๊ฐ์ฉ์ฑ ์ธ์คํด์ค 2๊ฐ) | ๐ ๋ฐ๋ก๊ฐ๊ธฐ |
| compensaTX-consumer-oehwa | ์ธํ(OEHW) Kafka ์ปจ์๋จธ (๊ณ ๊ฐ์ฉ์ฑ ์ธ์คํด์ค 2๊ฐ) | ๐ ๋ฐ๋ก๊ฐ๊ธฐ |
| compensaTX-consumer-dlq | DLQ ์ ์ฉ Kafka ์ปจ์๋จธ (๋ณด์ ํธ๋์ญ์ ์ฌ์๋/๋ณต๊ตฌ) | ๐ ๋ฐ๋ก๊ฐ๊ธฐ |
| .github | GitHub Actions ๋ฐ ์ํฌํ๋ก ์ค์ ์ ์ฅ์ | ๐ ๋ฐ๋ก๊ฐ๊ธฐ |
ํ์ ์์ฒญ ์๋ฒ (Orchestrator)
- ์ ์ฒด ํ์ ์์ฒญ์ ๊ด๋ฆฌํ๊ณ ๋๊ธฐ ํธ์ถ๋ก ์ํยท์ธํ ๊ณ์ข ์๋ฒ์ ์ง์ ์ ๋ฐ์ดํธ ์์ฒญ
- ์คํจ ์ Kafka๋ก ๋ฉ์์ง๋ฅผ ์ ๋ฌํด ๋น๋๊ธฐ ์ฌ์๋ ๊ฒฝ๋ก๋ก ์ ํ
์ํ/์ธํ ๊ณ์ข ์๋ฒ
- ๊ฐ ํตํ ๊ณ์ข๋ณ ์ ์ถ๊ธ ์ฒ๋ฆฌ์ DB ์ฐ๋
- (์ํ: Oracle, ์ธํ: MySQL)
Kafka Broker
- ์คํจํ ์์ฒญ์ ๋น๋๊ธฐ ์ฌ์ฒ๋ฆฌํ๊ธฐ ์ํ ๋ฉ์์ง ๋ธ๋ก์ปค
- ๊ฐ Consumer ๊ทธ๋ฃน(์ํ, ์ธํ)์ผ๋ก ๋ฉ์์ง๋ฅผ ์ ๋ฌ
KRW/OEHWA Consumer
- ์ฌ์๋ ๋ก์ง์ ์ํํ๋ฉฐ DB๋ฅผ ๋ค์ ์ ๋ฐ์ดํธ
- ์ฒ๋ฆฌ ์คํจ ์ ๋ฉ์์ง๋ฅผ DLQ๋ก ์ด๋
DLQ Consumer
- ์ฌ์๋์๋ ์คํจํ ์์ฒญ์ ์ต์ข ๋ณด์ยท์ ๋ฆฌ ์ฒ๋ฆฌ
- ์ฅ์ ๋๋ ๋ณด์ ํธ๋์ญ์ ์ํฉ์ Slack์ผ๋ก ์๋ฆผ
- ๋จ์ผ ์๋ฒ, ๋จ์ผ DB โ DB ํธ๋์ญ์ ๋ง์ผ๋ก ์์์ฑ ๋ณด์ฅ
- ์ํ/์ธํ ๊ณ์ข ์๋ฒ์ DB๊ฐ ๋ถ๋ฆฌ โ ๋จ์ผ ํธ๋์ญ์ ์ ์ฉ ๋ถ๊ฐ
- ์ ์ถ๊ธ ์ค ํ์ชฝ๋ง ์ฑ๊ณตํ ๊ฒฝ์ฐ ๋ฐ์ดํฐ ๋ถ์ผ์น(์ ํฉ์ฑ ๋ฌธ์ ) ๋ฐ์
- ์ฝ๋๋ค์ดํฐ๊ฐ ๊ฐ ์๋ฒ์ ์ปค๋ฐ ๊ฐ๋ฅ์ฌ๋ถ๋ฅผ ์ง์, ๋ชจ๋ OK ์ ์ปค๋ฐ, ์๋๋ฉด ๋กค๋ฐฑ
- ๋ฌธ์ ์ :
- ๋๋ฆฐ ์ฐธ์ฌ์์ ์ํด ์ ์ฒด ์ง์ฐ
- ๊ฐ์ฉ์ฑ๊ณผ ํ์ฅ์ฑ ์ ํ
- ๋จ์ผ ์ฅ์ ์ ์ํ
- ๊ฐ ์๋น์ค๊ฐ ๋ก์ปฌ ํธ๋์ญ์ ์ ๊ฐ๋ณ ์ปค๋ฐ, ์คํจ ์ ์ด๋ฏธ ์ปค๋ฐ๋ ๋ถ๋ถ์ ๋ณด์ ํธ๋์ญ์ ์ผ๋ก ๋กค๋ฐฑ
- ์ฅ์ :
- ๋์ ํ์ฅ์ฑ, ๊ฐ์ฉ์ฑ
- ์๋ก์ด ์๋น์ค(์นด๋, ํ๊ณ ๋ฑ)๋ ์ฐธ์ฌ ์ฉ์ด
- ๋จ์ :
- ์ค๊ฐ์ํ ๋ ธ์ถ
- ๋ณด์ ํธ๋์ญ์ ์ง์ ๊ตฌํ ํ์
-
Saga ํจํด ์ค โ์ค์ผ์คํธ๋ ์ด์ ๋ฐฉ์โ ์ ํ
- ์ค์ผ์คํธ๋ ์ดํฐ(ํ์ ์๋ฒ)๊ฐ ์ ์ฒด ํ๋ก์ฐ์ ์ํ ์ถ์
- ํ์ ํ๋, ํ์ฌ ์งํ ์ํ ๋ฑ ๊ด๋ฆฌ ์ฉ์ด
-
ํ์ ์๋ฒ: ์ ์ฒด ํ์ ์ํ ๊ด๋ฆฌ, ์ค์ผ์คํธ๋ ์ดํฐ ์ญํ
-
์ํ/์ธํ ๊ณ์ข ์๋ฒ: ๊ฐ ๊ณ์ข๋ณ ์ ์ถ๊ธ ๋ฐ DB ๊ด๋ฆฌ
-
Kafka/DLQ/Scheduler/Batch: ์ฅ์ ์ ๋ณด์ ํธ๋์ญ์ , ์๋ ์ฌ์๋, ๋๋ ์ด ๋ฉ์์ง, ๋ฐฐ์น ๋ณต๊ตฌ ๋ด๋น
- Saga(Orchestration) ํจํด ๊ธฐ๋ฐ ๋ถ์ฐ ํธ๋์ญ์ ๊ตฌํ
- ์ถ๊ธ โ ์ ๊ธ ์์ ์์์ ํ์ ๋ฐ ๋ณด์ ํธ๋์ญ์ ์ค๊ณ
- Kafka DLQ ๋ฐ Scheduler๋ก ์ฅ์ /์ง์ฐ ์ํฉ ์๋ ๋ณต๊ตฌ
- **State Table(์ํ ๋ก๊ทธ)**๋ก ์ ์ฒด ์ด๋ ฅ ๋ฐ ์ํ ์ถ์
- Batch/Alert๋ฅผ ํตํ ๋ฏธ์ฒ๋ฆฌ ํ์ ์๋/์๋ ๋ณต๊ตฌ
- Loose Coupling: ์ ๊ท ์๋น์ค/๊ณ์ข/์ฐธ์ฌ์ ์์ฌ์ด ํ์ฅ
- ํ์ ์๋ฒ โ ์ํ ์ถ๊ธ ์์ฒญ (HTTP)
- ์ถ๊ธ ์ฑ๊ณต โ ์ธํ ์ ๊ธ ์์ฒญ (HTTP)
- ์ ๊ธ ์ฑ๊ณต โ ํ์ ์ฑ๊ณต ์ฒ๋ฆฌ
- ์ถ๊ธ ์คํจ โ ์ฆ์ ํ์ ์คํจ ์ฒ๋ฆฌ
- ์ ๊ธ ์คํจ โ ๋ณด์ ํธ๋์ญ์ (์ถ๊ธ ์ทจ์) ๋ฉ์์ง Kafka๋ก ๋ฐํ
- HTTP ํ์์์/๋คํธ์ํฌ ์ค๋ฅ ๋ฐ์์ Kafka Scheduler๋ก ๋๋ ์ด ์ฌ์๋
- ์ฌ๋ฌ ์ฐจ๋ก ์คํจ ์ Batch์์ ์ค๋จ ์ํ ํ์ง, Alert ํ ์๋/์๋ ๋ณต๊ตฌ
- ๋ณด์ ํธ๋์ญ์ ๋ฉ์์ง(์ถ๊ธ ์ทจ์)๊ฐ ์ปจ์๋จธ์์ ์คํจ โ DLQ ์๋ฒ์์ ์๋ ์ฌ์๋
- ์ผ์ ํ์ ์ด๊ณผ ์ ์ด์ ๊ฐ์ (์ฝ๋/์๋ฒ ๋ณต๊ตฌ ํ ์ฌ๋ฐํ)
- ํ์ ์คํจ ์ฒ๋ฆฌ + ๋ณด์ ๋ฉ์์ง ๋ฐํ์ ์์์ ์ผ๋ก ์ฒ๋ฆฌ (Kafka Producer DLQ ํ์ฉ)
๋ถ์ฐ ํ์ ์์คํ ๊ฐ๋ฐ ๊ณผ์ ์์ ์ค์ ๋ก ๊ฒช์๋ ์ฃผ์ ์ด์์ ํด๊ฒฐ ๋ฐฉ์์ ๊ธฐ๋กํฉ๋๋ค.
-
๋ฌธ์
JPA์์ ํ ์ํฐํฐ๊ฐ ๋ค๋ฅธ ์ํฐํฐ๋ฅผ ์ฐธ์กฐ(์ฐ๊ด๊ด๊ณ ๋งคํ)ํ ๋, ์ฐธ์กฐ ์ํฐํฐ์ ๊ฐ์ฒด ์์ฒด๊ฐ ์๋๋ผ ID ๊ฐ๋ง ์ด์ฉํด ์กฐํํ๊ฑฐ๋ ์ฟผ๋ฆฌ๋ฅผ ์์ฑํด์ผ ํ ๊ฒฝ์ฐ๊ฐ ์์์.
์ต์ํ์ง ์์ JPA ๋ฌธ๋ฒ(์:entity.field.id,@ManyToOne(fetch = FetchType.LAZY)๋ฑ)์ผ๋ก ์ธํด ์ ์ ํ JPQL, Criteria, ๋ค์ดํฐ๋ธ ์ฟผ๋ฆฌ ์์ฑ์ ์ด๋ ค์์ ๊ฒช์. -
ํด๊ฒฐ
๊ณต์ ๋ฌธ์ ๋ฐ ์ฌ๋ฌ ์์ ๋ค์ ์ฐธ๊ณ ํ์ฌ,
์ฐ๊ด ์ํฐํฐ์ ID ๊ฐ๋ง ์ด์ฉํ ์กฐ๊ฑด ๊ฒ์/์กฐ์ธ ๋ฐฉ๋ฒ์ ํ์ตํ๊ณ ,
join fetch๋๋where e.otherEntity.id = :id์ ๊ฐ์ด JPQL์์ ์ํฐํฐ ๊ฐ์ฒด๊ฐ ์๋ ID ๊ฐ ๊ธฐ์ค์ ๊ฒ์ ๋ฐฉ์์ผ๋ก ๊ฐ์ .
-
๋ฌธ์
HTTP ํต์ ์์ ๋น์ฆ๋์ค ๋ก์ง ์ ์คํจ(์: ์์ก ๋ถ์กฑ ๋ฑ)๋ฅผ 599 ๋ฑ์ 5xx ์๋ฒ ์๋ฌ๋ก ๋ฐํํ๋๋,
์์คํ ์์ธ์ ๋น์ฆ๋์ค ์์ธ๊ฐ ๋์ผํ๊ฒ ์ฒ๋ฆฌ๋์ด
์ฌ์๋/์ฅ์ ๊ฐ์ง/์๋ฆผ ๋ฑ์์ ํผ์ ๋ฐ์. -
ํด๊ฒฐ
๋ช ํํ **๋น์ฆ๋์ค ์คํจ(์: 200 OK + ์คํจ ์ฌ์ ๋ฉ์์ง)**์
**์์คํ ์ฅ์ (5xx)**๋ฅผ ๊ตฌ๋ถํ์ฌ
๋น์ฆ๋์ค ์คํจ๋ 2xx ์ํ์ฝ๋(์ฃผ๋ก 200/202 ๋ฑ)๋ก ๋ด๋ ค์ฃผ๊ณ ,
์ค์ ์๋ฌ ์ ๋ณด๋ ๋ณธ๋ฌธ(body)์ ๋ด์ ์ปจ์๋จธ์์ ๋ถ๊ธฐ ์ฒ๋ฆฌํ๋๋ก ์์ .
-
๋ฌธ์
HTTP ์คํจ ์์ฒญ์ Kafka๋ก ๋๊ฒจ ์ผ์ ์๊ฐ ํ ์ฌ์คํํ๋ ๊ตฌ์กฐ์์,
์ด์ ์์ฒญ์ DTO๋ฅผ ์ด์ฉํด ์ํฐํฐ๋ฅผ ์๋ก ๋ง๋ค๋ฉด JPA์์ ์์ง ์ ์ฅํ์ง ์์ ์์ ์ํ๋ผ ID ๊ฐ์ด ์์.
์ํฐํฐ ์์ฒด๋ฅผ Kafka๋ก ๋๊ธฐ๋ ๊ฒ์ ๋นํจ์จ์ ์ด๋ฉฐ,
save() ํธ์ถ ์์๋ ID๊ฐ ์๋ก ๋ถ์ฌ๋์ด ์๋ ์์ฒญ๊ณผ ๋งค์นญ๋์ง ์๋ ๋ฌธ์ ๋ฐ์. -
ํด๊ฒฐ
์์ฒญ DTO์ UUID ๋ฑ ๊ณ ์ ์๋ณ์๋ฅผ ํ์๋ก ํฌํจ์์ผ
Kafka Consumer์์๋ ์ด UUID๋ฅผ ์ด์ฉํด
๊ธฐ์กด DB์์ ์ํฐํฐ๋ฅผ ์กฐํ ๋ฐ ์ฌ์ฒ๋ฆฌํ๋๋ก ๊ตฌ์กฐ ๊ฐ์ .
-
๋ฌธ์
Kafka ํ๋ก๋์/์ปจ์๋จธ ๊ฐ DTO์ JSON ๋ณํ ๊ณผ์ ์์
๋งคํ ์ค๋ฅ, ํ๋ ๋๋ฝ ๋ฑ ํ์ฑ ์์ธ๊ฐ ๋ฐ์ํ์ผ๋
๋น์ฆ๋์ค ํธ๋์ญ์ ๊ณผ๋ ์ง์ ๊ด๋ จ์ด ์์ด ์์คํ ๋ก์ง๊ณผ ํผ์ฌ๋จ. -
ํด๊ฒฐ
Kafka์ Serializer/Deserializer ์ค์ ์ ํต์ผํ๊ณ
(ex: Jackson, Gson ๋ฑ ๋ช ํํ ์ผ์น์ํค๊ณ , ๋ถ์ผ์น ์ ์์ธ ๋ฐ์),
JSON ํ์ฑ ์์ธ๋ฅผ Kafka ์ค์ ์์ ์ฒ๋ฆฌ(์ฆ, ๊ฐ๋ณ ๋น์ฆ๋์ค ๋ก์ง์์ try-catch๋ก ์ก์ง ์์)
โ ์นดํ์นด ์์คํ ๋ ๋ฒจ์์ ์์ธ ์ฒ๋ฆฌ ๋ฐ DLQ๋ก ์์.
-
๋ฌธ์
Kafka ํ ํฝ ๋ฐํ ์ ์ฌ์ฉํ๋ ํ์(์ง๋ ฌํ/์ญ์ง๋ ฌํ ๋ฐฉ์)๊ฐ ์๋ฒ/์๋น์ค๋ณ๋ก ์ผ์นํ์ง ์์
DTOโ๏ธ JSON ๋ณํ์ ์คํจ, ๋ฉ์์ง ์๋น ๋ถ๊ฐ -
ํด๊ฒฐ
Kafka ํ๋ก๋์/์ปจ์๋จธ์ ์ง๋ ฌํ/์ญ์ง๋ ฌํ ํ์๋ฅผ ํต์ผ
(๋์ผํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๋ฐ ์ค์ ์ฌ์ฉ, DTO ์คํค๋ง/๋ฒ์ ๊ด๋ฆฌ)
โ ๋ฉ์์ง ํฌ๋งท ์ผ๊ด์ฑ ํ๋ณด
-
๋ฌธ์
Kafka๊ฐ ๋ค์ด๋๋ฉด ๋ณด์ ํธ๋์ญ์ ์ด ๋์ํ์ง ์์
์ฌ์ฉ์ ์๊ธ ์์ค, ๋ฐ์ดํฐ ๋ถ์ผ์น ๋ฑ ์น๋ช ์ ๋ฆฌ์คํฌ ์กด์ฌ -
ํด๊ฒฐ
Kafka ๋ธ๋ก์ปค ๋ณต์ (Replication) ๋ฐ ํด๋ฌ์คํฐ๋ง ์ ์ฉ- ์ต์ 2๋ ์ด์์ ๋ธ๋ก์ปค๋ก ๊ตฌ์ฑ,
- ํํฐ์
/๋ฆฌ๋/ํ๋ก์ ๊ตฌ์กฐ๋ก ํ์ชฝ ์๋ฒ๊ฐ ์ฅ์ ๋ฐ์ ์์๋
๋ค๋ฅธ ๋ธ๋ก์ปค๊ฐ Failoverํ์ฌ ๋ฉ์์ง ์์ค/๋๋ฝ ์์ด ์ฒ๋ฆฌ
โ ์์คํ ์ ๊ณ ๊ฐ์ฉ์ฑ(HA) ๋ฐ ์ ๋ขฐ์ฑ ํ๋ณด
์ค์๋น์ค ํ๊ฒฝ์์ ๋ฐ์ํ๋ ํธ๋ฌ๋ธ์ ๊ธฐ๋ฐ์ผ๋ก,
์ฅ์ /์๋ฌ ๋์๋ ฅ๊ณผ ๋ถ์ฐ ํ๊ฒฝ์์์ ์ผ๊ด์ฑ ์๋ ํธ๋์ญ์ ๊ด๋ฆฌ ๊ฒฝํ์ ์ถ์ ํ์์ต๋๋ค.