캐싱이란 나중에 해당 데이터에 액세스하는 데 걸리는 시간을 줄이기 위해 메모리나 SSD와 같이 빠르게 액세스할 수 있는 위치에 데이터를 임시로 저장하는 컴퓨팅 기술이다.
캐싱 이면의 아이디어는 곧 다시 필요할 가능성이 있는 데이터를 하드 디스크 드라이브와 같이 더 느리고 더 먼 저장 위치에서 액세스해야 하는 경우보다 더 빨리 검색할 수 있는 위치에 저장하는 것이다.
캐싱은 하드웨어 수준(예: CPU 캐시)에서 애플리케이션 수준(예: 웹 페이지 캐싱)까지 컴퓨팅 시스템의 다양한 수준에서 구현될 수 있다.
웹 개발 맥락에서 캐싱은 브라우저나 프록시 서버에 자주 액세스하는 콘텐츠(예: 이미지, CSS 파일, JavaScript 파일)를 저장하여 웹 페이지의 전달 속도를 높이는 데 자주 사용된다.
콘텐츠를 더 빠르게 제공할 수 있고 이는 페이지 로드 시간을 줄이고 네트워크를 통해 전송해야 하는 데이터 양을 최소화하여 사용자 경험을 향상시킬 수 있다.
백엔드 관점에서 캐싱은 애플리케이션의 성능과 효율성을 향상시키기 위해 캐시에 데이터를 임시로 저장하는 것을 말한다.
애플리케이션이나 웹사이트가 클라이언트로부터 요청을 받으면 해당 요청을 이행하는 데 필요한 데이터를 가져와야 한다. 이는 특히 데이터가 원격 데이터베이스나 서비스에 저장된 경우 시간이 많이 걸리는 프로세스일 수 있다. 동일한 데이터를 반복적으로 가져오는 오버헤드를 피하기 위해 캐싱을 사용하면 애플리케이션이 데이터를 캐시에 임시로 저장할 수 있다. 캐시는 일반적으로 원래 데이터 소스보다 액세스 속도가 빠르다.
다음에 동일한 요청이 있을 때 애플리케이션은 원래 데이터 소스로 이동하는 대신 캐시에서 데이터를 가져올 수 있으므로 응답 시간이 크게 단축되고 애플리케이션의 전반적인 성능이 향상될 수 있다.
캐싱은 웹 페이지, 데이터베이스 쿼리, API 응답 등과 같이 자주 변경되지 않는 자주 액세스되는 데이터에 대한 백엔드 개발에서 자주 사용된다. 이 데이터를 캐싱함으로써 애플리케이션은 데이터를 반복적으로 가져오는 것을 방지하고 사용자 경험을 개선할 수 있다.
Redis
: Redis
는 데이터베이스, 캐시 및 메시지 브로커로 사용할 수 있는 메모리 내 데이터 구조 저장소이다. 높은 성능과 많은 양의 데이터를 처리할 수 있는 능력 때문에 캐싱 도구로 자주 사용된다.
Amazon ElastiCache
: Amazon ElastiCache
는 아마존에서 제공하는 서비스로 클라우드에서 인 메모리 데이터 스토어 또는 캐시를 손쉽게 구축, 운영 및 확장할 수 있도록 지원하는 웹 서비스이다. 이 서비스는 더 느린 디스크 기반 데이터베이스에 전적으로 의존하기보다는, 빠른 관리형 인 메모리 데이터 스토어에서 정보를 검색할 수 있도록 지원하여 웹 애플리케이션의 성능을 높인다.
Memcached
: Memcached
는 범용 분산 메모리 캐싱 시스템이다. 외부 데이터 소스(예: 데이터베이스)를 읽어야 하는 횟수를 줄이기 위해 데이터와 개체를 RAM에 캐싱하여 동적 웹 응용 프로그램의 속도를 높이는 데 자주 사용된다.
Varnish
: Varnish
는 웹 페이지 및 기타 HTTP 요청을 캐시하는 HTTP 가속기이다. 요청이 있을 때마다 서버에서 검색하는 대신 캐시된 콘텐츠를 메모리에서 직접 제공하여 웹 사이트 속도를 높이는 데 자주 사용된다.
Squid
: Squid
는 웹 페이지, DNS 조회 및 기타 네트워크 리소스를 캐싱하는 데 사용할 수 있는 캐싱 프록시 서버이다. 메모리에서 캐시된 콘텐츠를 제공하여 웹 애플리케이션 속도를 높이고 대역폭 사용량을 줄이는 데 자주 사용된다.
Nginx
: Nginx
는 캐싱 도구로도 사용할 수 있는 고성능 웹 서버 및 리버스 프록시이다. 웹 페이지 및 기타 리소스를 메모리에 캐시하도록 구성하여 웹 애플리케이션 속도를 높이고 서버 부하를 줄일 수 있다.
Redis는 데이터베이스, 캐시 및 메시지 브로커로 사용할 수 있는 메모리 내 데이터 구조 저장소이다. 키-값 저장소 또는 NoSQL 데이터베이스라고도 하며 이는 데이터를 키-값 쌍으로 저장한다는 의미이다. Redis는 고성능, 확장성 및 안정성을 위해 2009년 살바토르 산필리포가 처음 개발했고 2015년부터 Redis Labs가 지원하고 있다.
Redis는 종종 캐시로 사용된다. 데이터가 메모리에 저장되기 때문에 디스크에 저장된 경우보다 훨씬 빠르게 액세스할 수 있다. 또한 개발자가 사용자 세션 데이터를 메모리에 저장하여 웹 애플리케이션의 성능을 크게 향상시킬 수 있으므로 세션 관리에 자주 사용된다.
Redis에는 문자열, 해시, 목록, 세트 및 정렬된 세트를 포함하여 여러 데이터 구조가 내장되어 있다. 이를 통해 개발자는 응용 프로그램의 요구 사항에 따라 다양한 방식으로 데이터를 저장하고 조작할 수 있다.
또한 Redis에는 고가용성 및 장애 조치를 위해 서버 클러스터에서 Redis를 실행할 수 있는 복제, 개발자가 사용자 지정 스크립트를 작성하여 Redis에서 데이터를 조작할 수 있는 Lua 스크립팅과 같은 여러 고급 기능이 있다.
전반적으로 Redis는 웹 애플리케이션의 성능과 안정성을 개선하기 위해 다양한 방법으로 사용할 수 있는 강력하고 유연한 도구이다.
속도
: Redis는 매우 빠르고 초당 많은 양의 요청을 처리할 수 있으므로 빠른 데이터 액세스가 필요한 실시간 애플리케이션에 적합하다.
유연성
: Redis는 문자열, 해시, 목록, 세트 등을 포함한 광범위한 데이터 구조를 지원한다. 따라서 캐싱, 세션 관리 및 실시간 메시징과 같은 다양한 사용 사례에 적합하다.
확장성
: Redis는 수평적으로 쉽게 확장할 수 있으므로 트래픽이 증가함에 따라 클러스터에 더 많은 노드를 추가할 수 있다.
지속성
: Redis는 데이터 지속성을 지원하므로 데이터를 디스크에 저장하고 나중에 복원할 수 있다. 따라서 Redis는 장기간 데이터를 저장해야 하는 애플리케이션에 적합하다.
커뮤니티
: Redis에는 개발에 기여하고 지원을 제공하며 유용한 타사 도구 및 라이브러리를 생성하는 크고 활동적인 커뮤니티가 있다.
메모리 내 제한
: Redis는 모든 데이터를 메모리에 저장하므로 대용량 데이터 세트의 경우 제한이 될 수 있다. 즉, Redis는 많은 양의 데이터를 저장해야 하는 애플리케이션에 최선의 선택이 아닐 수 있다.
단일 스레드
: Redis는 단일 스레드이므로 한 번에 하나의 명령만 처리할 수 있다. 이는 일부 사용 사례에서 이점이 될 수 있지만 일부 시나리오에서는 성능을 제한할 수도 있다.
데이터 일관성
: Redis는 엄격한 데이터 일관성을 보장하지 않는다. 즉, 메모리에 저장된 데이터와 디스크에 저장된 데이터 간에 약간의 불일치가 있을 수 있다.
복잡성
: Redis는 추가 리소스와 전문 지식이 필요할 수 있는 다른 캐싱 솔루션보다 설정 및 구성이 더 복잡할 수 있다.
SQL 지원 안 함
: Redis는 광범위한 데이터 구조를 지원하지만 기존 SQL은 지원하지 않으므로 일부 사용 사례에 제한이 있을 수 있다.
(Weekly Downloads가 360만이다. (redis는 310만))
ioredis
는 Redis 데이터베이스에 연결하고 상호 작용하기 위한 사용하기 쉬운 인터페이스를 제공하는 인기 있는 Redis용 Node.js 클라이언트이다.
다음과 같이 Redis 클라이언트 라이브러리에 비해 많은 기능과 이점을 제공한다.
고성능
: ioredis는 처음부터 성능을 염두에 두고 제작되었다. 한 번에 Redis에 여러 명령을 보낼 수 있는 파이프라이닝 기술을 사용하여 결과를 얻는 데 필요한 왕복 횟수를 줄인다. 또한 즉시 사용 가능한 클러스터링을 지원하므로 수평으로 쉽게 확장할 수 있다.
더 많은 기능
: ioredis는 Redis의 모든 기능과 많은 추가 기능을 지원한다. 예를 들어 Lua 스크립팅, 트랜잭션, 게시/구독 메시징 등을 기본적으로 지원한다.
향상된 안정성
: ioredis에는 Redis와의 연결이 끊어진 경우 자동 재연결 지원 기능이 내장되어 있다. 또한 바로 사용 가능한 센티널 및 클러스터 모드를 지원하므로 고가용성 Redis 클러스터를 보다 쉽게 설정할 수 있다.
더 나은 개발자 경험
: ioredis에는 일관되고 직관적인 현대적이고 사용하기 쉬운 API가 있다. 또한 훌륭한 문서와 번성하는 커뮤니티가 있어 질문에 대한 답을 쉽게 찾을 수 있다.
먼저 자신의 프로젝트에서 ioredis를 설치해준다.
yarn add ioredis
redis를 사용하는 미들웨어
// cache.js
const Redis = require('ioredis'); // ioredis 라이브러리 가져오기
const redisClient = new Redis(); // 새 Redis 클라이언트 인스턴스 생성 (따로 설정이 없으면 127.0.0.1:6379 에서 실행된다.)
const cacheMiddleware = async (req, res, next) => {
try {
const cachedResponse = await redisClient.get(req.originalUrl);
if (cachedResponse) {
console.log('Serving response from cache');
res.send(JSON.parse(cachedResponse));
return;
} // 미들웨어 기능 내에서 먼저 Redis에서 요청된 URL에 대해 캐시된 응답이 있는지 확인하고 캐시된 응답이 있으면 클라이언트로 다시 보낸다.
res.sendResponse = res.send;
res.send = async body => {
await redisClient.set(req.originalUrl, JSON.stringify(body), 'EX', 3600);
res.sendResponse(body);
}; // 캐시된 응답이 존재하지 않는 경우 res.send() 메서드를 가로채 응답을 클라이언트에 다시 보내기 전에 캐시한다. TTL(time-to-live)이 1시간인 요청된 URL을 키로 사용하여 Redis에 대한 응답을 저장한다. 그런 다음 res.sendResponse()를 호출하여 응답을 다시 클라이언트로 보낸다.
next();
} catch (error) {
console.error(error);
next();
}
};
module.exports = cacheMiddleware;
비교를 위해 만든 API
모든 게 똑같고 cache 미들웨어를 중간에 사용하는지 안 하는지만 다르다.
// index.js
const express = require('express');
const redis = express.Router();
const cacheMiddleware = require('middlewares/cache');
const { getFileLocal, getFileCache } = require('./redis.ctrl');
redis.get('/local', getFileLocal); // redis를 사용하지 않았을 때
redis.get('/cache', cacheMiddleware, getFileCache); // redis를 사용했을 때
module.exports = redis;
// redis.ctrl.js
const asyncWrapper = require('middlewares/async-wrapper');
const { getFileLocal, getFileCache } = require('./redis.svc');
exports.getFileLocal = asyncWrapper(async (req, res) => {
const file = await getFileLocal();
res.status(200).send(file);
});
exports.getFileCache = asyncWrapper(async (req, res) => {
const file = await getFileCache();
res.status(200).send(file);
});
// redis.svc.js
const axios = require('axios');
exports.getFileLocal = async () => {
const { data } = await axios.get(
'https://jsonplaceholder.typicode.com/todos', // 데이터를 주는 API
);
return data;
};
exports.getFileCache = async () => {
const { data } = await axios.get(
'https://jsonplaceholder.typicode.com/todos',
);
return data;
};
redis를 사용하지 않았을 때
redis를 사용했을 때
속도가 평균 40ms -> 1ms로 빨라졌다. (불러오는 데이터가 클수록 더 차이가 크다.)
다음에는 redis를 통한 세션 관리에 관한 글을 작성하겠습니다.