๊ฐœ์š”

๋‚œ ๊ธฐ์ˆ ๊ณผ ๊ด€๋ จ๋œ ๊ธ€์„ ์จ์„œ ์ด ๋ธ”๋กœ๊ทธ์— ๊ฒŒ์žฌํ•˜๊ณ  ์žˆ๋‹ค. ์ตœ๊ทผ์—๋Š” ๋ธ”๋กœ๊ทธ ๊ธ€์„ GeekNews์— ๋งํฌ๋กœ ๊ณต์œ ํ•œ ์ ์ด ์žˆ์—ˆ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ๊ฐ‘์ž๊ธฐ ๋ธ”๋กœ๊ทธ ๋ฐฑ์—”๋“œ ์„œ๋ฒ„๊ฐ€ ์ž‘๋™ ๋ถˆ๋Šฅ์— ๋น ์ง€๋ฉด์„œ ๋ธ”๋กœ๊ทธ ์ ‘์† ์žฅ์• ๋ฅผ ๊ฒช์—ˆ๋‹ค.

๋กœ๊ทธ ๋ฐ ๋งคํŠธ๋ฆญ์„ ๋ถ„์„ํ•œ ๊ฒฐ๊ณผ, ๋ธ”๋กœ๊ทธ ๋ฐฑ์—”๋“œ ์„œ๋ฒ„์˜ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ ‘์† ๋ถˆ๊ฐ€๋กœ ์ธํ•œ ์„œ๋น„์Šค ๊ฑฐ๋ถ€ ์ง•ํ›„๊ฐ€ ํ™•์ธ๋˜์—ˆ๋‹ค.

์ด ๊ธ€์—์„œ๋Š” ์žฅ์•  ์žฌ๋ฐœ ๋ฐฉ์ง€๋ฅผ ์œ„ํ•ด ํƒํ•œ ๊ฐœ์„  ๋ฐฉ์•ˆ๊ณผ ๊ทธ ๊ฒฐ๊ณผ๋ฅผ ๊ธฐ๋กํ•œ๋‹ค.

๊ธ€์— ๊ธ€์–ด๊ฐ€๊ธฐ ์•ž์„œ, ์ด ๋ธ”๋กœ๊ทธ์˜ SLA1๋ฅผ ์ˆ˜์น˜ํ™”ํ•œ ๊ฒฐ๊ณผ๋ฅผ ๋จผ์ € ๊ณต์œ ํ•˜๊ฒ ๋‹ค. ๊ฐœ์„  ์ „/ํ›„๋ฅผ ๋น„๊ตํ•˜๋ฉด ์•„๋ž˜์™€ ๊ฐ™๋‹ค.

  • ๊ฐœ์„  ์ „: 51% (1๋ถ„๋‹น ์•ฝ 400ํšŒ ์š”์ฒญ์‹œ)
  • ๊ฐœ์„  ํ›„: 99.9996286% (๋ถ„๋‹น ์•ฝ 40,500ํšŒ ์š”์ฒญ์‹œ)

์ ‘์† ์žฅ์•  ๋‹น์‹œ ์ƒํ™ฉ

๋‚ด ๋ธ”๋กœ๊ทธ์˜ ์ ‘์† ๋ถˆ๊ฐ€ ์žฅ์•  ๋ฐœ์ƒ ์‚ฌ์‹ค์„ ์•Œ๋ ค์ค€ ๋Œ“๊ธ€ ์‚ฌ์ง„: ์ถœ์ฒ˜

2025๋…„ 4์›” 13์ผ ์˜ค์ „, ๋‚˜๋Š” ๋‚ด ๋ธ”๋กœ๊ทธ ๊ธ€์„ ํ•œ๊ตญ์–ด ๊ฐœ๋ฐœ ๋‰ด์Šค ์‚ฌ์ดํŠธ GeekNews์— ๋“ฑ๋กํ•˜์˜€๋‹ค2 3. ์ดํ›„ GeekNews ๋ฐฉ๋ฌธ์ž๋“ค์ด ๋‚ด ๋ธ”๋กœ๊ทธ์— ์œ ์ž…๋˜์—ˆ๋‹ค 4.

๊ทธ๋Ÿฐ๋ฐ, ์ผ๋ถ€ ๋ฐฉ๋ฌธ์ž๋Š” ์ ‘์† ์žฅ์• ๋ฅผ ๊ฒช์—ˆ๋‹ค.

ํ…Œํฌ ์Šคํƒ

์ด ๋ธ”๋กœ๊ทธ์˜ ๊ฒŒ์‹œ๋˜๋Š” ๋ชจ๋“  ๊ธ€๊ณผ ์‚ฌ์ง„์— ๋Œ€ํ•œ CRUD๋ฅผ ๋‹ด๋‹นํ•˜๋Š”, ๋ธ”๋กœ๊ทธ ๋ฐฑ์—”๋“œ ์„œ๋ฒ„์˜ ํ…Œํฌ ์Šคํƒ์€ ์•„๋ž˜์™€ ๊ฐ™์ด ์š”์•ฝ๋œ๋‹ค.

  • DB ํƒ€์ž…: PostgreSQL
  • PostgreSQL ๋ฐฐํฌ์ฒ˜: Supabase
  • SQL ํด๋ผ์ด์–ธํŠธ: launchbadge/sqlx::postgresql (์ดํ•˜ "sqlx")
  • ๋ฐฑ์—”๋“œ ์„œ๋ฒ„๋Š” ์„œ๋ฒ„๋ฆฌ์Šค ํ™˜๊ฒฝ(AWS Lambda)์— ๋ฐฐํฌ๋จ

