๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ

Java & Spring ์‹ค์ „ ๊ฐœ๋ฐœ

1ํŽธ. Spring Boot ์„ฑ๋Šฅ ํŠœ๋‹ — ์šด์˜ ์„œ๋ฒ„์—์„œ ์‹ค์ œ๋กœ ํšจ๊ณผ ๋ณธ ๋ฐฉ๋ฒ•

๋ฐ˜์‘ํ˜•

 

Spring Boot ์„ฑ๋Šฅ ํŠœ๋‹

๐ŸŸฆ 1ํŽธ. Spring Boot ์„ฑ๋Šฅ ํŠœ๋‹ — ์šด์˜ ์„œ๋ฒ„์—์„œ ์‹ค์ œ๋กœ ํšจ๊ณผ ๋ณธ ๋ฐฉ๋ฒ•

์šด์˜ ์„œ๋น„์Šค์—์„œ ์„ฑ๋Šฅ ๋ฌธ์ œ๋Š” ๋ณดํ†ต ์˜ˆ๊ณ  ์—†์ด ์ฐพ์•„์˜จ๋‹ค.
์–ด๋А ๋‚ , ํŠน์ • ์‹œ๊ฐ„๋Œ€์— API ์‘๋‹ต์ด ๊ฐ‘์ž๊ธฐ ํ‰๊ท  100ms → 2~3์ดˆ๊นŒ์ง€ ์น˜์†Ÿ๋Š” ์ด์Šˆ๊ฐ€ ๋ฐœ์ƒํ–ˆ๋‹ค.

๋‹จ์ˆœ ํŠธ๋ž˜ํ”ฝ ์ฆ๊ฐ€๋กœ ๋ณด๊ธฐ์—” ์ˆ˜์น˜๊ฐ€ ๋„ˆ๋ฌด ์ปธ๋‹ค. ์ด์ƒ ์ง•ํ›„๋ฅผ ํ™•์ธํ•˜๊ธฐ ์œ„ํ•ด APM์„ ์—ด์–ด๋ณด๋‹ˆ, ๊ฐ€์žฅ ๋จผ์ € ๋ˆˆ์— ๋ˆ ๊ฒƒ์€ DB Connection Pool ๋Œ€๊ธฐ ์‹œ๊ฐ„ ์ฆ๊ฐ€์˜€๋‹ค. HikariCP ๋ชจ๋‹ˆํ„ฐ๋ง ๊ทธ๋ž˜ํ”„๊ฐ€ ์ •ํ™•ํžˆ ํ”ผํฌ ์‹œ๊ฐ„๋Œ€์— ๊ธ‰๊ฒฉํžˆ ์ƒ์Šนํ•˜๊ณ  ์žˆ์—ˆ๊ณ , ๊ทธ ์ˆœ๊ฐ„ ์ „์ฒด API์˜ ์‘๋‹ต ์‹œ๊ฐ„์ด ํ•จ๊ป˜ ๋Š˜์–ด๋‚ฌ๋‹ค.

์ด๋Ÿฐ ๋ฌธ์ œ๋Š” ๊ฐœ๋ฐœ·ํ…Œ์ŠคํŠธ ํ™˜๊ฒฝ์—์„œ๋Š” ์ž˜ ๋“œ๋Ÿฌ๋‚˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ์šด์˜ ํ™˜๊ฒฝ์—์„œ๋งŒ ์žฌํ˜„๋˜๋Š” ์ผ€์ด์Šค๊ฐ€ ๋งŽ๋‹ค. ์˜ค๋Š˜์€ ์‹ค์ œ ์šด์˜์—์„œ ๊ฒช์€ ์ด ์ด์Šˆ๋ฅผ ๊ธฐ์ค€์œผ๋กœ Spring Boot ์„ฑ๋Šฅ ํŠœ๋‹ ๊ณผ์ •์„ ์ž์„ธํžˆ ์ •๋ฆฌํ•ด๋ณธ๋‹ค.


