๐ Redis ์บ์ฑ ์ ๋ต: ์น์ฌ์ดํธ ์๋ 10๋ฐฐ ๋น ๋ฅด๊ฒ ๋ง๋๋ ์ค์ ๊ฐ์ด๋
๊ด๋ฆฌ์
2๊ฐ์ ์
๐ Redis ์บ์ฑ ์ ๋ต: ์น์ฌ์ดํธ ์๋ 10๋ฐฐ ๋น ๋ฅด๊ฒ ๋ง๋๋ ์ค์ ๊ฐ์ด๋
๐ค ์น์ฌ์ดํธ๊ฐ ๋๋ ค์ ์ฌ์ฉ์๊ฐ ๋ ๋๊ฐ๋ค๊ณ ์?
๋ก๋ฉ์ด 3์ด๋ง ๋ฆ์ด์ ธ๋ ์ฌ์ฉ์์ 40%๊ฐ ๋ ๋๋ค๋ ํต๊ณ, ๋ค์ด๋ณด์ จ์ฃ ? ์ค์ ๋ก ๋ง์ ๊ฐ๋ฐ์๋ค์ด ๋ฐ์ดํฐ๋ฒ ์ด์ค ์ฟผ๋ฆฌ ๋๋ฌธ์ ๊ณ ์ํ๊ณ ์์ด์.
์ด๋ฐ ๊ฐ๋จํ ์ฟผ๋ฆฌ๋ ์ฌ์ฉ์๊ฐ ๋ง์์ง๋ฉด ๋ช ์ด์ฉ ๊ฑธ๋ฆฌ๋ ๊ฒฝ์ฐ๊ฐ ์๊ฑฐ๋ ์. ๊ทธ๋์ ์ค๋์ Redis ์บ์ฑ์ผ๋ก ์ด ๋ฌธ์ ๋ฅผ ํ ๋ฐฉ์ ํด๊ฒฐํ๋ ๋ฐฉ๋ฒ์ ์๋ ค๋๋ฆด๊ฒ์!
โก Redis๊ฐ ๋ญ๊ธธ๋ ์ด๋ ๊ฒ ๋น ๋ฅธ๊ฐ์?
Redis๋ ๋ฉ๋ชจ๋ฆฌ์ ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ๋ In-Memory ๋ฐ์ดํฐ๋ฒ ์ด์ค์์. ํ๋๋์คํฌ๊ฐ ์๋๋ผ RAM์ ์ ์ฅํ๋๊น ์ ๊ทผ ์๋๊ฐ ๋ง๋ ์ ๋๊ฒ ๋นจ๋ผ์.
์ค์ ์๋ ๋น๊ต:
- ํ๋๋์คํฌ: 10ms (๋๋ฆผ)
- SSD: 0.1ms (๋น ๋ฆ)
- Redis (๋ฉ๋ชจ๋ฆฌ): 0.01ms (์ด๊ณ ์!)
๊ทธ๋ฌ๋๊น Redis๋ฅผ ์ฐ๋ฉด 100๋ฐฐ~1000๋ฐฐ ๋น ๋ฅธ ๊ฑฐ์ฃ !
๐ฏ ์ธ์ Redis ์บ์ฑ์ ์จ์ผ ํ ๊น์?
โ ์ด๋ฐ ์ํฉ์ด๋ผ๋ฉด Redis๊ฐ ๋ต์ด์์
1. ๊ฐ์ ๋ฐ์ดํฐ๋ฅผ ์์ฃผ ์กฐํํ๋ ๊ฒฝ์ฐ
- ์ฌ์ฉ์ ํ๋กํ ์ ๋ณด
- ์ํ ๋ชฉ๋ก ๋ฐ์ดํฐ
- ๋ฉ๋ด, ์นดํ ๊ณ ๋ฆฌ ์ ๋ณด
2. ๋ณต์กํ ๊ณ์ฐ ๊ฒฐ๊ณผ๋ฅผ ์ ์ฅํ๊ณ ์ถ์ ๋
- ํต๊ณ ๋ฐ์ดํฐ (์ค๋์ ๋ฐฉ๋ฌธ์ ์)
- ์ธ๊ธฐ ๊ฒ์๊ธ ์์
- ์ถ์ฒ ์ํ ๋ฆฌ์คํธ
3. ์ธ์ ๊ด๋ฆฌ๊ฐ ํ์ํ ๊ฒฝ์ฐ
- ๋ก๊ทธ์ธ ์ํ ์ ์ง
- ์ฅ๋ฐ๊ตฌ๋ ์ ๋ณด
- ์์ ์ ์ฅ ๋ฐ์ดํฐ
๐ ๏ธ Redis ์ค์นํ๊ณ ์์ํ๊ธฐ
Windows์์ Redis ์ค์น
# Chocolatey๋ก ์ค์น (๊ฐ์ฅ ์ฌ์)
choco install redis-64
# ๋๋ WSL ์ฌ์ฉ
wsl --install
sudo apt update
sudo apt install redis-server
macOS์์ Redis ์ค์น
# Homebrew๋ก ์ค์น
brew install redis
# Redis ์คํ
brew services start redis
์ค์น ํ์ธ
redis-cli ping
# ์๋ต: PONG (์ฑ๊ณต!)
๐ก ์ค์ ์บ์ฑ ์ ๋ต 3๊ฐ์ง
1๏ธโฃ Cache-Aside ํจํด (๊ฐ์ฅ ๋ง์ด ์ฌ์ฉ)
์ฌ์ฉ์๊ฐ ๋ฐ์ดํฐ๋ฅผ ์์ฒญํ๋ฉด:
- ์บ์์ ์๋ ํ์ธ โ ์์ผ๋ฉด ๋ฐ๋ก ๋ฆฌํด
- ์์ผ๋ฉด DB์์ ์กฐํ โ ๊ฒฐ๊ณผ๋ฅผ ์บ์์ ์ ์ฅ ํ ๋ฆฌํด
// Node.js ์์
async function getUser(userId) {
// 1. Redis์์ ๋จผ์ ํ์ธ
const cached = await redis.get(`user:${userId}`)
if (cached) {
console.log('์บ์์์ ๊ฐ์ ธ์ด! ์ด๊ณ ์!')
return JSON.parse(cached)
}
// 2. ์บ์์ ์์ผ๋ฉด DB์์ ์กฐํ
const user = await db.user.findById(userId)
// 3. ๋ค์๋ฒ์ ์ํด ์บ์์ ์ ์ฅ (1์๊ฐ ์ ์ง)
await redis.setex(`user:${userId}`, 3600, JSON.stringify(user))
console.log('DB์์ ๊ฐ์ ธ์์ ์บ์์ ์ ์ฅํจ')
return user
}
2๏ธโฃ Write-Through ํจํด (๋ฐ์ดํฐ ์ผ๊ด์ฑ ์ค์ํ ๋)
๋ฐ์ดํฐ๋ฅผ ๋ณ๊ฒฝํ ๋ DB์ ์บ์๋ฅผ ๋์์ ์ ๋ฐ์ดํธํ๋ ๋ฐฉ์์ด์์.
async function updateUser(userId, userData) {
// 1. DB ์
๋ฐ์ดํธ
const updatedUser = await db.user.update(userId, userData)
// 2. ์บ์๋ ๋์์ ์
๋ฐ์ดํธ
await redis.setex(`user:${userId}`, 3600, JSON.stringify(updatedUser))
return updatedUser
}
3๏ธโฃ Write-Behind ํจํด (๊ณ ์ฑ๋ฅ์ด ํ์ํ ๋)
์บ์์๋ง ๋จผ์ ์ ์ฅํ๊ณ , DB๋ ๋์ค์ ๋น๋๊ธฐ๋ก ์ ๋ฐ์ดํธํ๋ ๋ฐฉ์์ด์์.
async function incrementViewCount(postId) {
// 1. ์บ์์์ ์ฆ์ ์ฆ๊ฐ (์ด๊ณ ์!)
await redis.incr(`post:views:${postId}`)
// 2. DB๋ ๋์ค์ ๋ฐฐ์น๋ก ์
๋ฐ์ดํธ (๋ฐฑ๊ทธ๋ผ์ด๋ ์์
)
await queue.add('updatePostViews', { postId })
}
๐ง ์ค๋ฌด์์ ์์ฃผ ์ฐ๋ Redis ๋ช ๋ น์ด๋ค
๊ธฐ๋ณธ ๋ช ๋ น์ด
# ๋ฌธ์์ด ์ ์ฅ (TTL: Time To Live)
SET user:123 "{'name': 'john', 'age': 30}" EX 3600
# ๋ฐ์ดํฐ ์กฐํ
GET user:123
# ์ญ์
DEL user:123
# ์กด์ฌ ํ์ธ
EXISTS user:123
ํด์(Hash) ํ์ฉ - ์ฌ์ฉ์ ์ ๋ณด ์ ์ฅ
# ํด์๋ก ์ฌ์ฉ์ ์ ๋ณด ์ ์ฅ (๋ ํจ์จ์ !)
HSET user:123 name "john" age 30 email "john@email.com"
# ํน์ ํ๋๋ง ์กฐํ
HGET user:123 name
# ์ ์ฒด ์ ๋ณด ์กฐํ
HGETALL user:123
๋ฆฌ์คํธ(List) ํ์ฉ - ์ต์ ๊ฒ์๊ธ
# ์ต์ ๊ฒ์๊ธ ID ์ถ๊ฐ (์์ชฝ์)
LPUSH recent:posts 456 789 123
# ์ต์ 5๊ฐ ๊ฒ์๊ธ ์กฐํ
LRANGE recent:posts 0 4
๐ ์ฑ๋ฅ ์ต์ ํ ๊ฟํ 5๊ฐ์ง
1. ์ ์ ํ ๋ง๋ฃ ์๊ฐ(TTL) ์ค์
// ๋ฐ์ดํฐ ์ฑ๊ฒฉ์ ๋ฐ๋ผ TTL ์กฐ์
await redis.setex('user:profile:123', 3600, data) // 1์๊ฐ
await redis.setex('product:list', 1800, data) // 30๋ถ
await redis.setex('trending:posts', 600, data) // 10๋ถ
2. ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ๋ ๋ชจ๋ํฐ๋ง
# Redis ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ๋ ํ์ธ
redis-cli info memory
# ๋ฉ๋ชจ๋ฆฌ ์ ํ ์ค์ (4GB)
redis-cli config set maxmemory 4gb
redis-cli config set maxmemory-policy allkeys-lru
3. Connection Pool ์ฌ์ฉ
// ์ฐ๊ฒฐ ํ๋ก ์ฑ๋ฅ ํฅ์
const redis = new Redis({
host: 'localhost',
port: 6379,
maxRetriesPerRequest: 3,
retryDelayOnFailover: 100,
// ์ฐ๊ฒฐ ํ ์ค์
lazyConnect: true,
maxLoadingTimeout: 5000
})
4. ๋ฐฐ์น ์์ ์ผ๋ก ์ฑ๋ฅ ๊ฐ์
// Pipeline์ผ๋ก ์ฌ๋ฌ ๋ช
๋ น์ด ํ ๋ฒ์ ์คํ
const pipeline = redis.pipeline()
pipeline.set('key1', 'value1')
pipeline.set('key2', 'value2')
pipeline.set('key3', 'value3')
await pipeline.exec() // ํ ๋ฒ์ ์คํ!
5. ์ ์ ํ ๋ฐ์ดํฐ ๊ตฌ์กฐ ์ ํ
- ๋ฌธ์์ด: ๊ฐ๋จํ ๊ฐ ์ ์ฅ
- ํด์: ๊ฐ์ฒด ์ ๋ณด (์ฌ์ฉ์, ์ํ)
- ๋ฆฌ์คํธ: ์์๊ฐ ์๋ ๋ฐ์ดํฐ (์ต์ ๊ธ)
- ์งํฉ: ์ค๋ณต ์๋ ๋ฐ์ดํฐ (ํ๊ทธ, ์นดํ ๊ณ ๋ฆฌ)
- ์ ๋ ฌ๋ ์งํฉ: ๋ญํน, ์์ (์ธ๊ธฐ ๊ธ)
๐จ Redis ์ฌ์ฉํ ๋ ์ฃผ์์ฌํญ
1. ๋ฉ๋ชจ๋ฆฌ ๋ถ์กฑ ๋๋น
Redis๋ ๋ฉ๋ชจ๋ฆฌ์ ์ ์ฅํ๋๊น RAM์ด ๋ถ์กฑํ๋ฉด ๋ฌธ์ ๊ฐ ๋ผ์.
// ๋ฉ๋ชจ๋ฆฌ ๋ถ์กฑ ์ ์๋ ์ญ์ ์ ์ฑ
์ค์
redis.config('SET', 'maxmemory-policy', 'allkeys-lru')
2. ์บ์ ๋ฌดํจํ ์ ๋ต
๋ฐ์ดํฐ๊ฐ ๋ณ๊ฒฝ๋๋ฉด ์บ์๋ ์ ๋ฐ์ดํธํด์ผ ํด์.
async function updateUser(userId, newData) {
// 1. DB ์
๋ฐ์ดํธ
await db.user.update(userId, newData)
// 2. ๊ด๋ จ ์บ์ ์ญ์
await redis.del(`user:${userId}`)
await redis.del(`user:profile:${userId}`)
}
3. ๋ฐ์ดํฐ ์ผ๊ด์ฑ ์ ์ง
์บ์์ DB ๋ฐ์ดํฐ๊ฐ ๋ค๋ฅผ ์ ์์ด์. ์ค์ํ ๋ฐ์ดํฐ๋ TTL์ ์งง๊ฒ ์ค์ ํ์ธ์.
๐ฏ ์ค์ ์ฑ๋ฅ ๊ฐ์ ์ฌ๋ก
Before (Redis ์ฌ์ฉ ์ )
- ์ฌ์ฉ์ ํ๋กํ ์กฐํ: 500ms
- ์ํ ๋ชฉ๋ก ๋ก๋ฉ: 2์ด
- ๋์ ์ ์์: 100๋ช ์์ ์๋ฒ ๋ค์ด
After (Redis ์ฌ์ฉ ํ)
- ์ฌ์ฉ์ ํ๋กํ ์กฐํ: 5ms (100๋ฐฐ ๋น ๋ฆ!)
- ์ํ ๋ชฉ๋ก ๋ก๋ฉ: 50ms (40๋ฐฐ ๋น ๋ฆ!)
- ๋์ ์ ์์: 1000๋ช ๋ ์์ ์
๊ฒฐ๊ณผ: TPS(์ด๋น ์ฒ๋ฆฌ๋) 500 โ 5000์ผ๋ก 10๋ฐฐ ํฅ์!
๐ฎ ๋ง๋ฌด๋ฆฌ: Redis๋ก ์ฑ๋ฅ ํ์ ํ๊ธฐ
Redis ์บ์ฑ์ ๊ฐ๋ฐ์์ ํ์ ๋ฌด๊ธฐ์์. ํนํ:
โ
์ฌ์ฉ์ ๊ฒฝํ ๊ฐ์ - ๋น ๋ฅธ ์๋ต ์๋
โ
์๋ฒ ๋น์ฉ ์ ์ฝ - DB ๋ถํ ๊ฐ์
โ
ํ์ฅ์ฑ ํ๋ณด - ๋ ๋ง์ ์ฌ์ฉ์ ์์ฉ ๊ฐ๋ฅ
์์ ํ๋ก์ ํธ๋ถํฐ ์์ํด์ ์ ์ ์บ์ฑ ๋ฒ์๋ฅผ ๋ํ๋๊ฐ์ธ์. ์ฒ์์ ์ฌ์ฉ์ ์ธ์ ๋ง ์บ์ฑํ๋ค๊ฐ, ๋์ค์ ์ ์ฒด API ์๋ต๊น์ง ์บ์ฑํ ์ ์์ด์.
"๋น ๋ฅธ ์น์ฌ์ดํธ = ์ฑ๊ณตํ๋ ์๋น์ค"
์ฌ๋ฌ๋ถ๋ Redis๋ก ์ฌ์ฉ์๋ค์ด "์, ์ด ์ฌ์ดํธ ์ง์ง ๋น ๋ฅด๋ค!"๋ผ๊ณ ๊ฐํํ๋ ์๋น์ค๋ฅผ ๋ง๋ค์ด๋ณด์ธ์! ๐
์ด ๊ธ์ด ๋์์ด ๋์ จ๋ค๋ฉด ์ข์์์ ๋๊ธ๋ก ์ฌ๋ฌ๋ถ์ Redis ๊ฒฝํ์ ๊ณต์ ํด์ฃผ์ธ์!
๋๊ธ 0๊ฐ
์์ง ๋๊ธ์ด ์์ต๋๋ค
์ฒซ ๋ฒ์งธ ๋๊ธ์ ์์ฑํด๋ณด์ธ์!