5 6

๋‹น์‹œ ํŠธ๋ž˜ํ”ฝ

๋ธ”๋กœ๊ทธ ์ ‘์† ์žฅ์•  ๋ฐœ์ƒ ์‹œ์ ์˜ ํŠธ๋ž˜ํ”ฝ ์ˆ˜์น˜๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

  • ๋ธ”๋กœ๊ทธ ๋ฐฑ์—”๋“œ ์„œ๋ฒ„์˜ ํ˜ธ์ถœ ๋นˆ๋„๋Š” ๋ถ„๋‹น ํ‰๊ท  96ํšŒ, ๋ถ„๋‹น ์ตœ๋Œ€ 400ํšŒ.
  • AWS Lambda concurrent execution ์ˆ˜์น˜๋Š” ๋ถ„๋‹น ์•ฝ 27๋‹จ์œ„7.

๋‹น์‹œ ์—๋Ÿฌ ๋กœ๊ทธ

์ ‘์† ๋ถˆ๊ฐ€ ํ˜„์ƒ์ด ๋ฐœ์ƒํ•  ๋•Œ ๊ธฐ๋ก๋œ8 ์—๋Ÿฌ ๋กœ๊ทธ๋Š” ์•„๋ž˜์™€ ๊ฐ™๋‹ค.

thread 'main' panicked at src/main.rs:52:10: can't connect to database: PoolTimedOut

sqlx์—์„œ PoolTimedOut ์—๋Ÿฌ๋ฅผ ์ผ์œผํ‚จ ๊ฒƒ์œผ๋กœ ํ™•์ธ๋œ๋‹ค.

์ค‘๊ฐ„ ์ •๋ฆฌ

  1. ์‹œ์Šคํ…œ์ด ๊ฐ๋‹นํ•˜์ง€ ๋ชปํ•˜๋Š” ํŠธ๋ž˜ํ”ฝ ์œ ์ž…์ด ๋ฐœ์ƒํ•˜์˜€๋‹ค.
  2. ํŠธ๋ž˜ํ”ฝ์— ๋Œ€์‘ํ•˜๊ธฐ ์œ„ํ•ด ๋งŽ์€ ์„œ๋ฒ„๊ฐ€ ๋™์‹œ์— ์ƒ์„ฑ๋˜์—ˆ๋‹ค.
  3. ๊ฐ ์„œ๋ฒ„๊ฐ€ 1๊ฐœ์˜ PostgreSQL ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์ ‘๊ทผ์„ ์‹œ๋„ํ•˜์˜€๋‹ค.
  4. ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์˜ ์ž์›์ด ๋น ๋ฅด๊ฒŒ ์†Œ์ง„๋˜์—ˆ๊ณ  ๊ฒฐ๊ตญ ๊ณ ๊ฐˆ๋˜์ž, ์ผ๋ถ€ ์„œ๋ฒ„๋Š” ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ ‘๊ทผ์„ ์‹คํŒจํ•˜๋Š” ์ƒํ™ฉ์ด ๋ฒŒ์–ด์กŒ๋‹ค.
  5. ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์„œ๋ฒ„ ์ ‘๊ทผ์— ์‹คํŒจํ•œ ์„œ๋ฒ„๋“ค์€ ํ”„๋กœ์„ธ์Šค๋ฅผ ๊ฐ•์ œ ์ข…๋ฃŒํ•˜์˜€๊ณ , ๋„คํŠธ์›Œํฌ ์‘๋‹ต์„ ๊ฑฐ๋ถ€ํ•˜์˜€๋‹ค.

์ฆ‰, ๋ธ”๋กœ๊ทธ ๋ฐฑ์—”๋“œ ์„œ๋ฒ„์˜ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ ‘์† ์‹คํŒจ๊ฐ€ ์ด์Šˆ ๋ฐœ์ƒ ์ง€์ ์ด๋‹ค.

์ด์Šˆ ์›์ธ ๋ถ„์„

์ด์Šˆ ์›์ธ ๋ถ„์„์— ์•ž์„œ, ์ด ๋ธ”๋กœ๊ทธ๋Š” ์ด 2๋‹จ๊ณ„์˜ ์ปค๋„ฅ์…˜ ํ’€์„ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋‹ค. ๊ฒฐ๋ก ์ ์œผ๋กœ๋Š” ์ด ์ปค๋„ฅ์…˜ ํ’€ ๊ด€๋ฆฌ์— ๋ฌธ์ œ๊ฐ€ ์žˆ์–ด ๋ฐœ์ƒํ•œ ์žฅ์• ์ธ๋ฐ, ๊ทธ ์ด์œ ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

