FastAPI ๋ฐฑ์๋ ์ต์ ํ: Supabase์์ ๋ก์ปฌ PostgreSQL๋ก DB ๋ง์ด๊ทธ๋ ์ด์ ๋ฐ ํธ๋ฌ๋ธ์ํ (asyncpg, 524 ์๋ฌ) ๊ฒฝํ๊ธฐ
์ต๊ทผ ์ ๋ ํ์ด์ฌ(FastAPI)๊ณผ SQLAlchemy๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ํ ์ปค๋ฎค๋ํฐ ํ๋ซํผ์ ๊ฐ๋ฐํ๋ฉฐ, ๋น ๋ฅด๊ณ ํธ๋ฆฌํ ํด๋ผ์ฐ๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ธ ์ํ๋ฒ ์ด์ค(Supabase)๋ฅผ ์ ๊ทน์ ์ผ๋ก ํ์ฉํ๊ณ ์์์ต๋๋ค. ์ด๊ธฐ์๋ ํด๋ผ์ฐ๋์ ํธ๋ฆฌํจ์ ๊ฐํํ๋ฉฐ ๋ง์กฑ์ค๋ฝ๊ฒ ์ฌ์ฉํ์ง๋ง, ์๋น์ค์ '์๋ํ ํฌ์คํ ๋ด' ๋ก์ง์ ์ฐ๋ํ๋ฉด์ ์ฌ๊ฐํ ๋ฒฝ์ ๋ถ๋ชํ๊ธฐ ์์ํ์ต๋๋ค.
์์ญ ๊ฐ์ ๊ฒ์๊ธ๊ณผ ์ธ๋ค์ผ ์ด๋ฏธ์ง๋ฅผ ๋ฒ์ญ API์ ์ฐ๋ํ์ฌ 4~16๋ถ ๊ฐ๊ฒฉ์ผ๋ก ๊ณ์ํด์ ๋ฐ์ด ๋ฃ๋ค ๋ณด๋(๋ฒํฌ ์ธ์ํธ), ํด๋ผ์ฐ๋ DB ํน์ ์ Disk I/O ๋ณ๋ชฉ ํ์๊ณผ ์ปค๋ฅ์ ํ๊ณ(Connection Limit)๊ฐ ๋ฐ์ํ ๊ฒ์ ๋๋ค. ๊ธ์ด ์ฌ๋ผ๊ฐ๋ค ๋ง๊ณ ์๋ฒ๊ฐ ๋ป์ด๋ฒ๋ฆฌ๋ ํ์์ ๋ณด๋ฉฐ, ์ ๋ ์ค๋ํ ๊ฒฐ๋จ์ ๋ด๋ ธ์ต๋๋ค.
"์ธ๋ถ ๋คํธ์ํฌ๋ฅผ ํ๋ฉด์ ๋ฐ์ํ๋ ์ง์ฐ(Latency)์ ์์ ๊ณ , ๋ด ์๋ฒ ์์์ 100% ํ์ฉํ์."
์ฆ, ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ฅผ ํด๋ผ์ฐ๋์์ ๋ฐฑ์๋ ์๋ฒ๊ฐ ๊ตฌ๋ ์ค์ธ ๋ก์ปฌ ํ๊ฒฝ(๋ก์ปฌ PostgreSQL, localhost:5432)์ผ๋ก ๋ง์ด๊ทธ๋ ์ด์
ํ๋ ๋๋์ ์ธ ๊ณต์ฌ๋ฅผ ์์ํ์ต๋๋ค. ์ค๋์ ์ด ๊ณผ์ ์์ ์ ๊ฐ ๊ฒช์๋ ํผ๋๋ฌผ ๋๋ 3๊ฐ์ง ํธ๋ฌ๋ธ์ํ
๊ฒฝํ์ ๊ณต์ ํด๋ณด๋ ค ํฉ๋๋ค.
1. ์ฒซ ๋ฒ์งธ ์ฝ์ง: ํ๊ฒฝ๋ณ์(.env)๋ฅผ ๋ฐ๊ฟจ๋๋ฐ ์ ์ ์์ ๋ชป ํ๋? (Connection refused)
๊ฐ์ฅ ๋จผ์ ๊ฒช์ ํฉ๋นํ ๋ฌธ์ ๋ DB ์ฐ๊ฒฐ ์ค๋ฅ์์ต๋๋ค. ๋ก์ปฌ ์๋ฒ์ PostgreSQL์ ๋ฌด์ฌํ ์ค์นํ๊ณ , .env ํ์ผ์ DB ์ ์ URL ํฌํธ๋ฅผ ํด๋ผ์ฐ๋์ฉ ํฌํธ์์ ๋ก์ปฌ ๊ธฐ๋ณธ ํฌํธ์ธ 5432๋ก ๋ณ๊ฒฝํ์ต๋๋ค. ๊ทธ๋ฆฌ๊ณ ์๋ฒ๋ฅผ ์ฌ์์ํ๋๋ฐ... ํ๋ฉด์ ๋์ฐํ ์๋ฌ๊ฐ ์ถ๋ ฅ๋์์ต๋๋ค.
Connection refused: Cannot connect to port 6543
๋ถ๋ช
.env์๋ 5432๋ก ์ ์ด๋์๋๋ฐ, ์๋ฒ๋ ๊ณ์ํด์ ์๋ฑํ 6543 ํฌํธ๋ฅผ ์ฐพ์ผ๋ฉฐ ์ฐ๊ฒฐ์ ๊ฑฐ๋ถํ๊ณ ์์์ต๋๋ค. ์บ์๋ฅผ ์ง์๋ณด๊ณ ์ปจํ
์ด๋๋ฅผ ๊ป๋ค ์ผ๋ด๋ ์์ฉ์ด ์์์ต๋๋ค. ๋๋์ฒด ์ด๋์ ํฌํธ ๋ฒํธ๊ฐ ๊ผฌ์ธ ๊ฒ์ผ๊น์?
์ ๋ ๋ฆฌ๋
์ค ํฐ๋ฏธ๋์ ์ด๊ณ grep ๋ช
๋ น์ด๋ฅผ ๋นผ๋ค์์ต๋๋ค.
grep -rn "6543" . (ํ์ฌ ํด๋์ ํ์ ํด๋์์ 6543์ด๋ผ๋ ํ
์คํธ๋ฅผ ๋ชจ๋ ์ฐพ์๋ผ!)
๊ฒ์ ๊ฒฐ๊ณผ๋ ์ถฉ๊ฒฉ์ ์ด์์ต๋๋ค. ๊ณผ๊ฑฐ์ Supabase ์ธ๋ถ ์ปค๋ฅ์
ํ๋ง(Connection Pooling)์ ์ธํ
ํ ๋, database.py ํ์ผ ๊น์ํ ๊ณณ์ URL ๋ฌธ์์ด ์ค .replace(":5432/", ":6543/")์ ํตํด ๊ฐ์ ๋ก ํฌํธ๋ฅผ ๋ณํํด๋ฒ๋ฆฌ๋ ํ๋์ฝ๋ฉ ๋ก์ง์ ์ ๊ฐ ์ง์ ์ง๋๊ณ ๊น๋งฃ๊ฒ ์๊ณ ์์๋ ๊ฒ์
๋๋ค.
์ด ํ๋์ฝ๋ฉ๋ ์ค์ ์ฐพ์๋ด์ด ๊น๋ํ๊ฒ ์ญ์ ํ๊ณ ๋๋, ๊ทธ์ ์ผ FastAPI๊ฐ ๋ก์ปฌ DB(5432)์ ์ ์์ ์ผ๋ก ๋ฟ๋ฆฌ๋ฅผ ๋ด๋ฆฌ๊ธฐ ์์ํ์ต๋๋ค. ๊ณผ๊ฑฐ์ ์ ๊ฐ ๋ง๋ ํจ์ ์ ์ ๊ฐ ๋น ์ง ์
์ด์ฃ .

