[REDIS] ๐ Node.js ์์ redis ๋ชจ๋ ์ฌ์ฉ๋ฒ (์บ์ฑ & ์ธ์ ์คํ ์ด)
Node ํ๋ก์ ํธ์์ pm2๋ก ๋ค์ค ํด๋ฌ์คํฐ ์ธํ๋ผ๋ฅผ ๊ตฌ์ถํ๋ค๋ฉด ์ธ์ ๋ถ์ผ์น ๋ฌธ์ ๊ฐ ์๊ธฐ๊ฒ ๋ง๋ จ์ด๋ค.
๋ง์ผ ์๋ฒ๊ฐ ์ข ๋ฃ๋์ด ๋ฉ๋ชจ๋ฆฌ๊ฐ ๋ ๋ผ๊ฐ๋ฉด ์ ์์๋ค์ ๋ก๊ทธ์ธ์ด ๋ชจ๋ ํ๋ ค๋ฒ๋ฆฌ๊ฒ ๋๋ค.
๋ฐ๋ผ์ ์ด๋ฅผ ๋ฐฉ์งํ๊ธฐ ์ํด ์ธ์ ์์ด๋์ ์ค์ ์ฌ์ฉ์ ์ ๋ณด๋ฅผ ์ธ๋ถ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ ์ฅํ๋ ํธ์ด๋ค.
์ด๋ ๊ฐ๋ฐ์๋ค์ด ๋ง์ด ์ฌ์ฉํ๋ ๊ฒ์ด Redis db์ด๋ค.
๋ค๋ฅธ ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ฅผ ์ฌ์ฉํด๋ ๋์ง๋ง, ์ธ์ ์ ๋น ๋ฆฟ๋น ๋ฆฟํ๊ฒ ์๋ต์ ํด์ผ๋๊ธฐ ๋๋ฌธ์ ๋ฉ๋ชจ๋ฆฌ ๊ธฐ๋ฐ์ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ธ ๋ ๋์ค๋ฅผ ์ฌ์ฉํ๋ค.
์ง๊ธ๋ถํฐ Node ํ๋ก์ ํธ์์ Redis์ ์ฐ๊ฒฐํ๊ณ ์ฌ์ฉํ๋ ๋ฒ์ ์์๋ณด์.
Redis Database ์ค์น
๋ ๋์ค๋ฅผ ๋ก์ปฌ์ ์ค์นํด๋ ๋๊ณ , ํด๋ผ์ฐ๋๋ก๋ ์ฌ์ฉํ ์๊ฐ ์๋ค. ๋ง์์ ๋๋ ๊ฒ์ ๊ณจ๋ผ ์ค์นํ์.
๊ฐ์ธ์ ์ผ๋ก ๋ก์ปฌ ๋ณด๋ค๋ ํด๋ผ์ฐ๋๋ก ํ๋๊ฒ ๊ด๋ฆฌ๋ ํ์ ์ธก๋ฉด์์ ํธ๋ฆฌํ๊ณ ๋ ์ข์๋ค.
Redis ๋ก์ปฌ(์๋์ฐ) ์ค์น
Redis ํด๋ผ์ฐ๋ ์ค์น
redislabs ๋ฑ๋ก์ ๋ง์ท์ผ๋ฉด, ์๋ฒ์์ ์์ redislabs ์ฌ์ดํธ์ ๋ ๋์ค db์ ์ ์ํ๊ธฐ ์ํด์๋, ํ์ํ ์ ๋ณด๊ฐ ์๋๋ฐ ๋ ๋์ค host์ port, username, password 4๊ฐ์ง๋ฅผ ์์์ผ ํ๋ค. (๋งํฌ ์ฐธ๊ณ )
๊ณ์ ์ ๋ฑ๋กํ๊ณ ์ป์ redis db์ host์ password ์ ๋ณด๋ค์ env ํ์ผ์ ํ๊ฒฝ๋ณ์๋ก ์ ์ฅํด์ค๋ค.
# .env ํ์ผ
REDIS_HOST=redis-10943.c114.us-east-1-4.ec2.cloud.redislabs.com
REDIS_PORT=10943
REDIS_USERNAME=default
REDIS_PASSWORD=abcdefghijklmnopqrstuvwsyz
๋ ธ๋์์ Cache ๊ธฐ๋ฅ ์ฌ์ฉํ๊ธฐ
Node ↔ Redis v4 ์ฐ๊ฒฐํ๊ธฐ
> npm i redis # redis ํจํค์ง ์ค์น
ํด๋น redis ๋ฒ์ ผ์ ์ต์ v4 ๊ธฐ์ค์ผ๋ก ์ฐ์ฌํ๋ค.
์ต๊ทผ redis v3์์ v4๋ก ์ ๊ทธ๋ ์ด๋ ๋ฌ๋๋ฐ, ๊ทธ๋ฅ ์๋ก์ด ํจํค์ง ํ๋๋ฅผ ๋ง๋ ๊ฒ๊ณผ ๊ฐ์์ ๋๋ก ๋ฌธ๋ฒ๊ณผ ๋ด๋ถ๋์์ด ์์ ํ ๋ฌ๋ผ์ก๋ค.
์ด์ redis v4 ๋ฒ์ ผ์ ์ฝ๋ฐฑ ๊ธฐ๋ฐ์ด ์๋ ๊ธฐ๋ณธ์ ์ผ๋ก promise ๊ฐ์ฒด ๊ธฐ๋ฐ ๋น๋๊ธฐ๋ก ๋์๋๋๋ก ๋ณ๊ฒฝํ๋ค.
๊ทธ๋๋ ์๋ ๋ฌธ๋ฒ์ผ๋ก ์ฌ์ฉํ๊ณ ์ถ๋ค๋ฉด,createClient({ legacyMode: true })๋ก ๋ ๊ฑฐ์ ๋ชจ๋๋ฅผ ์ค์ ํด์ฃผ๋ฉด ํธํ์ฑ ๋ฌธ์ ์์ด ์ฌ์ฉ์ด ๊ฐ๋ฅํ๋ค.
๊ฐ๋จํ๊ฒ v4์์ ๋ฌด์์ด ๋ฐ๋์๋์ง ์ดํด๋ณด๋ ค๋ฉด, ๋ค์ ๋ง์ด๊ทธ๋ ์ด์ ๊ฐ์ด๋๋ฅผ ์ฐธ๊ณ ํ๊ธธ ๋ฐ๋๋ค.
https://github.com/redis/node-redis/blob/HEAD/docs/v3-to-v4.md
๋ก์ปฌ redis์ ์ฐ๊ฒฐํ๊ธฐ
const express = require('express');
const dotenv = require('dotenv');
const redis = require('redis');
dotenv.config(); // envํ๊ฒฝ๋ณ์ ํ์ผ ๊ฐ์ ธ์ค๊ธฐ
//* Redis ์ฐ๊ฒฐ
const redisClient = redis.createClient({ legacyMode: true }); // legacy ๋ชจ๋ ๋ฐ๋์ ์ค์ !!
redisClient.on('connect', () => {
console.info('Redis connected!');
});
redisClient.on('error', (err) => {
console.error('Redis Client Error', err);
});
redisClient.connect().then(); // redis v4 ์ฐ๊ฒฐ (๋น๋๊ธฐ)
const redisCli = redisClient.v4; // ๊ธฐ๋ณธ redisClient ๊ฐ์ฒด๋ ์ฝ๋ฐฑ๊ธฐ๋ฐ์ธ๋ฐ v4๋ฒ์ ผ์ ํ๋ก๋ฏธ์ค ๊ธฐ๋ฐ์ด๋ผ ์ฌ์ฉ
redis ํด๋ผ์ฐ๋์ ์ฐ๊ฒฐํ๊ธฐ
const express = require('express');
const dotenv = require('dotenv');
const redis = require('redis');
dotenv.config(); // envํ๊ฒฝ๋ณ์ ํ์ผ ๊ฐ์ ธ์ค๊ธฐ
//* Redis ์ฐ๊ฒฐ
// redis[s]://[[username][:password]@][host][:port][/db-number]
const redisClient = redis.createClient({
url: `redis://${process.env.REDIS_USERNAME}:${process.env.REDIS_PASSWORD}@${process.env.REDIS_HOST}:${process.env.REDIS_PORT}/0`,
legacyMode: true, // ๋ฐ๋์ ์ค์ !!
});
redisClient.on('connect', () => {
console.info('Redis connected!');
});
redisClient.on('error', (err) => {
console.error('Redis Client Error', err);
});
redisClient.connect().then(); // redis v4 ์ฐ๊ฒฐ (๋น๋๊ธฐ)
const redisCli = redisClient.v4; // ๊ธฐ๋ณธ redisClient ๊ฐ์ฒด๋ ์ฝ๋ฐฑ๊ธฐ๋ฐ์ธ๋ฐ v4๋ฒ์ ผ์ ํ๋ก๋ฏธ์ค ๊ธฐ๋ฐ์ด๋ผ ์ฌ์ฉ
Javascript Redis ๋ฌธ๋ฒ
์๋ฐ์คํฌ๋ฆฝํธ redis ๋ฌธ๋ฒ์ ๋๋ถ๋ถ redis cli ๋ฌธ๋ฒ ๊ทธ๋๋ก ๋ฉ์๋ ํํ๋ก ๋ถ์ฌ ์ฐ๋ฉด ๋๋ค.
๋ง์ผ ์๋์ ๊ฐ์ด String ํค-๊ฐ์ ๊ฐ์ ธ์ค๋ redis cli ๋ช
๋ น์ด๊ฐ ์์ ๊ฒฝ์ฐ, ์๋ฐ์คํฌ๋ฆฝํธ์์ redis db์ ์ฐ๊ฒฐํด์ค ๊ฐ์ฒด์ redisClient.๋ช
๋ น์ด(key, value) ์ด๋ฐ์์ผ๋ก ์ฌ์ฉํ๋ฉด ๋๋ค.
> set key 123
> get key
// redis v3 ๋ฌธ๋ฒ (์ฝ๋ฐฑ ํจ์ ๊ธฐ๋ฐ)
redisClient.set('key', '123');
redisClient.get('key', (err, value) => {
console.log(value); // 123
})
// redis v4 ๋ฌธ๋ฒ (ํ๋ก๋ฏธ์ค ๊ฐ์ฒด ๊ธฐ๋ฐ)
let bool = await redisClient.v4.set('key', '123'); // OK
let data = await redisClient.v4.get('key'); // 123
Redis CRUD ๊ตฌํ
const redisCli = redisClient.v4 // ๊ธฐ๋ณธ redisClient ๊ฐ์ฒด๋ ์ฝ๋ฐฑ๊ธฐ๋ฐ์ธ๋ฐ v4๋ฒ์ ผ์ ํ๋ก๋ฏธ์ค ๊ธฐ๋ฐ์ด๋ผ ์ฌ์ฉ
// GET
router.get('/', (req, res, next) => {
await redisCli.get('username');
});
// POST
router.post('/set', (req, res, next) => {
await redisCli.set('username', 'inpa');
});
// DELETE
router.delete('/del', (req, res, next) => {
// exist : ํค๊ฐ ์กด์ฌํ๋์ง
const n = await redisCli.exists('username'); // true: 1 , false: 0
if(n) await redisCli.del('username');
});
// PUT
router.put('/rename', (req, res, next) => {
// username์ด๋ผ๋ ํค๊ฐ์ด ์๋ค๋ฉด ๊ทธ ๊ฐ์ helloname์ผ๋ก ๋ฐ๊ฟ
redisCli.rename('username', 'helloname');
});
Redis ์๋ฃํ ๋ช ๋ น์ด
const redisCli = redisClient.v4 // ๊ธฐ๋ณธ redisClient ๊ฐ์ฒด๋ ์ฝ๋ฐฑ๊ธฐ๋ฐ์ธ๋ฐ v4๋ฒ์ ผ์ ํ๋ก๋ฏธ์ค ๊ธฐ๋ฐ์ด๋ผ ์ฌ์ฉ
// String
await redisCli.set('name', 'nyong')
await redisCli.get('name') // nyong
// List
await redisCli.rpush('fruits', 'apple', 'orange', 'pineapple')
await redisCli.lpush('fruits', 'banana', 'pear')
await redisCli.lrange('fruits', 0, -1) // ['pear', 'banana', 'apple', 'orange', 'apple']
// 0 ๊ณผ -1์ ์์๊ณผ ๋ ์ธ๋ฑ์ค๋ฅผ ์๋ฏธ
// Hash
await redisCli.hmset('friends', 'name', 'nyong', 'age', 30)
await redisCli.hgetall('friends') // { name : 'nyong', age : 30 }
// Set
await redisCli.sadd('fruits', 'apple', 'orange', 'pear', 'banana', 'apple')
await redisCli.smembers('fruits') // ['banana', 'apple', 'orange', 'pear'] // apple์ 2๊ฐ์ฌ์ ์ค๋ณต์ ๊ฑฐ
// Sorted Set
await redisCli.zadd('fruits', 1, 'apple', 5, 'orange', 3, 'pear', 4, 'banana', 8, 'grape')
await redisCli.zrange('fruits', 0, -1) // ['apple', 'pear', 'banana', 'orange', 'grape']
Redis Events ์ข ๋ฅ
connect | ํด๋ผ์ด์ธํธ๊ฐ ์๋ฒ์ ๋ํ ์ฐ๊ฒฐ์ด ๋ ๊ฒฝ์ฐ |
ready | ํด๋ผ์ด์ธํธ๊ฐ ์๋ฒ์ ๋ํ ์ฐ๊ฒฐ์ ์ฑ๊ณต์ ์ผ๋ก ์์ํ ๊ฒฝ์ฐ |
end | ํด๋ผ์ด์ธํธ๊ฐ .quit() ๋๋ .disconnect()๋ฅผ ํตํด ์๋ฒ ์ฐ๊ฒฐ์ ๋์์ ๊ฒฝ์ฐ |
error | ์๋ฒ์ ์ฐ๊ฒฐํ ์ ์๊ฑฐ๋ ์๊ธฐ์น ์๊ฒ ์ฐ๊ฒฐ์ด ๋์ด์ง๋ ๋ฑ ๋คํธ์ํฌ ์ค๋ฅ๊ฐ ๋ฐ์ํ ๊ฒฝ์ฐ. |
reconnecting | ํด๋ผ์ด์ธํธ๊ฐ ์๋ฒ์ ๋ค์ ์ฐ๊ฒฐ์ ์๋ํ๊ณ ์์ ๊ฒฝ์ฐ |
redisClient.on('connect', () => {
console.info('Redis connected!');
});
redisClient.on('error', (err) => {
console.error('Redis Client Error', err);
});
Redis ํธ๋์ญ์ (Transactions)
.multi() ๋ฅผ ํธ์ถํ ๋ค์ ๋ช
๋ น ๋ฉ์๋๋ค์ ์ฒด์ด๋์ผ๋ก ์ฐ๊ฒฐํ์ฌ ํธ๋์ญ์
์ ๊ตฌ์ฑํ ์ ์๋ค.
ํธ๋์ญ์ ์ด ์๋ฃ๋๋ฉด .exec()๋ฅผ ํธ์ถํ๊ณ ๊ฒฐ๊ณผ๊ฐ ํฌํจ๋ ๋ฐฐ์ด์ ๋ค์ ๋ฐ๊ฒ ๋๋ค.
await redisCli.set('another-key', 'another-value');
const [setKeyReply, otherKeyValue] = await redisCli
.multi()
.set('key', 'value')
.get('another-key')
.exec(); // ['OK', 'another-value']
์ธ๋ผ์ธ Redis Command
๋ง์ผ ์๋ฐ์คํฌ๋ฆฝํธ ํจํค์ง์์ ์ง์ํ๋ redis cli ๋ช ๋ น์ด api๊ฐ ์์ ๊ฒฝ์ฐ, ๋ค์๊ณผ ๊ฐ์ด ์ธ๋ผ์ธ์ผ๋ก ์ง์ ์ง์ ํด์ ๋ณด๋ผ์ ์๋ค. (orm์ ์ธ๋ผ์ธ ์ฟผ๋ฆฌ ๊ฐ์ ๊ฐ๋ )
await client.sendCommand(['SET', 'key', 'value', 'NX']); // 'OK'
await client.sendCommand(['HGETALL', 'key']); // ['key1', 'field1', 'key2', 'field2']
Redis ์บ์ฑ ์ ๋ต ๊ตฌํํ๊ธฐ
Cache Aside ํจํด ๊ตฌํํ๊ธฐ
app.get('/get', async (req, res) => {
let value = await redisCli.get(req.key); // redis get key ๋ฅผ ํ๋ค.
if (value) {
// ๋ง์ฝ redis(์บ์ ๋ฉ๋ชจ๋ฆฌ)์ ๋ฐ์ดํฐ๊ฐ ์๋ค๋ฉด ๊ทธ๋๋ก ๋ฐํ → Cache Hit
res.send(value);
} else {
// ๋ง์ฝ redis(์บ์ ๋ฉ๋ชจ๋ฆฌ)์ ๋ฐ์ดํฐ๊ฐ ์๋ค๋ฉด DB์์ ์กฐํ → Cache Miss
let data = await sequelize.query('SELECT data FROM tables where id = key');
await redisCli.set(key, data); // ๊ทธ๋ฆฌ๊ณ ๊ทธ ๋ฐ์ดํฐ๋ฅผ ์บ์์ ์ ์ฅํ๊ณ ๋ฐํ
res.send(value);
}
});
Cache Check ๋ฏธ๋ค์จ์ด ํ์ฉ
๋ณด๋ค ๊น๋ํ ๋ผ์ฐํ ์ฝ๋๋ฅผ ์ํ๋ค๋ฉด, express์ ๋ฏธ๋ค์จ์ด ํจ์๋ก ๋ค์๊ณผ ๊ฐ์ด ๊ตฌํํ ์๋ ์๋ค.
// ์บ์ ์ฒดํฌ๋ฅผ ์ํ ๋ฏธ๋ค์จ์ด
const checkCache = (req, res, next) => {
let value = await redisCli.get(req.key); // redis get key ๋ฅผ ํ๋ค.
if (value) {
// Redis์ ์ ์ฅ๋๊ฒ ์กด์ฌํ๋ฉด ๋ฐ๋ก ํด๋ผ์ด์ธํธ์ ์๋ต
res.send(data);
} else {
// Redis์ ์ ์ฅ๋๊ฒ ์๊ธฐ ๋๋ฌธ์ ๋ค์ ๋ฏธ๋ค์จ์ด ์คํ
next();
}
};
app.get('/get', checkCache, async (req, res) => {
// ๋ง์ฝ redis(์บ์ ๋ฉ๋ชจ๋ฆฌ)์ ๋ฐ์ดํฐ๊ฐ ์๋ค๋ฉด DB์์ ์กฐํ → Cache Miss
let data = await sequelize.query(`SELECT data FROM tables where id = ${req.key}`);
await redisCli.set(key, data); // ๊ทธ๋ฆฌ๊ณ ๊ทธ ๋ฐ์ดํฐ๋ฅผ ์บ์์ ์ ์ฅํ๊ณ ๋ฐํ
res.send(value);
});
์บ์ฑ ๊ธฐ๊ฐ ์ค์ ํ๊ธฐ
์บ์ ๋ฉ๋ชจ๋ฆฌ๋ ๊ธฐ๋ณธ์ ์ผ๋ก ์ฉ๋์ด ๋งค์ฐ ์ ๊ธฐ ๋๋ฌธ์, ๋ฐ์ดํฐ๋ฅผ ์บ์ฑํ ๋ ํญ์ ๊ธฐ๊ฐ์ ์ค์ ํ์ฌ ์๋ ์ญ์ ๋๋๋ก ์ค์ ํด์ผ ํ๋ค.
router.post('/set', (req, res, next) => {
await redisCli.set('username', 'inpa');
await redisCli.expire('username', 3600); // 3600์ด ํ์ username ํค ์ญ์
if(redisCli.ttl('username') < 300) {
// usename ํค ๋จ์ ์๊ฐ์ด 300์ด ์ดํ ์ผ ๊ฒฝ์ฐ...
}
});
await redisCli.setex('username', 3600, 'inpa'); // setex ๋ช
๋ น์ด๋ก ํค-๋ฐธ๋ฅ์ ๊ธฐ๊ฐ์ ํ๋ฒ์ ์ง์ ํ ์๋ ์๋ค.
๋ ธ๋์์ Session Store ์ฌ์ฉํ๊ธฐ
Redis ๋ฅผ ์ ์ฉํ๊ฒ ํ์ฉํ ์ ์๋ ๊ฒฝ์ฐ ๋ ํ๋๋ session ์ด๋ค.
์ผ๋ฐ์ ์ผ๋ก express-session์์์ ์ธ์ ์ ํ๋ฐ์ฑ ์ธ๋ฉ๋ชจ๋ฆฌ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ ๊น ์ ์ฅ๋๊ณ ์๋ฒ๊ฐ ์ข ๋ฃ๋๋ฉด ์ฌ๋ผ์ง๊ฒ ๋๋ค.
์ด๋ redis db์๋ฒ๋ฅผ ์ฌ์ฉํ์ฌ ์ธ์ ๊ด๋ฆฌ๋ฅผ ํ๋ฉด ์๋ฒ๊ฐ ๊บผ์ ธ๋ ๋ฐ์ดํฐ๊ฐ ์ ์ง๋๊ฒ ํ ์ ์์ผ๋ฉฐ, ๋ณต์ ์๋ฒ ํ๊ฒฝ(ํด๋ฌ์คํฐ๋ง)์์๋ ์ธ์ ์ ๊ณต์ ํ ์ ์๊ฒ ๋๋ค.
Connect-redis ์ค์น & ์ฌ์ฉ๋ฒ
connect-redis๋ ๋ฉํฐ ํ๋ก์ธ์ค ๊ฐ ์ธ์ ๊ณต์ ๋ฅผ ์ํด ๋ ๋์ค์ ์ต์คํ๋ ์ค๋ฅผ ์ฐ๊ฒฐํด์ฃผ๋ ํจํค์ง์ด๋ค.
๊ธฐ์กด์๋ ๋ก๊ทธ์ธํ ๋ express-session์ ์ธ์ ์์ด๋์ ์ค์ ์ฌ์ฉ์ ์ ๋ณด๊ฐ ์๋ฒ ๋ฉ๋ชจ๋ฆฌ์ ์ ์ฅ๋๋ค.
์ฑ๊ธ ์๋ฒ๋ฅผ ์ฌ์ฉํ ๋ ๋ฌธ์ ๊ฐ ์์ง๋ง pm2๋ฅผ ํตํด ๋ ธ๋ ํด๋ฌ์คํฐ ์๋ฒ ์ธํ๋ผ๋ฅผ ๊ตฌ์ถํ์๋ ์ธ์ ๋ถ์ผ์น ๋ฌธ์ ๊ฐ ์๊ธด๋ค.
๋ฐ๋ผ์ ์ธ์ ๋ถ์ผ์น๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด ์ด ์ธ์ ๋ฐ์ดํฐ๋ฅผ ์๋ฒ ๋ฉ๋ชจ๋ฆฌ๊ฐ ์๋ redis db์ ์ ์ฅํ๋๋ก ์ฝ๋๋ฅผ ๊ตฌํํด๋ณด์.
> npm i connect-redis
const express = require('express');
const cookieParser = require('cookie-parser');
const dotenv = require('dotenv');
const session = require('express-session');
const redis = require('redis');
const RedisStore = require('connect-redis')(session); // express-session ๊ฐ์ฒด๋ฅผ ๋ฃ๋๋ค.
dotenv.config(); // envํ๊ฒฝ๋ณ์ ํ์ผ ๊ฐ์ ธ์ค๊ธฐ
const app = express();
//* Redis ์ฐ๊ฒฐ
// redis[s]://[[username][:password]@][host][:port][/db-number]
const redisClient = redis.createClient({
url: `redis://${process.env.REDIS_USERNAME}:${process.env.REDIS_PASSWORD}@${process.env.REDIS_HOST}:${process.env.REDIS_PORT}/0`,
legacyMode: true, // ๋ฐ๋์ ์ค์ !! ์ค์ ์ํ๋ฉด connect-redis ๋์ ์ํจ
});
redisClient.on('connect', () => {
console.info('Redis connected!');
});
redisClient.on('error', (err) => {
console.error('Redis Client Error', err);
});
redisClient.connect().then(); // redis v4 ์ฐ๊ฒฐ (๋น๋๊ธฐ)
const redisCli = redisClient.v4; // ๊ธฐ๋ณธ redisClient ๊ฐ์ฒด๋ ์ฝ๋ฐฑ๊ธฐ๋ฐ์ธ๋ฐ v4๋ฒ์ ผ์ ํ๋ก๋ฏธ์ค ๊ธฐ๋ฐ์ด๋ผ ์ฌ์ฉ
//* ์ธ์
์ฟ ํค ๋ฏธ๋ค์จ์ด
app.use(cookieParser(process.env.COOKIE_SECRET));
const sessionOption = {
resave: false,
saveUninitialized: true,
secret: process.env.COOKIE_SECRET,
cookie: {
httpOnly: true,
secure: false,
},
store: new RedisStore({ client: redisClient, prefix: 'session:' }), // ์ธ์
๋ฐ์ดํฐ๋ฅผ ๋ก์ปฌ ์๋ฒ ๋ฉ๋ชจ๋ฆฌ๊ฐ ์๋ redis db์ ์ ์ฅํ๋๋ก ๋ฑ๋ก
};
app.use(session(sessionOption));
createClient({ legacyMode: true })๋ก ๋ ๊ฑฐ์ ๋ชจ๋๋ฅผ ์ค์ ํ์ง ์์ผ๋ฉด connect-redis ๋ชจ๋์ด ๋์ ์ํ๋ ์ฃผ์
sessionOption.store๋ ์ธ์ ์ ์ด๋์ ์ ์ฅํ ์ง ๊ณ ๋ฅด๋ ์ต์ ์ ๋ณด๋ก, ๊ธฐ๋ณธ๊ฐ์ ์๋ฒ์ ๋ฉ๋ชจ๋ฆฌ ์คํ ๋ฆฌ์ง์ ์ ์ฅํ๋๋ฐ, ์ด๊ฒ์ RedisStore๋ก ๋ฐ๊พธ๊ฒ ๋๋ฉด ์ธ์ ๋ฐ์ดํฐ๋ฅผ Redis์ ์ ์ฅํ๊ฒ ๋๋ค.
์ฆ, ์ฌ๊ธฐ๋์ ํ์ฌ๋ ์ธ์ ์ด ๋ ๋ผ๊ฐ๋ ๋ฌธ์ ๊ฐ ๋ฐ์ํ์ง ์๋๋ก ์ฒ๋ฆฌํด์ค ์ ์๋ค.
์ด์ ์๋ฒ๋ฅผ ์คํํด๋ณด๊ณ ๊ฐ๋ฐ์ ๋๊ตฌ์ Application ํญ์ cookies ํญ์ ํ์ธํ๋ฉด ๋ค์๊ณผ ๊ฐ์ด connect.sid ๋ก ์ธ์ ์ฟ ํค๊ฐ ์๋ช ๋์ด ์ ์ฅ๋์ด ์๋ ๊ฒ์ ๋ณผ ์ ์๋ค.
๊ทธ๋ฆฌ๊ณ redis db๋ฅผ ํ์ธํด ๋ณด๋ฉด ๋ค์๊ณผ ๊ฐ์ด session:์ธ์
ID ํํ๋ก ํค๊ฐ ์ ์ฅ ๋จ์ ํ์ธ ํ ์ ์๋ค.
๊ฐ์ ์กฐํํด ๋ณด๋ฉด ์ธ์ ์ฟ ํค ๊ฐ์ฒด๊ฐ ๋ฌธ์์ด ํํ๋ก ๋ค์ด์๋ ๊ฒ์ ํ์ธ ํ ์ ์๋ค.
Node API ์๋ฒ๋ฅผ ๊ตฌ์ถํ ๋ ์ฌ๋๋ค์ด ๋ง์ด ๋ค ์ฐ๋ api ์ฌ์ฉ๋์ ์ ํํ๋ ํจํค์ง 'express-rate-limit' ์ญ์ ์ฌ์ฉ๋์ ์๋ฒ ๋ฉ๋ชจ๋ฆฌ์ ๊ธฐ๋กํ๋ฏ๋ก ์๋ฒ๋ฅผ ์ฌ์์ํ๊ฑฐ๋ ๋ค๋ฅธ ์๋ฒ๋ก ๋ก๋๋ฐธ๋ฐ์ฑ ํ๋ฉด ์ฌ์ฉ๋ ๊ธฐ๋ก์ด ์ด๊ธฐํ๋๊ฒ ๋๋ค.
๋ฐ๋ผ์ ์ด๊ฒ๋ redis์ ๊ธฐ๋กํ๋ ๊ฒ์ด ์ข๋ค.
express-rate-limit ํจํค์ง์ rate-limit-redis ํจํค์ง๋ฅผ ๊ฐ์ด ์ฌ์ฉํ๋ฉด ๋๋ค.