Skip to content

๐Ÿ“SWAVE - ์˜จํ”„๋ผ๋ฏธ์Šค ๊ธฐ๋ฐ˜ MSA ์•„ํ‚คํ…์ฒ˜์˜ ์„ค๋ฌธ ๊ด€๋ฆฌ ์„œ๋น„์Šค - WaveForm - (๋ฐฑ์—”๋“œ)๊ฐœ์„  ํ”„๋กœ์ ํŠธ

Notifications You must be signed in to change notification settings

tomy8964/Swave_Survey_Update

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 

History

94 Commits
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

GCP ๊ธฐ๋ฐ˜ MSA ์•„ํ‚คํ…์ฒ˜์˜ ์„ค๋ฌธ ๊ด€๋ฆฌ ์„œ๋น„์Šค - ๊ฐœ์„  ํ”„๋กœ์ ํŠธ

  • ๊ธฐ๊ฐ„ : 2023๋…„ 10์›” 2์ผ ~ 2024๋…„ 4์›” (6 ๊ฐœ์›”)

  • GitHub: https://github.com/tomy8964/Swave_Survey_Update

  • ๊ธฐ์ˆ  ์Šคํƒ : Java, SpringBoot, Spring Cloud Gateway, Spring Security, Gradle, JUnit5, Mockito, queryDsl, Docker, Kubernetes, GitHub, Jenkins, MySQL, MySQLOpretor, Prometheus, Grafana, Elastic, Kibana, Fluentd, GCP, Redis, ArgoCD, Slack, nGrinder

  • ๊ฐœ์š” : WaveForm์€ ์„ค๋ฌธ ์ƒ์„ฑยท๊ด€๋ฆฌ์™€ ์‘๋‹ต ์ˆ˜์ง‘ ๋ฐ ๋ถ„์„์„ ์ œ๊ณตํ•˜๋Š” MSA ๊ธฐ๋ฐ˜ ์„œ๋น„์Šค๋กœ, ์‚ฌ์šฉ์ž๊ฐ€ ๋น ๋ฅด๊ฒŒ ์„ค๋ฌธ ๋ฆฌ์ŠคํŠธ๋ฅผ ์กฐํšŒํ•˜๊ณ  ์งˆ๋ฌธ์„ ํƒ์ƒ‰ํ•  ์ˆ˜ ์žˆ์–ด์•ผ ํ–ˆ์Šต๋‹ˆ๋‹ค.

    ํ•˜์ง€๋งŒ nGrinder๋กœ ํ•ต์‹ฌ ์„ค๋ฌธ ์กฐํšŒ API์— ๋Œ€ํ•ด 3,000 Vuser ๋ถ€ํ•˜ ํ…Œ์ŠคํŠธ๋ฅผ ์ˆ˜ํ–‰ํ•ด ๋ณธ ๊ฒฐ๊ณผ, TPS๊ฐ€ ๋‹จ 64.4์— ๋ถˆ๊ณผํ•ด ์‹ค์„œ๋น„์Šค ์šด์˜ ๊ธฐ์ค€(>500 TPS)์— ํฌ๊ฒŒ ๋ชป ๋ฏธ์น˜๋Š” ๊ฒƒ์œผ๋กœ ํ™•์ธ๋์Šต๋‹ˆ๋‹ค.

    ์ด์— ๋”ฐ๋ผ ํŒ€์›๋“ค๊ณผ ์ง„ํ–‰ํ–ˆ๋˜ WaveForm ํ”„๋กœ์ ํŠธ๋ฅผ ๊ฐœ์„ ํ•˜๋Š” ํ”„๋กœ์ ํŠธ๋ฅผ ํ˜ผ์ž์„œ ์‹œ์ž‘ํ•˜๊ฒŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์ตœ์ข…์ ์œผ๋กœ TPS๋ฅผ 14๋ฐฐ (60.4 -> 841.4) ํ–ฅ์ƒ ์‹œ์ผฐ์œผ๋ฉฐ ํ…Œ์ŠคํŠธ ์ปค๋ฒ„๋ฆฌ์ง€ 100%๋ฅผ ๋ชฉํ‘œ๋กœ 147๊ฐœ ์ด์ƒ์˜ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๊ณ  ๊ฐ์ฒด์ง€ํ–ฅ์  ๋ฆฌํŒฉํ† ๋ง์„ ๋‹ฌ์„ฑํ•˜์˜€์Šต๋‹ˆ๋‹ค.

TPS 60.4์—์„œ 841.4๊นŒ์ง€ ์ง„์งœ ๋ณ‘๋ชฉ์„ ํ•ด๊ฒฐํ•œ ์„ฑ๋Šฅ ๊ฐœ์„ 

๋ฌธ์ œ ์ƒํ™ฉ ๋ฐ ๋ถ„์„

์„œ๋น„์Šค์˜ ํ•ต์‹ฌ์ธ ์„ค๋ฌธ ์กฐํšŒ API์— ๋Œ€ํ•ด nGrinder๋กœ ์„ฑ๋Šฅ ํ…Œ์ŠคํŠธ ์‹œ Spring Cloud Gateway ์ธ์Šคํ„ด์Šค(replica=1)๊ฐ€ ๋ฐ˜๋ณต์ ์œผ๋กœ ๋‹ค์šด๋˜๋Š” ํ˜„์ƒ์ด ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค.