1์ฐจ ์ปค๋„ฅ์…˜ ํ’€: Supabase์˜ PostgreSQL Connection Pooler

์‚ฌ์ง„ ์ถœ์ฒ˜: Supabase Documentation - Connecting to your database

Supabase๋Š” PostgreSQL SaaS๋กœ์จ, ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ๋Œ€ํ•œ ์ž์ฒด์ ์ธ ์ปค๋„ฅ์…˜ ํ’€์„ ์ œ๊ณตํ•œ๋‹ค.

Supabase์˜ 'Connection Pooler'๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ปค๋„ฅ์…˜ ํ’€์„ ํ†ตํ•œ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ ‘๊ทผ์ด ๋ณด์žฅ๋œ๋‹ค. ์ง์ ‘ ์ ‘๊ทผ ๋ฐฉ์‹๋ณด๋‹ค ์ข€ ๋” ๋น ๋ฅธ ์ปค๋„ฅ์…˜ ํš๋“์ด ๊ฐ€๋Šฅํ•˜๋‹ค๋Š” ์žฅ์ ์ด ์žˆ๋‹ค.

ํ•œํŽธ, ๋ธ”๋กœ๊ทธ ์„œ๋ฒ„๋Š” prepared statements๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ฟผ๋ฆฌ ๋‚ด ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ์น˜ํ™˜ํ•œ๋‹ค. sqlx๋Š” ์ด๋ฅผ ๊ธฐ๋ณธ์œผ๋กœ ์ง€์›ํ•˜๊ณ  ์žˆ์œผ๋‚˜9, Supabase์˜ "transaction mode connection pooler"๋Š” ํ˜„์žฌ prepared statements๋ฅผ ์ง€์›ํ•˜์ง€ ์•Š๊ณ  ์žˆ๋‹ค10.

๋”ฐ๋ผ์„œ ๋‚˜๋Š” prepared statements๊ฐ€ ์ง€์›๋˜๋Š” Connection Pooler๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด, Supabase์˜ "session mode connection pooler"๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์ ‘์†ํ•˜๋„๋ก ํ–ˆ๋‹ค.

์ด๋•Œ ์ปค๋„ฅ์…˜ ํ’€ ์„ค์ •์„ Supabase ๋Œ€์‹œ๋ณด๋“œ์—์„œ ์ง์ ‘ ์ง€์ •ํ•  ์ˆ˜ ์žˆ๋‹ค11. Supabase์˜ pool size ๊ธฐ๋ณธ๊ฐ’์€ 15์ด๋‹ค. ๋‚˜๋Š” ๊ธฐ๋ณธ๊ฐ’ ๊ทธ๋Œ€๋กœ ๋ฐฐํฌํ•˜์˜€๋‹ค.

2์ฐจ ์ปค๋„ฅ์…˜ ํ’€: ๋ฐฑ์—”๋“œ ๋‚ด๋ถ€

Supabase์˜ 1์ฐจ์ ์ธ ์ปค๋„ฅ์…˜ ํ’€๊ณผ ๋ณ„๊ฐœ๋กœ 2์ฐจ์ ์ธ ์ปค๋„ฅ์…˜ ํ’€์„ ๋ฐฑ์—”๋“œ ์„œ๋ฒ„ ์•ˆ์— ๋‘๊ณ  ์‹ถ์—ˆ๊ธฐ์—, ๋‚˜๋Š” sqlx ๋ฌธ์„œ์— ์†Œ๊ฐœ๋œ ์ปค๋„ฅ์…˜ ํ’€ ์˜ˆ์ œ ์ฝ”๋“œ๋ฅผ ๊ฑฐ์˜ ๊ทธ๋Œ€๋กœ ๋ณต์‚ฌํ•˜์—ฌ ๋‚ด ์ฝ”๋“œ์— ๋ถ™ํ˜€๋„ฃ์—ˆ๋‹ค.

use sqlx::postgres::PgPoolOptions;

let pg_pool = PgPoolOptions::new()
    .max_connections(5)
    .acquire_timeout(Duration::from_secs(3))
    .connect(&db_connection_str)
    .await
    .expect("can't connect to database");

let conn = pg_pool.acquire().await.map_err(|_| internal_error())?;

2์ฐจ ์ปค๋„ฅ์…˜ ํ’€์˜ ์ด์Šˆ