2. ๋ ๋ฒ์งธ ์ฝ์ง: ์ฑ๋ฅ์ ํ๊ณ ๋ํ, ๋น๋๊ธฐ ๋๋ผ์ด๋ฒ(asyncpg)๋ก์ ์ ํ
๋ก์ปฌ DB๋ก ์ฐ๊ฒฐ์ ์ฑ๊ณตํ์ง๋ง, ๋๋์ ํธ๋ํฝ์ ๊ฐ๋นํ๊ธฐ ์ํด ์ ๋ ๊ธฐ์กด์ ์ฌ์ฉํ๋ ๋๊ธฐ์ ๋๋ผ์ด๋ฒ์ธ psycopg ๋์ , ํ์ด์ฌ์์ ๊ฐ์ฅ ๋น ๋ฅธ ๋น๋๊ธฐ PostgreSQL ๋๋ผ์ด๋ฒ์ธ asyncpg๋ก ์์ง์ ๊ต์ฒดํ๊ธฐ๋ก ํ์ต๋๋ค.
ํ์ง๋ง ๋๋ผ์ด๋ฒ๋ฅผ ๋ฐ๊พธ์ ์ด๋ฒ์๋ SQLAlchemy ์ค์ ์์ ํธํ์ฑ ์๋ฌ๊ฐ ๋ฟ์ด์ ธ ๋์์ต๋๋ค. ๊ธฐ์กด ๋๊ธฐ์์์ ์ ์๋ํ๋ ์ปค๋ฅ์
ํ์์์์ด๋ ์๋ฒ ์ธํ
์ธ์๋ค์ด asyncpg ๊ท๊ฒฉ๊ณผ ๋ง์ง ์์๊ธฐ ๋๋ฌธ์
๋๋ค. ๊ณต์ ๋ฌธ์๋ฅผ ๋ค์ ธ๊ฐ๋ฉฐ database.py์ connect_args ์ค์ ์ ๋น๋๊ธฐ ๊ท๊ฒฉ์ ๋ง๊ฒ ํ๋ํ์ต๋๋ค.