โ–  ๋ฌธ์ œ 1: HikariCP ์ปค๋„ฅ์…˜ ํ’€ ๊ณ ๊ฐˆ

โœ” ์–ด๋–ค ํ˜„์ƒ์ด ๋ฐœ์ƒํ–ˆ๋‚˜?

  • ์—ฐ๊ฒฐ์„ ๋นŒ๋ ค์˜ค๋Š” ๋ฐ๋งŒ 500ms ์ด์ƒ ๊ฑธ๋ฆผ
  • maxPoolSize ๋Š” ์ถฉ๋ถ„ํ•ด ๋ณด์ด๋Š”๋ฐ๋„ ๊ณ„์† ํ’€ ๋ถ€์กฑ์ด ๋ฐœ์ƒ
  • ํŠน์ • ์‹œ๊ฐ„๋Œ€์—๋งŒ ๋ฐ˜๋ณต์ ์œผ๋กœ ๋ฐœ์ƒ

HikariCP ๋กœ๊ทธ๋ฅผ DEBUG ์ˆ˜์ค€์œผ๋กœ ์—ด์–ด๋ณด๋‹ˆ, ํŠธ๋ž˜ํ”ฝ์ด ๋ชฐ๋ฆฌ๋Š” ์ˆœ๊ฐ„๋งˆ๋‹ค ๋‹ค์Œ ๋ฉ”์‹œ์ง€๊ฐ€ ๋ฐ˜๋ณต์ ์œผ๋กœ ์ถœ๋ ฅ๋˜๊ณ  ์žˆ์—ˆ๋‹ค.

HikariPool-1 - Pool stats (total=40, active=40, idle=0)
HikariPool-1 - Timeout failure waiting for a connection.

์ฆ‰ ๋ชจ๋“  ์ปค๋„ฅ์…˜์ด ์‚ฌ์šฉ ์ค‘(active=40) ์ด๊ณ , ๋ฐ˜ํ™˜์ด ๋Šฆ์–ด์ง€๋ฉด์„œ ๋Œ€๊ธฐ์—ด์ด ์Œ“์ธ ๊ฒƒ์ด๋‹ค.


โ— ์›์ธ ๋ถ„์„

1) DB ์„ค์ •๊ณผ HikariCP maxLifetime ๋ถˆ์ผ์น˜

์šด์˜ DB(MySQL, MariaDB ๋“ฑ)๋Š” ๋ณดํ†ต wait_timeout, interactive_timeout ์„ค์ • ๊ฐ’์ด ์žˆ๋‹ค.
์ด ๊ฐ’๋ณด๋‹ค ๋” ์˜ค๋ž˜ ์‚ด์•„ ์žˆ๋Š” ์ปค๋„ฅ์…˜์€ DB๊ฐ€ ๋จผ์ € ๋Š์–ด๋ฒ„๋ฆฐ๋‹ค.
๊ทธ๋Ÿฐ๋ฐ HikariCP๋Š” DB๊ฐ€ ์ปค๋„ฅ์…˜์„ ๋Š์€ ์ค„ ๋ชจ๋ฅด๊ณ  ๊ณ„์† ์‚ฌ์šฉํ•˜๋ ค๋‹ค Dead Connection ์„ ๋ฐ›๊ฒŒ ๋˜๊ณ , ์ด๋กœ ์ธํ•ด ์žฌ์‹œ๋„ ๋ฐ ๋Œ€๊ธฐ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.

ํ…Œ์ŠคํŠธ ๊ฒฐ๊ณผ:

  • DB wait_timeout: 1800์ดˆ(30๋ถ„)
  • Hikari maxLifetime: 1800000ms(30๋ถ„) (๊ธฐ๋ณธ๊ฐ’)

์ฆ‰ ๋‘˜์ด ์ •ํ™•ํžˆ ๊ฐ™์€ ๊ฐ’์ด๋ผ DB๊ฐ€ ๋Š์–ด๋ฒ„๋ฆฌ๋Š” ํƒ€์ด๋ฐ๊ณผ ๊ฑฐ์˜ ๋™์ผํ–ˆ๋‹ค.