Prometheus์™€ Grafana๋ฅผ ํ†ตํ•ด Gateway Pod์™€ ํด๋Ÿฌ์Šคํ„ฐ ๋…ธ๋“œ์˜ CPUยท๋ฉ”๋ชจ๋ฆฌยท๋„คํŠธ์›Œํฌ I/O๋ฅผ 1๋ถ„ ๋‹จ์œ„๋กœ ๋ชจ๋‹ˆํ„ฐ๋งํ–ˆ๊ณ , ๋ถ€ํ•˜ ํ…Œ์ŠคํŠธ๊ฐ€ ์‹œ์ž‘๋˜์ž๋งˆ์ž ์ธ์Šคํ„ด์Šค ํ•˜๋‚˜๊ฐ€ CPU 70% ์ด์ƒ์„ ์ง€์†์ ์œผ๋กœ ์‚ฌ์šฉํ•˜๋‹ค ์ตœ๋Œ€ ๋ถ€ํ•˜ ์‹œ 95%๋ฅผ ๋ŒํŒŒํ–ˆ์œผ๋ฉฐ, HTTP 5xx ์˜ค๋ฅ˜์œจ๋„ 15%๊นŒ์ง€ ๊ธ‰๋“ฑํ•˜๋Š” ํ˜„์ƒ์„ ์‹ค์‹œ๊ฐ„์œผ๋กœ ํ™•์ธํ–ˆ์Šต๋‹ˆ๋‹ค.

ํ•˜์ง€๋งŒ ๋‹จ์ˆœํžˆ Gateway์˜ replica ์ˆ˜๋งŒ ๋Š˜๋ ค์„œ๋Š” ์ง„์งœ ๋ณ‘๋ชฉ์„ ํ•ด๊ฒฐํ•  ์ˆ˜ ์—†๋‹ค๊ณ  ํŒ๋‹จํ–ˆ์Šต๋‹ˆ๋‹ค. ํŠธ๋ž˜ํ”ฝ์ด Gateway๋ฅผ ๊ฑฐ์ณ ๋ฐฑ์—”๋“œ๊นŒ์ง€ ์ „๋‹ฌ๋˜๋Š” ๊ณผ์ • ์–ด๋”˜๊ฐ€์— ๊ทผ๋ณธ ๋ณ‘๋ชฉ์ด ์ˆจ์–ด ์žˆ์„ ๊ฒƒ์ด๋ผ ํŒ๋‹จํ–ˆ์Šต๋‹ˆ๋‹ค.