์ด๋ฒˆ ์ด์Šˆ๋ฅผ ํ™•์ธํ•˜๋ฉด์„œ ๋ฐฑ์—”๋“œ ์†Œ์Šค์ฝ”๋“œ๋ฅผ ๋‹ค์‹œ ํ™•์ธํ•˜์˜€๋‹ค. ์œ„ ์ฝ”๋“œ์˜ ์ง„์งœ ์˜๋ฏธ๋Š” ์•„๋ž˜์™€ ๊ฐ™์•˜๋‹ค.

  • ์ตœ์ดˆ์—๋Š” ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ปค๋„ฅ์…˜์„ 0๊ฐœ๋งŒ ์ ์œ ํ•จ.
  • ํ•„์š”ํ•œ ๊ฒฝ์šฐ์— ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋กœ๋ถ€ํ„ฐ ์ปค๋„ฅ์…˜์„ ์ƒˆ๋กญ๊ฒŒ 1๊ฐœ ์ ์œ ํ•ด์˜ค๊ณ , ์„œ๋ฒ„ ๋‚ด ์ปค๋„ฅ์…˜ ํ’€์— ๋“ฑ๋ก.
  • ์ปค๋„ฅ์…˜ ํ’€์— ๋“ฑ๋ก๋œ ์ปค๋„ฅ์…˜์€ ์„œ๋ฒ„ ์•ˆ์—์„œ๋งŒ ์žฌ์‚ฌ์šฉํ•จ.
  • ์„œ๋ฒ„ ๋‚ด ์ปค๋„ฅ์…˜ ํ’€์— ์ตœ๋Œ€ 5๊ฐœ ์ปค๋„ฅ์…˜์„ ์ ์œ  ๊ฐ€๋Šฅ.
  • ํ•œ ๋ฒˆ ์ ์œ ํ•ด์˜จ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ปค๋„ฅ์…˜์€ 10๋ถ„ ๋’ค์— ์ž๋™์œผ๋กœ ๋ฐ˜ํ™˜.
  • ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ปค๋„ฅ์…˜์„ ์ƒˆ๋กญ๊ฒŒ ์ ์œ ํ•ด์˜ฌ ๋•Œ ๋งŒ์•ฝ 3์ดˆ ์•ˆ์— ํš๋“ํ•ด์˜ค์ง€ ๋ชปํ•˜๋ฉด ์„œ๋ฒ„ ๊ฐ•์ œ ์ข…๋ฃŒ ์ฒ˜๋ฆฌ.

ํŠนํžˆ, "์ปค๋„ฅ์…˜์„ 10๋ถ„ ๋’ค ๋ฐ˜ํ™˜"ํ•˜๋Š” ๊ฒƒ์€ sqlx ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์˜ ์ž๋™ ๊ธฐ๋ณธ๊ฐ’์ด๊ธฐ์—12, ๋ณ„๋„๋กœ ์ง€์ •ํ•˜์ง€ ์•Š์€ ๋‚ด ์˜๋„์™€๋Š” ๋‹ค๋ฅด๊ฒŒ ์ ์šฉ๋œ ์ •์ฑ…์ธ ์…ˆ์ด๋‹ค.

๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•  ์‹œ๋‚˜๋ฆฌ์˜ค๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

๋จผ์ €, '๋ธ”๋กœ๊ทธ ๊ฒŒ์‹œ๋ฌผ ์กฐํšŒ'๊ฐ€ ๋™์‹œ์— 15ํšŒ ๋ฐœ์ƒํ•˜์˜€๋‹ค๊ณ  ๊ฐ€์ •ํ•ด๋ณด์ž. ์ฆ‰์‹œ 15๊ฐœ์˜ AWS Lambda ์„œ๋ฒ„๊ฐ€ ์ƒ์„ฑ๋  ๊ฒƒ์ด๋‹ค. ์ด๋•Œ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ปค๋„ฅ์…˜์„ ๊ฐ์ž 1๊ฐœ์”ฉ ์ ์œ ํ•˜๊ฒŒ ๋œ๋‹ค. ์ด๋Š” Supabase์˜ pool size ๊ธฐ๋ณธ๊ฐ’์ธ 15๊ฐœ ์ „๋ถ€๋ฅผ ๋ฒŒ์จ ์ ์œ ํ•ด๋ฒ„๋ฆฌ๊ฒŒ ๋˜๋Š” ์…ˆ์ด๋‹ค.

์•ž์„œ ์ฒ˜๋ฆฌ๋˜๋Š” ์™€์ค‘, '๋ธ”๋กœ๊ทธ ๊ฒŒ์‹œ๋ฌผ ์กฐํšŒ'๊ฐ€ ๋”ฑ 1๊ฑด ๋” ๋ฐœ์ƒํ•˜๋ฉด ์–ด๋–ป๊ฒŒ ๋ ๊นŒ? ์•ž์„œ ์ƒ์„ฑ๋œ 15๊ฐœ์˜ AWS Lambda ์„œ๋ฒ„๋“ค์€ ์•„์ง ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•˜๋А๋ผ ๋ฐ”์˜๊ธฐ์—, ์ƒˆ๋กœ์šด ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์œ„ํ•œ ์ƒˆ๋กœ์šด 16๋ฒˆ์งธ AWS Lambda ์„œ๋ฒ„๊ฐ€ ์ƒ์„ฑ๋  ๊ฒƒ์ด๋‹ค. ์ด ์„œ๋ฒ„ ๋˜ํ•œ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ปค๋„ฅ์…˜ ์ ์œ ๋ฅผ ์‹œ๋„ํ•  ๊ฒƒ์ด๋‹ค. ๊ทธ๋Ÿฐ๋ฐ Supabase๋Š” ๋” ์ด์ƒ ํ• ๋‹น์‹œํ‚ฌ ์ปค๋„ฅ์…˜ ์ž์›์ด ์—†๊ธฐ ๋•Œ๋ฌธ์— ์ ์œ  ๋Œ€๊ธฐ๋ฅผ ๋ฐœ์ƒ์‹œํ‚จ๋‹ค.