2) ํŠธ๋ž˜ํ”ฝ ํญ์ฃผ ๊ตฌ๊ฐ„์—์„œ ์„ธ์…˜์ด ์˜ค๋ž˜ ์œ ์ง€๋จ

ํŠน์ • API๋Š” ๋‹ค์†Œ ๋ฌด๊ฑฐ์šด ์กฐํšŒ ์ฟผ๋ฆฌ๋ฅผ ์ˆ˜ํ–‰ํ•˜๊ณ  ์žˆ์—ˆ๊ณ , ์ด API๊ฐ€ ๋™์‹œ ๋‹ค๋ฐœ์ ์œผ๋กœ ํ˜ธ์ถœ๋˜๋ฉด์„œ ์ปค๋„ฅ์…˜ ์ ์œ  ์‹œ๊ฐ„์ด ๊ธธ์–ด์กŒ๋‹ค.

๊ฒฐ๊ณผ์ ์œผ๋กœ:

  • ํ‰์ƒ์‹œ์—” ๋ฌธ์ œ ์—†์Œ
  • ํ”ผํฌ ํƒ€์ž„์—๋งŒ ์ ‘์† ๋Œ€๊ธฐ ์ฆ๊ฐ€ → ์ „์ฒด API ์ง€์—ฐ

โ— ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•

DB ์„ค์ •์„ ๋จผ์ € ํ™•์ธํ•˜๊ณ , ์ด๋ฅผ ๊ธฐ์ค€์œผ๋กœ HikariCP ์„ค์ •์„ ์กฐ์ •ํ–ˆ๋‹ค.

spring:
  datasource:
    hikari:
      maximum-pool-size: 40
      minimum-idle: 10
      max-lifetime: 1700000   # DB wait_timeout ์˜ ์•ฝ 90%๋กœ ๋งž์ถค
      connection-timeout: 3000

โœ” ์„ค์ • ์ ์šฉ ํ›„ ํšจ๊ณผ

  • ๋ถˆ๊ทœ์น™ํ–ˆ๋˜ dead connection ์ด ์‚ฌ๋ผ์ง
  • active pool ๊ทธ๋ž˜ํ”„๊ฐ€ ์•ˆ์ •์ ์œผ๋กœ ์œ ์ง€๋จ
  • ํŠธ๋ž˜ํ”ฝ ํ”ผํฌ ์‹œ๊ฐ„๋Œ€ API ์‘๋‹ต 2~3์ดˆ → 110~140ms๋กœ ํšŒ๋ณต
  • APM DB ๋Œ€๊ธฐ ๊ตฌ๊ฐ„ ์ง€์—ฐ์ด ๊ฑฐ์˜ 0์— ๊ฐ€๊น๊ฒŒ ๊ฐ์†Œ

์ฆ‰ HikariCP๊ฐ€ ์ปค๋„ฅ์…˜์„ ๋จผ์ € ์ •๋ฆฌํ•˜๊ณ  ์žฌ์ƒ์„ฑํ•˜๋„๋ก ๋งŒ๋“œ๋Š” ๊ฒƒ๋งŒ์œผ๋กœ๋„ ํฐ ํšจ๊ณผ๋ฅผ ๋ณด์•˜๋‹ค.


โ— ์‹ค์ „ ํŒ 3๊ฐœ (์šด์˜ ํ™˜๊ฒฝ ๊ธฐ์ค€)

1. maxLifetime ์€ ๋ฐ˜๋“œ์‹œ DB wait_timeout ์˜ 90%๋กœ ์„ค์ •ํ•œ๋‹ค

  • DB๊ฐ€ ๋จผ์ € ์—ฐ๊ฒฐ์„ ๋Š์–ด๋ฒ„๋ฆฌ๋ฉด ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ์žฅ์• ๋ฅผ ๋งž๋Š”๋‹ค.
  • ์ปค๋„ฅ์…˜์€ “DB๊ฐ€ ๋Š๊ธฐ๊ธฐ ์ „์—” HikariCP๊ฐ€ ๋จผ์ € ์ œ๊ฑฐํ•ด์•ผ ํ•œ๋‹ค.