์„ฑ๋Šฅ ๊ฐœ์„  ๊ณผ์ •

  1. DB ์ตœ์ ํ™”

    ๋จผ์ € ์„ค๋ฌธ ์กฐํšŒ ์ฟผ๋ฆฌ๋ฅผ ๋ถ„์„ํ•ด๋ณด๋‹ˆ, N+1 ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜๊ณ  ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. ์‹ค์ œ๋กœ ๊ฐ„๋‹จํ•œ ์„ค๋ฌธ ํ•˜๋‚˜๋ฅผ ์กฐํšŒํ•  ๋•Œ๋งŒ ํ•ด๋„ 6ํšŒ ์ด์ƒ์˜ ์ฟผ๋ฆฌ๊ฐ€ ์‹คํ–‰๋˜๊ณ  ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

    ์ด๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ์„ค๋ฌธ ์กฐํšŒ ๋กœ์ง์„ ๋‘ ๋‹จ๊ณ„๋กœ ์žฌ๊ตฌ์„ฑํ–ˆ์Šต๋‹ˆ๋‹ค.

    ๋จผ์ € QueryDSL์˜ fetch join์„ ์ ์šฉํ•˜์—ฌ, ์„ค๋ฌธ์„ ์กฐํšŒํ•  ๋•Œ ์ผ๋Œ€์ผ ๊ด€๊ณ„์ธ ๊ฒƒ๋“ค ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ์ผ๋Œ€๋‹ค ๊ด€๊ณ„์ธ ์งˆ๋ฌธ ๋ฆฌ์ŠคํŠธ๊นŒ์ง€ ํ•œ ๋ฒˆ์˜ ์กฐ์ธ์œผ๋กœ ์ฒ˜๋ฆฌํ•˜๋„๋ก ์ฟผ๋ฆฌ๋ฅผ ์ˆ˜์ •ํ–ˆ์Šต๋‹ˆ๋‹ค.

    ๊ทธ ๋‹ค์Œ ์งˆ๋ฌธ๊ณผ ์ผ๋Œ€๋‹ค ๊ด€๊ณ„์ธ ์„ ํƒ์ง€ ๋ฆฌ์ŠคํŠธ๋Š” ๋ณ„๋„ fetch join์œผ๋กœ ํ•œ ๋ฒˆ์— ์กฐํšŒํ•˜๊ณ , ๊ทธ ์™ธ ์ผ๋Œ€๋‹ค ๊ด€๊ณ„๋Š” default_batch_fetch_size ์„ค์ •์— ๋”ฐ๋ผ IN์ ˆ๋กœ ๋ฌถ์–ด ๋กœ๋”ฉํ•˜๋„๋ก ํ–ˆ์Šต๋‹ˆ๋‹ค.

    ๊ทธ ๊ฒฐ๊ณผ, ์›๋ž˜๋Š” ์„ค๋ฌธ ์กฐํšŒ 1ํšŒ, ์งˆ๋ฌธ ์กฐํšŒ 1ํšŒ, ์„ ํƒ์ง€ ์กฐํšŒ 2ํšŒ(2๊ฐœ์˜ ์„ ํƒ์ง€๊ฐ€ ์žˆ๋Š” ์˜ˆ์‹œ), ๊ทธ ์™ธ ์ผ๋Œ€๋‹ค ๊ด€๊ณ„ ์กฐํšŒ 2ํšŒ๋กœ ์ด 6ํšŒ ์‹คํ–‰๋˜๋˜ ์ฟผ๋ฆฌ๊ฐ€ ์„ค๋ฌธ+์ผ๋Œ€์ผ+์งˆ๋ฌธ ์กฐํšŒ 1ํšŒ, ์„ ํƒ์ง€ ์กฐํšŒ 1ํšŒ, ๊ทธ ์™ธ ์ผ๋Œ€๋‹ค ๊ด€๊ณ„ ์กฐํšŒ 1ํšŒ๋กœ ์ด 6ํšŒ โ†’ 3ํšŒ๋กœ ์ค„์–ด๋“ค์—ˆ์Šต๋‹ˆ๋‹ค.

    ๋‹ค์Œ์œผ๋กœ ์„œ๋น„์Šค์˜ ์š”๊ตฌ์‚ฌํ•ญ์ธ is_deleted ํ”Œ๋ž˜๊ทธ๋ฅผ ํ†ตํ•ด ์‚ญ์ œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ด€๋ฆฌํ•˜๊ณ  ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. ์ด์— ๋”ฐ๋ผ ์งˆ๋ฌธ ํ…Œ์ด๋ธ”์—์„œ survey_document_id์™€ is_deleted์— ๊ฐ๊ฐ ๋‹จ์ผ ์ธ๋ฑ์Šค๋ฅผ ์„ค์ •ํ•ด๋‘์—ˆ์œผ๋‚˜, ์‹ค์ œ MySQL ์˜ตํ‹ฐ๋งˆ์ด์ €๋Š” survey_document_id ์ธ๋ฑ์Šค๋งŒ ์‚ฌ์šฉํ•˜๊ณ  is_deleted๋Š” ํ›„์ฒ˜๋ฆฌ๋กœ๋งŒ ์ ์šฉํ•ด ์ˆ˜๋ฐฑ ๊ฑด์„ ์Šค์บ”ํ•˜๋Š” ๋น„ํšจ์œจ์ด ๋“œ๋Ÿฌ๋‚ฌ์Šต๋‹ˆ๋‹ค.

    ์ด๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ๋‘ ์ปฌ๋Ÿผ์„ ํ•œ ๋ฒˆ์— ์ฒ˜๋ฆฌํ•˜๋Š” ๋ณตํ•ฉ ์ธ๋ฑ์Šค (survey_document_id, is_deleted)๋ฅผ ์„ค๊ณ„ยท์ ์šฉํ–ˆ๊ณ , ์‹คํ–‰ ๊ณ„ํš ์žฌ๊ฒ€์ฆ ๊ฒฐ๊ณผ ์Šค์บ” ๋Œ€์ƒ์ด 300๊ฑด์—์„œ 52๊ฑด์œผ๋กœ ์ค„์–ด๋“ค๋ฉฐ ํ‰๊ท  ์‘๋‹ต ์†๋„๊ฐ€ ์•ฝ 0.15ms์—์„œ 0.05ms๋กœ 3๋ฐฐ ์ด์ƒ ๊ฐœ์„ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ ๋‚˜๋จธ์ง€ ํ…Œ์ด๋ธ”์— ๋Œ€ํ•ด์„œ๋„ ๋ณตํ•ฉ ์ธ๋ฑ์Šค๋ฅผ ์ ์šฉํ•˜์˜€์Šต๋‹ˆ๋‹ค.

    ์ด ๊ฐœ์„ ๋งŒ์œผ๋กœ ์„œ๋น„์Šค ์ „์ฒด TPS๋Š” 64.4์—์„œ ์•ฝ 200๊นŒ์ง€ ์ƒ์Šนํ–ˆ์Šต๋‹ˆ๋‹ค.

  2. Redis ๊ธ€๋กœ๋ฒŒ ์บ์‹œ ๋„์ž…

    ์ž์ฃผ ์กฐํšŒ๋˜๋Š” ์„ค๋ฌธ ๋ฐ์ดํ„ฐ๋ฅผ Redis์— ์บ์‹ฑํ•ด DB ์กฐํšŒ ํšŸ์ˆ˜๋ฅผ ๋Œ€ํญ ์ค„์˜€์Šต๋‹ˆ๋‹ค. ์บ์‹ฑ ์ ์šฉ ํ›„ TPS๋Š” 200์—์„œ 500๊นŒ์ง€ ์ถ”๊ฐ€๋กœ ๋†’์•„์กŒ์Šต๋‹ˆ๋‹ค.

  3. Gateway ํ™•์žฅ ๋ฐ ์˜คํ† ์Šค์ผ€์ผ๋ง

    Kubernetes์—์„œ Gateway replica๋ฅผ 1โ†’3์œผ๋กœ ํ™•์žฅํ•˜๊ณ , CPU ์‚ฌ์šฉ๋ฅ  70% ์ดˆ๊ณผ ์‹œ ์ž๋™์œผ๋กœ Pod๋ฅผ ์ฆ์„คํ•˜๋Š” Horizontal Pod Autoscaler(HPA)๋ฅผ ๋„์ž…ํ–ˆ์Šต๋‹ˆ๋‹ค.

    ๊ทธ ๊ฒฐ๊ณผ TPS๋Š” 500โ†’800 ์ด์ƒ์œผ๋กœ ํฌ๊ฒŒ ์ฆ๊ฐ€ํ–ˆ๊ณ , ํ•„์š”์‹œ ์ตœ๋Œ€ 5๊ฐœ๊นŒ์ง€ ์ž๋™ ํ™•์žฅ๋˜๋„๋ก ์„ค์ •ํ•ด ์•ˆ์ •์„ฑ์„ ๊ฐ•ํ™”ํ–ˆ์Šต๋‹ˆ๋‹ค.

  4. MySQL InnoDB Cluster๋ฅผ ํ†ตํ•œ ์ฝ๊ธฐ ์ฒ˜๋ฆฌ๋Ÿ‰ ํ™•๋Œ€ ๋ฐ ๊ณ ๊ฐ€์šฉ์„ฑ

    ์„ค๋ฌธ ์กฐํšŒยท์‘๋‹ต ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•˜๋Š” MySQL ๋‹จ์ผ ์ธ์Šคํ„ด์Šค๋Š” ๋…ธ๋“œ ์žฅ์•  ์‹œ ์ „์ฒด ์„œ๋น„์Šค ๊ฐ€์šฉ์„ฑ์— ์น˜๋ช…์ ์ด๊ธฐ ๋•Œ๋ฌธ์—, MySQL Operator๋ฅผ ํ™œ์šฉํ•ด Kubernetes ์œ„์— InnoDB Cluster๋ฅผ ๊ตฌ์ถ•ํ–ˆ์Šต๋‹ˆ๋‹ค.

    MySQL Router๋ฅผ ํ†ตํ•ด ์„ค๋ฌธ ์กฐํšŒ์™€ ๊ฐ™์€ ๋นˆ๋ฒˆํ•œ ์ฝ๊ธฐ ์š”์ฒญ์„ ์—ฌ๋Ÿฌ ๋ฆฌ๋” ๋…ธ๋“œ๋กœ ์ž๋™ ๋ผ์šฐํŒ…ํ•จ์œผ๋กœ์จ ์ฝ๊ธฐ ์ฒ˜๋ฆฌ๋Ÿ‰์„ ๋Š˜๋ ธ์Šต๋‹ˆ๋‹ค.