์•ž์„œ ์ƒ์„ฑ๋œ 15๊ฐœ์˜ ์„œ๋ฒ„๋“ค์€ ์ตœ์žฅ 10๋ถ„๊ฐ„ ์ปค๋„ฅ์…˜ ์ž์›์„ ๋‚ด๋†“์ง€ ์•Š์„ ๊ฒƒ์ด๋‹ค. ์ด์— 16๋ฒˆ์งธ ์„œ๋ฒ„๋Š” ์ปค๋„ฅ์…˜ ์ง€์—ฐ์„ ๊ธฐ๋‹ค๋ฆฌ๋‹ค 3์ดˆ๊ฐ€ ์ง€๋‚˜๋ฒ„๋ฆฌ๋Š” ์ˆœ๊ฐ„, ํ•ด๋‹น ์„œ๋ฒ„๋Š” ๊ฐ•์ œ ์ข…๋ฃŒ๋˜๊ณ  ์‘๋‹ต์— ์‹คํŒจํ•˜๊ฒŒ ๋œ๋‹ค. 17๋ฒˆ์งธ, 18๋ฒˆ์งธ ์š”์ฒญ์ด ๋“ค์–ด์˜ค๋”๋ผ๋„, ์ปค๋„ฅ์…˜ ์ž์›์ด ๊ณ ๊ฐˆ๋œ ์ด์ƒ ์‘๋‹ต์— ์‹คํŒจํ•  ์ˆ˜ ๋ฐ–์— ์—†๋‹ค.

์ฆ‰, 2์ฐจ ์ปค๋„ฅ์…˜ ํ’€์˜ ์ž˜๋ชป๋œ ์„ค์ •์œผ๋กœ ์ธํ•ด, 1์ฐจ ์ปค๋„ฅ์…˜ ํ’€์„ ๋ชจ๋‘ ์†Œ์ง„ํ•˜๊ณ  ์ž์› ๊ณ ๊ฐˆ์„ ๋ฐœ์ƒ์‹œํ‚จ ์…ˆ์ด๋‹ค.

์ตœ์ข… ์ •๋ฆฌ

๋ธ”๋กœ๊ทธ ๋ฐฑ์—”๋“œ ์„œ๋ฒ„๋Š” Supabase์˜ 1์ฐจ์ ์ธ ์ปค๋„ฅ์…˜ ํ’€์—์„œ ์ปค๋„ฅ์…˜์„ ํš๋“ํ•ด์˜ค๊ณ  ์žˆ์—ˆ๋‹ค. 1์ฐจ ์ปค๋„ฅ์…˜ ํ’€์˜ ์‚ฌ์ด์ฆˆ๋Š” 15๊ฐœ๋กœ ๋‹ค์†Œ ํ•œ์ •์ ์ธ ์ƒํ™ฉ์ด์—ˆ๋‹ค.

๋ธ”๋กœ๊ทธ ๋ฐฑ์—”๋“œ ์„œ๋ฒ„๊ฐ€ ์•ž์„œ ๊ฐ€์ ธ์˜จ ์ปค๋„ฅ์…˜์„ ์„œ๋ฒ„ ๋‚ด๋ถ€์— ๋ณด๊ด€ํ•˜๋Š” 2์ฐจ์ ์ธ ์ปค๋„ฅ์…˜ ํ’€์„ ์ƒ์„ฑํ•˜๋„๋ก ๊ตฌํ˜„๋˜์—ˆ๋Š”๋ฐ, pool size๋Š” 5๊ฐœ๋กœ ์ ์—ˆ์ง€๋งŒ ์ปค๋„ฅ์…˜ ์ ์œ  ํ›„ ๋ฐ˜ํ™˜ ์ „ ๋Œ€๊ธฐ ์‹œ๊ฐ„์ด 10๋ถ„์œผ๋กœ ๊ณผ๋„ํ•˜๊ฒŒ ๊ธธ์—ˆ๋‹ค.

ํ•œํŽธ, 2์ฐจ ์ปค๋„ฅ์…˜ ํ’€์€ ๊ฐ ์„œ๋ฒ„ ๋‚ด๋ถ€์—์„œ๋งŒ ์‚ฌ์šฉ๋˜๋ฉฐ, ๋‹ค๋ฅธ ์„œ๋ฒ„์™€ ๊ณต์œ ๋˜์ง€ ์•Š๊ณ  ์žˆ๋‹ค.