2. idleTimeout ์€ maxLifetime ๋ณด๋‹ค ํ•ญ์ƒ ์ž‘์•„์•ผ ํ•œ๋‹ค

  • idle ์ƒํƒœ์˜ ์ปค๋„ฅ์…˜๋„ ์ ์ ˆํžˆ ์žฌ์ƒ์„ฑ๋˜๋„๋ก ํ•ด์•ผ ํ•œ๋‹ค.
  • ์ผ๋ฐ˜์ ์œผ๋กœ idleTimeout ≈ maxLifetime ์˜ 50~60% ์ˆ˜์ค€์ด ์•ˆ์ •์ ์ด๋‹ค.

3. ํ’€ ๋ถ€์กฑ์ด๋ผ๊ณ  ๋ฌด์กฐ๊ฑด maximum-pool-size ๋ฅผ ๋Š˜๋ฆฌ์ง€ ๋งˆ๋ผ

๋Œ€๋ถ€๋ถ„์˜ ๊ฒฝ์šฐ root cause ๋Š” ๋‹ค์Œ ์ค‘ ํ•˜๋‚˜๋‹ค:

  • ๋А๋ฆฐ SQL
  • ๋Œ€๋Ÿ‰ JOIN
  • ๋ถˆํ•„์š”ํ•œ ์ฟผ๋ฆฌ ํ˜ธ์ถœ
  • ํŠธ๋žœ์žญ์…˜ ๋ฒ”์œ„ ๊ณผ๋„ํ•˜๊ฒŒ ํผ

์ฆ‰ ํ’€์„ ๋Š˜๋ฆฌ๋Š” ๊ฒƒ์€ ์ตœํ›„์˜ ์ˆ˜๋‹จ์ด๊ณ , SQL ํŠœ๋‹์ด ์˜คํžˆ๋ ค ๋” ํฐ ํšจ๊ณผ๋ฅผ ๋งŒ๋“ ๋‹ค.


๐Ÿงฉ ๋งˆ๋ฌด๋ฆฌ

Spring Boot ์„ฑ๋Šฅ ํŠœ๋‹์€ ๋‹จ์ˆœํžˆ ์„ค์ • ๊ฐ’์„ ๋ฐ”๊พธ๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ
ํ™˜๊ฒฝ ์ „์ฒด(DB ์„ค์ • → Hikari ์„ค์ • → SQL → API ์„ค๊ณ„) ๋ฅผ ํ•จ๊ป˜ ๊ณ ๋ คํ•ด์•ผ ํ•œ๋‹ค.

์ด๋ฒˆ ๊ธ€์€ ๊ทธ์ค‘์—์„œ๋„ ๊ฐ€์žฅ ๋งŽ๊ณ  ์‹ค์ œ ์šด์˜์—์„œ ์ž์ฃผ ๋ฐœ์ƒํ•˜๋Š” “HikariCP ์ปค๋„ฅ์…˜ ํ’€ ๊ณ ๊ฐˆ” ๋ฌธ์ œ๋ฅผ ๋‹ค๋ค˜๋‹ค. ๋‹ค์Œ ๊ธ€์—์„œ๋Š” Jackson ์ง๋ ฌํ™” ํŠœ๋‹, ThreadPool ์กฐ์ • ๋“ฑ ๋˜ ๋‹ค๋ฅธ ์‹ค์ „ ๊ฒฝํ—˜์„ ๊ธฐ๋ฐ˜์œผ๋กœ ๋” ๊นŠ์€ ๋‚ด์šฉ์„ ๋‹ค๋ฃฐ ์˜ˆ์ •์ด๋‹ค.


๐Ÿ”– TAGS

Java, SpringBoot, PerformanceTuning, HikariCP, DatabaseOptimization, ProductionIssue, BackendEngineering, RealWorldTips

๋ฐ˜์‘ํ˜•