โจ Redis ๋?
Remote Dictionary Server (DB) ์ด๋ฉฐ, In-memory Data structure Store ๋ก, ๋ฉ๋ชจ๋ฆฌ ์์ ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ๋ค. ๋ค์ํ ์๋ฃ ๊ตฌ์กฐ๋ฅผ ์ ์ฅํ์ง๋ง, ๊ธฐ๋ณธ์ ์ผ๋ก ๋ชจ๋ ๋ฐ์ดํฐ๋ Key-Value ์์ ์ด๋ฃจ๊ธฐ ๋๋ฌธ์ NoSQL DB ๋ก ํ์ฉ๋๋ค. ๋์คํฌ์ ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํด ์๋๊ฐ ๋๋ฆฐ RDBMS ๋ฑ์ DBMS ๋ณด๋ค ํ์ฉ๋๊ฐ ๋์ ์ผ์ด์ค๊ฐ ์ข ์ข ์๋๋ฐ, ๊ทธ ๋ํ์ ์ธ ์๊ฐ ์บ์ (Cache) ์ด๋ค.
ํด๋ผ์ด์ธํธ์์ ์๋ฒ์๊ฒ ๋ฐ์ดํฐ๋ฅผ ๋ฌ๋ผ๋ ์์ฒญ์ ๋ณด๋ด๋ฉด ์๋ฒ๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค์์ ๋ฐ์ดํฐ๋ฅผ ์ป์ด์ค๊ฒ ๋๋๋ฐ, ๋์ผํ ์์ฒญ์ด ์ฌ๋ฌ ๋ฒ ์ฌ ๊ฒฝ์ฐ ๊ณ์ ๋ฐ์ดํฐ๋ฒ ์ด์ค์์ ๊ฐ์ ๋ฐ์ดํฐ๋ฅผ ์ฐพ๋๋ค. ์ด๋ ์๋นํ ๋นํจ์จ์ ์ด๋ฉฐ, ๋ฐ์ดํฐ์ ํฌ๊ธฐ์ ๋ฐ๋ผ ์๋ต ์๋๊ฐ ๊ณ์ ์ง์ฐ๋ ์ ์๊ธฐ ๋๋ฌธ์ ํด๋ผ์ด์ธํธ์๊ฒ ์ข์ง ์์ ์ฌ์ฉ ๊ฒฝํ์ ์ค ์ ์๋ค.
์ด ๋, ์์ฒญ ๊ฒฐ๊ณผ๋ฅผ ๋ฏธ๋ฆฌ ์ ์ฅํด๋์๋ค๊ฐ ๋์ผํ ๋ฐ์ดํฐ๋ฅผ ์ป๊ณ ์ ํ๋ ์์ฒญ์ด ๋ค์ด์ค๋ฉด ์ ์ฅํ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ๋ก ์ค ์ ์๋๋ก ํ๋ ๊ฒ์ด "์บ์" ๋ค. ์บ์๋ ์์ฃผ ๋ฐ๋์ง ์์ง๋ง ์์ฃผ ์ ๊ทผ๋๋ฉฐ, ์ฌ์ฉ์์๊ฒ ๋น ๋ฅด๊ฒ ์ ๋ฌ๋์ด์ผ ํ๋ค๋ ํน์ง์ ๊ฐ์ง๊ณ ์๊ธฐ ๋๋ฌธ์ SSD ๋ฑ์ Storage ๊ฐ ์๋ Main memory ์ ์ ์ฅ๋๋ค. Redis ์ญ์ ์๋ฒ์ ์บ์๋ฅผ ์ ์ฅํ ์ ์๋๋ก ํ๋ in memory ์ค ํ๋์ด๋ค.
โจ Redis ์์ ์ง์ํ๋ ์๋ฃ ๊ตฌ์กฐ
- String
- List
- Set
- Sorted Set
- Hash (Object)
- Etc..
โจ Redis ์ ์บ์ ์๋ฒ
3-tier ์ํคํ ์ณ์์๋ ๊ธฐ๋ณธ์ ์ผ๋ก ํด๋ผ์ด์ธํธ์ ์๋ฒ, ๋ฐ์ดํฐ๋ฒ ์ด์ค๊ฐ์ ํต์ ์ด ์ด๋ฃจ์ด์ง๋ค. ํด๋ผ์ด์ธํธ๊ฐ ์๋ฒ์๊ฒ ์์ฒญ์ ๋ณด๋ด๋ฉด ์๋ฒ๊ฐ ๋ฐ์ดํฐ๋ฒ ์ด์ค์์ ๋ฐ์ดํฐ๋ฅผ ์ป์ด์ ํด๋ผ์ด์ธํธ์๊ฒ ์๋ตํ๋ ๊ตฌ์กฐ๋ฅผ ๋ ๋๋ฐ, ์ด ๋ Redis ๋ฅผ ํ์ฉํ๋ฉด ์๋ต ์๋๋ฅผ ํ์ ํ ๋ฎ์ถ ์ ์๋ค.
๋ค์ ์์ ์ ํตํด ์ด ๋ด์ฉ์ ์๋ฏธ๋ฅผ ๋ช ํํ ํ๊ณ ์ ํ๋ค.
1. Redis ์ค์น ๋ฐ ์คํํ๊ธฐ (MacOS)
Redis ์ค์น ๋งํฌ๋ฅผ ์ฐธ๊ณ ํ์ฌ ๋ก์ปฌํธ์คํธ์ ์ค์น๋ฅผ ์งํํ๋ค.
$ wget https://download.redis.io/releases/redis-6.2.4.tar.gz
$ tar xzf redis-6.2.4.tar.gz
$ cd redis-6.2.4
$ make
$ redis-server
$ redis-cli
redis-server ๋ช ๋ น์ด๋ฅผ ํตํด ์๋ฒ๋ฅผ ์คํํ๊ณ , redis-cli ๋ช ๋ น์ด๋ฅผ ํตํด redis ์๋ฒ์ ์ ์ํ ์ ์๋ค. ์ ์ ํ cli ์ฐฝ์ด ๋ค์๊ณผ ๊ฐ๋ค๋ฉด ์ฑ๊ณต์ด๋ค.
( ์ด ๋ ์ปดํจํฐ๋ฅผ ์ฌ๋ถํ ํ๊ฒ ๋ ๊ฒฝ์ฐ, redis-cli ์ ๋ ฅ ์ ํฐ๋ฏธ๋์ redis-server ๋ช ๋ น์ด๋ฅผ ๊ผญ ๋จผ์ ์ ๋ ฅํด์ฃผ์ด์ผ ์๋ฒ๊ฐ ์คํ๋๋ค. ๊ทธ๋ ์ง ์์ ๊ฒฝ์ฐ Could not connect to Redis at 127.0.0.1:6379: Connection refused ์ ๊ฐ์ ์๋ฌ๋ฅผ ๋ง๋๊ฒ ๋๋ค.)
2. ExpressJs ์๋ฒ์ Redis ์๋ฒ ์ฐ๊ฒฐํ๊ธฐ
Redis ์บ์ ์๋ฒ๋ฅผ ํ์ฉํ๋ ค๋ฉด ์๋ํ๋ ์๋ฒ ํ๋๋ฅผ ๋จผ์ ๊ตฌ์ฑํด์ผ ํ๋ค. ์ด๋ฅผ ์ํด Express ๋ชจ๋์ ํ์ฉํด ์๋ฒ๋ฅผ ๋ง๋ ๋ค.
const express = require('express');
const axios = require('axios');
const cors = require('cors');
const app = express()
app.use(cors())
app.listen(3001, () => console.log('Listening on port 3001'))
Redis ์๋ฒ์ ์ฐ๊ฒฐํ๊ธฐ ์ํด redis ๋ชจ๋์ ์ค์นํ๋ค.
$ npm i redis
๋ง๋ค์ด ๋์ ์๋ฒ์ Redis ์๋ฒ๋ฅผ ์ฐ๊ฒฐํ๋ค.
const express = require('express');
const axios = require('axios');
const cors = require('cors');
const Redis = require('redis'); // Redis ๋ชจ๋ ๋ถ๋ฌ์ค๊ธฐ
const redisClient = new Redis.createClient();
const DEFAULT_EXPIRATION = 3600 //seconds
const app = express()
app.use(cors())
app.listen(3001, () => console.log('Listening on port 3001'))
createClient() ๋ฉ์๋๋ ์๋ก์ด RedisClient ๊ฐ์ฒด๋ฅผ ์์ฑํ๋๋ฐ, redis ์๋ฒ์ express ์๋ฒ๊ฐ ๊ฐ์ ํธ์คํธ์์ ๋์๊ฐ๊ณ ์๋ค๋ฉด createClient() ์ ๋ณ๋์ ์ค์ ์ ํด ์ฃผ์ง ์์๋ ๋๋ค. ๋ง์ฝ ํธ์คํธ๊ฐ ๋ค๋ฅด๋ค๋ฉด ํธ์คํธ url, ํฌํธ ๋ฒํธ ๋ฑ์ ์ค์ ์ ์ถ๊ฐํด์ฃผ์ด์ผ ํ๋ค.
์ฌ๊ธฐ๊น์ง ์๋ค๋ฉด redisClient ๊ฐ์ฒด๋ฅผ ํตํด redis ์๋ฒ์ ์ฟผ๋ฆฌ๋ฅผ ๋ ๋ฆด ์ ์๊ฒ ๋๋ค. ์ง๊ธ๋ถํฐ ๋ณธ๊ฒฉ์ ์ผ๋ก redis ์๋ฒ๊ฐ ์ด๋ป๊ฒ ์บ์ฑ์ ํ๊ฒ ๋๋์ง ๋ณด์.
3. DB ๋ฅผ ์ป์ด์ค๊ธฐ ์ , Redis ์๋ฒ์์ ์บ์๋ฅผ ๋จผ์ ํ์ธํ๊ธฐ
ํด๋ผ์ด์ธํธ์์ ์๋ฒ์ "photos ๋ฐ์ดํฐ๋ฅผ ๋ณด๋ด๋ฌ๋ผ" ๋ ์์ฒญ์ ๋ณด๋ผ ๊ฒฝ์ฐ, ์ผ๋ฐ์ ์ผ๋ก ์๋ฒ๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค (๋๋ api) ์ ์์ฒญ์ ๋ง๋ ๊ฒฐ๊ณผ๋ฅผ ๋ฐํํ๋ค. ์ด๋ฅผ ์ํ ์ฝ๋์ ์๋ต์ ๊ฑธ๋ฆฌ๋ ์๊ฐ์ ๋ค์๊ณผ ๊ฐ๋ค.
// get all photos from api
app.get('/photos', async(req, res) => {
const albumId = req.query.albumId
const {data} = await axios.get(
'https://jsonplaceholder.typicode.com/photos',
{params : {albumId}},
)
res.json(data)
})
๋ณด์ด๋ค์ํผ ์ฝ๋๊ฐ ์๋ํ๋ ๋ฐ๋ ๋ฌธ์ ๊ฐ ์๊ฒ ์ง๋ง, '/photos' path ๋ก ์์ฒญ์ด ์ฌ ๋๋ง๋ค ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ๋์ผํ ์์ฒญ์ ๋ณด๋ด๊ฒ ๋ ๊ฒ์ด๋ฉฐ, ๋งค๋ฒ 3.25 ์ด์ ๋ฌํ๋ ์๋ต ์๊ฐ์ด ๊ฑธ๋ฆด ๊ฒ์ด๋ค. ๋ฐ๋ผ์ ์ต์ด ์์ฒญ ์ ๋ฐ์ดํฐ๋ฅผ redis ์๋ฒ์ ์บ์ฑํด ๋์๋ค๊ฐ ๋ค์์ ๋์ผํ ์์ฒญ์ด ๋ค์ด์ฌ ๊ฒฝ์ฐ ์บ์๋ฅผ ๋ฐํํ๋ฉด ์๋ต ์๊ฐ์ด ์ค๊ฒ ๋๋ค.
์ด๋ฅผ ์ํ ์ฝ๋๋ ๋ค์๊ณผ ๊ฐ๋ค.
// check if redis server has data, if not get from api, store in redis and return
app.get('/photos', async(req, res) => {
const albumId = req.query.albumId
redisClient.get('photos', async (err, data) => { // check data from redis server
if (err) console.error(error)
if (data) {
res.json(JSON.parse(data)) // cache hit
} else { // cache miss
const {data} = await axios.get(
'https://jsonplaceholder.typicode.com/photos',
{params : {albumId}},
)
redisClient.setex('photos', DEFAULT_EXPIRATION, JSON.stringify(data)) // set with an expiration time (or can use other redis expressions
// redis can only store strings, so we need to convert the data to a string
res.json(data)
}
})
์ ์ฝ๋์ ๋ก์ง์ ์ธ๋ถ์ ์ผ๋ก ์ดํด๋ณด์.
์ฐ์ , '/photos' ๋ก ์์ฒญ์ด ๋ค์ด์ค๋ฉด redisClient ๊ฐ์ฒด๋ฅผ ํตํด redis ์๋ฒ์ ํด๋น ๋ฐ์ดํฐ๊ฐ ์บ์ฑ๋์ด ์๋์ง ํ์ธํ๋ค. get ๋ฉ์๋๋ ์ฒซ ๋ฒ์งธ ์ธ์๋ก key ๊ฐ์ ๋ฐ์๋ค์ด๊ณ , ๋ ๋ฒ์งธ ์ธ์๋ก ์ฝ๋ฐฑ ํจ์๋ฅผ ์ ๋ฌ๋ฐ๋๋ค. ์ด ๊ฒฝ์ฐ 'photos' ๋ก ์ ์ฅ๋์ด ์๋ Value ๊ฐ ์๋์ง ํ์ธํ๊ณ , ์บ์๊ฐ์ด ์กด์ฌํ๋ค๋ฉด (Cache hit) ํด๋น ๋ฐ์ดํฐ๋ฅผ ๋ฐํํ๋ค.
'photos' ๋ก ์ ์ฅ๋์ด ์๋ value ๊ฐ ์๋ค๋ฉด (Cache miss), DB ์์ ๋ฐ์์ ์ฐ์ redis ์ ์บ์ฑํ๋ค. ์ด๋ฅผ ์ํด ์ฌ์ฉํ๋ ๋ฉ์๋๊ฐ setex ๋ก, ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ key ๊ฐ๊ณผ ์ ํจ์๊ฐ, ์ ์ฅํ value ๊ฐ์ ์ ๋ฌ์ธ์๋ก ๋ฐ๋๋ค. ์บ์ฑํ ์ดํ ๋ฐ์ดํฐ๋ฅผ ํด๋ผ์ด์ธํธ์ ๋ฐํํ๋ค.
์์ ์ด๋ฏธ ๋ฐ์ดํฐ๊ฐ ์บ์ฑ๋์์ผ๋ฏ๋ก, ๋ ๋ฒ์งธ ์์ฒญ์ ๊ฑธ๋ฆฌ๋ ์๋ถ ์๊ฐ์ 22 ms (millisecond) ์ด๋ค. ์ฒซ ๋ฒ์งธ ์์ฒญ ๋ 3.5 ์ด๊ฐ ๊ฑธ๋ ธ๋ ๊ฒ์ ์๊ฐํ๋ฉด ๋งค์ฐ ํฐ ๋ฐ์ ์ด๋ค.
4. session-store ์ ํจ๊ป ํ์ฉํ๊ธฐ
Redis ๋ฅผ ์ ์ฉํ๊ฒ ํ์ฉํ ์ ์๋ ๊ฒฝ์ฐ ๋ ํ๋๋ session ์ด๋ค. http ๋ ๊ธฐ๋ณธ์ ์ผ๋ก ๋ฌด์ํ์ฑ (stateless) ์ ๋ ๋๋ฐ, ์ ์ ์ ์ธ์ ์ ๋ณด๋ฅผ ์ ์งํ๊ธฐ ์ํ ์๋จ์ผ๋ก ์ธ์ ๋๋ ํ ํฐ์ ํ์ฉํ๊ณค ํ๋ค. ์ธ์ ์ ์ฌ์ฉํ ๋ ์ธ์ ์ ๋ณด๋ ๊ธฐ๋ณธ์ ์ผ๋ก ์๋ฒ์ ๋ฉ๋ชจ๋ฆฌ์ ์ ์ ์ฅ๋๋๋ฐ, ์๋ฒ๊ฐ ๊บผ์ง๋ฉด ์ธ์ ๋ฐ์ดํฐ๊ฐ ๋ค ๋ ์๊ฐ๊ฒ ๋๋ค. redis ์๋ฒ๋ฅผ ์ฌ์ฉํ์ฌ ์ธ์ ๊ด๋ฆฌ๋ฅผ ํ๋ฉด ์๋ฒ๊ฐ ๊บผ์ ธ๋ ๋ฐ์ดํฐ๊ฐ ์ ์ง๋๋ฉฐ, ๋ณต์ ์๋ฒ ํ๊ฒฝ์์๋ ์ธ์ ์ ๊ณต์ ํ ์ ์๊ฒ ๋๋ค.
์์ ์์ฑํ๋ redisClient ๊ฐ์ฒด๋ฅผ session ์ ์ ์ฅ์๋ก ์ง์ ํด์ฃผ๋ฉด session store ์ Redis ๋ฅผ ํจ๊ป ์ฌ์ฉํ ์ ์๋ค.
const session = require('express-session')
let RedisStore = require('connect-redis')(session)
// use redis for session store
app.use(session({
secret: "secret",
saveUninitialized: false,
resave: false,
store: new RedisStore(redisClient)
}))
โจ ๋ง๋ฌด๋ฆฌ
Redis ๋ ์ ํ์ฉํ๋ฉด ์ ํ๋ฆฌ์ผ์ด์ ์ ์๋์ ์ฑ๋ฅ์ ํฌ๊ฒ ์ฆ๊ฐ์ํค๋ ์ญํ ์ ํ ์ ์๋ค. ๋ฌผ๋ก ๊ทธ๋ฌ๊ธฐ ์ํด in-memory ์ disk ์ ์ฐจ์ด, RAM ๋ฐ์ดํฐ์ ํ๋ฐ์ฑ ์ด์ ๋ฑ์ ์ฌ์ ์ ์ ์์๋์ด์ผ ํ ๊ฒ์ด๋ค.
โจ ์ฐธ๊ณ ์๋ฃ
What is Redis and What Does It Do?
'๐ป DEV > Database' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[Database] Redis Vs Memcached (0) | 2021.08.10 |
---|---|
[Database] ์ค๋ฉ(Sharding) ์ด๋? (0) | 2021.07.14 |
[Database] Row oriented DB, Column oriented DB ๋? (0) | 2021.07.13 |
[Database] DB ํจ๋ฌ๋ค์ (Paradigm) ์ด๋? (0) | 2021.07.08 |
[Database] ๊ด๊ณํ ๋ฐ์ดํฐ๋ฒ ์ด์ค(RDBMS) ์ SQL (0) | 2021.01.05 |
๋๊ธ