์ด๋Ÿฌํ•œ 2์ฐจ ์ปค๋„ฅ์…˜ ํ’€ ์ƒ์„ฑ์œผ๋กœ ์ธํ•ด Supabase ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ปค๋„ฅ์…˜ ์ž์›์ด ์™„์ „ํžˆ ์†Œ๋ชจ๋˜์—ˆ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ 2์ฐจ ์ปค๋„ฅ์…˜ ํ’€์—์„œ๋Š” ํ•œ ๋ฒˆ ์ ์œ ํ•ด์˜จ ์ปค๋„ฅ์…˜์„ ์ฆ‰์‹œ ๋ฐ˜ํ™˜ํ•˜์ง€ ์•Š์•˜๊ธฐ์—, 1์ฐจ ์ปค๋„ฅ์…˜ ํ’€์˜ ์ž์› ๊ณ ๊ฐˆ ์ƒํƒœ๊ฐ€ ์ผ์ • ์‹œ๊ฐ„ ์œ ์ง€๋˜์—ˆ๋‹ค.

์ž์› ๊ณ ๊ฐˆ ์ƒํƒœ์—์„œ ์ปค๋„ฅ์…˜์„ ์‹œ๋„ํ•œ ์„œ๋ฒ„ ํ”„๋กœ์„ธ์Šค๋Š” ์ „๋ถ€ ๊ฐ•์ œ ์ข…๋ฃŒ๋˜๋Š” ๊ฒฐ๊ณผ๋ฅผ ๋‚ณ์•˜๊ณ , ์ด๋Š” ์„œ๋ฒ„ ์‹œ์Šคํ…œ์˜ ์ „์ฒด์ ์ธ ์‘๋‹ต ๊ฑฐ๋ถ€๋กœ ์ด์–ด์กŒ๋‹ค.

๊ฐœ์„  ๋ฐฉ์•ˆ

์ผ๋‹จ 1์ฐจ ์ปค๋„ฅ์…˜ ํ’€ ์ •์ฑ…์„ ์ตœ๋Œ€ ์ˆ˜์ค€์œผ๋กœ ๋Š˜๋ ธ๋‹ค. Supabase ๋ฌด๋ฃŒ ํ”Œ๋žœ์—์„œ๋Š” pool size๋ฅผ 48๊ฐœ๊นŒ์ง€ ๋Š˜๋ฆด ์ˆ˜ ์žˆ๊ธฐ์— ๋ฐ”๋กœ ์ ์šฉํ•˜์˜€๋‹ค.

๊ทธ๋ฆฌ๊ณ  2์ฐจ ์ปค๋„ฅ์…˜ ํ’€ ์ •์ฑ…์„ ์ตœ์†Œ ์ˆ˜์ค€์œผ๋กœ ์ค„์˜€๋‹ค. ์„œ๋ฒ„ ๋‚ด ์ปค๋„ฅ์…˜ ํ’€ ๊ด€๋ฆฌ ์ •์ฑ…์„ ์†๋ณด์•˜๋‹ค13.

let pg_pool = PgPoolOptions::new()
     .max_connections(1)
     .acquire_timeout(Duration::from_secs(3))
     .idle_timeout(Duration::from_secs(3))
     .connect(&db_connection_str)
     .await
     .expect("can't connect to database");

์˜๋ฏธ๋Š” ์•„๋ž˜์™€ ๊ฐ™๋‹ค.

  • ํ•œ ์„œ๋ฒ„์—์„œ ๋™์‹œ์— ์ ์œ  ๊ฐ€๋Šฅํ•œ ์ตœ๋Œ€ ์ปค๋„ฅ์…˜ ๊ฐœ์ˆ˜๋Š” 1๊ฐœ.
  • ํ•œ ๋ฒˆ ์ ์œ ํ•ด์˜จ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ปค๋„ฅ์…˜์€ ์‚ฌ์šฉ์—ฌ๋ถ€๋ฅผ ์ฒดํฌํ•˜์—ฌ 3์ดˆ ๋’ค์— ์ž๋™์œผ๋กœ ๋ฐ˜ํ™˜.

2์ฐจ ์ปค๋„ฅ์…˜ ํ’€์„ ์ตœ์†Œํ•œ์œผ๋กœ ์œ ์ง€ํ•˜์—ฌ ์„œ๋ฒ„ ๋‚ด ์ปค๋„ฅ์…˜ ์žฌํ™œ์šฉ์„ ๊ฐ€๋Šฅ์ผ€ ํ•˜๋Š” ๋™์‹œ์—, ๋„ˆ๋ฌด ์˜ค๋ž˜ ์ปค๋„ฅ์…˜์„ ์ ์œ ํ•˜์ง€ ์•Š๊ฒŒ ์ˆ˜์ •ํ•˜์—ฌ 1์ฐจ ์ปค๋„ฅ์…˜ ํ’€์ด ํ•ญ์ƒ ์—ฌ์œ ๋กญ๋„๋ก ๊ฐœ์„ ํ•˜์˜€๋‹ค. ๋™์‹œ์— 1์ฐจ ์ปค๋„ฅ์…˜ ํ’€์˜ ํฌ๊ธฐ๋ฅผ ํ‚ค์›Œ ๋งŽ์€ ์–‘์˜ ์ปค๋„ฅ์…˜์„ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜์˜€๋‹ค.

๊ฐœ์„ ์•ˆ ๊ฒ€์ฆ

์‚ฌ์ง„: ๋ถ€ํ•˜ ํ…Œ์ŠคํŒ… ์„œ๋น„์Šค 'loadster'๋กœ ์ด ๋ธ”๋กœ๊ทธ์— ๋ถ€ํ•˜ ํ…Œ์ŠคํŠธ๋ฅผ ์ง„ํ–‰ํ•˜์˜€๋‹ค.

