티스토리 뷰
개인 프로젝트에서 redis를 도입했던 사례를 공유하겠다.
redis는 데이터를 메모리에 저장하기에 빠른 성능을 나타낸다.
또한 ttl이라는 유효기간을 통해 별도의 삭제 처리 없이 간단한 구현을 할 수 있다.
아래는 redis를 사용하기 좋은 사례들이다.
- RDB의 부하를 줄이고 성능 향상을 위한 캐시 용도
- 좋아요 수, 조회수, 인기 게시글, 사용자 정보
- 분산 서버 환경에서 각 서버에 공유되어야할 정보
- 사용자 세션, 리프레시 토큰, 분산락
- 데이터의 유효기간이 존재하는 경우
- 3분 동안 유효한 인증 코드, 알림, 최근 읽은 게시글 목록, 최근 1개월간 담은 장바구니
위의 사례들 중 내가 적용했던 사레들을 공유하겠다.
RDB 부하 분산 및 성능 향상 목적의 캐시 목적 사례
사용자 정보
HandlerMethodArgumentResolver를 사용하면 컨트롤러 메서드의 파라미터에 특정 어노테이션을 붙여주면 값을 넣어 줄 수 있다.
나의 경우 사용자 id, email, 권한 정보 등을 넣어주고 있다.
@Component
@Qualifier("userDetail")
public class UserDetailArgumentResolver implements HandlerMethodArgumentResolver {
@Override
public boolean supportsParameter(MethodParameter parameter) {
// 특정 어노테이션 붙어 있는 경우 활성화
}
@Nullable
@Override
public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) {
// rdb에서 사용자 정보 조회하여 리턴
}
}
@PostMapping("")
fun likeContents(
@UserId userId: UUID, // 추출된 사용자 정보
): ResponseEntity<ResponseData<Any>> {
// 로직 수행
}
세션을 사용하지 않는 stateless한 서버 프로젝트에서는 api 요청마다 rdb에 접근하여 사용자 정보를 가져와야한다.
비즈니스 로직을 수행하기 위해 사용자 정보는 필수적인데 rdb에 접근하지 않고, Redis에 캐싱하여 사용한다면 RDB의 부하도 줄일 수 있고, 성능 향상 또한 이룰 수 있다.
캐싱 시점 | 클라이언트 요청 인증/인가 시점 - 인증/인가 로직 수행시 사용자 인증 정보를 가져오는데 look-aside 방식으로 redis에 존재하면 redis에서 조회 미존재시 RDB에서 조회한 후 redis에 캐싱 |
삭제시점 | 사용자 정보 중 하나라도 변경이 이뤄진다면 데이터의 일관성이 깨지므로 삭제 처리 진행 - 회원정보 수정 - 회원 탈퇴 |
ttl | 캐시 히트율을 높이고 불필요하게 오래 저장하지 않도록 하기 위해 사용자 평균 접속 시간 조금 길게 설정 - 3시간 |
자료구조 | RedisHash를 사용함 - 간편한 구현을 위해서 - 만약 polyglot한 환경이라면 자바의 클래스 타입까지 함께 저장되는 RedisHash 보다는 json 타입으로 저장해야함 |
좋아요
좋아요 기능은 생성과 삭제가 빈번하게 일어난다는 특징을 갖는다.
이를 고려하여, 좋아요 정보를 캐싱하기 위해 Look-Aside 방식과 Write-Back 방식을 함께 사용하였다.
Look-Aside 방식은 조회 시 캐시 DB(Redis)에 먼저 접근하고, 데이터가 없을 경우 RDB에서 조회한 뒤 캐시에 저장하는 방식이다.
이 방식은 캐시 DB에 장애가 발생하더라도 RDB에서 데이터를 가져올 수 있으므로 안정성 측면에서 유리하다.
한편, Write-Back 방식은 쓰기 작업 발생 시 RDB에 즉시 반영하지 않고, 먼저 캐시 DB에만 저장한 뒤 비동기적으로 일괄 처리(batch) 방식으로 RDB에 반영한다.
이는 생성/삭제 요청이 빈번한 좋아요와 같은 기능의 응답 속도 개선과 RDB 부하 완화에 효과적이다.
다만, Write-Back 전략은 데이터가 RDB에 반영되기 전 캐시가 손실될 경우, 데이터 유실의 위험성이 존재한다.
만약 자신의 서비스에서 좋아요 정보가 어느 정도 데이터 손실이 발생하더라도 괜찮다면 이와 같은 방식이 적절한 선택이 될 수 있으나,
데이터 유실에 민감하다면 다른 장애 대응 로직을 고려해볼 필요가 있다.(ex. kafka)
캐싱 시점 | - 게시글 상세 조회시 - 좋아요 누를시 set에 userId 저장 |
삭제시점 | - 좋아요 취소 누를시 set에서 userId 삭제 |
ttl | 3시간 |
사용목적 | 신규 좋아요 사용자 정보를 캐싱 후에 RDB에 일괄 반영하여 쓰기 부하 줄이는 목적 |
자료구조 | Set |
분산 서버 환경에서 각 서버에 공유되어야할 정보
세션
이를 위해 분산된 서버 환경에서는 세션이 공유될 필요가 있고 세션 공유 방법을 세션 클러스터링이라고 한다.
Redis를 이용한 세션 클러스터링 방법은 세션을 관리할 서버를 따로 두어 사용하는 방식이다.
위와 같이 서버에서 세션을 Redis 서버로 보내주어 세션을 관리하면 사용자의 서버의 접속 경로가 바뀌게 되더라도
세션이 서버에서 관리되지 않고 별도 외부 서버에서 관리되므로 로그인이 계속 유지된채로 사용할 수 있다.
이부분은 아래 블로그글 참고하기 바란다.
리프레시 토큰
리프레시 토큰은 액세스 토큰을 재발급하는 용도로 사용된다.
액세스 토큰의 경우 토큰 내부에 사용자 식별값을 포함하기에 유효기간을 짧게 설정하고 리프레시 토큰을 상대적으로 유효기간을 길게하고 액세스 토큰을 주기적으로 재발급하도록 하여 보안성을 강화시킨다.
이때 리프레시 토큰 또한 서버 측에서 관리하게 되면 보안성을 더욱 강화시킬 수 있다.
나의 경우 리프레시 토큰 발급자 정보를 서버측에서 관리하여 액세스 토큰 발급자와 리프레시 토큰의 발급자가 같은지 검증하고 있다.
이를 통해 해커가 액세스 토큰을 탈취하고 리프레시 토큰은 다른 무작위 사용자로 부터 탈취하여 사용하는 사례를 방지할 수 있다.
(물론 한 사용자의 액세스 토큰과 리프레시 토큰 모두 탈취 되는 경우에는 토큰 관리 방식만으로는 보안성 강화하는데 한계가 있기에 2차 인증과 같은 별도의 장치가 필요하다.)
캐싱 시점 | 클라이언트 요청 인증/인가 시점 - 인증/인가 로직 수행시 리프레시 토큰의 발급자와 액세스 토큰의 발급자 같은지 검증 하기 위해 RDB에 미리 저장해둔 정보를 가져오는데 이 시점에 캐싱함 |
삭제시점 | - 로그아웃(로그아웃 했다면 앞으로 해당 리프레시 토큰을 사용하지 못하게 삭제해야함) - 로그인(혹시나 브라우저 저장소에 토큰이 남아있다면 해당 정보를 삭제해야함) - 리프레시 토큰 유효기간 만료시 |
ttl | - 45일 |
자료구조 | 문자열 |
분산락
분산 락이란 분산 서버 환경에서 공유 자원에 대한 제어가 필요한 경우 하나의 중앙 서버에서 락을 위치시키고 잠금 매커니즘이 구현될 수 있도록 한 것이다.
내용이 길고 알아야할 부분이 많기에 아래 포스팅에서 별도로 설명해두었다.
데이터의 유효기간이 존재하는 경우
이메일 인증 코드
서비스에서 회원가입시 이메일 인증코드를 발급한다.
발급한 인증코드는 3분내에 입력하여 본인이 해당 이메일의 소유주라는 것을 검증해야한다.
따라서 해당 인증코드는 3분 동안만 유효한 정보이며 이후에는 관리할 필요가 없는 정보이다.
이렇게 데이터의 유효기간이 존재한다는 것은 데이터가 영구 저장될 필요가 없다는 것을 의미하기도 한다.
Redis의 TTL 기능을 사용한다면 유효 시간 내에만 데이터를 관리할 수 있어 메모리 관리 측면에서도 효율적이며
애플리케이션 구현도 굉장히 단순해진다.
캐싱 시점 | 인증 코드 발급시 |
삭제시점 | 별도로 구현 필요 없음 - 재발급시에도 키값이 같다면 덮어쓰기처럼 수행 되기에 기존 정보를 삭제할 필요 없음 |
ttl | 3분 |
자료구조 | RedisHash - 구현을 단순화할 목적으로 RedisHash 사용 |
'DB > redis' 카테고리의 다른 글
스프링 Redis 연동(feat. 스프링 캐시) (4) | 2025.07.17 |
---|---|
Redis 자료구조(feat. 시간복잡도) (0) | 2025.07.14 |
Redis - 싱글스레드, 영구성, 고가용성(feat. docker 환경설정) (1) | 2025.07.14 |
분산락을 활용한 동시성 제어[2] - 레디스 분산락 (0) | 2025.06.10 |
분산락을 활용한 동시성 제어[1] - mysql 네임드 락 (1) | 2025.06.10 |