์ถ”๊ฐ€ ๊ณ ๋ ค

ํ˜„์žฌ ๋ฐ์ดํ„ฐ ํ…Œ์ด๋ธ” ๊ตฌ์กฐ๊ฐ€ ์ผ๋Œ€๋‹ค ๊ด€๊ณ„๊ฐ€ ์ค‘์ฒฉ๋˜์–ด ์žˆ์–ด ์กฐํšŒ ์‹œ ์—ฌ๋Ÿฌ ๋ฒˆ์˜ ์กฐ์ธ๊ณผ batch_fetch๊ฐ€ ๋ฐœ์ƒํ•˜๋Š” ๊ตฌ์กฐ์  ํ•œ๊ณ„๊ฐ€ ๋‚จ์•„ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด๋ฅผ ์™„ํ™”ํ•˜๊ธฐ ์œ„ํ•ด ์—ญ์ •๊ทœํ™”๋ฅผ ์ ์šฉํ•˜์—ฌ ์ตœ์†Œํ•œ์˜ ์กฐ์ธ์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ์กฐํšŒํ•˜๋Š” ๋ฐฉ๋ฒ•๋„ ๊ณ ๋ คํ•ด๋ณด๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ, ์“ฐ๊ธฐ ๋ชจ๋ธ๊ณผ ์ฝ๊ธฐ ๋ชจ๋ธ์„ ๋ถ„๋ฆฌํ•˜์—ฌ ์ฝ๊ธฐ ์ „์šฉ ์ตœ์ ํ™”๋œ ์Šคํ‚ค๋งˆ๋‚˜ ํ…Œ์ด๋ธ”์„ ๋ถ„๋ฆฌํ•˜๋Š” ๋ฐฉ๋ฒ•๋„ ๋„์ž…ํ•  ์˜ˆ์ •์ž…๋‹ˆ๋‹ค.

ํ…Œ์ŠคํŠธ ์ปค๋ฒ„๋ฆฌ์ง€ 100%๋ฅผ ๋ชฉํ‘œ๋กœ 147๊ฐœ ์ด์ƒ์˜ ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑ

๊ธฐ๋Šฅ ๋‹จ์œ„๋กœ๋Š” Controllerโ†’Serviceโ†’Repository๊นŒ์ง€ ๊ฐ ๊ณ„์ธต๋ณ„๋กœ ๋‹จ์œ„ ํ…Œ์ŠคํŠธ๋ฅผ ์„ธ๋ถ„ํ™”ํ–ˆ๊ณ , WebClient๋‚˜ ์™ธ๋ถ€ API ์—ฐ๋™ ๋ถ€๋ถ„์€ MockWebServer๋ฅผ ํ™œ์šฉํ•ด ์‹ค์ œ HTTP ํ˜ธ์ถœ ์‹œ๋‚˜๋ฆฌ์˜ค๋ฅผ ๊ทธ๋Œ€๋กœ ์žฌํ˜„ํ–ˆ์Šต๋‹ˆ๋‹ค.

@WebMvcTest, @DataJpaTest, @SpringBootTest ๋“ฑ์„ ์ƒํ™ฉ์— ๋งž๊ฒŒ ์กฐํ•ฉํ•˜๋ฉด์„œ โ€œ์ด ํ…Œ์ŠคํŠธ๊ฐ€ ์ง„์งœ ๊ฒ€์ฆํ•ด์•ผ ํ•  ํ–‰๋™์ด ๋ฌด์—‡์ธ๊ฐ€โ€๋ฅผ ๋งค๋ฒˆ ๊ณ ๋ฏผํ–ˆ๊ณ , Mockito์˜ when/thenReturnโ€ฏvs. ์‹ค์ œ ๋ ˆํฌ์ง€ํ† ๋ฆฌ ์‚ฌ์šฉ ์—ฌ๋ถ€๋ฅผ ์ฒ ์ €ํžˆ ๊ธฐ์ค€ํ™”ํ•ด ํ…Œ์ŠคํŠธ์˜ ์‹ ๋ขฐ์„ฑ๊ณผ ์œ ์ง€๋ณด์ˆ˜์„ฑ์„ ๋ชจ๋‘ ํ™•๋ณดํ–ˆ์Šต๋‹ˆ๋‹ค.

์„ค๋ฌธ ์‘๋‹ต ๋™์‹œ์„ฑ ๋ฌธ์ œ ํ•ด๊ฒฐ

๋™์ผ ์„ค๋ฌธ์— ๋Œ€ํ•œ ์ค‘๋ณต ์‘๋‹ต ์š”์ฒญ์ด ๋Œ€๋Ÿ‰์œผ๋กœ ๋“ค์–ด์˜ฌ ๋•Œ DB ํŠธ๋žœ์žญ์…˜๋งŒ์œผ๋กœ๋Š” ์„ฑ๋Šฅ ์ €ํ•˜์™€ ์ž ์žฌ์  ๋ฐ๋“œ๋ฝ ์œ„ํ—˜์„ ์™„์ „ํžˆ ํ•ด์†Œํ•  ์ˆ˜ ์—†๋‹ค๋Š” ๊ฒƒ์„ ํ™•์ธํ–ˆ์Šต๋‹ˆ๋‹ค.

์ฒ˜์Œ์—๋Š” ๋‚™๊ด€์  ๋ฝ(๋ฒ„์ „ ์ปฌ๋Ÿผ)์ด๋‚˜ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์˜ ๋น„๊ด€์  ๋ฝ(SELECTย โ€ฆย FORย UPDATE)์„ ๊ณ ๋ คํ–ˆ์ง€๋งŒ, ์ด๋“ค์€ ์š”์ฒญ ์ง€์—ฐ์ด ๊ธธ์–ด์งˆ์ˆ˜๋ก DB ์ปค๋„ฅ์…˜์„ ์žฅ์‹œ๊ฐ„ ์ ์œ ํ•˜๊ฒŒ ๋˜์–ด ํ™•์žฅ์„ฑ ์ธก๋ฉด์—์„œ ํ•œ๊ณ„๊ฐ€ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

๋ฐ˜๋ฉด Redis ๋ถ„์‚ฐ๋ฝ์€ ๊ฐ€๋ฒผ์šด I/O, ์œ ์—ฐํ•œ ๋งŒ๋ฃŒ ์„ค์ •, ํด๋Ÿฌ์Šคํ„ฐยทSentinel ๋ชจ๋“œ ์ง€์› ๋“ฑ MSA ํ™˜๊ฒฝ์— ์ตœ์ ํ™”๋œ ํŠน์„ฑ์„ ์ง€๋‹ˆ๊ณ  ์žˆ์—ˆ๊ธฐ์—, โ€œ๋ฝ ํš๋“ ๋Œ€๊ธฐโ€์™€ โ€œ์ž๋™ ๋งŒ๋ฃŒโ€๋ฅผ ํ†ตํ•ด ํ•œ ๋ฒˆ์— ์˜ค์ง ํ•˜๋‚˜์˜ ์ธ์Šคํ„ด์Šค๋งŒ ํ•ต์‹ฌ ๋กœ์ง์„ ์‹คํ–‰ํ•˜๊ฒŒ๋” ์„ค๊ณ„ํ–ˆ์Šต๋‹ˆ๋‹ค.