์‚ฌ์ง„: ๋ถ€ํ•˜ ํ…Œ์ŠคํŠธ๊ฐ€ ์ด๋ฃจ์–ด์ง„ ํ›„ AWS Lambda ๋Œ€์‹œ๋ณด๋“œ๋ฅผ ํ†ตํ•ด ํ™•์ธํ•œ ๋งคํŠธ๋ฆญ.

๊ฐœ์„ ์ ์„ ์ „๋ถ€ ์ ์šฉํ•œ ํ›„ ์ผ๋ถ€๋Ÿฌ ๋” ๊ทน์‹ฌํ•œ ํŠธ๋ž˜ํ”ฝ์„ ์„ค์ •ํ•˜๊ณ  ๋ถ€ํ•˜ ํ…Œ์ŠคํŠธ๋ฅผ ์ง„ํ–‰ํ•˜์˜€๋‹ค.

๋ถ€ํ•˜ ํ…Œ์ŠคํŠธ๋Š” 3๋ถ„ ๋‚ด์™ธ ์‹œ๊ฐ„๋™์•ˆ ์ง„ํ–‰๋˜์—ˆ์œผ๋ฉฐ, ๋ถ€ํ•˜์˜ ์ •์ ์„ ์ฐ์—ˆ์„ ๋•Œ์—๋Š” 1๋ถ„๊ฐ„ ์•ฝ 40,500ํšŒ ์ •๋„์˜ ์š”์ฒญ์ด ์„œ๋ฒ„์— ์ „์†ก๋˜์—ˆ๋‹ค.

๊ฐœ์„ ์•ˆ ๊ฒ€์ฆ ๊ฒฐ๊ณผ

Amazon CloudWatch์— ๊ธฐ๋ก๋œ ์„œ๋ฒ„ ๋กœ๊ทธ๋ฅผ ์ง‘๊ณ„ํ•œ ๊ฒฐ๊ณผ, 107,705ํšŒ์˜ ์ „์ฒด ์š”์ฒญ ์ค‘ ์‘๋‹ต ๊ฑฐ๋ถ€ ์‚ฌ๋ก€๊ฐ€ ์ด 40ํšŒ ๋ฐœ๊ฒฌ๋˜์—ˆ๋‹ค.

์ตœ์†Œ ์„œ๋น„์Šค ๊ฐ€์šฉ์„ฑ์„ ์ˆ˜์น˜ํ™”ํ•ด๋ณธ ๊ฒฐ๊ณผ๊ฐ€ ์žฌ๋ฏธ์žˆ๋‹ค.

  • ๊ธฐ์กด: 51% (1๋ถ„๋‹น ์•ฝ 400ํšŒ ์š”์ฒญ์‹œ)
  • ํ˜„์žฌ: 99.9996286% (1๋ถ„๋‹น ์•ฝ 40,500ํšŒ ์š”์ฒญ์‹œ)

๊ฒฐ๋ก 

๋ธ”๋กœ๊ทธ์—์„œ ๋ฐœ์ƒํ–ˆ๋˜ ์ ‘์† ๋ถˆ๋Šฅ ์žฅ์•  ์›์ธ์„ ์„ฑ๊ณต์ ์œผ๋กœ ํŒŒ์•…ํ•˜์˜€๊ณ , ์žฅ์•  ๋ฐœ์ƒ๋ฅ ์„ "์‚ฌ์‹ค์ƒ ๊ทน๋ณตํ–ˆ๋‹ค"๊ณ  ๋ณผ ์ˆ˜ ์žˆ๋Š” ์ˆ˜์ค€๊นŒ์ง€ ๋‚ฎ์ถœ ์ˆ˜ ์žˆ์—ˆ๋‹ค. ๋‹คํ–‰ํžˆ๋„ ๋น„์šฉ ๋ถ€๋‹ด์ด ๋ณ„๋„๋กœ ๋ฐœ์ƒํ•˜๊ฑฐ๋‚˜ ์ถ”๊ฐ€๋˜์ง€ ์•Š์•˜์œผ๋ฉฐ, ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋ฅผ ๋‹ค๋ฃจ๋Š” ํ˜„ํ–‰ ๊ตฌ์กฐ๋ฅผ ํฌ๊ฒŒ ๋ฐ”๊พธ์ง€ ์•Š์„ ์ˆ˜ ์žˆ์—ˆ๋‹ค.

์†Œ๊ฐ

๊ฒฐ๋ก ์ ์œผ๋กœ๋Š”, ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ์–ด๋–ค ๊ธฐ๋ณธ๊ฐ’์„ ๊ฐ€์ง€๊ณ  ๊ตฌ์„ฑ๋˜๋Š”์ง€12 ํ™•์ธํ•˜์˜€๋‹ค๋ฉด ๋ง‰์„ ์ˆ˜ ์žˆ์—ˆ์„ ๊ฒƒ ๊ฐ™์•„์„œ, ํ™•์ธ์ด ๋ˆ„๋ฝ๋œ ๋ถ€๋ถ„์ด ์•„์‰ฝ๊ฒŒ ๋А๊ปด์ง„๋‹ค. ๊ทธ๋ฆฌ๊ณ , ์‚ฌ์ „ ๋ถ€ํ•˜ ํ…Œ์ŠคํŠธ์˜ ์ค‘์š”์„ฑ์„ ๋‹ค์‹œ๋” ๋А๊ฒผ๋‹ค.

