[Redis] 파이프라인과 자료구조
자바, 파이썬, 자바스크립트 등 백엔드를 구축할 때 사용되는 다양한 프로그래밍 언어와 프레임워크 수준에서 Redis를 사용할 수 있도록 지원하는 라이브러리를 제공한다.
자바는 Jedis 라이브러리로 Redis를 사용하는 직관적인 API를 제공하고,
스프링 프레임워크는 Spring Data Redis 라이브러리를 사용해 스프링에서 Redis를 더 쉽게 다룰 수 있다.
이 라이브러리들은 내부적으로 Redis 명령어를 사용해 Redis 서버와 상호작용하니.. Redis의 명령어 구성을 추상화하고 프로그래밍 언어와 프레임워크의 특성에 맞춘 직관적인 API를 제공한다고 생각하면 된다.
const cacheRoutes = [
'/about', '/privacy', '/auth/signin', '/auth/signup'
]
export const getCachedPage = (route: string) => {
if (cacheRoutes.includes(route)) return client.get('pagecache#' + route);
return null;
};
export const setCachedPage = (route: string, page: string) => {
if (cacheRoutes.includes(route)) return client.set('pagecache#' + route, page, {
EX: 2,
});
};
SvelteKit 에서 Redis를 사용해 특정 라우트의 페이지를 캐싱하는 예시이다.
key - value 쌍으로 데이터를 저장하는데, key는 unique 값이고 다른 사람들이 처음 보더라도 직관적으로 이해할 수 있도록 작성해 주자.
key의 이름을 설정할 때는 보통 '-' / '#' / ':' 같은 구분자를 사용해 key를 체계적으로 관리한다.
Redis의 해시 자료구조는 key-value 쌍을 저장할 때 사용한다.
애초에 Redis는 문자열인 key와 다양한 자료구조로 이루어진 value 쌍으로 데이터를 저장하는데
해시 자료구조를 사용하면 기본적인 key - value 구조에서 또 다른 여러 key - value 쌍을 가진 자료구조를 다룰 수 있다.
다만 JSON처럼 해시 구조 안에 또 다른 해시를 값으로 저장하는건 불가능하고, 1-depth의 key-value 쌍 까지만 지원한다.
(참조 값이나 JSON 문자열을 사용하면 중첩 key-value 쌍을 흉내 낼 수는 있다)
데이터가 여러 속성 값을 가지거나, 정렬된 리스트 형태인 경우 해시 자료구조를 사용해 데이터를 저장하는게 합리적이고
상품의 좋아요, 조회수 같은 단일 값을 저장하는 경우 다른 자료구조를 사용한는 편이 합리적이다.
RDB를 다룰 때는 스키마 기반으로 데이터를 조직화하지만, Redis는 스키마를 사용하지 않는 NoSQL 데이터베이스로 각 데이터 유형에 가장 적합한 자료구조를 선택해야 한다. (Sorted Set, HyperLogLogs, List ...)
export const getUserById = async (id: string) => {
const user = await client.hGetAll(usersKey(id));
return deserialize(id, user);
};
export const createUser = async (attrs: CreateUserAttrs) => {
const id = genId();
await client.hSet(usersKey(id), serialize(attrs));
return id;
};
const serialize = (user: CreateUserAttrs) => {
return {
username: user.username,
password: user.password
}
}
const deserialize = (id: string, user: {[key: string]: string}) => {
return {
id: id,
username: user.username,
password: user.password
}
}
Redis는 기본적으로 데이터를 저장할 때 문자열을 사용하고, 메모리를 저장소로 사용하니 불필요한 요소를 제거해 줘야 한다.
예시는 node-redis 라이브러리를 사용해 Redis를 다루는데, 이 때 serialize와 deserialize를 사용해 불필요한 요소를 제거하고 저장 형식으로 데이터를 조작한다.
export const getItems = async (ids: string[]) => {
const commands = ids.map((id => {
return client.hGetAll(itemsKey(id));
}))
const results = await Promise.all(commands);
return results.map((result, i) => {
if(Object.keys(result).length === 0) return null;
return deserialize(ids[i], result);
})
};
export const getItems2 = async (ids: string[]) => {
const pipeline = client.pipeline();
pipeline.set('key1', 'value1');
pipeline.get('key1');
pipeline.set('key2', 'value2');
pipeline.get('key2');
const results = await pipeline.exec();
return results;
};
Redis는 Pipeline으로 여러 명령을 모아두고 한 번에 처리한다.
여러 명령을 한 번에 서버로 전송하니 네트워크를 한 번만 타게 돼 오버헤드가 줄고, 명령을 연속적으로 빠르게 처리할 수 있어 효과적이다.
Redis 클라이언트 라이브러리는 대부분 파이프라인을 지원해 코드를 쉽게 작성할 수 있다.
예시는 node-redis 라이브러리로 파이프라인을 사용한다.
여러 명령어를 한 번에 처리할 때 파이프라인을 사용하는게 효과적이긴 하지만..
그 전에 Redis가 제공하는 다른 명령어들로 연산을 최적화하는게 중요하다.
Redis 가 제공하는 명령어 중 SORT 명령어에 대해 살펴보자.
SORT key [BY pattern] [LIMIT offset count] [GET pattern [GET pattern ...]] [ASC | DESC] [ALPHA] [STORE destination]
let results: any = await client.sort(
itemsByViewsKey(),
{
GET: [
'#',
`${itemsKey('*')}->name`,
`${itemsKey('*')}->views`,
`${itemsKey('*')}->endingAt`,
`${itemsKey('*')}->imageUrl`,
`${itemsKey('*')}->price`,
],
// BY: 'score',
BY: 'nosort',
DIRECTION: order,
LIMIT: {
offset,
count
}
}
)
SORT items:views BY 'nosort' GET '#' GET 'items#1->name' GET 'items#1->views' GET 'items#1->endingAt' GET 'items#1->imageUrl' GET 'items#1->price' DESC LIMIT 0 10
SORT 명령어는 이름처럼 정렬을 수행하기도 하지만.. BY 와 GET 명령어를 사용해 특정 값이 다른 key에 저장된 경우 해당 key를 참조해서 값을 다룰 수 있는 기능을 제공한다.
SQL에서 FK로 조인을 걸어 값을 다루는것과 유사하니.. 간단한 조인 작업을 수행할 수 있다고 생각하면 된다.
기본적으로 자료구조를 순회하니 현재 참조하는 값은 *로 가져올 수 있고 -> 로 해시 자료구조의 필드에 접근할 수 있다.
#은 정렬된 요소 자체를 의미한다.
'Database > Redis' 카테고리의 다른 글
[Redis] Stream (0) | 2024.10.10 |
---|---|
[Redis] Module - RediSearch (0) | 2024.10.06 |
[Redis] 동시성 제어 (4) | 2024.05.25 |
[Redis] 캐시 서버와 명령어 (0) | 2024.04.27 |
댓글
이 글 공유하기
다른 글
-
[Redis] Stream
[Redis] Stream
2024.10.10 -
[Redis] Module - RediSearch
[Redis] Module - RediSearch
2024.10.06 -
[Redis] 동시성 제어
[Redis] 동시성 제어
2024.05.25 -
[Redis] 캐시 서버와 명령어
[Redis] 캐시 서버와 명령어
2024.04.27