ํ์ด์ฌ FastAPI ์๋ฒ ์์กด๊ธฐ: Redis๋ฅผ ํ์ฉํ API Rate Limiting(์๋ ์ ํ) ๊ตฌํ๊ณผ ํธ๋ํฝ ๋ฐฉ์ด ์๊ณ ๋ฆฌ์ฆ
์น์ฌ์ดํธ๋ฅผ ์ด์ํ๋ฉฐ ๋ฐฉ๋ฌธ์๊ฐ ๋์ด๋๋ ๊ฒ์ ๋ถ๋ช ๊ฐ์ด ๋ฒ ์ฐฌ ์ผ์ ๋๋ค. ํ์ง๋ง ํธ๋ํฝ์ด ์ฆ๊ฐํ ์๋ก ํ์ฐ์ ์ผ๋ก ๋ถ์ฒญ๊ฐ๋ ํจ๊ป ๋์ด๋๊ธฐ ๋ง๋ จ์ ๋๋ค. ์ด๋ ๋ ์๋ฒฝ, ํ์จํ๊ฒ ๋์๊ฐ๋ ์๋ฒ์ CPU ์ ์ ์จ์ด ๊ฐ์๊ธฐ ์น์๋ ์๋์ ๋ฐ๊ณ ํฉ๊ธํ ์ ์ํ ์ ์ด ์์ต๋๋ค. ํ์ธํด ๋ณด๋ ํน์ ํด์ธ IP ๋ช ๊ฐ๊ฐ ์ ํฌ ์ปค๋ฎค๋ํฐ์ '๋ก๊ทธ์ธ' ๋ฐ 'ํ์๊ฐ์ ' ์๋ํฌ์ธํธ(API)๋ฅผ 1์ด์ ์์ญ ๋ฒ์ฉ ๋ฌด์ฐจ๋ณ์ ์ผ๋ก ์ฐ๋ฅด๊ณ (Brute-force) ์์์ต๋๋ค.
ํด๋ผ์ฐ๋ํ๋ ์ด(Cloudflare) ๊ฐ์ ์๋จ์ ์น ๋ฐฉํ๋ฒฝ(WAF)์ผ๋ก 1์ฐจ์ ์ธ ๋ด ์ฐจ๋จ์ ํ๊ณ ์์์ง๋ง, ์ ์์ ์ธ ๋ธ๋ผ์ฐ์ ๋ก ์์ฅํ์ฌ ๋ค์ด์ค๋ ์ ์์ ์ธ ์์ฒญ๊น์ง 100% ๊ฑธ๋ฌ๋ด๊ธฐ๋ ์ด๋ ค์ ์ต๋๋ค. ๋ง์ฝ ์ด๋๋ก ๋ฐฉ์นํ๋ค๋ฉด ๋ฐฑ์๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค(DB) ์ปค๋ฅ์ ์ด ๊ณ ๊ฐ๋์ด, ์ ์ ์ฌ์ดํธ๋ฅผ ์ด์ฉํ๋ ค๋ ์ง์ง ํ์๋ถ๋ค์ด ์ ์ํ์ง ๋ชปํ๋ ์ต์ ์ '์๋น์ค ์ฅ์ '๋ก ์ด์ด์ง ์ ์๋ ์์ฐํ ์ํฉ์ด์์ต๋๋ค.
๊ทธ๋์ ์ ๋ ์๋ฒ์ ๊ฐ์ฅ ๊น์ํ ๊ณณ, ๋ฐฑ์๋ ์ ํ๋ฆฌ์ผ์ด์ ๋จ์ ์ง์ 'API Rate Limiting(์๋ ์ ํ)'์ด๋ผ๋ ๊ฐ๋ ฅํ ๋ฐฉํจ๋ฅผ ๊ตฌ์ถํ๊ธฐ๋ก ๊ฒฐ์ฌํ์ต๋๋ค. ์ค๋์ 1์ธ ๊ฐ๋ฐ์๊ฐ ํ์ด์ฌ(Python) FastAPI ํ๊ฒฝ์์ ์ด๋ป๊ฒ ํธ๋ํฝ ํญ์ฃผ๋ฅผ ์ฐ์ํ๊ฒ ํต์ ํ๋์ง, ๊ทธ ์ํคํ ์ฒ์ ๊ณ ๋ฏผ์ ๊ณผ์ ์ ๋๋์ด ๋ณด๋ ค ํฉ๋๋ค.
1. ํธ๋ํฝ ํญํ์ ๊ณตํฌ: ์ ์ ํ๋ฆฌ์ผ์ด์ ๋ ๋ฒจ์ ์๋ ์ ํ์ด ํ์์ผ๊น?
๋ณดํต ํธ๋ํฝ ๋ฐฉ์ด๋ผ๊ณ ํ๋ฉด ์ธํ๋ผ ๋จ๊ณ(AWS, Cloudflare ๋ฑ)์์ ํด๊ฒฐํด์ผ ํ๋ค๊ณ ์๊ฐํ๊ธฐ ์ฝ์ต๋๋ค. ํ์ง๋ง ๋ฐฑ์๋ ์๋ฒ(FastAPI) ๋ด๋ถ์๋ ๋ฐ๋์ ๋ธ๋ ์ดํฌ๊ฐ ํ์ํฉ๋๋ค.
์๋ฅผ ๋ค์ด, ๋๊ตฐ๊ฐ ๊ฒ์ํ์ 1์ด ๋ง์ 100๊ฐ์ '์๋ฏธ ์๋ ๋๋ฐฐ ๊ธ'์ ์์ฑํ๋ ์คํฌ๋ฆฝํธ๋ฅผ ๋๋ ธ๋ค๊ณ ๊ฐ์ ํด ๋ณด๊ฒ ์ต๋๋ค. ์ด ์์ฒญ๋ค์ ๋ฌธ๋ฒ์ ์ผ๋ก ์๋ฒฝํ ํํ๋ฅผ ๋ ๊ณ ์์ผ๋ฏ๋ก ์ธ๋ถ ๋ฐฉํ๋ฒฝ์ ์ด๋ฅผ ์ ์์ ์ธ ์ฌ์ฉ์๋ก ์ฐฉ๊ฐํ๊ณ ํต๊ณผ์ํต๋๋ค. ๊ฒฐ๊ตญ ์ด 100๊ฐ์ ๋ฐ์ดํฐ๋ ๊ณ ์ค๋ํ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ๊ฝํ๊ฒ ๋๊ณ , ์๋ฒ ์ฉ๋๊ณผ ํธ๋ํฝ ๋น์ฉ์ ๋ฌด์๋ฏธํ๊ฒ ๊ฐ์๋จน๊ฒ ๋ฉ๋๋ค.
๋ฐ๋ผ์ ์๋ฒ๋ "๋์ผํ ์ฌ์ฉ์(IP ๋๋ ๊ณ์ )๊ฐ 1๋ถ์ 5๋ฒ๊น์ง๋ง ๊ธ์ ์ธ ์ ์๋ค"๋ผ๋ ๋ช ํํ ๊ท์น์ ๊ฐ์ง๊ณ ์์ด์ผ ํฉ๋๋ค. ์ด ๊ท์น์ ๋์ด์๋ ์์ฒญ์ด ๋ค์ด์ค๋ฉด ์๋ฒ๋ ์ฆ์ ๋ฌธ์ ๋ซ๊ณ , "๋๋ฌด ๋น ๋ฅธ ์์ฒญ์ ๋๋ค. ์ ์ ํ ๋ค์ ์๋ํด ์ฃผ์ธ์"๋ผ๋ ๋ฉ์์ง๋ฅผ ๋ฐํํด์ผ ํฉ๋๋ค. ์ด๊ฒ์ด ๋ฐ๋ก Rate Limiting์ ํต์ฌ ๋ชฉ์ ์ ๋๋ค.
2. FastAPI์ Redis์ ํ์์ ์ธ ์ฝ๋ผ๋ณด๋ ์ด์
ํ์ด์ฌ ์น ํ๋ ์์ํฌ์ธ FastAPI์์ ์๋ ์ ํ์ ๊ตฌํํ๋ ๋ฐฉ๋ฒ์ ์ฌ๋ฌ ๊ฐ์ง๊ฐ ์์ต๋๋ค. ๊ฐ์ฅ ์ฌ์ด ๋ฐฉ๋ฒ์ ํ์ด์ฌ ๋ด๋ถ ๋ฉ๋ชจ๋ฆฌ๋ ๊ด๊ณํ ๋ฐ์ดํฐ๋ฒ ์ด์ค(RDBMS)์ ์ ์ ๊ธฐ๋ก์ ์ ์ฅํ๋ ๊ฒ์ ๋๋ค.
ํ์ง๋ง ์ ๋ ์ด์ ์ฑ๋ฅ ์ต์ ํ ์์ ๋ ๋์ ํ๋ Redis(๋ ๋์ค)๋ฅผ ์๋ ์ ํ์ ์ ์ฅ์๋ก ์ ๊ทน ํ์ฉํ๊ธฐ๋ก ํ์ต๋๋ค. ๊ด๊ณํ DB(PostgreSQL, MySQL ๋ฑ)๋ ๋ฌด๊ฑฐ์ด ๋์คํฌ I/O๋ฅผ ๋ฐ์์ํค๊ธฐ ๋๋ฌธ์, 1์ด์๋ ์์ญ ๋ฒ์ฉ "์ด IP๊ฐ ๋ช ๋ฒ ์ ์ํ์ง?"๋ฅผ ๋ฌป๊ณ ์ ๋ฐ์ดํธํ๋ ์์ ์๋ ์ ํ ์ ํฉํ์ง ์์ต๋๋ค. ๋ฐ๋ฉด, ์ธ๋ฉ๋ชจ๋ฆฌ(In-Memory) ๊ธฐ๋ฐ์ธ Redis๋ ๋น์ฒ๋ผ ๋น ๋ฅธ ์๋๋ก ๋ฐ์ดํฐ๋ฅผ ์ฝ๊ณ ์ฐ๋ฉฐ, ์ฌ์ง์ด ๋ฐ์ดํฐ์ ๋ง๋ฃ ์๊ฐ(TTL: Time To Live)์ ์์ฒด์ ์ผ๋ก ๊ด๋ฆฌํด ์ฃผ๋ ๊ธฐ๋ฅ๊น์ง ๊ฐ์ถ๊ณ ์์ด ์๋ ์ ํ ์์คํ ์ ๊ทธ์ผ๋ง๋ก ์ฐฐ๋ก๊ถํฉ์ด์์ต๋๋ค.
3. ๊ณ ์ ์๋์ฐ(Fixed Window) ์๊ณ ๋ฆฌ์ฆ์ผ๋ก ํจ์จ์ฑ ์ก๊ธฐ
Rate Limiting์ ๊ตฌํํ๋ ์๊ณ ๋ฆฌ์ฆ์๋ 'ํ ํฐ ๋ฒํท(Token Bucket)', '์ฌ๋ผ์ด๋ฉ ์๋์ฐ(Sliding Window)' ๋ฑ ๋ค์ํ ๋ฐฉ์์ด ์์ง๋ง, ์ ๋ 1์ธ ๊ฐ๋ฐ์์ ์ ์ง๋ณด์์ฑ๊ณผ ์๋ฒ ๋ฆฌ์์ค๋ฅผ ๊ณ ๋ คํ์ฌ ๊ฐ์ฅ ์ง๊ด์ ์ด๊ณ ๊ฐ๋ฒผ์ด '๊ณ ์ ์๋์ฐ(Fixed Window)' ๋ฐฉ์์ ์ ํํ์ต๋๋ค.
๋ก์ง์ ์๊ฐ๋ณด๋ค ๋จ์ ๋ช ์พํฉ๋๋ค.
์ฌ์ฉ์๊ฐ API(์: ๋ก๊ทธ์ธ)๋ฅผ ์์ฒญํ๋ฉด, ์๋ฒ๋ ๊ทธ ์ฌ์ฉ์์ IP ์ฃผ์๋ฅผ ์ถ์ถํฉ๋๋ค.
Redis์
rate_limit:192.168.0.1:login์ด๋ผ๋ ๊ณ ์ ํ ํค(Key)๋ฅผ ์์ฑํ๊ณ , ์นด์ดํธ๋ฅผ 1 ์ฌ๋ฆฝ๋๋ค.์ด ํค์ ์๋ช (TTL)์ 60์ด๋ก ์ค์ ํฉ๋๋ค. ์ฆ, 1๋ถ์ด ์ง๋๋ฉด ์ด ๊ธฐ๋ก์ Redis์์ ํ์ ๋ ์์ด ์ฌ๋ผ์ง๋๋ค. (Garbage Collection์ ์๋ฒฝํ ์๋ํ!)
๋ง์ฝ 60์ด ์์ ์ด ์นด์ดํธ๊ฐ ์ ๊ฐ ์ค์ ํ ์๊ณ์น(์: 1๋ถ๋น 10ํ)๋ฅผ ์ด๊ณผํ๊ฒ ๋๋ฉด, FastAPI๋ ๊ทธ ์ฆ์ ์๋ฌ๋ฅผ ๋ฐ์์ํต๋๋ค.
์ด ๋ก์ง์ ๋ชจ๋ API๋ง๋ค ํ๋์ฝ๋ฉํ๋ ๊ฒ์ ๋นํจ์จ์ ์ด๋ฏ๋ก, FastAPI์ ์์กด์ฑ ์ฃผ์
(Dependency Injection) ๊ธฐ๋ฅ์ ํ์ฉํ์ฌ ํ๋์ ๊ณตํต '๋ฐฉ์ด ๋ชจ๋'๋ก ๋ฌถ์ด๋์์ต๋๋ค. ์ด์ ์๋ก์ด ๊ธฐ๋ฅ(์ชฝ์ง ๋ณด๋ด๊ธฐ, ๋๊ธ ๋ฌ๊ธฐ ๋ฑ)์ ๊ฐ๋ฐํ ๋๋ง๋ค ํจ์ ์๋จ์ @limiter(requests=5, window=60)์ด๋ผ๋ ์ฝ๋ ํ ์ค๋ง ์ ์ธํด ์ฃผ๋ฉด, ๊ทธ ์ฆ์ ์๋ฒฝํ ๋ฐฉ์ด๋ง์ด ์ณ์ง๊ฒ ๋ฉ๋๋ค.
4. 429 Too Many Requests: ์ ์ ๊ฒฝํ(UX)์ ์งํค๋ ์ฐ์ํ ๊ฑฐ์
์๋ ์ ํ์์ ๊ธฐ์ ์ ์ธ ๊ตฌํ๋งํผ์ด๋ ์ค์ํ ๊ฒ์ '์ ์์ ์ธ ์ ์ ๊ฐ ๊ฒช์ ๋ถํธํจ์ ์ต์ํํ๋ ๊ฒ'์ ๋๋ค.
์ค์๋ก ์๋ก๊ณ ์นจ(F5)์ ์ฐํํ ์ ๋ํ ํ์์๊ฒ ๋ฌด์๋ฌด์ํ ์๋ฒ ์๋ฌ(500 Internal Server Error) ํ๋ฉด์ ๋์ฐ๊ฑฐ๋, ์์ ์ ์์ ์๊ตฌ ์ฐจ๋จํด ๋ฒ๋ฆฐ๋ค๋ฉด ์ปค๋ฎค๋ํฐ์ ์ ๋ขฐ๋๋ ๋ฐ๋ฅ์ผ๋ก ๋จ์ด์ง ๊ฒ์ ๋๋ค.
๊ทธ๋์ ์์คํ
์ด ์๊ณ์น๋ฅผ ๋์ ์์ฒญ์ ์ฐจ๋จํ ๋๋, ํ์ค HTTP ์ํ ์ฝ๋์ธ 429 Too Many Requests๋ฅผ ์ ํํ๊ฒ ๋ฐํํ๋๋ก ๋ฐฑ์๋๋ฅผ ์ค๊ณํ์ต๋๋ค. ํ๋ก ํธ์๋(UI)์์๋ ์ด 429 ์ฝ๋๋ฅผ ๊ฐ์งํ๋ฉด ๋ถ์์ ๊ฒฝ๊ณ ์ฐฝ ๋์ , "์์ฒญ์ด ๋๋ฌด ๋ง์ต๋๋ค. ์พ์ ํ ํ๊ฒฝ์ ์ํด 1๋ถ ๋ค์ ๋ค์ ์๋ํด ์ฃผ์ธ์"๋ผ๋ ๋ถ๋๋ฌ์ด ํ ์คํธ ํ์
(Toast Popup)์ ๋์ฐ๋๋ก ์์ธ ์ฒ๋ฆฌ๋ฅผ ํด๋์์ต๋๋ค. ํด์ปค์๊ฒ๋ ๋์ ์ ์๋ ์ฒ ๋ฒฝ์ ์น๋ฉด์๋, ์ผ๋ฐ ์ ์ ์๊ฒ๋ ์น์ ํ ์๋ด๋ฅผ ์ ๊ณตํ๋ ๋ฐธ๋ฐ์ค๋ฅผ ๋ง์ถ ๊ฒ์
๋๋ค.
๋งบ์ผ๋ฉฐ: ๋ณด์ด์ง ์๋ ๋ฌด๊ธฐ๊ฐ ์ฌ์ดํธ์ ์๋ช ์ ๊ฒฐ์ ํฉ๋๋ค.
์ด๋ฒ API Rate Limiting ๊ธฐ๋ฅ์ ์์ฒด์ ์ผ๋ก ๊ตฌํํ๊ณ ์๋ฒ์ ๋ฐฐํฌํ ์ฒซ๋ , Redis ๋ก๊ทธ์ ์๋ฐฑ ๊ฐ์ ๋ฌด์๋ฏธํ ๋ก๊ทธ์ธ ๋ด ์์ฒญ๋ค์ด 429 ์๋ฌ๋ฅผ ๋ง๊ณ ํ๊ฒจ ๋๊ฐ๋ ๊ฒ์ ๋ณด๋ฉฐ ์์ฒญ๋ ์๋๊ฐ๊ณผ ์พ๊ฐ์ ๋๊ผ์ต๋๋ค. ๋๋ถ์ ๋ฐฑ์๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ ํ์จ์ ๋์ฐพ์๊ณ , ์ฌ์ดํธ ๋ก๋ฉ ์๋๋ ์ด์ ๋ณด๋ค ํจ์ฌ ์์ ์ ์ผ๋ก ์ ์ง๋๊ณ ์์ต๋๋ค.
ํ๋ คํ ํ๋ก ํธ์๋ ๋์์ธ์ด๋ ์๋ก์ด ๊ฒ์ํ์ ์ถ๊ฐํ๋ ๊ฒ๋ ์ค์ํ์ง๋ง, ์ปค๋ฎค๋ํฐ๊ฐ 1๋ , 5๋ , 10๋ ์ด์ ํผํผํ๊ฒ ์ด์๋จ๊ธฐ ์ํด์๋ ๊ฒฐ๊ตญ ๋ณด์ด์ง ์๋ ์๋ฒ ๋ท๋จ์ ๋ฐฉ์ด ์ํคํ ์ฒ๊ฐ ์ผ๋ง๋ ๊ฒฌ๊ณ ํ์ง๊ฐ ์ฑํจ๋ฅผ ๊ฐ๋ฆ ๋๋ค.
์ง๊ธ ๋น์ฅ ํธ๋ํฝ์ด ๋ง์ง ์๋๋ผ๋, ์ธ์ ๊ฐ ์ฐพ์์ฌ 'ํธ๋ํฝ ๊ธ์ฆ'์ด๋ผ๋ ์ฆ๊ฑฐ์ด ์๊ธฐ๋ฅผ ์์ผ๋ฉฐ ๋ง์ดํ ์ ์๋๋ก ๋ฐฉ์ด๋ง์ ๋ฏธ๋ฆฌ ์ณ๋๋ ๊ฒ. ๊ทธ๊ฒ์ด ๋ฐ๋ก 1์ธ ๊ฐ๋ฐ์๊ฐ ์ฝ๋๋ฅผ ์์ฑํ๋ฉฐ ๊ฐ์ฅ ์ ๊ฒฝ ์จ์ผ ํ ๊ธฐ๋ณธ๊ธฐ๋ผ๊ณ ์๊ฐํฉ๋๋ค. ์ค๋๋ ์์ ํ๊ณ ์พ์ ํ IT ์ปค๋ฎค๋ํฐ ์ํ๊ณ๋ฅผ ๋ง๋ค๊ธฐ ์ํด ๊ณ ๋ฏผํ๊ณ ๊ณ์ค ์๋ง์ ์๋ฒ ๊ฐ๋ฐ์๋ถ๋ค์ ๋์ ์ ์ง์ฌ์ผ๋ก ์์ํฉ๋๋ค. ๊ณ์ํด์ ์ฌ์ดํธ๋ฅผ ๋ค๋ฌ์ด๊ฐ๋ ์์ํ ๊ฐ๋ฐ๊ธฐ๋ก ๋ค์ ์ฐพ์์ค๊ฒ ์ต๋๋ค!
๐ฌ ๋๊ธ 0๊ฐ