Redis ํด๋ผ์ด์–ธํŠธ๋ฅผ ์„ ํƒํ•  ๋•Œ๋„ ๋‹จ์ˆœ RedisTemplate ๋Œ€์‹  RedissonClient๋ฅผ ๋„์ž…ํ•œ ์ด์œ ๋Š”, tryLock(waitTime, leaseTime) API๊ฐ€ ์ œ๊ณตํ•˜๋Š” ๋ช…์‹œ์  ๋Œ€๊ธฐยท๋งŒ๋ฃŒ ํƒ€์ด๋ฐ ์ œ์–ด์™€ auto-renewal ๊ธฐ๋Šฅ ๋•๋ถ„์— โ€œ์„œ๋น„์Šค๊ฐ€ ์˜ˆ๊ธฐ์น˜ ์•Š๊ฒŒ ์ค‘๋‹จ๋˜๋”๋ผ๋„ ๋ฝ์ด ์ž๋™ ํ•ด์ œ๋œ๋‹คโ€๋Š” ๋ณด์žฅ์ด ์žˆ์—ˆ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ๋˜ํ•œ Spring AOP๋กœ ๋ฝ ๋กœ์ง์„ @DistributedLock(key = "survey:#{#dto.id}") ํ•œ ์ค„๋กœ ์ถ”์ƒํ™”ํ•˜๋ฉด์„œ, ๋น„์ฆˆ๋‹ˆ์Šค ์ฝ”๋“œ๋Š” ๋ฝ ํš๋“ยทํ•ด์ œ ์Šค๋ ˆ๋“œ ์•ˆ์ „์„ฑ์— ๋Œ€ํ•ด ์ „ํ˜€ ์‹ ๊ฒฝ ์“ฐ์ง€ ์•Š์•„๋„ ๋˜๋„๋ก ๋ถ„๋ฆฌํ–ˆ์Šต๋‹ˆ๋‹ค.

์™œ Filter์—์„œ JWT ์ธ์ฆ์„ ์ฒ˜๋ฆฌํ–ˆ๋Š”๊ฐ€?

JWT ์ธ์ฆ ๋กœ์ง์„ Spring MVC์˜ ์ธํ„ฐ์…‰ํ„ฐ๊ฐ€ ์•„๋‹ˆ๋ผ ์„œ๋ธ”๋ฆฟ ์ปจํ…Œ์ด๋„ˆ ๋‹จ๊ณ„์—์„œ ์‹คํ–‰๋˜๋Š” Filter๋กœ ๊ตฌํ˜„ํ•œ ๊ฒƒ์€, โ€œ๋ชจ๋“  ์š”์ฒญ์— ๋Œ€ํ•ด ์ธ์ฆ์ด ๊ฐ€์žฅ ๋จผ์ €, ๊ทธ๋ฆฌ๊ณ  ์ผ๊ด€๋˜๊ฒŒ ์ฒ˜๋ฆฌ๋˜์–ด์•ผ ํ•œ๋‹คโ€๋Š” ๋ณธ์งˆ์ ์ธ ์š”๊ตฌ์—์„œ ์ถœ๋ฐœํ–ˆ์Šต๋‹ˆ๋‹ค.

์ฒ˜์Œ์—๋Š” Spring MVC ์ธํ„ฐ์…‰ํ„ฐ๋‚˜ AOP ๊ธฐ๋ฐ˜ ์–ด๋…ธํ…Œ์ด์…˜ ๋ฐฉ์‹๋„ ๊ณ ๋ คํ–ˆ์Šต๋‹ˆ๋‹ค. ์ธํ„ฐ์…‰ํ„ฐ๋Š” ์ปจํŠธ๋กค๋Ÿฌ ํ˜ธ์ถœ ์ „ํ›„์— ๋กœ์ง์„ ์‚ฝ์ž…ํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, DispatcherServlet ๋ฐ”๊นฅ์˜ ์ •์  ๋ฆฌ์†Œ์Šค๋‚˜ ํ”„๋ก์‹œ๋œ ์—”๋“œํฌ์ธํŠธ ์š”์ฒญ์€ ๋ณดํ˜ธํ•˜์ง€ ๋ชปํ•œ๋‹ค๋Š” ํ•œ๊ณ„๊ฐ€ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

AOP ์–ด๋…ธํ…Œ์ด์…˜์€ ๋น„์ฆˆ๋‹ˆ์Šค ์ฝ”๋“œ์™€ ๋ถ„๋ฆฌ๋œ ๊ด€์‹ฌ์‚ฌ ๋ถ„๋ฆฌ์— ์œ ๋ฆฌํ•˜์ง€๋งŒ, HTTP ์š”์ฒญ ์ฒ˜๋ฆฌ ํ๋ฆ„์˜ ๊ฐ€์žฅ ์ดˆ๊ธฐ ๋‹จ๊ณ„์—์„œ ์‹คํ–‰๋œ๋‹ค๋Š” ๋ณด์žฅ์€ ์—†์—ˆ์Šต๋‹ˆ๋‹ค.

๋ฐ˜๋ฉด ํ•„ํ„ฐ๋Š” โ€œ์„œ๋ธ”๋ฆฟ ๋ ˆ๋ฒจ์—์„œ ๋ฌด์กฐ๊ฑด ์‹คํ–‰โ€๋˜๊ณ , Spring Security๊ฐ€ ์ œ๊ณตํ•˜๋Š” ๋ณด์•ˆ ์ฒด์ธ๊ณผ ์ผ์ฒดํ™”๋˜์–ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์—, ์ธ์ฆ ๋กœ์ง์„ ๊ฐ€์žฅ ๋ช…ํ™•ํ•˜๊ณ  ์•ˆ์ „ํ•˜๊ฒŒ ๋ฐฐ์น˜ํ•  ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

