- ์๋น์ค ์ค๋ช
: ์ฌ์ฉ์๋ค์ด ๋๊ตฌ๋ ๊ฒ์ํ์ ๋ง๋ค ์ ์๊ณ , ๊ฒ์ํ์ ํตํด ์ ๋ณด, ์ผ์ ๊ณต์ ๋ฅผ ํ ์ ์๋๋ก ํ๊ธฐ ์ํ Restful API ํํ์ ์ปค๋ฎค๋ํฐ ์๋น์ค
- ๋ฐฑ์๋ ๊ธฐ๋ฅ์ ์ง์คํ๊ณ ์, ํ๋ก ํธ์๋ ๊ธฐ๋ฅ ๊ตฌํ์ ํ์ง ์์์ต๋๋ค.
- API ๋ฃจํธ ๊ฒฝ๋ก :
https://api.board-system.site - API ๋ฌธ์ : https://api.board-system.site/docs
- Github ๋งํฌ : https://github.com/ttasjwi/board-system
- Wiki: https://github.com/ttasjwi/board-system/wiki
- ์ฃผ์๊ธฐ๋ฅ : ๋ก๊ทธ์ธ/์์ ๋ก๊ทธ์ธ, ๊ฒ์๊ธ ๊ธฐ๋ฅ, ๊ฒ์๊ธ ์ข์์/์ซ์ด์ ๊ธฐ๋ฅ, ๊ฒ์๊ธ ๋๊ธ ๊ธฐ๋ฅ, ๊ฒ์๊ธ ์กฐํ์ ๊ธฐ๋ฅ, โฆ
- Kotlin, Spring Boot, MySQL, Redis, JPA, AWS(EC2, RDS, ElastiCache), Docker, Github Actions, K6, ...
-
๋์ ๋ฐฐ๊ฒฝ
- ์๋น์ค ๊ธฐ๋ฅ์ ํ ์คํธ ์ฝ๋๋ก ์ด๋ ์ ๋ ๊ฒ์ฆํ์ง๋ง, ์ค์ ๋ก ๋ง์ ๋์ ์ฌ์ฉ์ ์์ฒญ์ด ๋ค์ด์์ ๋ ์ฑ๋ฅ์ด ์ ์ง๋ ์ ์๋์ง๋ ํ์ธํ ์ ์์์ต๋๋ค.
- ํนํ, ๋๊ท๋ชจ ๋ฐ์ดํฐ๊ฐ ์ฝ์ ๋ ์ด์ ํ๊ฒฝ๊ณผ ์ ์ฌํ ์กฐ๊ฑด์์์ ์ฑ๋ฅ์ ๊ฒ์ฆํ๋ ๊ฒฝํ์ด ํ์ํ๋ค๊ณ ํ๋จํ์ต๋๋ค.
-
๋ฌธ์ ํด๊ฒฐ ๊ณผ์ : ์ง์ ์ ์ธ ํธ๋ํฝ ๊ฒฝํ์ ์ด๋ ต์ง๋ง, ์ด๋ฅผ ๋์ฒดํ ์ ์๋ ํ๊ฒฝ์ ๊ตฌ์ฑํด๋ณด๊ธฐ๋ก ํ์ต๋๋ค.
- ํ์ 1,200๋ง ๊ฑด, ๊ฒ์๊ธ 2,400๋ง ๊ฑด, ๋๊ธ 2,400๋ง ๊ฑด ๋ฑ ๋๊ท๋ชจ ๋ฐ์ดํฐ๋ฅผ ์ฝ์ ํ์ฌ ์ด์ ํ๊ฒฝ์ ๊ฐ๊น์ด ๋ฐ์ดํฐ ์ค์ผ์ผ์ ๊ตฌ์ฑํ์ต๋๋ค.
- ๋จ์ํ ๋ก์ปฌ ์ปดํจํฐ ํ ์คํธ์์ ๊ทธ์น์ง ์๊ณ , AWS EC2 ์ธ์คํด์ค์ ์ค์ ๋ก ์๋น์ค๋ฅผ ๋ฐฐํฌํจ์ผ๋ก์ ์ค๋ฌด์ ์ ์ฌํ ํ๊ฒฝ์ ๊ตฌ์ฑํ์ต๋๋ค.
- ๋ถํ ํ
์คํธ ๋๊ตฌ๋ก๋ ์คํ์์ค์ธ
k6๋ฅผ ์ฌ์ฉํ์ต๋๋ค.k6๋ ๊ฐ๋ณ๊ณ , ์ค์น ๋ฐ ์ค์ ์ด ๊ฐํธํ๋ฉฐ, ๋ถํ ์์ฑ ๋ฅ๋ ฅ๋ ์ถฉ๋ถํด ์ ํํ๊ฒ ๋์์ต๋๋ค. - ๋์ ์์ฒญ ์๋ฅผ 1๋ช ๋ถํฐ 50๋ช (๋ง๊ฒ๋ 1,000๋ช )๊น์ง ์ ์ง์ ์ผ๋ก ์ฆ๊ฐ์ํค๋ฉฐ, ์์ฒญ ์ฒ๋ฆฌ ๊ฐ๋ฅ ์์ ์๋ต ์๊ฐ์ ๋ณํ ๋ฑ์ ์ธก์ ํ์ต๋๋ค.
-
- ๋ก์ปฌ ํ ์คํธ์์๋ ์ํํ๊ฒ ๋์ํ๋ ๊ธฐ๋ฅ์ด์์ง๋ง, ์ค์ ๋ถํ ํ ์คํธ ๊ฒฐ๊ณผ ์๋ต ์๋๊ฐ ์ต๋ 30์ด๊น์ง ์น์๊ณ , TPS๊ฐ ๋ถ์์ ํด์ง๋ ํ์์ ๋ฐ๊ฒฌํ ์ ์์์ต๋๋ค.
- CloudWatch๋ฅผ ํตํด RDS์ CPU ์ฌ์ฉ๋ฅ ์ ๊ธ์ฆํ ๋ฐ๋ฉด EC2๋ ๋ฎ์ ์์ค์ ์ ์งํ๊ณ ์๋ค๋ ์ ์์ DB ์ฑ๋ฅ ๋ณ๋ชฉ์ด ์์ธ์์ ํ์ ํ ์ ์์์ต๋๋ค.
- ์ด๋ฅผ ๊ณ๊ธฐ๋ก DB ์ธ๋ฑ์ฑ ์ต์ ํ, ์กฐํ ์ฟผ๋ฆฌ ๊ฐ์ , ์ปค๋ฒ๋ง ์ธ๋ฑ์ค ํ์ฉ ๋ฑ ์ฑ๋ฅ ๊ฐ์ ์ ์งํํ๊ณ , ๊ทธ ๊ฒฐ๊ณผ๋ ์๋ ํญ๋ชฉ์์ ์์ธํ ์์ ํ์์ต๋๋ค.
-
๋์ ๋ฐฐ๊ฒฝ
- ๋ถํ ํ ์คํธ ๊ฒฐ๊ณผ, ๊ฒ์๊ธ ์๊ฐ ์ฝ 2,400๋ง ๊ฑด์ ์ด๋ฅด๋ ์ํฉ์์ ๊ฒ์๊ธ ๋ชฉ๋ก ์กฐํ ์๋๊ฐ ๊ธ๊ฒฉํ ๋๋ ค์ง๋ ํ์์ ํ์ธํ์ต๋๋ค.
-
- MySQL์ ์คํ ๊ณํ ๋๊ตฌ(
EXPLAIN,EXPLAIN ANALYZE)๋ฅผ ํ์ฉํด ์ฟผ๋ฆฌ์ ๋นํจ์จ์ ์ธ ์คํ ๋ฐฉ์์ ๋ถ์ํ์ต๋๋ค. - ๋ถ์ ๊ฒฐ๊ณผ, ๊ธฐ์กด ์ฟผ๋ฆฌ๋ ๋ชจ๋ ํ
์ด๋ธ์ ํ์ค์บํ ๋ค ์กฐ๊ฑด์ ๋ง๋ ๊ฒ์๊ธ์ ํํฐ๋งํ๊ณ , ์ ๋ ฌ ๋ฐ Offset์ ์ ์ฉํด
LIMIT์๋งํผ ์กฐํํ๋ ๋ฐฉ์์ด์์ต๋๋ค. - ์ด๋ ์ ๋ ฌ ๊ธฐ์ค์ด ์ธ๋ฑ์ค์ ํฌํจ๋์ด ์์ง ์์, ๋งค๋ฒ ์ ๋ ฌ ๋ฐ ํํฐ๋ง ์ฐ์ฐ์ด ์ถ๊ฐ ๋ฐ์ํ๊ณ ์์๊ณ , ์ด๋ก ์ธํด ์ฑ๋ฅ์ด ํฌ๊ฒ ์ ํ๋์์ต๋๋ค.
- MySQL์ ์คํ ๊ณํ ๋๊ตฌ(
-
- MySQL์ด ํํฐ๋ง๊ณผ ์ ๋ ฌ ์์ด๋ ํจ์จ์ ์ผ๋ก ๊ฒ์๊ธ์ ์กฐํํ ์ ์๋๋ก ๋ฉํฐ ์ปฌ๋ผ ์ธ๋ฑ์ค๋ฅผ ์ถ๊ฐํ์ต๋๋ค.
- ์ธ๋ฑ์ค ๊ตฌ์ฑ:
board_id ASC, article_id DESC
- ์ธ๋ฑ์ค ๊ตฌ์ฑ:
- ์ด ์ธ๋ฑ์ค๋ โํน์ ๊ฒ์ํ ๋ด์์ ์ต์ ๊ฒ์๊ธ ๋ชฉ๋ก์ ํ์ด์ง ๋จ์๋ก ์กฐํโ ํ๋ ํจํด๊ณผ ์์ ํ ์ผ์นํฉ๋๋ค.
- ์ธ๋ฑ์ค๊ฐ ์ ์ฉ๋ ์ดํ, MySQL์ ๋ ์ด์ ํ ์ด๋ธ ํ์ค์บ ์์ด ์ธ๋ฑ์ค ๋ ์ธ์ง ์ค์บ๋ง์ผ๋ก ํ์ํ ๊ฒ์๊ธ์ ๋น ๋ฅด๊ฒ ์กฐํํ ์ ์๊ฒ ๋์์ต๋๋ค.
- MySQL์ด ํํฐ๋ง๊ณผ ์ ๋ ฌ ์์ด๋ ํจ์จ์ ์ผ๋ก ๊ฒ์๊ธ์ ์กฐํํ ์ ์๋๋ก ๋ฉํฐ ์ปฌ๋ผ ์ธ๋ฑ์ค๋ฅผ ์ถ๊ฐํ์ต๋๋ค.
-
- ์คํ ๊ณํ ํ์ธ ๊ฒฐ๊ณผ, ์ฟผ๋ฆฌ๊ฐ ์๋ก ์์ฑํ ์ธ๋ฑ์ค๋ฅผ ์ ํํ ํ์ฉํ๋ ๊ฒ์ ํ์ธํ์ต๋๋ค.
- ์ธ๋ฑ์ค ์์์ ๊ฒ์๊ธ๋ค์ด ๊ฒ์ํ๋ณ๋ก ์ต์ ์์ผ๋ก ์ ๋ ฌ๋์ด ์์ด ์ถ๊ฐ์ ์ธ ์ ๋ ฌ ์์ ์์ด ํจ์จ์ ์ผ๋ก ์กฐํ๊ฐ ๊ฐ๋ฅํด์ก์ต๋๋ค.
- ๋ถํ ํ
์คํธ ์ฑ๊ณผ
- ๊ฐ์ ์ : ๋ฎ์ ๋์ ์ฌ์ฉ์ ์(VUs)์์๋ TPS๊ฐ ๋ถ์์
- ๊ฐ์ ํ: TPS๊ฐ VUs 23 ๋ถ๊ทผ์์ ์ต๋ 20.8๊น์ง ์์น, ๋ถํ๋ฅผ ์์ ์ ์ผ๋ก ์ฒ๋ฆฌ
- API ์๋ต ์๋ ๋น๊ต
- ๊ฐ์ ์ : 500๋ฒ ๊ฒ์ํ์ 20ํ์ด์ง ์กฐํ ์ ์ฝ 1,550ms
- ๊ฐ์ ํ: ๋์ผ ์กฐ๊ฑด์์ ์ฝ 43ms
โ ์ฝ 36๋ฐฐ ์ฑ๋ฅ ํฅ์
- ์ด์ ๋น์ทํ ๋ฐฉ์์ผ๋ก ๋๊ธ ๋ชฉ๋ก ์กฐํ ์ฑ๋ฅ ์ญ์ ๋ํญ ์ฑ๋ฅ์ ํฅ์์์ผฐ์ต๋๋ค.
- ๊ฐ์ ์ : 1์๊ฐ์ด ๋๋๋ก ๋๊ธ ๋ชฉ๋ก ์กฐํ ์๋ต์ด ์ค์ง ์์. (์ฑ๋ฅ ํ์ธ ๋ถ๊ฐ๋ฅ ์์ค)
- ๊ฐ์ ํ: 104ms ๋ง์ ๋๊ธ ๋ชฉ๋ก ์กฐํ ์๋ต์ด ์ค๋๋ก API ์ฑ๋ฅ ๊ฐ์
-
๋์ ๋ฐฐ๊ฒฝ
- ์ธ๋ฑ์ค๋ฅผ ์ ์ฉํด 36๋ฐฐ์ ์ฑ๋ฅ ํฅ์์ ์ด๋ฃจ์์ง๋ง, ์ธ๊ธฐ ๊ฒ์ํ์์ ํ์ด์ง ๋ฒํธ๊ฐ 1,000 ์ด์์ผ๋ก ์ปค์ง ๊ฒฝ์ฐ ์ฌ์ ํ ์ฑ๋ฅ ์ ํ๊ฐ ๋ฐ์ํ๋ ๊ฒ์ ํ์ธํ์ต๋๋ค.
-
- ํ์ด์ง ๋ฒํธ๊ฐ ์ปค์ง์๋ก
OFFSET์ด ์ปค์ง๊ณ , ๊ทธ๋ก ์ธํด ์กฐํ ์๊ฐ์ด ๊ธ๊ฒฉํ ๋์ด๋ฉ๋๋ค. - ๊ฒ์๊ธ ๋ชฉ๋ก์ ์กฐํํ ๋ ์ ์ฒด ๊ฒ์๊ธ ์๋ฅผ ๊ตฌํ๊ธฐ ์ํ
COUNT(*)์ฟผ๋ฆฌ๋ ์ฑ๋ฅ ์ ํ์ ์์ธ์ด ๋ฉ๋๋ค. - ๋ํ, ์กฐํ ๋์ ๊ฒ์๊ธ์ ํฌํจ๋ ์ปฌ๋ผ๋ค์ด ์ธ๋ฑ์ค์ ์กด์ฌํ์ง ์์ผ๋ฉด ํ ์ด๋ธ ์ ๊ทผ์ด ๋ฐ์ํ๊ณ , ์ด๋ Disk I/O ์ฆ๊ฐ๋ก ์ด์ด์ง๋๋ค.
- ๋ฐ๋ผ์ ์ธ๋ฑ์ค๋ง์ผ๋ก ์ ๋ ฌยทํํฐ๋งํ๊ณ , ์ค์ ํ ์ด๋ธ ์ ๊ทผ์ ํ์ํ ๊ฒฝ์ฐ์๋ง ์ต์ํํ๋ ๋ฐฉํฅ์ด ํ์ํ์ต๋๋ค.
- ํ์ด์ง ๋ฒํธ๊ฐ ์ปค์ง์๋ก
-
๊ฐ์ ๋ฐฉํฅ
-
ํ์ด์ง ๋ฒํธ ์ ํ: ๊ณผ๋ํ
OFFSET์ผ๋ก ์ธํ ๋นํจ์จ์ ๋ฐฉ์งํ๊ธฐ ์ํด ํ์ด์ง ๋ฒํธ๋ฅผ 1~100 ์ฌ์ด๋ก ์ ํํ์ต๋๋ค. -
๊ฒ์๊ธ ์ ๋น์ ๊ทํ: ๊ฒ์ํ ๋ณ ๊ฒ์๊ธ ์๋ฅผ ๋ณ๋ ํ ์ด๋ธ์์ ๊ด๋ฆฌํจ์ผ๋ก์จ
COUNT(*)์์ด๋ ์ด ํ์ด์ง ์๋ฅผ ๋น ๋ฅด๊ฒ ๊ณ์ฐํ ์ ์๋๋ก ํ์ต๋๋ค. -
์ฟผ๋ฆฌ ํ๋ (CTE + ์ปค๋ฒ๋ง ์ธ๋ฑ์ค):

-
OFFSET์ ๊ทผ ์ ์ฑ๋ฅ ์ ํ๋ฅผ ์ค์ด๊ธฐ ์ํด ์ปค๋ฒ๋ง ์ธ๋ฑ์ค๊ฐ ์ ์ฉ๋๋ ํํ๋ก ์ฟผ๋ฆฌ๋ฅผ ์ฌ๊ตฌ์ฑํ์ต๋๋ค.- ํ๋์ ์ฟผ๋ฆฌ ์์์ CTE(Common Table Expression) ๋ฅผ ํ์ฉํ์ฌ, ๋จผ์ ์ธ๋ฑ์ค๋ง์ผ๋ก ์ํ๋ ๊ฒ์๊ธ
ID๋ชฉ๋ก์ ์ถ์ถํ ๋ค, ํด๋น ID๋ค์ ๊ธฐ์ค์ผ๋ก ์ค์ ๊ฒ์๊ธ ์ ๋ณด๋ฅผ ์กฐํํ๋ ๋ฐฉ์์ ๋๋ค. - ์์ ์ฟผ๋ฆฌ:
WITH cte(article_id) AS ( SELECT article_id FROM articles WHERE board_id = 1 ORDER BY article_id DESC LIMIT 50 OFFSET 199950 ) SELECT ... FROM articles a JOIN cte ON a.article_id = cte.article_id ...
CTE๋ด๋ถ์SELECT๋ ์ธ๋ฑ์ค ์ปฌ๋ผ(board_id, article_id)๋ง์ ์กฐํํ์ฌ ๋์คํฌ ์ ๊ทผ ์์ด ์ธ๋ฑ์ค ๋ ๋ฒจ์์ ๋น ๋ฅด๊ฒ ์ฒ๋ฆฌ๋ฉ๋๋ค.- ์ดํ ๋ณธ๋ฌธ ์ฟผ๋ฆฌ์์๋
JOIN์ ํตํด ํ์ํ ์ ๋ณด๋ง ํ ์ด๋ธ์์ ์กฐํํจ์ผ๋ก์จ Disk I/O๋ฅผ ์ต์ํํ๊ณ , ์ ๋ ฌ/ํํฐ๋ง ๋น์ฉ๋ ์ค์ด๋ ๊ตฌ์กฐ๋ฅผ ๊ตฌํํ์ต๋๋ค.
- ํ๋์ ์ฟผ๋ฆฌ ์์์ CTE(Common Table Expression) ๋ฅผ ํ์ฉํ์ฌ, ๋จผ์ ์ธ๋ฑ์ค๋ง์ผ๋ก ์ํ๋ ๊ฒ์๊ธ
-
-
์ฑ๊ณผ
-
๊ฐ์ ์ :
- ์ต๋ TPS: 20.8 (VUs 23 ๊ธฐ์ค)
- RDS๊ฐ ๋ณ๋ชฉ ์ง์
-
- ์ต๋ TPS: 207.5 (VUs 224 ๊ธฐ์ค, 10.4๋ฐฐ ํฅ์)
- RDS CPU ์ฌ์ฉ๋ฅ : 21.4%๋ก ๊ฐ์
- EC2 CPU ์ฌ์ฉ๋ฅ : 99%์ ๋๋ฌ โ ๋ณ๋ชฉ์ด EC2๋ก ์ด๋
-
์ด๋ฅผ ํตํด ๋ณ๋ชฉ ์์ธ์ RDS โ EC2 ๋ก ์ด๋์ํฌ ์ ์์๊ณ , ์ดํ ์ฒ๋ฆฌ๋์ ๋ ๋์ด๊ธฐ ์ํด์๋ EC2 ์ธ์คํด์ค๋ฅผ ์ํ ํ์ฅํ๋ ๋ฐฉ์์ด ํ์ํจ์ ํ์ธํ์ต๋๋ค. ๋ค๋ง ํ ์คํธ ํ๊ฒฝ ๋น์ฉ ๋ฑ์ ์ด์ ๋ก ์ค์ ํ์ฅ์ ์งํํ์ง ์์์ต๋๋ค.
-
-
- ๊ฒ์๊ธ์ "์ข์์"๋ฅผ ๋๋ฅผ ์ ์๋ ๊ธฐ๋ฅ์ ๊ตฌํํ์ผ๋ฉฐ, ์ข์์ ์๋ ์กฐํ ์ฑ๋ฅ์ ๋์ด๊ธฐ ์ํด ๋น์ ๊ทํ๋ ํํ๋ก ๋ณ๋๋ก ์ ์ฅํ๊ณ ์์์ต๋๋ค.
- ๊ทธ๋ฌ๋ ์์ฒ ๋ช ์ ์ฌ์ฉ์๊ฐ ๋์์ ๊ฐ์ ๊ฒ์๊ธ์ ์ข์์ ์์ฒญ์ ๋ณด๋ผ ๊ฒฝ์ฐ, ๊ธฐ๋๊ฐ๋ณด๋ค ์ ์ ์์ ์ข์์๊ฐ ๋ฐ์๋๋ ํ์์ด ๋ฐ์ํ์ต๋๋ค.
- ์๋ฅผ ๋ค์ด, 3000๋ช ์ด ๋์์ ์์ฒญํ์์๋ ์ข์์ ์๋ 3000์ด ์๋ 302 ์ ๋๋ง ์ฆ๊ฐํ๋ ๋ฌธ์ ๊ฐ ์์์ต๋๋ค.
-
- ํด๋น ํ์์ ์ข์์ ์๋ฅผ ์กฐํ โ ์ฆ๊ฐ โ ์ ์ฅํ๋ ๊ธฐ์กด์ ๊ตฌํ ๋ฐฉ์์ด ํธ๋์ญ์ ๊ฐ ์ถฉ๋์ ์ทจ์ฝํ ๊ตฌ์กฐ์๊ธฐ ๋๋ฌธ์ ๋ฐ์ํ์ต๋๋ค.
- ๋ค์์ ํธ๋์ญ์ ์ด ๋์ผํ ์ข์์ ์ ๋ ์ฝ๋๋ฅผ ๊ฑฐ์ ๋์์ ์กฐํํ๊ณ , ๊ฐ์์ ์ํ์์ 1์ ์ฆ๊ฐ์ํจ ํ ์ ์ฅํ๋ ๋ฐฉ์์ด์๊ธฐ ๋๋ฌธ์ ๋์์ฑ ๋ฌธ์ ๊ฐ ๋ฐ์ํ๊ณ , ์ด๋ก ์ธํด ์ต์ข ๊ฒฐ๊ณผ๊ฐ ๋ฎ์ด์จ์ง๋ ๋ฌธ์ ๊ฐ ์์์ต๋๋ค.
- ํนํ ์ข์์ ์ ๋ ์ฝ๋๊ฐ ์กด์ฌํ์ง ์๋ ๊ฒฝ์ฐ ์ด๊ธฐํ ๊ณผ์ ์์๋ ์ค๋ณต INSERT ์ถฉ๋์ด ๋ฐ์ํ ์ ์์ด, ๋จ์ํ ๋ฝ์ ๊ฑธ์ด๋ ์์ ํ ํด๊ฒฐ์ด ์ด๋ ค์ด ๊ตฌ์กฐ์์ต๋๋ค.
-
๋ฌธ์ ํด๊ฒฐ ๋ฐฉ์ ๊ณ ๋ฏผ
- ๋๊ด์ ๋ฝ (Optimistic Lock)
versionํ๋๋ฅผ ํตํด ์ถฉ๋์ ๊ฐ์งํ๊ณ ์ฌ์๋ํฉ๋๋ค.- ๊ตฌํ์ ๊ฐ๋จํ์ง๋ง, ๋์ ์์ฒญ์ด ๋ง์ ๊ฒฝ์ฐ ์ถฉ๋๋ฅ ์ด ๋์ ์ฑ๋ฅ ์ ํ ์ฐ๋ ค๊ฐ ์์ต๋๋ค.
- ์ต์ด ์ข์์์ ์ด๊ธฐํ ์ ํ ์์ฒด๊ฐ ์กด์ฌํ์ง ์์ผ๋ฏ๋ก ์ค๋ณต insert ์ถฉ๋ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ ์ ์์ต๋๋ค.
- ๋น๊ด์ ๋ฝ (Pessimistic Lock)
SELECT ... FOR UPDATE๋ฅผ ์ฌ์ฉํด ํ์ ๋ฐฐํ์ ๋ฝ์ ๊ฑธ๊ณ ์์ฐจ์ ์ผ๋ก ์ฒ๋ฆฌํฉ๋๋ค- ์ ํ๋๋ ๋ณด์ฅ๋์ง๋ง, ๋ณ๋ชฉ ๊ฐ๋ฅ์ฑ๊ณผ ๋ฐ์ดํฐ๋ฒ ์ด์ค ๋ถํ ์ฆ๊ฐ ์ฐ๋ ค๊ฐ ์์ต๋๋ค.
- ์ต์ด ์ข์์์ ์ด๊ธฐํ ์ ํ ์์ฒด๊ฐ ์กด์ฌํ์ง ์์ผ๋ฏ๋ก ์ค๋ณต insert ์ถฉ๋ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ ์ ์์ต๋๋ค.
- Redis ๊ธฐ๋ฐ ๋ถ์ฐ ๋ฝ
- Redis ์ SetIfAbsent ๊ธฐ๋ฅ์ ํ์ฉํ ๋ถ์ฐ๋ฝ์ ํตํด ๊ฒ์๊ธ ์ข์์ ๊ธฐ๋ฅ์ ๋์ ์ ๊ทผ ์ ํ์ ๋ก๋๋ค.
- ์ต์ด ์ข์์์ ์ด๊ธฐํ ๋ฅผ ํ๋ ์ํฉ์๋ Redis ๋ฅผ ํตํด ๋ฝ์ ํ๋ํ๋ฏ๋ก, ์ค๋ณต insert ์ถฉ๋ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ ์ ์๊ธด ํฉ๋๋ค.
- ์ ๋ขฐ์ฑ์ด ๋์ง๋ง ์ธํ๋ผ ๋ณต์ก๋ ๋ฐ ๋น์ฉ์ด ์ฆ๊ฐํฉ๋๋ค.
- ์ด๊ธฐํ ์์ ๋ณ๊ฒฝ + ๋๊ด์ ๋ฝ / ๋น๊ด์ ๋ฝ ์ฌ์ฉ
- ๊ฒ์๊ธ ์์ฑ ์ ์ข์์ ์๋ฅผ ํจ๊ป ์ด๊ธฐํ ์์ฑํ์ฌ ์ต์ด ์ข์์ ์์ ์๋ โ์ข์์ ์โ๊ฐ ์ด๋ฏธ ์กด์ฌํ๊ฒ ํ๋ ๋ฐฉ๋ฒ์ ๋๋ค.
- ์์ ๋๊ด์ ๋ฝ / ๋น๊ด์ ๋ฝ ๋ฐฉ์์ ์ฌ์ฉ ๊ฐ๋ฅํ๊ฒ ํฉ๋๋ค.
- ํ์ง๋ง ๊ฒ์๊ธ ๋งฅ๋ฝ์์ โ๊ฒ์๊ธ ์ข์์โ ๋งฅ๋ฝ์ ์์กดํ๊ฒ ๋๋ฏ๋ก, ๋งฅ๋ฝ๊ฐ ๊ฐ๋ ์ํ์ฐธ์กฐ ๋ฌธ์ ๊ฐ ๋ฐ์ํ๊ฒ ๋ฉ๋๋ค.
- ๋๊ด์ ๋ฝ (Optimistic Lock)
-
- ๊ธฐ์กด ๊ตฌ์กฐ์ ๋ณต์ก๋์ ์ฑ๋ฅ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๋ฉด์๋ ๋ฝ ์์ด ์ ํ์ฑ์ ๋ณด์ฅํ ์ ์๋ ๋ฐฉ๋ฒ์ผ๋ก, MySQL์
INSERT ... ON DUPLICATE KEY UPDATE์ฟผ๋ฆฌ ์ฌ์ฉ์ผ๋ก ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ์ต๋๋ค.- ์ข์์ ์๋ฅผ ์กฐํํ๊ณ ๊ฐ์ฒด๋ฅผ ์กฐ์ํ๋ ๋์ , ****๋งค ์์ฒญ ์์ ๋ง๋ค DB์ ์ง์ INSERT ์๋
- ์ด๋ฏธ ํด๋น ๊ฒ์๊ธ์ ๋ํ ์ข์์ ์ ๋ ์ฝ๋๊ฐ ์กด์ฌํ ๊ฒฝ์ฐ, ์ค๋ณตํค ์ถฉ๋์ ์ ๋ํด
UPDATE๋ก ์ ํ - ๊ฒฐ๊ณผ์ ์ผ๋ก DB ์ํ๋ฅผ ๊ธฐ์ค์ผ๋ก ์ฆ์ 1 ์ฆ๊ฐ์ํค๋ ์์ ์ฐ์ฐ์ด ์ํ๋จ
- ์ด ๋ฐฉ์์ ๋ค์๊ณผ ๊ฐ์ ์ฅ์ ์ด ์์ต๋๋ค.
- ๋ฝ์ ์ฌ์ฉํ์ง ์์๋ ๋์์ฑ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ ์ ์์ต๋๋ค.
- ์ข์์ ์ ๊ฐ์ฒด์ ์กด์ฌ ์ ๋ฌด์ ๊ด๊ณ์์ด ๋์ผํ ์ฟผ๋ฆฌ๋ก ์ฒ๋ฆฌํ ์ ์์ต๋๋ค.
- ์ถ๊ฐ์ ์ธ ์ธํ๋ผ ๋น์ฉ ํฌ์ ์์ด๋ ์ ํ์ฑ๊ณผ ์ฑ๋ฅ์ ๋ชจ๋ ํ๋ณด ๊ฐ๋ฅ
- ๊ธฐ์กด ๊ตฌ์กฐ์ ๋ณต์ก๋์ ์ฑ๋ฅ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๋ฉด์๋ ๋ฝ ์์ด ์ ํ์ฑ์ ๋ณด์ฅํ ์ ์๋ ๋ฐฉ๋ฒ์ผ๋ก, MySQL์
-
- ๊ธฐ์กด์๋ ์์ฒ ๋ช ์ด ๋์์ ์์ฒญํด๋ ์์ญ ๊ฑด๋ง ๋ฐ์๋๋ ๋ฌธ์ ๊ฐ, 3000๋ช ์ด ๋์์ ์ข์์ ์์ฒญ ์ ์ ํํ 3000๊ฑด์ด ๋ฐ์๋๋๋ก ๊ฐ์ ๋์ต๋๋ค.
- Redis ๋ฑ ์ธ๋ถ ์บ์๋ ๋ฝ ์ ์ฅ์๋ฅผ ๋์ ํ์ง ์๊ณ ๋, ๋ฐ์ดํฐ๋ฒ ์ด์ค(MySQL)์ ๊ธฐ๋ฅ๋ง์ผ๋ก ์ ํฉ์ฑ๊ณผ ์ฑ๋ฅ์ ๋ชจ๋ ๋ฌ์ฑํ์ต๋๋ค.
- ๋ฐ์ดํฐ ์กฐ์ ๋ก์ง์ด ๋๋ฉ์ธ ๊ฐ์ฒด ์ค์ฌ์ด ์๋ DB ์ฐ์ฐ ์ค์ฌ์ด ๋๋ ์ ์์ ๋ค์ ์์ฌ์์ด ์์ง๋ง, ์ ํฉ์ฑ, ์ฑ๋ฅ ๋ฌธ์ ๋ฅผ ๋ชจ๋ ๋ง์กฑ์ํค๋ ์ค์ฉ์ ์ธ ์ ํ์ด์๋ค๊ณ ์๊ฐํฉ๋๋ค.
-
- ์ฐ๋ฆฌ ์๋น์ค์์๋ ์ฌ์ฉ์ ์กฐํ์ ์ฆ๊ฐ API ๋ฅผ ๋ณ๋๋ก ๊ด๋ฆฌํ๊ณ ์์ต๋๋ค. ์ฌ์ฉ์๊ฐ ์์ฒญ์ ํ๋ฉด ๊ฒ์๊ธ์ ์กฐํ์๊ฐ 1 ์ฆ๊ฐํฉ๋๋ค.
- ๊ทธ๋ฌ๋ ๋์์ ํน์ ์ฌ์ฉ์๊ฐ ์ ์ฉ ๋ชฉ์ ์ผ๋ก ๊ฒ์๊ธ ์กฐํ์ ์ฆ๊ฐ๋ฅผ ๋์์ ๋งค์ฐ ๋ง์ด ์์ฒญํ ๊ฒฝ์ฐ, ๊ฒ์๊ธ ์กฐํ์๊ฐ ์์๊ฐ์ ํญ์ฆํ๋ ๋ฌธ์ ๊ฐ ๋ฐ์ํฉ๋๋ค. (์ ์ฉ, ์ด๋ทฐ์ง)
-
- ๊ธฐ์กด ๋ก์ง์, '๊ฒ์๊ธ ์กฐํ์ ๋ฝ' ํ๋ ๋ก์ง์ ์ถ๊ฐํ์ต๋๋ค
- ์ฌ์ฉ์๋ ์์ฒญํ ๋๋ง๋ค ๊ฒ์๊ธ ์กฐํ์ ๋ฝ ํ๋์ ์๋ํฉ๋๋ค. ๋ฝ ํ๋์ ์ฑ๊ณตํ๋ฉด ๊ฒ์๊ธ ์กฐํ์ ์ฆ๊ฐ ๋ก์ง์ ์ํํ๊ณ , ๋ฝ ํ๋์ ์คํจํ๋ฉด ์กฐํ์ ์ฆ๊ฐ๋ฅผ ํ์ง ์์ต๋๋ค.
- Redis ์์๋ setIfAbsent ๋ผ๋ ๊ธฐ๋ฅ์ ์ ๊ณตํฉ๋๋ค.
- key ๊ฐ ์กด์ฌํ์ง ์์ผ๋ฉด value ๋ฅผ ์ ์ฅํ ์ ์์ต๋๋ค. ์ ์ฅ์ ์ฑ๊ณตํ๋ฉด true ๊ฐ ๋ฐํ๋ฉ๋๋ค.(ttl ์ง์ ๊ฐ๋ฅ)
- key ๊ฐ ์กด์ฌํ๋ฉด value๋ฅผ ์ ์ฅํ ์ ์์ต๋๋ค. ์ด ๊ฒฝ์ฐ false๊ฐ ๋ฐํ๋ฉ๋๋ค.
- ์ต์ด ๋ฝ ํ๋ ์๋์, 10๋ถ๊ฐ ์ ํจํ๋๋ก setIfAbsent ๋ฅผ ํธ์ถํ์ฌ, 10๋ถ๊ฐ value ๋ฅผ ์ ์ฅํ ์ ์๊ฒ ํ๋ ๊ฒ์
๋๋ค.
- ์ต์ด ์์ฒญ ์ set์ ์ฑ๊ณตํ๋ฉด true ๊ฐ ๋ฐํ๋๋๋ฐ(10๋ถ๊ฐ ์ ์ฅ๋จ) ์ด๋ฅผ ๋ฝ ํ๋ ์ฑ๊ณต์ผ๋ก ๊ฐ์ฃผํฉ๋๋ค.
- ์ดํ 10๋ถ๊ฐ ์์ฒญ ์ false ๋ฅผ ๋ฐํ๋ฐ๋๋ฐ, ์ด๋ฅผ ๋ฝ ํ๋ ์คํจ๋ก ๊ฐ์ฃผํ๊ฒ ํ๋ฉด ๋ฉ๋๋ค.
- ์ด ๊ธฐ๋ฅ์ ํ์ฉํ์ฌ ๋ถ์ฐ๋ฝ์ ๊ตฌํํ ์ ์์ต๋๋ค.
-
- ๋์์ ํ ์ฌ์ฉ์๊ฐ 1๋ง๋ฒ ์กฐํ์ ์ฆ๊ฐ ์์ฒญ์ ํ๊ฒ ์๋ฎฌ๋ ์ด์ ํ ๊ฒฐ๊ณผ(100๊ฐ ์ค๋ ๋), ์กฐํ์๋ 1 ์ ๋๋ง ์ฆ๊ฐํ๋ ๊ฒ์ ํ์ธํ์ต๋๋ค.
- 10๋ถ ์ด๋ด๋ก ๊ฐ์ ์ฌ์ฉ์๊ฐ ์กฐํ์ ์ฆ๊ฐ ์ด๋ทฐ์ง์ ํ๋๋ผ๋ ์กฐํ์๊ฐ ํญ์ฆํ๋ ์ด๋ทฐ์ง ํ์์ ๋ง์ ์ ์๊ฒ ๋์ต๋๋ค.
-
๋์ ๋ฐฐ๊ฒฝ
- ์ฝ๋ ๋ณ๊ฒฝ ์, ๊ธฐ์กด ๊ธฐ๋ฅ๊ณผ์ ํตํฉ์ด ์ ๋๋ก ์ด๋ฃจ์ด์ก๋์ง๋ฅผ ๋งค๋ฒ ์๋์ผ๋ก ํ์ธํด์ผ ํ์ต๋๋ค.
- ์ ํ๋ฆฌ์ผ์ด์ ๋ฐฐํฌ ๊ณผ์ ๋ ์์์ ์ผ๋ก ์งํํ๊ธฐ ๋๋ฌธ์, ๋ฌด์ค๋จ ๋ฐฐํฌ๋ฅผ ์ค์ ์์ด ์ํํ๊ธฐ ์ด๋ ค์ด ๊ตฌ์กฐ์์ต๋๋ค.
- ํ ์คํธ ๋ฐ ๋ฐฐํฌ ์์ ์ ์์๋๋ ์๊ฐ๋ ๊ธธ์ด ๊ฐ๋ฐ ์์ฐ์ฑ์ ๋จ์ด๋จ๋ฆฌ๋ ์์ธ์ด ๋์์ต๋๋ค.
-
GitHub Actions์ Docker๋ฅผ ํ์ฉํ์ฌ CI/CD ํ์ดํ๋ผ์ธ์ ์๋ํํ๊ณ , EC2 + Nginx ๊ธฐ๋ฐ์ ๋ฌด์ค๋จ ๋ฐฐํฌ ๊ตฌ์กฐ๋ฅผ ๊ตฌ์ถํ์ต๋๋ค.
-
CI ๋จ๊ณ:
- PR ์์ฑ ์ ์๋์ผ๋ก ๋น๋ ๋ฐ ํ ์คํธ ์คํ
- ํ ์คํธ ์คํจ ์ ๋ณํฉ ์ฐจ๋จ โ ์ฝ๋ ํ์ง ๋ณด์ฅ
-
CD๋จ๊ณ:
master๋ธ๋์น์ ๋ณํฉ๋๋ฉด ์๋์ผ๋ก ๋ฐฐํฌ ํ์ดํ๋ผ์ธ ์คํ- JAR โ Docker ์ด๋ฏธ์ง ์์ฑ
- DockerHub๋ก Push
- EC2 ์๋ฒ์์ ์ด๋ฏธ์ง Pull ๋ฐ ์ ์ปจํ ์ด๋ ์คํ
- ํฌ์ค์ฒดํฌ ์๋ฃ ์, Nginx์ ๋ฆฌ๋ฒ์ค ํ๋ก์ ๋ผ์ฐํ ๋ณ๊ฒฝ
- ์ด์ ๋ฒ์ ์ปจํ ์ด๋ ์ข ๋ฃ ๋ฐ ๋ถํ์ํ ์ด๋ฏธ์ง ์ ๋ฆฌ
-
ํ๊ฒฝ ๊ฐ ์ผ๊ด์ฑ ํ๋ณด:
- Docker๋ฅผ ํตํด ๋ฐฐํฌ ํ๊ฒฝ์ ์ปจํ ์ด๋ํํจ์ผ๋ก์จ, ํ๊ฒฝ ์ฐจ์ด์ ์ํ ๋ฐฐํฌ ์ค๋ฅ ๋ฐฉ์ง
- EC2 ์ธ์คํด์ค ์ด๋์๋ ๋์ผํ ํ๊ฒฝ ์กฐ๊ฑด์ผ๋ก ์ ํ๋ฆฌ์ผ์ด์ ์คํ ๊ฐ๋ฅ
-
-
์ฑ๊ณผ
- ์๋ํ๋ ํ ์คํธ ๋ฐ ๋ฐฐํฌ๋ก ์ค์ ๊ฐ๋ฅ์ฑ ๊ฐ์ ๋ฐ ๊ฐ๋ฐ ์์ฐ์ฑ ํฅ์
- ๋ฌด์ค๋จ ๋ฐฐํฌ ๊ตฌํ: ๊ธฐ์กด ํธ๋ํฝ ์ฒ๋ฆฌ ์ค์ธ ์ปจํ ์ด๋์ ์ํฅ์ ์ฃผ์ง ์๊ณ ์ ๋ฒ์ ์ผ๋ก ์์ ํ๊ฒ ์ ํ
- Docker ๊ธฐ๋ฐ ์ปจํ ์ด๋ ๊ฒฉ๋ฆฌ๋ฅผ ํตํด, ์ปจํ ์ด๋ ๋ด๋ถ ์๋น์ค ์ฅ์ ๊ฐ ๋ฐ์ํด๋ ํธ์คํธ ํ๊ฒฝ์๋ ์ํฅ์ด ์์ต๋๋ค.
-
- ๊ธฐ์กด์๋ ๋ชจ๋ ๊ธฐ๋ฅ์ด ํ๋์ ๋ชจ๋์ ๊ฒฐํฉ๋๊ณ ํจํค์ง ์์กด ๋ฐฉํฅ์ด ๋ช ํํ์ง ์์ ๊ตฌ์กฐ์์ต๋๋ค.
- ๊ธฐ๋ฅ์ด ๋์ด๋๋ฉด์ ์์กด์ฑ ๋ฐฉํฅ์ด ๋ค์์ด๊ณ ํต์ ๋ถ๊ฐ๋ฅํด์ง๋ ๋ฌธ์ ๊ฐ ๋ฐ์ํ์ต๋๋ค.
- ์๋ฅผ ๋ค์ด, ๋จ์ํ Redis ๊ธฐ๋ฅ๋ง ํ ์คํธํ๊ณ ์ถ์ด๋, ์ ํ ์๊ด์๋ RDBMS ์ค์ ์ค๋ฅ๋ก ํ ์คํธ๊ฐ ์คํจํ๋ ์ผ์ด ์์ฃผ ๋ฐ์ํ์ต๋๋ค.
-
๊ฐ์ ๋ฐฉํฅ
- ํฅ์ฌ๊ณ ๋ ์ํคํ
์ฒ ์ ์ฉ + ์์กด์ฑ ์ญ์ ์์น(DIP) ์ ๊ทน ๋์
- ๊ณ์ธต ๊ฐ ์์กด์ ๋ด๋ถ ์ธํฐํ์ด์ค๋ฅผ ํตํด ์ฐ๊ฒฐ
- ์ค์ ๊ตฌํ์ฒด ๋์ mock, fixture ๋ฑ์ ํ์ฉํ ๋ ๋ฆฝ์ ํ ์คํธ ๊ฐ๋ฅ
- ์ฝ๋ ๋ณ๊ฒฝ ์ ์ถ์ํ ์์ค์์์ ์์ ์ผ๋ก ๋ณ๊ฒฝ ์ํฅ ์ต์ํ
- ๊ธฐ๋ฅ ๋จ์ ๋ชจ๋ํ ๋ฐ ์์กด ๋ฐฉํฅ ๋ช
์์ ํต์
- ํํ ๊ณ์ธต์ ๋๋ฉ์ธ ๊ณ์ธต์ ๋ชจ๋ฅด๋๋ก
- ์ ํ๋ฆฌ์ผ์ด์ ๊ณ์ธต์ ์์์ฑ ๊ณ์ธต์ ๋ชจ๋ฅด๋๋ก
- ๊ฒ์๊ธ์ ์ข์์ ๊ธฐ๋ฅ์ ๋ชจ๋ฅด๋๋ก
- Redis ๋ชจ๋์ RDBMS ๋ชจ๋๊ณผ ์์ ํ ๋ถ๋ฆฌ
- ํฅ์ฌ๊ณ ๋ ์ํคํ
์ฒ ์ ์ฉ + ์์กด์ฑ ์ญ์ ์์น(DIP) ์ ๊ทน ๋์
-
- ๊ณ์ธต๋ณ ์ญํ ๋ถ๋ฆฌ์ ๋ชจ๋ํ๋ก ์ธํด, ํ
์คํธ๊ฐ ๊ฐ๋ณ๊ณ ๋ช
ํํด์ก์ต๋๋ค.
- ์: Redis ๊ธฐ๋ฅ ํ ์คํธ ์ RDBMS ์ค์ ๋ถํ์
- ๋ชจ๋ ๊ณ์ธต์ ์์ ์๊ฒ ํ์ํ ์ธํฐํ์ด์ค๋ง ์์กดํ๊ฒ ๋์ด ์ ์ง๋ณด์๊ฐ ์ฌ์์ก์ต๋๋ค.
- ๋๋ฉ์ธ ๊ฐ๋ ์ โ๋งฅ๋ฝโ ๋จ์๋ก ๋ถ๋ฆฌํ๊ณ , ์์กด์ฑ ๋ฐฉํฅ์ ๋ช ํํ ํต์ ํด ํฅํ ๋ง์ดํฌ๋ก์๋น์ค ๊ตฌ์กฐ๋ก์ ์ ํ๋ ์์ํ ๊ธฐ๋ฐ์ด ๋ง๋ จ๋์์ต๋๋ค.
- ๊ธฐ๋ฅ ์ถ๊ฐ ๋๋ ๊ธฐ์ ๊ต์ฒด ์, ์ ์ฒด ๊ตฌ์กฐ๋ฅผ ๊ฑด๋๋ฆด ํ์ ์์ด ๋ถ๋ถ ์์ ๊ฐ๋ฅํ ์ ์ฐํ ๊ตฌ์กฐ๊ฐ ๋์์ต๋๋ค.
- ๊ณ์ธต๋ณ ์ญํ ๋ถ๋ฆฌ์ ๋ชจ๋ํ๋ก ์ธํด, ํ
์คํธ๊ฐ ๊ฐ๋ณ๊ณ ๋ช
ํํด์ก์ต๋๋ค.
-
- ํ ์คํธ ์ฝ๋ ์์ฑ ์, ํ ์คํธ์ ํ์ํ ๋๋ฉ์ธ ๋ชจ๋ธ ๊ฐ์ฒด ์์ฑ์๋ ๋ง์ ์์ ์ฝ๋๊ฐ ํ์ํ ๋๊ฐ ๋ง์ต๋๋ค. ์ด๋ฐ ์ฝ๋๋ค์ ๋ณดํต fixture ํํ๋ก ๊ตฌ์ฑ๋์ด ์ฌ์ฌ์ฉํ๊ธฐ ์ํด ์ฌ์ฉํฉ๋๋ค.
- ๊ทธ๋ฌ๋ ๊ฐ์ ์ฌ๋ฌ ๋ชจ๋์์ ๋์ผํ ํ ์คํธ ํฝ์ค์ณ๋ฅผ ์ฌ์ฉํด์ผํ ๋๊ฐ ๋ง์๋ฐ ์ด๋ด ๊ฒฝ์ฐ test ์์ค์ ๋ด๋ถ์์ ๋์ผํ fixture ์ฝ๋๋ฅผ ์์ฑํด์ผํ๋ ๋ฌธ์ ๊ฐ ๋ฐ์ํฉ๋๋ค.
- ์ฌ๋ฌ ๋ชจ๋์์ ๊ณต์ ํ ์ ์๋๋ก ๋ณ๋์ ํ ์คํธ ํฝ์ค์ณ ๋ชจ๋์์ ๊ตฌํํ๋ ๋ฐฉ๋ฒ๋ ์์ง๋ง, ์๋ณธ ๋ชจ๋ ๋ด๋ถ์์๋ ์บก์ํ ์ํฌ ์ ์๋ ๋๋ฉ์ธ ์ง์์ด ์ธ๋ถ๋ก ์ ์ถ๋๋ ๋ฌธ์ ๊ฐ ๋ฐ์ํ ์ ์๊ณ , ์ํ์ฐธ์กฐ ๋ฌธ์ ๊ฐ ๋ฐ์ํ ์ ์์ต๋๋ค.
-
๊ฐ์ ๋ฐฉํฅ
- gradle์ java-fixtures ํ๋ฌ๊ทธ์ธ์ ํ์ฉํ์ฌ ์์ฃผ ์ฌ์ฉ๋๋ ํ ์คํธ ํฝ์ค์ณ๋ฅผ textFixtures ์์ค์ ์ผ๋ก ๊ตฌ์ฑํฉ๋๋ค.
- ์๋ณธ ๋๋ฉ์ธ ๋ชจ๋ธ๊ณผ ๊ฐ์ ๋ชจ๋ ๋ด์์, testFixtures ์์ค์ ์ ํ ์คํธ ํฝ์ค์ณ๋ฅผ ๊ตฌํํ ์ ์์ต๋๋ค. ์๋ณธ ๋ชจ๋ ๋ด๋ถ์์ ํ ์คํธ ํฝ์ค์ณ ์์ฑ์ ๊ดํ ํต์ฌ ๋๋ฉ์ธ ์ง์์ ์บก์ํ์ํฌ ์ ์์ต๋๋ค.
-
- ํ ์คํธ ํฝ์ค์ณ ์์ฑ์ ๊ดํ ๋ก์ง์ ๊ฐ์ ๋ชจ๋ ๋ด์์ ํ ์ ์๊ฒ ๋์ต๋๋ค. ์ธ๋ถ ๋ชจ๋์์๋ ๋ณต์กํ ํฝ์ค์ณ ์์ฑ ๊ด๋ จ ์ง์์ ์ ๊ทผํ ์ ์์ต๋๋ค.
- ์ฌ๋ฌ ๋ชจ๋๋ค์์ ๋ค๋ฅธ ์ธ๋ถ ๋ชจ๋์ ํ ์คํธํฝ์ค์ณ๋ฅผ ์์กดํ ์ ์๊ฒ ๋์ด, ํ ์คํธํฝ์ค์ณ ์ฌ์ฌ์ฉ์ฑ์ด ํฅ์ ๋์ต๋๋ค.
- ๋์
๋ฐฐ๊ฒฝ
- REST API ๊ธฐ๋ฐ์ ์๋น์ค์์๋ ํด๋ผ์ด์ธํธ์ ์์ฒญ๋ง๋ค ์ฌ์ฉ์๋ฅผ ์ธ์ฆํ ์๋จ์ด ํ์ํฉ๋๋ค.
- ๋ํ API๋ง๋ค ์ ๊ทผ ๊ถํ์ด ๋ค๋ฅด๊ธฐ ๋๋ฌธ์, ์ธ์ฆ๋ ์ฌ์ฉ์๋ง ์ ๊ทผ ๊ฐ๋ฅํ๊ฑฐ๋, ๊ด๋ฆฌ์๋ง ์ฌ์ฉํ ์ ์๋ ์๋ํฌ์ธํธ์ ๋ํ ์ธ๋ถํ๋ ์ธ๊ฐ ๋ก์ง์ด ํ์ํฉ๋๋ค.
- ์ธ์ ๊ธฐ๋ฐ ์ธ์ฆ ๋ฐฉ์์ ์ฐ๋ ๊ฒ์ ๊ณ ๋ คํด๋ดค์ผ๋, ๋ถ์ฐ ํ๊ฒฝ์์ ํ์ฅ์ฑ๊ณผ ์ ์ง๋ณด์์ ์ ์ฝ์ด ์์์ต๋๋ค.
- ๊ฐ API ๋ณ๋ก ์ธ์ฆ/์ธ๊ฐ ๊ธฐ๋ฅ์ ์๋์ผ๋ก ๊ตฌํํ๊ธฐ์ ๊ฐ API๋ง๋ค ๋ฐ๋ณต์ ์ธ ๋ณด์ ๋ก์ง์ด ํ์ํ์ต๋๋ค.
- ๊ธฐ์ ์ ํ ๋ฐ ๊ตฌํ
-
JWT ๊ธฐ๋ฐ ์ธ์ฆ (Access Token + Refresh Token)
- Statelessํ ๊ตฌ์กฐ๋ฅผ ์ํด ์ธ์ ์ด ์๋ JWT ๊ธฐ๋ฐ ์ธ์ฆ์ ๋์ ํ์ต๋๋ค.
- Access Token์๋ ์ฌ์ฉ์ ์๋ณ์ ์ํ ์ต์ ์ ๋ณด๋ง ๋ด๊ณ , ์๋ช ํค๋ฅผ ์ด์ฉํด ์๋ณ์กฐ ์ฌ๋ถ๋ฅผ ๊ฒ์ฆํฉ๋๋ค.
- ๋ณด์ ๊ฐํ๋ฅผ ์ํด ์ ํจ๊ธฐ๊ฐ์ด ์งง์ Access Token๊ณผ, ๊ฐฑ์ ์ฉ๋์ Refresh Token์ ๋ถ๋ฆฌํ์ฌ ์ฌ์ฉํ์ต๋๋ค.
- Refresh Token์ Redis์ ์ ์ฅํ๋ฉฐ, ์ฌ์ฉ์๋น ์ต๋ 5๊ฐ๊น์ง๋ง ์ ์งํ์ฌ ๋์ ๋ก๊ทธ์ธ ์ ์ ํ ๋ฐ ํ ํฐ ํ์ทจ ๋์์ด ๊ฐ๋ฅํ๊ฒ ํ์ต๋๋ค.
-
Spring Security๋ฅผ ํ์ฉํ ์ธ์ฆ ํ๋ฆ ๊ตฌ์ฑ
- Spring Security์ ์๋ธ๋ฆฟ ํํฐ ์ฒด์ธ ๊ตฌ์กฐ๋ฅผ ํ์ฉํ์ฌ, ์ธ์ฆ ๋ก์ง์ MVC ์๋จ์์ ๊ณตํต ์ฒ๋ฆฌํ๋๋ก ๊ตฌ์ฑํ์ต๋๋ค.
- ์ฌ์ฉ์๋ ๋งค ์์ฒญ ์ ํ ํฐ์ ํค๋์ ๋ด์ ์ ์กํ๋ฉฐ, ํํฐ์์๋ ํ ํฐ ํ์ฑ ๋ฐ ์ฌ์ฉ์ ์ธ์ฆ ๊ฐ์ฒด(SecurityContext) ์ฃผ์ ์ ๋ด๋นํฉ๋๋ค.
- ์ด ๊ตฌ์กฐ๋ฅผ ํตํด API ๋ฉ์๋๋ง๋ค ์ธ์ฆ ์ฝ๋๋ฅผ ๋ฐ๋ณตํ์ง ์๊ณ ์ ์ญ ์ธ์ฆ ์ฒ๋ฆฌ๊ฐ ๊ฐ๋ฅํด์ก์ต๋๋ค.
-
Spring AOP ๊ธฐ๋ฐ ์ธ๊ฐ(Authorization) ์ฒ๋ฆฌ
- API๋ณ ์ ๊ทผ ์ ์ด๋ ์ปค์คํ ์ด๋ ธํ ์ด์ (@RequireAuthnticated, @RequireAdminRole ๋ฑ) ์ ์ปจํธ๋กค๋ฌ์ ์ ์ธํ์ฌ ๋ช ์ํฉ๋๋ค.
- ๊ณตํต ๊ถํ ๊ฒ์ฆ ๋ก์ง์ Aspect๋ก ๋ถ๋ฆฌํ์ฌ, ์ด๋ ธํ ์ด์ ๊ธฐ๋ฐ์ผ๋ก ์๋ ์ ์ฉ๋๋๋ก ๊ตฌ์ฑํ์ต๋๋ค.
- AOP ํ๋ก์๋ฅผ ํตํด ์ค์ ์ปจํธ๋กค๋ฌ๊ฐ ์คํ๋๊ธฐ ์ ๊ถํ ๊ฒ์ฌ๋ฅผ ์ํํ๋ฉฐ, ์ธ๊ฐ ์คํจ ์ ์์ธ๋ฅผ ๋ฐ์์์ผ ****์ปจํธ๋กค๋ฌ ์ง์ ์ ๋ฐฉ์งํฉ๋๋ค.
-
- ์ฑ๊ณผ
- ์ธ์ฆยท์ธ๊ฐ ๋ก์ง์ ์ฌ์ฌ์ฉ ๊ฐ๋ฅํ๊ณ ํ์ฅ ๊ฐ๋ฅํ ๊ตฌ์กฐ๋ก ๋ชจ๋ํํ์ฌ, API๋ง๋ค ์ค๋ณต ์ฝ๋๋ฅผ ์์ฑํ์ง ์์๋ ๋ฉ๋๋ค.
- ํฅํ ์๋น์ค๊ฐ ๋ง์ดํฌ๋ก์๋น์ค ์ํคํ ์ฒ๋ก ํ์ฅ๋๋๋ผ๋, JWT ๊ธฐ๋ฐ ์ธ์ฆ ๋ฐฉ์์ ํตํด ๊ฐ ์๋น์ค ๊ฐ ์ธ์ ๊ณต์ ์์ด ์ธ์ฆ ์ฐ๋์ด ๊ฐ๋ฅํฉ๋๋ค.
- Refresh Token์ ๋ณ๋๋ก ์ ์ฅํด ๊ด๋ฆฌํด์ผ ํ๋ ๋ถ๋ด์ ์์ง๋ง, ํ์/์ธ์ฆ ์๋ฒ ๋จ์ผ ์ง์ (์๋น์ค ๋ถ๋ฆฌ ์)์์๋ง ๊ด๋ฆฌ๋๋ฏ๋ก ๊ตฌ์กฐ์ ์ผ๋ก ๋จ์ํ๋ฉฐ, ํ ํฐ ํ์ทจ์ ๊ฐ์ ๋ณด์ ์ด์์๋ ๋ ๊ฒฌ๊ณ ํ ๋์์ด ๊ฐ๋ฅํด์ก์ต๋๋ค.
- ์ ๊ท API ์ถ๊ฐ ์ ์ด๋ ธํ ์ด์ ํ ์ค๋ง์ผ๋ก ๊ถํ ์ ์ด๊ฐ ์ ์ฉ๋์ด, ๋ณด์ ์ ์ฑ ์ ์ฉ์ด ์ผ๊ด๋๊ณ ์ ์ง๋ณด์๋ ๊ฐํธํด์ก์ต๋๋ค.
-
๋์ ๋ฐฐ๊ฒฝ
- ์ผ๋ฐ์ ์ธ ์ด๋ฉ์ผ/ํจ์ค์๋ ๋ฐฉ์ ์ธ์๋, ์ฌ์ฉ์ ์ ๊ทผ์ฑ์ด ๋์ ์์ ๋ก๊ทธ์ธ ๋ฐฉ์์ด ๋๋ฆฌ ์ฌ์ฉ๋๊ณ ์์ต๋๋ค.
- ํนํ Google, Kakao, Naver ๋ฑ ๋์ค์ ์ธ ์๋น์ค๋ OAuth2 ๊ธฐ๋ฐ ์ธ์ฆ/์ธ๊ฐ ํ๋ฆ์ ์ ๊ณตํฉ๋๋ค.
- ์ฌ์ฉ์๋ ๊ฐ ์๋น์ค์ ๋ณ๋์ ๊ณ์ ์ ์์ฑํ ํ์ ์์ด, ๊ธฐ์กด ์์ ๊ณ์ ์ ํ์ฉํ์ฌ ๋น ๋ฅด๊ฒ ๋ก๊ทธ์ธํ ์ ์์ต๋๋ค.
-
๋ฌธ์ ์ํฉ
-
ํ์ฅ์ฑ ๋ฌธ์
- OAuth2 ๊ธฐ๋ฐ์ด๋ผ๋ ๊ฐ ์์ ์๋น์ค๋ง๋ค API ๋ช ์ธ๋ ์๋ต ํ์์ด ์์ดํฉ๋๋ค.
- ์ด๊ธฐ์๋ ํ๋์ ์์ ์๋น์ค๋ฅผ ๊ธฐ์ค์ผ๋ก ๊ตฌํํ๋๋ผ๋, ๋ค๋ฅธ ์์ ์๋น์ค๊ฐ ์ถ๊ฐ๋ ๋๋ง๋ค ์ฝ๋๊ฐ ์ค๋ณต๋ ์ฐ๋ ค๊ฐ ์์ต๋๋ค.
- ๊ฐ ์์ API๋ฅผ ๊ฐ๋ณ์ ์ผ๋ก ๊ตฌํํ ๊ฒฝ์ฐ ์ ์ง๋ณด์ ๋ถ๋ด์ด ์ปค์ง๊ณ , ๊ณตํต ํ๋ฆ์ ์ฌ์ฌ์ฉํ์ง ๋ชปํ๋ ๋ฌธ์ ๊ฐ ์์ต๋๋ค.
-
๋ณด์ ๋ฌธ์
- ์น์์ ์ง์ ์์ ์๋น์ค๋ก ๋ฆฌ๋ค์ด๋ ํธํ๋ ๋ฐฉ์์ ๋ณด์ ์ทจ์ฝ์ ์ด ์กด์ฌํฉ๋๋ค.
- ์๋ฅผ๋ค๋ฉด ์ธ๋ถ ์ ์ฑ ์ฌ์ดํธ๊ฐ OAuth2 ์ธ๊ฐ ์ฝ๋๋ฅผ ์ด์ฉํด ์ฐ๋ฆฌ ์๋น์ค์ ๋ก๊ทธ์ธ์ ์๋ํ ์ ์์ต๋๋ค.
- ์ด๋ฅผ ๋ฐฉ์งํ๊ธฐ ์ํด ์ธ๊ฐ ์์ฒญ์ ๋ฐ๋์ ์ฐ๋ฆฌ ์๋ฒ๋ฅผ ํตํด ์ค๊ณํ๋๋ก ์ค๊ณํด์ผ ํ์ต๋๋ค.
-
-
๊ธฐ์ ์ ํ : Spring Security OAuth2 Client vs ์ง์ ๊ตฌํ
- ์ด๊ธฐ์๋ Spring Security OAuth2 Client๋ฅผ ํ์ฉํ์ฌ ์์ ๋ก๊ทธ์ธ ๊ธฐ๋ฅ์ ๊ตฌํํ์ต๋๋ค. ์ด ๋ฐฉ์์ ๋ง์ ์ค์ ๊ณผ ๋ก์ง์ด ์๋ํ๋์ด ๋น ๋ฅด๊ฒ ๊ธฐ๋ฅ์ ์์ฑํ ์ ์๋ค๋ ์ฅ์ ์ด ์์ต๋๋ค.
- ํ์ง๋ง ์ค์ ๋ก ์ ์ฉํด๋ณธ ๊ฒฐ๊ณผ, ์ ๋ฐ์ ์ธ ์ ์ง๋ณด์์ฑ๊ณผ ํ
์คํธ ์ฝ๋ ์์ฑ ๊ด์ ์์ ํ๊ณ๋ฅผ ๋๊ผ์ต๋๋ค.
- ์ฃผ์ OAuth2 ์ธ์ฆ/์ธ๊ฐ ํ๋ฆ์ด Spring Security ํํฐ ์ฒด์ธ ๋ฐ ๋ด๋ถ ์ปดํฌ๋ํธ์ ์จ๊ฒจ์ ธ ์์ด, ๋ก์ง์ ๋ช ํํ ์ถ์ ํ๊ณ ์ ์ดํ๊ธฐ ์ด๋ ค์ ์ต๋๋ค.
- ์ผ๋ฐ์ ์ธ ๋น์ฆ๋์ค ๋ก์ง์
์ปจํธ๋กค๋ฌ โ ์ ํ๋ฆฌ์ผ์ด์ ์๋น์ค์ ๋ช ํํ ํ๋ฆ์ ๋ฐ๋ฅด์ง๋ง, Spring Security OAuth2 Client ๋ฐฉ์์ ๋ก์ง์ด ํํฐ ์ฒด์ธ ๊น์์ด ์์นํ๊ณ ์ถ์ํ์ ๊น์ด๊ฐ ๊น์ด์ ธ ๋๋ฒ๊น ๊ณผ ํ ์คํธ๊ฐ ๋ณต์กํด์ก์ต๋๋ค.
- ์ด๋ฌํ ์ด์ ๋ก, Spring Security์ OAuth2 ํ๋ฆ์ ๊ทธ๋๋ก ๋ชจ๋ฐฉํ๋, ์ปค์คํ
๋ฐฉ์์ผ๋ก ์ง์ ๊ตฌํํ๊ธฐ๋ก ๊ฒฐ์ ํ์ต๋๋ค.
- ๋ด๋ถ ๋ก์ง์ ๊ธฐ์กด์ ์ด๋ฉ์ผ ๋ก๊ทธ์ธ ๋ฑ ๋ค๋ฅธ ์ธ์ฆ API๋ค๊ณผ ๋์ผํ๊ฒ,
์ปจํธ๋กค๋ฌ โ ์ ํ๋ฆฌ์ผ์ด์ ์๋น์ค์ ํ๋ฆ ์์ ์์ ๋ก๊ทธ์ธ ๋ก์ง์ ํตํฉํ ์ ์์ต๋๋ค - ์ด๋ฅผ ํตํด ๋๋ฉ์ธ ๋ก์ง์ ์ฑ ์ ๋ถ๋ฆฌ ์์น์ ์ ์งํ๋ฉด์๋, ๊ธฐ๋ฅ ํ๋ฆ์ ์ผ๊ด๋๊ฒ ๊ตฌ์ฑํ ์ ์์ต๋๋ค.
- ๋ด๋ถ ๋ก์ง์ ๊ธฐ์กด์ ์ด๋ฉ์ผ ๋ก๊ทธ์ธ ๋ฑ ๋ค๋ฅธ ์ธ์ฆ API๋ค๊ณผ ๋์ผํ๊ฒ,
-
๋ฌธ์ ํด๊ฒฐ ๊ณผ์
-
์ธ๊ฐ ์์ฒญ ๋ถ๋ฆฌ ๋ฐ ๋ฆฌ๋ค์ด๋ ํธ ํ๋ฆ ๊ตฌ์ฑ
- ์ฌ์ฉ์๊ฐ ์์ ๋ก๊ทธ์ธ ๋ฒํผ์ ๋๋ฅด๋ฉด, ์ฐ์ ์ฐ๋ฆฌ API ์๋ฒ๋ก ์์ฒญ์ ๋ณด๋ด๋ ๊ฒ์ ์ ์ ๋ก ์๋น์ค๋ฅผ ๊ตฌ์ฑํ์ต๋๋ค.(๋ค๋ง ์น์ฌ์ดํธ๋ ๊ตฌํํ์ง ์์์ต๋๋ค.)
- ์๋ฒ๋ ์ธ๊ฐ ์์ฒญ์ ํ์ํ ์ ๋ณด๋ค์ ์์ฑ ๋ฐ ์ ์ฅํ ๋ค, ์ฌ์ฉ์๋ฅผ ์์ ์๋น์ค๋ก ๋ฆฌ๋ค์ด๋ ํธํฉ๋๋ค.
- ์ด ๋ฐฉ์์ ๋ก๊ทธ์ธ ํ๋ก์ธ์ค๋ฅผ ์๋ฒ๊ฐ ์ ์ ์ผ๋ก ํต์ ํ ์ ์๊ฒ ํ๋ฉฐ, ๋ณด์ ํ๋ผ๋ฏธํฐ๋ ์์ ํ๊ฒ ๊ด๋ฆฌํ ์ ์์ต๋๋ค.
-
๋ณด์ ํ๋ผ๋ฏธํฐ ์ ์ฉ
-
state: ์ฌ์ฉ์์ ์ธ๊ฐ ์์ฒญ ์ํ๋ฅผ ์๋ณํ๋ ๊ฐ
-
nonce: OpenID Connect ๋ฐฉ์์์ ID ํ ํฐ ์๋ณ์กฐ ๋ฐฉ์ง์ฉ์ผ๋ก ์ฌ์ฉ.
-
PKCE (Proof Key for Code Exchange) ์ ์ฉ
code_verifier๋ฅผ ๋๋ค์ผ๋ก ์์ฑcode_challenge = hash(code_verifier)- ์ต์ด ์ธ๊ฐ ์์ฒญ ์
code_challenge์ ์ก - ํ ํฐ ์์ฒญ ์
code_verifier๋ฅผ ํจ๊ป ๋ณด๋ด ๊ฒ์ฆ - โ ์ด๋ฅผ ํตํด ํ ํฐ ์์ฒญ์ ์์กฐ๋ฅผ ๋ฐฉ์งํ ์ ์์ต๋๋ค.
-
-
๊ตฌ์กฐ ์ค๊ณ ๋ฐ ์ถ์ํ : Spring Security OAuth2 Client ํ๋ฆ์ ์ฐธ์กฐํ์ฌ ๊ณตํต ํ๋ฆ์ ์ถ์ํํ์ต๋๋ค.
- ๋ค์์ ํ๋ฆ์ ๊ธฐ์ค์ผ๋ก ์๋น์ค๋ณ ์ฐจ์ด๋ฅผ ์ค์ ๊ธฐ๋ฐ์ผ๋ก ๊ณตํต๋ก์ง๊ณผ, ๊ฐ๋ณ ๊ตฌํ์ฌํญ์ ๋ถ๋ฆฌํ์ต๋๋ค.
- ์์
์๋น์ค๋ณ ์ค์ : ์ค์ ํ์ผ ๊ธฐ๋ฐ์ผ๋ก
ClientRegistration์๋ ์์ฑ - ์ฌ์ ์์ฒญ ์์ฑ:
OAuth2AuthorizationRequest๊ฐ์ฒด ์์ฑ ๋ฐ ์ ์ฅ - ์ฌ์ฉ์ ๋ฆฌ๋ค์ด๋ ํธ:
OAuth2AuthorizationRequest๋ฅผ ํตํด ์ธ๊ฐ URL ์์ฑ ํ ํด๋ผ์ด์ธํธ๋ฅผ ์์ ์๋น์ค๋ก ์ด๋ - ์ฝ๋ฐฑ ์ฒ๋ฆฌ: state ๊ฐ์ผ๋ก ์์ฒญ ์ ๋ณด ์กฐํ ํ ๋ก๊ทธ์ธ ์ฒ๋ฆฌ
- ์์
์๋น์ค๋ณ ์ค์ : ์ค์ ํ์ผ ๊ธฐ๋ฐ์ผ๋ก
- ์ ์ฒด ํ๋ฆ์ ๋จ์ผํ ์ปจํธ๋กค๋ฌ ๋ฐ ์ ํ๋ฆฌ์ผ์ด์ ์๋น์ค ๊ณ์ธต์ผ๋ก ์ถ์ํ๋์ด ์์ผ๋ฉฐ, ์ดํ ์์ ์๋น์ค๊ฐ ์ถ๊ฐ๋๋๋ผ๋ ์ค์ ๋ฐ ์๋ต ๋งคํ ์ ๋๋ง ํ์ฅํ๋ฉด ๋ฉ๋๋ค.
- ๋ค์์ ํ๋ฆ์ ๊ธฐ์ค์ผ๋ก ์๋น์ค๋ณ ์ฐจ์ด๋ฅผ ์ค์ ๊ธฐ๋ฐ์ผ๋ก ๊ณตํต๋ก์ง๊ณผ, ๊ฐ๋ณ ๊ตฌํ์ฌํญ์ ๋ถ๋ฆฌํ์ต๋๋ค.
-
-
์ฑ๊ณผ
- ์ด๋ฉ์ผ/๋น๋ฐ๋ฒํธ ๋ก๊ทธ์ธ ์ธ์๋ Google, Naver, Kakao ๋ก๊ทธ์ธ์ด ๊ฐ๋ฅํด์ก์ต๋๋ค.
- ์ธ๊ฐ ์์ฒญ์ ํ๋ฆ์ ์ ๋ฉด ํต์ ํจ์ผ๋ก์จ ๋ณด์ ์์(nonce, PKCE, state ๋ฑ)๋ฅผ ํจ๊ณผ์ ์ผ๋ก ์ ์ฉํ ์ ์์์ต๋๋ค.
- ํต์ฌ ํ๋ฆ์ ๊ณตํตํ ๋ฐ ์ถ์ํ๋์ด ์์ด, ํฅํ Facebook, GitHub ๋ฑ์ ์์ ๋ก๊ทธ์ธ ์ถ๊ฐ๋ ์ต์ํ์ ์ฝ๋ ๋ณ๊ฒฝ๋ง์ผ๋ก ๊ฐ๋ฅํฉ๋๋ค.
-
๋์ ๋ฐฐ๊ฒฝ
- API ๋ช ์ธ๋ ํด๋ผ์ด์ธํธ-์๋ฒ ๊ฐ ํ์ ์ ํต์ฌ์ ๋๋ค.
- ํ์ง๋ง ์ด๊ธฐ ๊ฐ๋ฐ ๋จ๊ณ์์๋ API ์ฌ์์ด ์์ฃผ ๋ณ๊ฒฝ๋๊ณ , ๊ทธ์ ๋ฐ๋ฅธ ๋ฌธ์ ์ ๋ฐ์ดํธ๊ฐ ์ง์ฐ๋๋ฉฐ API ๋ฌธ์์ ์ค์ ๋์ ๊ฐ ๋ถ์ผ์น๊ฐ ๋ฐ์ํ๊ธฐ ์ฝ์ต๋๋ค.
-
- ์๋ฅผ ๋ค์ด๋ณด๋ฉด, ๊ธฐ์กด ํ์๊ฐ์
API ์๋ํฌ์ธํธ๋
/api/v1/members์ธ๋ฐ ์ดํ/api/v1/users๋ก ๋ณ๊ฒฝ๋์๋ค๊ณ ํด๋ณด๊ฒ ์ต๋๋ค. - ํ์ง๋ง GitHub Wiki์ ๋จ๊ฒจ๋ ๋ช
์ธ๋ ์ ํ
/api/v1/members๋ก ๋์ด ์์ด ํผ๋์ ์ด๋ํ ์ ์์ต๋๋ค. - API ๋ณ๊ฒฝ ์ ์๋์ผ๋ก ๋ช ์ธ๋ฅผ ๊ฐฑ์ ํด์ผ ํ๋ ์ ์ด ๊ฐ๋ฐ์-ํด๋ผ์ด์ธํธ ๊ฐ ์ปค๋ฎค๋์ผ์ด์ ๋น์ฉ์ ์ฆ๊ฐ์ํฌ ๊ฐ๋ฅ์ฑ์ด ์์ต๋๋ค.
- ์๋ฅผ ๋ค์ด๋ณด๋ฉด, ๊ธฐ์กด ํ์๊ฐ์
API ์๋ํฌ์ธํธ๋
-
๋์ ๊ฒํ
- GitHub Wiki, Notion ๋ฑ ์๊ธฐ ์์ฑ (๊ธฐ์กด ๋ฐฉ์)
- ์์ ๋ก์ด ์์ ์ด ๊ฐ๋ฅํ์ง๋ง, ์ฝ๋ ๋ณ๊ฒฝ ์ ์๋ ๋ฐ์์ด ๋ถ๊ฐ๋ฅํฉ๋๋ค.
- Swagger
- ์๋ํ๋ ๋์ง๋ง, ์ค์ ๋์๊ณผ ์ด๊ธ๋ ์ ์๊ณ , ์ ํ๋ฆฌ์ผ์ด์ ์ฝ๋์ ๋ฌธ์ํ๋ฅผ ์ํ ์ฝ๋๊ฐ ์นจํฌํ๋ ๋ฌธ์ ๊ฐ ๋ฐ์ํฉ๋๋ค.
- Spring Rest Docs (์ต์ข
์ ํ)
- ํ ์คํธ ์ฝ๋ ๊ธฐ๋ฐ์ผ๋ก ๋ช ์ธ๋ฅผ ์์ฑํด, API ๋ฌธ์์ ์ค์ ๋์์ ์์ ํ ์ผ์น๋ฅผ ๋ณด์ฅํฉ๋๋ค.
- ๋ฌธ์ํ๋ฅผ ์ํ ๋ณ๋ ์ ๋ํ ์ด์ ์ด ๋ถํ์ํฉ๋๋ค.
- Swagger ๋๋น UI๋ ๋ค์ ๋จ์ํ์ง๋ง, ์ ํ์ฑ ๋ฉด์์ ํ์ํฉ๋๋ค.
- GitHub Wiki, Notion ๋ฑ ์๊ธฐ ์์ฑ (๊ธฐ์กด ๋ฐฉ์)
-
- API ๋ฌธ์๊ฐ ํ ์คํธ ์ฝ๋์ ์ฐ๋๋์ด ์๋ ์์ฑ๋ฉ๋๋ค.
- API ์ฌ์ ๋ณ๊ฒฝ ์, ํ ์คํธ ์คํจ๋ฅผ ํตํด ์ฆ์ ๊ฐ์ง๊ฐ ๊ฐ๋ฅํด์ก์ต๋๋ค.
- ํฅํ API ์ ์ง๋ณด์, ์์ ๊ณผ์ ์์ ์ต์ ํ ๋๋ฝ ๋ฌธ์ ๋ฅผ ์๋ฐฉํ ์ ์๊ฒ ๋์ต๋๋ค.
- ํด๋ผ์ด์ธํธ์์ API ๊ณ์ฝ ์ ๋ขฐ์ฑ์ด ํฅ์๋์ต๋๋ค.
-
๋์ ๋ฐฐ๊ฒฝ
- API ์ฒ๋ฆฌ ์ค ์์ธ๊ฐ ๋ฐ์ํ์ ๋, ์ฌ์ฉ์์๊ฒ ๋งฅ๋ฝ์ ๋ง๋ ์๋ฌ ๋ฉ์์ง๋ฅผ ๋ช ํํ๊ณ ์ผ๊ด๋๊ฒ ์ ๋ฌํ๋ ๊ฒ์ ๋งค์ฐ ์ค์ํฉ๋๋ค.
- ํ์ง๋ง ๋ชจ๋ ์ปจํธ๋กค๋ฌ์์ ๋ฉ์์ง๋ฅผ ์ง์ ๊ตฌ์ฑํ๋ฉด ์ค๋ณต ๋ก์ง์ด ๋ง์์ง๊ณ ์ ์ง๋ณด์๊ฐ ์ด๋ ต์ต๋๋ค.
- ๋ํ ์์ธ ํด๋์ค ์์ฒด์์ ๋ฉ์์ง๋ฅผ ํฌํจํ ๊ฒฝ์ฐ, ๋ค๊ตญ์ด(๋ค๊ตญ์ ํ๊ฒฝ) ๋์์ด ๋ถ๊ฐ๋ฅํ๊ฑฐ๋ ์ ํ๋ฉ๋๋ค.
- API ๋ก์ง์ ์คํํ๋ ๊ณผ์ ์์ ์์ธ๊ฐ ๋ฐ์ํ๋ฉด ๊ทธ์ ๋ง๊ฒ ์ฌ์ฉ์๋ค์๊ฒ ์ ์ ํ ์์ธ ๋ฉ์์ง๋ฅผ ์ ๋ฌํ ์ ์์ด์ผํฉ๋๋ค. ๊ทธ๋ฌ๋ ๋ชจ๋ ์ปจํธ๋กค๋ฌ์์ ์ด ๊ธฐ๋ฅ์ ๊ตฌํํ๋ ๊ฒ์ ๋ถํธํด์ง๋๋ค.
- ๋, ์์ธ ํด๋์ค๊ฐ ์์ธ ๋ฉ์์ง๋ฅผ ๊ฐ์ง๊ฒ ํ๊ณ ์ด๋ฅผ ์ฌ์ฉ์์๊ฒ ๋ด๋ณด๋ด๊ธฐ๋ง ํ๋ฉด ๋ค๊ตญ์ด ํ๊ฒฝ์ ๋ง๊ฒ ๊ฐ๊ฐ ๋ค๋ฅธ ๋ฉ์์ง๋ฅผ ์ ๊ณตํ๊ธฐ ์ด๋ ต์ต๋๋ค.
-
๊ฐ์ ๋ฐฉํฅ
-
์์ธ ํด๋์ค ์ถ์ํ: ๋ชจ๋ ๋๋ฉ์ธ ์์ธ๋
CustomException์ ์์๋ฐ์ ๊ตฌํ๋๋ฉฐ, ๋ค์๊ณผ ๊ฐ์ ๊ตฌ์กฐ๋ฅผ ๊ฐ์ง๋๋ค.abstract class CustomException( val status: ErrorStatus, // ์์ธ๊ฐ ๋ฐ์ํ ์ด์ ๋ฅผ ์ค๋ช ํ๋ ์ํ ์ ๋ณด. val code: String, // ์์ธ ๋ฉ์์ง ๊ตฌ์ฑ์ ์ํ ์ฝ๋ ("Error.xxx" ํ์). val args: List<Any?>, // ๋ฉ์์ง ํ ํ๋ฆฟ์์ ์ฌ์ฉํ ์ธ์๋ค (๋น ๋ฆฌ์คํธ์ผ ๊ฒฝ์ฐ ์ธ์ ์๊ณ , ์์๋๋ก ์ฌ์ฉ๋จ). val source: String, // ์์ธ๋ฅผ ๋ฐ์์ํจ ํ๋ ๋๋ ๋งฅ๋ฝ์ ์ค๋ช ํ๋ ๊ฐ (์: "nickname") val debugMessage: String, // ๋๋ฒ๊น ์ ์ํ ๋ฉ์์ง (์ฌ์ฉ์์๊ฒ ์ ๊ณต๋์ง ์์). cause: Throwable? = null // ๊ทผ๋ณธ ์์ธ์ด ๋๋ ์์ธ (์ ํ์ ). ) : RuntimeException(debugMessage, cause)
- ๊ฐ ์์ธ๋ ๋ฉ์์ง๋ฅผ ์ง์ ๋ค๊ณ ์์ง ์๊ณ , ์์ธ ์ฝ๋์ ํ๋ผ๋ฏธํฐ๋ง ๋ณด์ ํฉ๋๋ค.
- ์ด๋ฅผ ํตํด ๋ฉ์์ง ์ถ๋ ฅ์ ๋ก์ผ์ผ ๋ฐ ๋ฉ์์ง ํ์ผ์ ํตํด ๋์ ์ผ๋ก ์ฒ๋ฆฌ๋ฉ๋๋ค.
-
๋ค๊ตญ์ด ๋ฉ์์ง ๊ตฌ์ฑ (YAML)
NullArgument: message: "ํ์๊ฐ ๋๋ฝ" description: "''{0}''์(๋) ํ์์ ๋๋ค." InvalidEmailFormat: message: "์ ํจํ์ง ์์ ์ด๋ฉ์ผ ํฌ๋งท" description: "์ด๋ฉ์ผ ํฌ๋งท์ด ์ฌ๋ฐ๋ฅด์ง ์์ต๋๋ค. (email = {0})" # ์๋ต
NullArgument: message: "Missing required value" description: "The field ''{0}'' is required." InvalidEmailFormat: message: "Invalid email format" description: "The email format is not valid. (email = {0})" # ์๋ต
- ๊ฐ ๋ฉ์์ง๋ ์์ธ ์ฝ๋ (
code)๋ฅผ ํค๋ก ํ์ฌ ๊ตญ๊ฐ๋ณ๋ก ๋ค๋ฅด๊ฒ ๋ฒ์ญ๋ฉ๋๋ค. {0},{1}๋ฑ์ ์์น ์ธ์๋ฅผ ํตํด ํ๋ผ๋ฏธํฐ๋ ์ ์ฐํ๊ฒ ์ฝ์ ๋ฉ๋๋ค.
- ๊ฐ ๋ฉ์์ง๋ ์์ธ ์ฝ๋ (
-
- ์์ธ๋
@RestControllerAdvice๋ฅผ ํตํด ์ ์ญ์ ์ผ๋ก ์ฒ๋ฆฌ๋ฉ๋๋ค.- ์ด๋ ๋ด๋ถ์ ์ผ๋ก Spring MVC๊ฐ ๋ฑ๋กํ
HandlerExceptionResolver๊ตฌํ์ฒด๊ฐ@RestControllerAdviceํด๋์ค๋ฅผ ๊ฐ์งํ๊ณ ์์ธ ๋ฐ์ ์ ํด๋น ํธ๋ค๋ฌ ๋ฉ์๋๋ก ์์ํ์ฌ ์๋ต์ ์์ฑํ๋ ๋ฐฉ์์ผ๋ก ๋์ํฉ๋๋ค. Accept-Languageํค๋๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ์ฌ์ฉ์์ ๋ก์ผ์ผ์ ๊ฐ์งํ๊ณ ,- ์์ธ ์ธ์คํด์ค์
code,args๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ์ ์ ํ ๋ฉ์์ง๋ฅผ ๋ฐํํฉ๋๋ค.
- ์ด๋ ๋ด๋ถ์ ์ผ๋ก Spring MVC๊ฐ ๋ฑ๋กํ
- ์คํ๋ง MVC ์๋จ(์: ์๋ธ๋ฆฟ ํํฐ)์์ ๋ฐ์ํ ์์ธ๋ ์ปค๋ฒํ ์ ์๋๋ก,
- ์ ์ญ ์์ธ ์ฒ๋ฆฌ์ฉ ์๋ธ๋ฆฟ ํํฐ๋ฅผ ์ถ๊ฐํ์์ต๋๋ค.
- ์ด ํํฐ๋ ๋ด๋ถ์ ์ผ๋ก
HandlerExceptionResolver๋ฅผ ํธ์ถํ์ฌ ๋ชจ๋ ์์ธ๋ฅผ ๊ณตํต ์ฒ๋ฆฌ ํ๋ฆ์ ํตํฉํฉ๋๋ค.
- ์์ธ๋
-
-
- ์์ธ ๋ฐ์ ์, ๊ตญ๊ฐ๋ณ๋ก ์์ฐ์ค๋ฌ์ด ์ธ์ด์ ๋ฉ์์ง๋ฅผ ์ ๊ณตํ ์ ์๊ฒ ๋์์ต๋๋ค.
- ์์ธ ์ฒ๋ฆฌ ๋ก์ง์ ์์ ํ ๊ณตํตํํจ์ผ๋ก์จ, ๋ชจ๋ ์ปจํธ๋กค๋ฌ ๋ฐ ํํฐ ๊ณ์ธต์์๋ ์ผ๊ด๋ ๋ฐฉ์์ผ๋ก ์ฒ๋ฆฌํ ์ ์๊ฒ ๋์์ต๋๋ค.
- ์์ธ ๋ฉ์์ง ๊ตฌ์กฐ๊ฐ ์ ํํ๋์ด ์์ด, ๋ก๊น ๋ฐ ํ ์คํธ, ๋ถ์์๋ ์ฉ์ดํฉ๋๋ค.
- ์ ํ๋ฆฌ์ผ์ด์ ์ Amazon AWS ์ธํ๋ผ ์์ ๋ฐฐํฌ ๋ฐ ์ด์๋๊ณ ์์ต๋๋ค. ์์ ์ ์ธ ์๋น์ค ์ ๊ณต๊ณผ ๋ณด์ ๊ฐํ๋ฅผ ์ํด ๋ค์ํ AWS ์๋น์ค๋ฅผ ํ์ฉํ์ต๋๋ค.
- ์ฃผ์ ์ธํ๋ผ ๊ตฌ์ฑ
- VPC (Virtual Private Cloud)
- AWS์์ ์ ๊ณตํ๋ ๊ฐ์ ์ฌ์ค๋ง(Virtual Network).
- ์๋น์ค ์ ๋ฐ์ ํ๋์ VPC ๋จ์๋ก ๊ฒฉ๋ฆฌํ์ฌ ๊ด๋ฆฌํฉ๋๋ค.
- ์๋ธ๋ท ๋ถ๋ฆฌ (Subnet)
- ๋ณด์ ์์ค์ ๋ฐ๋ผ ํผ๋ธ๋ฆญ/ํ๋ผ์ด๋น ์๋ธ๋ท์ผ๋ก ๋ถ๋ฆฌํด ๊ตฌ์ฑํ์ต๋๋ค.
- ํผ๋ธ๋ฆญ ์๋ธ๋ท: ์ธ๋ถ ์ฌ์ฉ์ ์ ๊ทผ์ด ํ์ํ ๋ฆฌ์์ค (์: EC2).
- ํ๋ผ์ด๋น ์๋ธ๋ท: ์ธ๋ถ ์ ๊ทผ์ด ์ฐจ๋จ๋ ๋ด๋ถ ๋ฆฌ์์ค (์: RDS, ElastiCache).
- ๋ณด์ ๊ทธ๋ฃน (Security Group)
- ELB, EC2, RDS, ElastiCache ๋ฑ ๊ฐ ๋ฆฌ์์ค๋ง๋ค ์ ๊ทผ ๊ฐ๋ฅํ IP, ํฌํธ ๋ฒ์๋ฅผ ์ ์ดํฉ๋๋ค.
- ์ต์ํ์ ์ ๊ทผ๋ง ํ์ฉํ์ฌ ๋คํธ์ํฌ ๋ ๋ฒจ ๋ณด์์ ๊ฐํํ์ต๋๋ค.
- ELB (Elastic Load Balancer)
- HTTPS ๊ธฐ๋ฐ์ ์ ํ๋ฆฌ์ผ์ด์ ๋ก๋ ๋ฐธ๋ฐ์๋ฅผ ์ฌ์ฉํ์ฌ ์ธ๋ถ ์์ฒญ์ ์ฒ๋ฆฌํฉ๋๋ค.
- SLA(์๋น์ค ์์ค ๊ณ์ฝ) ๊ธฐ์ค ๊ฐ์ฉ์ฑ:
- ๋ค์ค AZ: 99.99%
- ๋จ์ผ AZ: 99.9%
- ์์ฒญ์ ELB๋ฅผ ํตํด EC2 ์ธ์คํด์ค๋ก ๋ถ์ฐ๋ฉ๋๋ค.
- ์ปจํ ์ด๋ ์ํ ํ์ฅ ์์๋ ์ ์ฐํ ๋ถํ ๋ถ์ฐ์ด ๊ฐ๋ฅํฉ๋๋ค.
- Route 53 (DNS ์๋น์ค)
- AWS์ ๊ณ ๊ฐ์ฉ์ฑ ๋๋ฉ์ธ ๋ค์ ์์คํ (DNS) ์๋น์ค์ ๋๋ค.
- "api.board-system.site"์ ๊ฐ์ ๋๋ฉ์ธ ์ด๋ฆ์ ELB์ ๋งคํํ์ฌ, ํด๋ผ์ด์ธํธ ์์ฒญ์ด ์ฌ๋ฐ๋ฅธ ์๋ํฌ์ธํธ๋ก ๋๋ฌํ ์ ์๋๋ก ํฉ๋๋ค.
- EC2
- ์ค์ ์ ํ๋ฆฌ์ผ์ด์ ์ด ๋ฐฐํฌ๋๋ ๊ฐ์ ๋จธ์ .
- ํ์ฌ๋ ๋จ์ผ EC2 ์ธ์คํด์ค์์ ์ด์๋๊ณ ์์ผ๋ฉฐ, Nginx ๋ฐ Spring Boot ์ปจํ ์ด๋๊ฐ Docker ํ๊ฒฝ์์ ์คํ ์ค์ ๋๋ค.
- RDS(Relational Database Service)
- MySQL ๊ธฐ๋ฐ์ ๊ด๊ณํ ๋ฐ์ดํฐ๋ฒ ์ด์ค.
- ํ๋ผ์ด๋น ์๋ธ๋ท์ ์์น์์ผ ์ธ๋ถ ์ ๊ทผ์ ์ฐจ๋จํ๊ณ , EC2 ์ปจํ ์ด๋๋ง ์ ๊ทผํ ์ ์๋๋ก ์ค์ ํ์ต๋๋ค.
- ElastiCache
- ์ธ๋ฉ๋ชจ๋ฆฌ ์บ์ ์๋ฒ๋ก Redis๋ฅผ ์ฌ์ฉ.
- ํ๋ผ์ด๋น ์๋ธ๋ท์ ์์นํ๋ฉฐ, ์ธ๋ถ ๋ ธ์ถ ์์ด EC2 ์ ํ๋ฆฌ์ผ์ด์ ์์๋ง ์ ๊ทผํ ์ ์์ต๋๋ค.
- VPC (Virtual Private Cloud)
- ์์ฒญ ํ๋ฆ
- ์ฌ์ฉ์๊ฐ
https://api.board-system.site๋ก ์์ฒญ์ ๋ณด๋ ๋๋ค. ์ด ๋๋ฉ์ธ์ Amazon Route 53์ ๋ฑ๋ก๋์ด ์์ผ๋ฉฐ, DNS ์ง์ ์ AWS ELB(์ ํ๋ฆฌ์ผ์ด์ ๋ก๋ ๋ฐธ๋ฐ์) ์ ์๋ํฌ์ธํธ๋ฅผ ์๋ตํฉ๋๋ค. - ์ฌ์ฉ์์ ์์ฒญ์ HTTPS ํ๋กํ ์ฝ์ ํตํด ELB์ 443 ํฌํธ๋ก ์ ๋ฌ๋ฉ๋๋ค. ELB๋ ๋ฑ๋ก๋ EC2 ์ธ์คํด์ค๋ก ํธ๋ํฝ์ ๋ถํ ๋ถ์ฐํ๋ฉฐ, ํ์ฌ๋ ๋จ์ผ EC2 ์ธ์คํด์ค๊ฐ ๋์ ์ค์ ๋๋ค.
- ELB๋ EC2 ์ธ์คํด์ค์ 80๋ฒ ํฌํธ๋ก ์์ฒญ์ ์ ๋ฌํ๊ณ , ์ด ํฌํธ๋ ๋ด๋ถ์ ์ผ๋ก Docker ์ปจํ ์ด๋์ 80๋ฒ ํฌํธ์ ํฌ์๋ฉ๋์ด ์์ต๋๋ค. ํด๋น ์ปจํ ์ด๋์๋ Nginx ๋ฆฌ๋ฒ์ค ํ๋ก์ ์๋ฒ๊ฐ ์คํ๋๊ณ ์์ต๋๋ค.
- Nginx๋ ํ์ฌ ์ค์ ์ ๋ฐ๋ผ Blue ๋๋ Green ์ปจํ ์ด๋๋ก ํธ๋ํฝ์ ์ ๋ฌํฉ๋๋ค. ๋ ์ปจํ ์ด๋ ๋ชจ๋ Spring Boot ๊ธฐ๋ฐ ์ ํ๋ฆฌ์ผ์ด์ ์ด ์คํ ์ค์ด๋ฉฐ, ์น ์ ํ๋ฆฌ์ผ์ด์ ์๋ฒ ์ญํ ์ ์ํํฉ๋๋ค.
- Blue/Green ๋ฐฐํฌ ์ ๋ต์ด ์ ์ฉ๋์ด ์์ด, ์๋ก์ด ๋ฒ์ ์ด ๋ฐฐํฌ๋ ๋๋ ํ์ฌ ๋์ ์ค์ด์ง ์์ ์ปจํ ์ด๋(Green ๋๋ Blue)์ ์ ๋ฒ์ ์ ๋ฐฐํฌํ๊ณ , ์ ์์ ์ผ๋ก ๋์ํจ์ ํ์ธํ ํ Nginx๊ฐ ์ ์ปจํ ์ด๋๋ก ํธ๋ํฝ์ ์ ํํฉ๋๋ค. ์ด๋ฅผ ํตํด ๋ฌด์ค๋จ ๋ฐฐํฌ(Zero Downtime Deployment) ๊ฐ ๊ฐ๋ฅํฉ๋๋ค.
- ์น ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ด๋ถ์ ์ผ๋ก AWS์ RDS(MySQL) ์ ElastiCache(Redis) ๋ฅผ ์ฌ์ฉํด ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ๊ฑฐ๋ ์กฐํํฉ๋๋ค. ๋ ์๋น์ค ๋ชจ๋ ํ๋ผ์ด๋น ์๋ธ๋ท ๋ด์ ์์นํ์ฌ ์ธ๋ถ ์ ๊ทผ์ด ์ฐจ๋จ๋ ์์ ํ ๊ตฌ์กฐ์ ๋๋ค.
- ์ฌ์ฉ์๊ฐ
- ์ฐ๋ฆฌ ์์คํ ์ ๋ฐ์ดํฐ๋ฒ ์ด์ค ERD ์ ๋๋ค.
- ๋๋ถ๋ถ์ ์ ๊ทํ ๋ ํํ๋ก ์ค๊ณํ์ผ๋, ์ผ๋ถ๋ถ ํ ์ด๋ธ์ ์ฑ๋ฅํ ์คํธ ์ ๋ฐ๊ฒฌํ ์กฐํ ์ฑ๋ฅ ๋ฌธ์ ๋ก ์ธํด ๋น์ ๊ทํ๋ฅผ ํ๊ณ , ์ ํฉ์ฑ์ ์ ํ๋ฆฌ์ผ์ด์ ์์ค์์ ๋ง์ถ๋๋ก ํ์ต๋๋ค.
- ๊ตฌ์ฑ ํ
์ด๋ธ
users: ์ฌ์ฉ์social_connections: ์์ ์ฐ๋boards: ๊ฒ์ํarticle_categories: ๊ฒ์๊ธ ์นดํ ๊ณ ๋ฆฌarticles: ๊ฒ์๊ธboard_article_counts: ๊ฒ์ํ๋ณ ๊ฒ์๊ธ ์ (๋น์ ๊ทํ)article_likes: ๊ฒ์๊ธ ์ข์์article_like_counts: ๊ฒ์๊ธ ์ข์์ ์ (๋น์ ๊ทํ)article_dislikes: ๊ฒ์๊ธ ์ซ์ด์article_dislike_counts: ๊ฒ์๊ธ ์ซ์ด์ ์ (๋น์ ๊ทํ)article_comments: ๊ฒ์๊ธ ๋๊ธarticle_comment_counts: ๊ฒ์๊ธ ๋๊ธ ์ (๋น์ ๊ทํ)
- ์ ํ๋ฆฌ์ผ์ด์ ์ ์์ ์ฑ, ์ ๋ขฐ์ฑ ๋ณด์ฅ์ ์ํด ๊ฐ ๋ชจ๋๋จ์ ํ ์คํธ๋ฅผ ์์ฑํ์ต๋๋ค.
- ๊ธฐ๋ณธ๊ณ์ธต์ธ api ๊ณ์ธต, ์ ํ๋ฆฌ์ผ์ด์ ๊ณ์ธต, ๋๋ฉ์ธ ๊ณ์ธต์ ๋ํ ํ ์คํธ ์ปค๋ฒ๋ฆฌ์ง๋ฅผ ์ต๋ํ ์ ์งํ๋๋ก ํ๊ณ ์์ต๋๋ค. (์ธํ ๋ฆฌ์ ์ด ๊ธฐ์ค ํ ์คํธ ์ปค๋ฒ๋ฆฌ์ง 100% ์งํฅ)
- ์ธ๋ถ ๊ธฐ์ ์ ์ฌ์ฉํ๋ ๋ถ๋ถ์ ์ฃผ์ ์ง์ ์์ ๊ฒ์ฆ ์ฝ๋๋ฅผ ์์ฑํ๊ณ ๋ฌธ์ ๊ฐ ๋ฐ์ํ์ ๋ ์ถ๊ฐ์ ์ธ ๋์ ๋ฐ ํ ์คํธ ๋ณด๊ฐํ๋๋ก ํ๊ณ ์์ต๋๋ค.
- ํ์ฉ
- CI/CD ์คํฌ๋ฆฝํธ์ ๋น๋ํ ์คํธ ๊ณผ์ ์์ ํจ๊ป ๊ณ์ ์คํ๋์ด, ํ ์คํธ๊ฐ ๊นจ์ง๋ ์ฝ๋๊ฐ ๋ฐฐํฌ๋์ง ์๋๋ก ํ๊ณ ์์ต๋๋ค.
- Spring Rest Docs ๋ฌธ์ํ ๊ณผ์ ์์ ํ ์คํธ์ฝ๋ ํต๊ณผ๋ฅผ ์ ํ ์กฐ๊ฑด์ผ๋ก ๋ ์ผ๋ก์, API ๋ฌธ์ ์ต์ ํ์๋ ์ ๊ทน์ ์ผ๋ก ํ์ฉํ๊ณ ์์ต๋๋ค.
- 2025.06.25 ๊ธฐ์ค 1102๊ฐ ํ
์คํธ๊ฐ ์์ฑ๋์ด ์์ต๋๋ค.
- ๊ณตํต ๋ชจ๋: 113๊ฐ
core: 90๊ฐdata-serializer: 1๊ฐid-generator: 2๊ฐtoken: 20๊ฐ
- ์ฌ์ฉ์ ๋ชจ๋: 261๊ฐ
user-application-output-port: 38๊ฐuser-application-service: 86๊ฐuser-domain: 116๊ฐuser-email-format-validate-adapter: 5๊ฐuser-email-oauth2-client-adapter: 3๊ฐuser-password-adapter: 3๊ฐuser-web-adapter: 10๊ฐ
- ๊ฒ์ํ ๋ชจ๋: 128๊ฐ
board-application-output-port: 16๊ฐboard-application-service: 27๊ฐboard-domain: 81๊ฐboard-web-adapter: 4๊ฐ
- ๊ฒ์๊ธ ๋ชจ๋: 105๊ฐ
article-application-output-port: 14๊ฐarticle-application-service: 44๊ฐarticle-domain: 40๊ฐarticle-web-adapter: 7๊ฐ
- ๊ฒ์๊ธ ๋๊ธ ๋ชจ๋: 101๊ฐ
article-comment-application-output-port: 17๊ฐarticle-comment-application-service: 41๊ฐarticle-comment-domain: 37๊ฐarticle-comment-web-adapter: 6๊ฐ
- ๊ฒ์๊ธ ์ข์์/์ซ์ด์ ๋ชจ๋: 103๊ฐ
article-like-application-output-port: 28๊ฐarticle-like-application-service: 32๊ฐarticle-like-domain: 33๊ฐarticle-like-web-adapter: 10๊ฐ
- ๊ฒ์๊ธ ์กฐํ ๋ชจ๋: 47๊ฐ
article-read-application-output-port: 15๊ฐarticle-read-application-service: 22๊ฐarticle-read-domain: 7๊ฐarticle-read-web-adapter: 3๊ฐ
- ๊ฒ์๊ธ ์กฐํ์ ๋ชจ๋: 23๊ฐ
article-view-application-output-port: 7๊ฐarticle-view-application-service: 8๊ฐarticle-view-domain: 5๊ฐarticle-view-web-adapter: 3๊ฐ
- ์ด๋ฉ์ผ ๋ฐ์ก ๋ชจ๋: 2๊ฐ
email-sender: 2๊ฐ
- ์ธ๋ถ ๊ธฐ์ ๋ชจ๋: 219๊ฐ
database-adapter: 109๊ฐevent-publisher: 1๊ฐjwt: 18๊ฐredis-adapter: 24๊ฐweb-support: 67๊ฐ
- ๊ณตํต ๋ชจ๋: 113๊ฐ










