์ด๋ฒˆ ์žฅ์• ๊ฐ€ ๋‚˜์—๊ฒŒ ์žˆ์–ด์„œ๋Š”, '์†Œ์Šค ์ฝ”๋“œ ์•ˆ์—์„œ๋Š” ๋ณด์ด์ง€ ์•Š๋Š” ๋ถ€๋ถ„๋“ค์„ ๊ฒ€์ฆํ•˜๋Š” ์ž‘์—…'์˜ ์ค‘์š”์„ฑ์„ ๋ป์ €๋ฆฌ๊ฒŒ ๋А๋ผ๋Š” ๊ณ„๊ธฐ๊ฐ€ ๋˜์—ˆ๋‹ค.

Footnotes

  1. Wikipedia - Service-level Agreement - Cloud Computing - "SLAs span across the cloud and are offered by service providers as a service-based agreements rather than a customer-based agreements. Measuring, monitoring and reporting on cloud performance is based on the end UX or their ability to consume resources." โ†ฉ

  2. https://blog.atj.sh/post/45 โ†ฉ

  3. GeekNews - ๊ทธ๋ƒฅ LLM์ด ์ฝ”๋“œ๋ฒ ์ด์Šค ์ „์ฒด๋ฅผ ์ดํ•ดํ•ด์ฃผ๋ฉด ์•ˆ ๋ ๊นŒ: ๋ฒˆ๋“ค๋ง์„ ํ†ตํ•œ RAG ์‹œ๋„ โ†ฉ

  4. ์ด์ฒ˜๋Ÿผ '๋” ํฐ ๊ทœ๋ชจ์˜ ์›น์‚ฌ์ดํŠธ๋กœ๋ถ€ํ„ฐ์˜ ํŠธ๋ž˜ํ”ฝ ์œ ์ž…์œผ๋กœ ์ธํ•œ ์„œ๋น„์Šค ์žฅ์• '์„ "์Šฌ๋ž˜์‹œ๋‹ท ํšจ๊ณผ"๋ผ ํ•œ๋‹ค. ์œ„ํ‚ค๋ฐฑ๊ณผ - ์Šฌ๋ž˜์‹œ๋‹ท ํšจ๊ณผ โ†ฉ

  5. ๋ธ”๋กœ๊ทธ ์ „์ฒด์— ๋Œ€ํ•œ ํ…Œํฌ ์Šคํƒ์€ ๋‹ค๋ฅธ ๊ธ€์— ์ •๋ฆฌํ•ด ๋‘์—ˆ๋‹ค. ์ „์„ฑํ›ˆ์˜ ๋ธ”๋กœ๊ทธ - blog.atj.sh โ†ฉ

  6. ์ „์„ฑํ›ˆ์˜ ๋ธ”๋กœ๊ทธ - PostgreSQL๋ฅผ ์ด๋ฏธ์ง€ ์ €์žฅ์†Œ๋กœ ํ™œ์šฉํ•˜๊ธฐ โ†ฉ

  7. ๋™์‹œ์— ์‹คํ–‰๋œ AWS Lambda ํ•จ์ˆ˜ ๊ฐœ์ˆ˜๋ฅผ ์˜๋ฏธํ•œ๋‹ค. Amazon AWS Documentation - Understanding Lambda function scaling โ†ฉ

  8. ์„œ๋น„์Šค ๋ชจ๋‹ˆํ„ฐ๋ง์„ ์œ„ํ•ด Amazon Cloudwatch๋กœ ๋กœ๊ทธ๋ฅผ ์ˆ˜์ง‘ํ•˜๊ณ  ์žˆ์—ˆ๋‹ค. โ†ฉ

  9. launchbadge/sqlx/README.md - "When using the high-level query API (sqlx::query), statements are prepared and cached per connection." โ†ฉ

  10. Supabase Database Documentation - Connect to your database - Supavisor transaction mode - "Transaction mode does not support prepared statements. To avoid errors, turn off prepared statements for your connection library." โ†ฉ

  11. Supabase Database Documentation - Connection management โ†ฉ

  12. sqlx์˜ ์ปค๋„ฅ์…˜ ํ’€ ์ƒ์„ฑ ์˜ต์…˜์˜ ๊ธฐ๋ณธ๊ฐ’๋“ค์€ launchbadge/sqlx - PoolOptions::new()์—์„œ ํ™•์ธํ•ด๋ณผ ์ˆ˜ ์žˆ๋‹ค. โ†ฉ โ†ฉ2

  13. https://github.com/atjsh/rust-blog/commit/a757834af7d9204684ae5a865922e9eb5d3659c5 โ†ฉ