์ด์ฒ˜๋Ÿผ โ€œ์–ด๋–ค ์š”์ฒญ์„, ์–ธ์ œ, ์–ด๋–ป๊ฒŒ ๊ฒ€์ฆํ•ด์•ผ ํ•˜๋Š”์ง€โ€๋ถ€ํ„ฐ โ€œ์‹คํŒจ ์‹œ ์˜ˆ์™ธ๋ฅผ ์–ด๋–ป๊ฒŒ ์ผ๊ด€๋˜๊ฒŒ ์ฒ˜๋ฆฌํ• ์ง€โ€๊นŒ์ง€ ์น˜๋ฐ€ํ•˜๊ฒŒ ๊ณ ๋ฏผํ•œ ๋์—, ํ•„ํ„ฐ ๊ธฐ๋ฐ˜ JWT ์ธ์ฆ์ด ์ตœ์ ์˜ ์„ ํƒ์ž„์„ ํ™•์‹ ํ•  ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

๋‹คํ˜•์„ฑ ๊ธฐ๋ฐ˜ OAuthService ๋ฆฌํŒฉํ† ๋ง์œผ๋กœ ํ™•์žฅ์„ฑยท์œ ์ง€๋ณด์ˆ˜์„ฑ ํ™•๋ณด

OAuth ํ†ตํ•ฉ ๋กœ์ง์„ ๋ฆฌํŒฉํ† ๋งํ•˜๋ฉด์„œ ๊ฐ€์žฅ ๋จผ์ € ๊ณ ๋ฏผํ•œ ๊ฒƒ์€ โ€œ์ƒˆ๋กœ์šด OAuth ๊ณต๊ธ‰์ž๊ฐ€ ์ถ”๊ฐ€๋  ๋•Œ๋งˆ๋‹ค if/switch๋‚˜ Enum ๊ฐ’์„ ์ˆ˜์ •ํ•ด์•ผ ํ•˜๋Š” ๋น„ํšจ์œจโ€์ด์—ˆ์Šต๋‹ˆ๋‹ค.

์ฒ˜์Œ์—” ์• ๋…ธํ…Œ์ด์…˜์ด๋‚˜ ๋ฆฌํ”Œ๋ ‰์…˜์„ ํ™œ์šฉํ•œ ๋™์  ๋งคํ•‘๋„ ๊ณ ๋ คํ–ˆ์ง€๋งŒ, ์ด ๋ฐฉ๋ฒ•์€ ๋ณต์žก๋„๋ฅผ ๋†’์ด๊ณ  ๋””๋ฒ„๊น…์ด ์–ด๋ ค์›Œ์ง€๋Š” ๋‹จ์ ์ด ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. ๊ฒฐ๊ตญ โ€œ๊ณต๊ธ‰์ž๋ณ„ ํ† ํฐ ํŒŒ์‹ฑยทํ”„๋กœํ•„ ๋งคํ•‘ ์ฑ…์ž„์„ Provider ์ธํ„ฐํŽ˜์ด์Šค ๊ตฌํ˜„์ฒด์— ์œ„์ž„ํ•˜๊ณ , ProviderList๋ผ๋Š” ์ผ์ข…์˜ ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ์—์„œ ํ•„์š”ํ•œ ๊ตฌํ˜„์ฒด๋ฅผ ์ฐพ์•„ ์“ฐ๋Š” ๋ฐฉ์‹โ€์„ ์„ ํƒํ–ˆ์Šต๋‹ˆ๋‹ค.

์ด ์„ค๊ณ„๋Š” ๋‹ค์Œ ์„ธ ๊ฐ€์ง€๋ฅผ ๋ณด์žฅํ•ฉ๋‹ˆ๋‹ค.

์ฒซ์งธ, ๋‹จ์ผ ์ฑ…์ž„ ์›์น™(SRP)์„ ์ง€์ผœ OAuthService๋Š” ์˜ค์ง HTTP ํ˜ธ์ถœ๊ณผ ํ๋ฆ„ ์ œ์–ด๋งŒ ๋‹ด๋‹นํ•˜๋ฉฐ, ํ† ํฐ ๋ฌธ์ž์—ด ๋ณ€ํ™˜ยทJSON ํŒŒ์‹ฑยทProfile ํด๋ž˜์Šค ์„ ํƒ์€ ๊ฐ ๊ตฌํ˜„์ฒด๊ฐ€ ์•Œ์•„์„œ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค.

๋‘˜์งธ, ๊ฐœ๋ฐฉโ€‘ํ์‡„ ์›์น™(OCP)์„ ์ถฉ์กฑํ•ด ์ƒˆ๋กœ์šด ๊ณต๊ธ‰์ž ์ถ”๊ฐ€ ์‹œ ์ฝ”๋“œ ์ˆ˜์ • ์—†์ด ๊ตฌํ˜„์ฒด์™€ ๋“ฑ๋ก๋งŒ์œผ๋กœ ๋ฐ”๋กœ ์ง€์›๋ฉ๋‹ˆ๋‹ค.