์ด ํ๋์ ๊ฑฐ์น ํ, ๋น๋๊ธฐ ์ฒ๋ฆฌ์ ๋ง๋ฒ์ด ์์๋์์ต๋๋ค. ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ฅผ ๊ธฐ๋ค๋ฆฌ๋๋ผ ๋ฉ์ถฐ์๋ ๋ฐฑ์๋ ์ค๋ ๋๋ค์ด ์์ ๋กญ๊ฒ ํ๋ ค๋๋ฉด์, ์๋ฒ์ ๋์ ์ฒ๋ฆฌ ๋ฅ๋ ฅ์ด ์ฐจ์์ด ๋ค๋ฅด๊ฒ ์พ์ ํด์ก์ต๋๋ค.
3. ์ธ ๋ฒ์งธ ์ฝ์ง: ํด๋ผ์ฐ๋ํ๋ ์ด(Cloudflare) 524 ์๋ฌ์ ๋ช
๋ง์นจ๋ด ์ํคํ ์ฒ ์ธํ ์ ๋๋ด๊ณ , ๋ด์ ๊ฐ๋ํ์ฌ ์์ญ ๊ฐ์ ๊ฒ์๊ธ์ ํ ๋ฒ์ ๋ฒํฌ ์ธ์ํธ(Bulk Insert) ํ๋ ํ ์คํธ๋ฅผ ์งํํ์ต๋๋ค. ๊ทธ๋ฐ๋ฐ ์ ๋ก๋ ๋์ค ๊ฐ์๊ธฐ ์น ํ๋ฉด์ 'Cloudflare 524 A timeout occurred' ์๋ฌ๊ฐ ๋จ๋ฉด์ ์ค๋ณต ๊ฒ์๊ธ์ด ์ฌ๋ผ๊ฐ๋ ์น๋ช ์ ์ธ ๋ฒ๊ทธ๊ฐ ๋ฐ์ํ์ต๋๋ค.
์์ธ์ ๋ฐฑ์๋์ '์ฒ๋ฆฌ ์๊ฐ'์ด์์ต๋๋ค. ๋ฒํฌ ์ ๋ก๋๋ฅผ ํ ๋ ๋จ์ํ DB์ ํ ์คํธ๋ง ๋ฃ๋ ๊ฒ์ด ์๋๋ผ, ์ธ๋ถ ๋ฒ์ญ API๋ฅผ ํธ์ถํ๊ณ ์ด๋ฏธ์ง๋ฅผ ๋ฆฌ์ฌ์ด์งํ๋ ๋ฌด๊ฑฐ์ด ์์ ์ด ํฌํจ๋์ด ์์์ต๋๋ค. ์ด ์์ ์ด 100์ด๋ฅผ ๋์ด๊ฐ์, ์๋ฒ ์๋จ์ ์งํค๊ณ ์๋ ํด๋ผ์ฐ๋ํ๋ ์ด๊ฐ "์๋ฒ๊ฐ ์ฃฝ์ ๊ฒ ๊ฐ์ผ๋ ์ฐ๊ฒฐ์ ๋๊ฒ ๋ค"๋ผ๋ฉฐ 100์ด ํ์์์(524 ์๋ฌ)์ ๋ฐ์์ํจ ๊ฒ์ ๋๋ค.
์๋ฒ๋ ๋ค์์ ๊ณ์ ๊ธ์ ์ฐ๊ณ ์๋๋ฐ ํ๋ก ํธ์๋ ์ฐ๊ฒฐ๋ง ๋๊ธฐ๋, ๋ด์ "์ ๋ก๋ ์คํจ์ธ๊ฐ?" ํ๊ณ ๊ธ์ ๋๋ค์ ์ ์กํ์ฌ ์ค๋ณต ํฌ์คํ ์ด ์ผ์ด๋ ๊ฒ์ด์์ฃ . ์ด๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํ ์ํคํ ์ฒ ์ต์ ํ๋ ์์ธ๋ก ๊ฐ๋จํ์ต๋๋ค.
์๋ํ ์คํฌ๋ฆฝํธ๊ฐ ํ ๋ฒ์ ์ ์กํ๋ ์ฒญํฌ ์ฌ์ด์ฆ(Chunk Size, ์ ์ก ๋จ์)๋ฅผ ๊ธฐ์กด 20๊ฐ์์ 5๊ฐ๋ก ๋ํญ ์ค์์ต๋๋ค. ํ ๋ฒ์ 5๊ฐ์ฉ๋ง ๋ฒ์ญํ๊ณ DB์ ๋ฐ์ด ๋ฃ๋๋ก ์ชผ๊ฐ์ด ์ฒ๋ฆฌํ๋, API ์๋ต ์๊ฐ์ด 20์ด ์ด๋ด๋ก ๋จ์ถ๋์ด ํด๋ผ์ฐ๋ํ๋ ์ด์ 100์ด ํ์์์ ์ฅ๋ฒฝ์ ์๋ฒฝํ๊ฒ ํผํด ๊ฐ ์ ์์์ต๋๋ค.
๋งบ์ผ๋ฉฐ: ๋ก์ปฌ DB ํ๊ท๊ฐ ๊ฐ์ ธ์จ ์์ฒญ๋ ๊ฒฐ์ค
๊ธธ๊ณ ํ๋ํ๋ ํธ๋ฌ๋ธ์ํ
์ ๋ง์น๊ณ ๋๋, ๊ฒฐ๊ณผ๋ ์์ ์ด์์ด์์ต๋๋ค. ๋ฐ์ดํฐ๋ฒ ์ด์ค๊ฐ ์ธ๋ถ ๋คํธ์ํฌ๋ฅผ ํ์ง ์๊ณ ๋ก์ปฌ(localhost) ๋ด๋ถ์์ ์ฆ๊ฐ์ ์ผ๋ก ํต์ ํ๊ฒ ๋๋ฉด์ DB ์๋ต ์๋๊ฐ ๋น์ฝ์ ์ผ๋ก ์์นํ์ต๋๋ค.
๋ฌด์๋ณด๋ค ์์ญ ๊ฐ์ ๊ฒ์๊ธ๊ณผ ์ธ๋ค์ผ ๋ฏธ๋์ด๋ฅผ ๋ค๋ฃจ๊ณ , 4~16๋ถ ๊ฐ๊ฒฉ์ผ๋ก ์์ฝ ๋ฐํํ๋ ์์ฃผ ๋ฌด๊ฑฐ์ด ์๋ํ ๋ด ๋ก์ง์ 3๊ฐ ์ด์ ๋์์ ๋๋ ค๋ ์๋ฒ ์์(CPU, RAM)์ด ๋๋ํ๊ฒ ์ ์ง๋์์ต๋๋ค. ์ธ๋ถ ํด๋ผ์ฐ๋ DB์ ์ปค๋ฅ์ ํ๊ณ์ ๋ฒ๋ฒ ๋จ๋ ๊ณผ๊ฑฐ์๋ ์๋ฒฝํ๊ฒ ์๋ณํ ๊ฒ์ ๋๋ค.
ํด๋ผ์ฐ๋๊ฐ ๋ฌด์กฐ๊ฑด ์ ๋ต์ ์๋๋๋ค. ํ์ฌ ์๋น์ค์ ํธ๋ํฝ ํจํด๊ณผ ์๋ํ ๋ก์ง์ ์ฑ๊ฒฉ์ ๋ฐ๋ผ, ๋๋ก๋ ์ด๋ ๊ฒ ์จํ๋ ๋ฏธ์ค(๋ก์ปฌ) ํ๊ฒฝ์ผ๋ก ๋ฌต์งํ๊ฒ ์์คํ ์ ์ฎ๊ธฐ๋ ๊ฒ์ด ์ต๊ณ ์ ์ํคํ ์ฒ๊ฐ ๋ ์ ์์์ ๋ผ์ ๋ฆฌ๊ฒ ๋ฐฐ์ด ์์คํ ๊ฒฝํ์ด์์ต๋๋ค.
โ ์์ฃผ ๋ฌป๋ ์ง๋ฌธ (FAQ)
Q1. Supabase(ํด๋ผ์ฐ๋)์์ ๋ก์ปฌ DB๋ก ์ด์ ํ๋ฉด ๋ฐฑ์ ์ ์ด๋ป๊ฒ ํ๋์?
A. ๋ก์ปฌ DB์ ๊ฐ์ฅ ํฐ ๋จ์ ์ ๋ฐฑ์
์ ์ง์ ํด์ผ ํ๋ค๋ ๊ฒ์
๋๋ค. ์ ๋ ๋ฆฌ๋
์ค cron ํญ๊ณผ pg_dump ๋ช
๋ น์ด๋ฅผ ํ์ฉํ์ฌ ๋งค์ผ ์๋ฒฝ 3์์ ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ฅผ ๋คํ(๋ฐฑ์
)ํ๊ณ , ๊ทธ ํ์ผ์ AWS S3๋ ๋ณ๋์ ์ธ๋ถ ์คํ ๋ฆฌ์ง๋ก ์๋ ์ ์กํ๋๋ก ์คํฌ๋ฆฝํธ๋ฅผ ์์ฑํ์ฌ ์์ ํ๊ฒ ๋ณด๊ดํ๊ณ ์์ต๋๋ค.
Q2. Cloudflare 524 ์๋ฌ๋ฅผ ๋ง๊ธฐ ์ํด ํด๋ผ์ฐ๋ํ๋ ์ด ์ค์ ์ ๋๋ฆด ์๋ ์๋์?
A. ๋ฌด๋ฃ ํ๋(Free)์ด๋ ํ๋ก ํ๋ ์ฌ์ฉ์ ๊ธฐ์ค, ํด๋ผ์ฐ๋ํ๋ ์ด์ 100์ด ํ์์์(524)์ ํ๋ ๋ฆฌ๋ฐ(Hard Limit)์ผ๋ก ์ค์ ๋์ด ์์ด ์ฌ์ฉ์๊ฐ ์์๋ก ๋๋ฆด ์ ์์ต๋๋ค. ์ํฐํ๋ผ์ด์ฆ(Enterprise) ์๊ธ์ ์์๋ง ์กฐ์ ์ด ๊ฐ๋ฅํ๋ฏ๋ก, ๋ฐฑ์๋ ๋ก์ง ์์ฒด๋ฅผ 100์ด ์ด๋ด๋ก ์๋ตํ๋๋ก ์ชผ๊ฐ๋ ๊ฒ(Chunking)์ด ์ ์ผํ๊ณ ์ฌ๋ฐ๋ฅธ ํด๊ฒฐ์ฑ ์ ๋๋ค.
Q3. ๋น๋๊ธฐ asyncpg ๋๋ผ์ด๋ฒ๋ฅผ ์ฐ๋ฉด ๋ฌด์กฐ๊ฑด ๋นจ๋ผ์ง๋์?
A. I/O ๋ฐ์ด๋ ์์
(DB๋ฅผ ์ฐ๋ฌ๋๊ณ ๊ธฐ๋ค๋ฆฌ๋ ์๊ฐ)์ด ๋ง์ ์น ์๋ฒ๋ผ๋ฉด ๋์์ฑ ์ฒ๋ฆฌ๊ฐ ์ข์์ ธ์ ๊ทน์ ์ธ ์ฑ๋ฅ ํฅ์์ ๋ณผ ์ ์์ต๋๋ค. ํ์ง๋ง, ํ์ด์ฌ ์ฝ๋ ์ ์ฒด๊ฐ async/await ๊ตฌ์กฐ๋ก ์๋ฒฝํ๊ฒ ์ง์ฌ ์์ง ์๊ณ ์ค๊ฐ์ ๋ธ๋กํน(Blocking) ์ฝ๋๊ฐ ์์ฌ ์๋ค๋ฉด ์คํ๋ ค ์ฑ๋ฅ์ด ์ ํ๋ ์ ์์ผ๋ ๋์
์ ์ํคํ
์ฒ ์ ๊ฒ์ด ํ์์ ์
๋๋ค.
๐ฌ ๋๊ธ 0๊ฐ