์…‹์งธ, ์˜์กด์„ฑ ์—ญ์ „ ์›์น™(DIP)์„ ๋”ฐ๋ฅด๋ฉด์„œ ํ…Œ์ŠคํŠธ๋„ ํ›จ์”ฌ ๊ฐ„๋‹จํ•ด์กŒ์Šต๋‹ˆ๋‹ค.

์ด ๊ณผ์ •์„ ํ†ตํ•ด โ€œ๋‹จ์ˆœํžˆ ๊ธฐ๋Šฅ์ด ๋™์ž‘ํ•˜๊ฒŒ ํ•˜๋Š” ์ˆ˜์ค€์„ ๋„˜์–ด, ํ™•์žฅ์„ฑ๊ณผ ์œ ์ง€๋ณด์ˆ˜์„ฑ์„ ๋ฏธ๋ฆฌ ์˜ˆ์ธกํ•ด ์•„ํ‚คํ…์ฒ˜๋ฅผ ์„ค๊ณ„ํ•˜๋Š” ๋Šฅ๋ ฅโ€์„ ๊ธธ๋ €์œผ๋ฉฐ, ์ง€๊ธˆ ๋‹ค์‹œ ๋งŒ๋“ ๋‹ค๋ฉด Spring์˜ DI ์ปจํ…Œ์ด๋„ˆ๋ฅผ ํ™œ์šฉํ•ด Provider ๊ตฌํ˜„์ฒด๋“ค์„ ์ž๋™ ํƒ์ƒ‰ํ•˜๊ณ , ๋ ˆ์ง€์ŠคํŠธ๋ฆฌ ํด๋ž˜์Šค๋ฅผ ์™„์ „ํžˆ ์ œ๊ฑฐํ•ด ๋”์šฑ ๊ฐ€๋ณ๊ณ  ์„ ์–ธ์ ์ธ ๊ตฌ์กฐ๋กœ ์ง„ํ™”์‹œํ‚ฌ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

์„ฑ๊ณผ ๋ฐ ๊ฒฐ๊ณผ

์„ฑ๋Šฅ ํŠœ๋‹์„ ํ†ตํ•ด, TPS๋ฅผ 64.4์—์„œ 841.4๋กœ 14๋ฐฐ ์ด์ƒ ํ–ฅ์ƒ ์‹œํ‚ค๊ณ , Redis ์บ์‹œ์™€ InnoDB Cluster๋ฅผ ํ™œ์šฉํ•ด ์ฝ๊ธฐ ์ฒ˜๋ฆฌ๋Ÿ‰์„ ํ™•์žฅํ•˜๋ฉด์„œ๋„ ์ผ๊ด€์„ฑ์„ ์ง€ํ‚ฌ ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

๋˜ํ•œ ์ฝ”๋“œ ๋ ˆ๋ฒจ์—์„œ๋Š” QueryDSL fetch join, Hibernate batch_fetch, ๋ณตํ•ฉ ์ธ๋ฑ์Šค ์ ์šฉ ๋“ฑ ๋‹ค์–‘ํ•œ ์ตœ์ ํ™” ๊ธฐ๋ฒ•์„ ์ ์šฉํ•˜๊ณ , ํ…Œ์ŠคํŠธ ์ปค๋ฒ„๋ฆฌ์ง€๋ฅผ 100% ๋‹ฌ์„ฑํ•˜๊ธฐ ์œ„ํ•ด 147๊ฑด์˜ ๋‹จ์œ„ยทํ†ตํ•ฉ ํ…Œ์ŠคํŠธ๋ฅผ ์ž‘์„ฑํ•˜๋ฉฐ ๊ฐ์ฒด ์ง€ํ–ฅ์  ๋ฆฌํŒฉํ† ๋ง์„ ์™„์„ฑํ–ˆ์Šต๋‹ˆ๋‹ค.

์ด ๊ณผ์ •์—์„œ โ€œํ‘œ๋ฉด์ ์ธ ์Šค์ผ€์ผ ์•„์›ƒ์ด ์•„๋‹Œ, ์–ด๋””์— ์ง„์งœ ๋ณ‘๋ชฉ์ด ์žˆ๋Š”์ง€ ์ฐพ์•„๋‚ด๊ณ  ํ•ด๊ฒฐํ•œ๋‹คโ€๋Š” ๊ฒฝํ—˜์„ ์Œ“์•˜๊ณ , MSA ํ™˜๊ฒฝ์—์„œ ์•ˆ์ •์„ฑ๊ณผ ์„ฑ๋Šฅ์„ ๋™์‹œ์— ๋งŒ์กฑ์‹œํ‚ค๋Š” ์„ค๊ณ„ยท๊ตฌํ˜„ ์—ญ๋Ÿ‰์„ ํฌ๊ฒŒ ๊ฐ•ํ™”ํ•  ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

Architecture

Image

Blog

About

๐Ÿ“SWAVE - ์˜จํ”„๋ผ๋ฏธ์Šค ๊ธฐ๋ฐ˜ MSA ์•„ํ‚คํ…์ฒ˜์˜ ์„ค๋ฌธ ๊ด€๋ฆฌ ์„œ๋น„์Šค - WaveForm - (๋ฐฑ์—”๋“œ)๊ฐœ์„  ํ”„๋กœ์ ํŠธ

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published