토큰 인증과 빈번한 데이터 조회가 많은 시스템에서는 성능과 보안 모두를 고려한 저장소 선택이 필요하다.
이번에는 Spring Boot 프로젝트에 Redis를 적용하여 Refresh Token을 안전하게 관리하고,
사용자 일정 데이터를 캐싱해 속도를 최적화한 과정을 정리했다.
Redis 란?
Redis는 Key-Value 기반의 인메모리 저장소이다.
모든 데이터를 메모리(RAM)에 저장하기 때문에 일반적인 관계형 데이터베이스보다 훨씬 빠르다.
특징
- 초고속 읽기/쓰기: 모든 데이터는 메모리에 상주한다.
- TTL 지원: key마다 만료시간 설정이 가능하다.
- 다양한 자료구조 지원: String, List, Set, Hash 등
- 서버 간 공유 용이: 여러 애플리케이션이 하나의 Redis 인스턴스를 공유한다.
- 적용 사례: 인증 토큰, 세션 관리, 캐시, 실시간 랭킹 시스템 등
Redis 적용
우선 Mac기준으로 Redis를 설치한다.
brew install redis
brew services start redis
# 정상 설치 확인
redis-cli ping
# → "PONG" 출력되면 정상
그 다음 Gradle 의존성을 추가하고
application.yml에 다음과 같이 설정한다.
spring:
data:
redis:
host: localhost
port: 6379
Redis 설정 클래스
@Configuration
public class RedisConfig {
@Bean
public RedisConnectionFactory redisConnectionFactory() {
return new LettuceConnectionFactory();
}
@Bean
public RedisTemplate<String, String> redisTemplate() {
RedisTemplate<String, String> template = new RedisTemplate<>();
template.setConnectionFactory(redisConnectionFactory());
template.setKeySerializer(new StringRedisSerializer());
template.setValueSerializer(new StringRedisSerializer());
return template;
}
}
Refresh Token을 Redis에 저장하기
@Service
@RequiredArgsConstructor
public class RefreshTokenService {
private final RedisTemplate<String, String> redisTemplate;
private static final long EXPIRATION = 7 * 24 * 60 * 60; // 7일
public void save(Long userId, String token) {
redisTemplate.opsForValue().set("refreshToken:" + userId, token, EXPIRATION, TimeUnit.SECONDS);
}
public Optional<String> get(Long userId) {
return Optional.ofNullable(redisTemplate.opsForValue().get("refreshToken:" + userId));
}
public void delete(Long userId) {
redisTemplate.delete("refreshToken:" + userId);
}
}
기존에는 DB에 저장하던 Refresh Token을 Redis에 옮겨
읽기/쓰기 속도가 향상되었고, 로그아웃 시 즉시 삭제가 가능하고,
TTL 설정으로 자동 만료도 가능하고, 다중 서버 환경에서 공유가 가능해졌다.
일정 데이터 캐싱
public List<ApplicationDTO> getAllApplicationsByUserId(Long userId) {
String cacheKey = "applications:user:" + userId;
String cachedData = redisTemplate.opsForValue().get(cacheKey);
if (cachedData != null) {
try {
return objectMapper.readValue(cachedData, new TypeReference<>() {});
} catch (Exception e) {
redisTemplate.delete(cacheKey); // 파싱 실패 시 캐시 제거
}
}
// DB 조회 → 캐싱
List<ApplicationDTO> result = applicationRepository.findApplicationsByUserId(userId)
.stream().map(this::convertToDTO).collect(Collectors.toList());
try {
String json = objectMapper.writeValueAsString(result);
redisTemplate.opsForValue().set(cacheKey, json, 5, TimeUnit.MINUTES);
} catch (Exception ignored) {}
return result;
}
Redis 적용시 주의사항
- TTL 설정: 만료 시간이 없다면 무한히 남아있게 된다. → 메모리 낭비 유발
- Key prefix 관리: refreshToken:, applications:user: 처럼 일관된 네이밍으로 구분해야 한다.
- 예외 처리: Redis 장애 시 fallback 로직이 필요하다. (예: DB 조회로 대체)
- 보안 설정: 운영환경에서는 Redis에 비밀번호 설정 또는 TLS 적용을 권장한다.
- 용도 구분: 인증/세션용 Redis와 캐시용 Redis를 분리할 수도 있다. (Redis Cluster)
마무리
Redis는 단순한 캐시 서버가 아니라, 빠르고 확장 가능한 인메모리 저장소로서
인증, 세션, 캐싱, 실시간 처리 등 다양한 분야에 적용할 수 있다.
이번 구현을 통해 Refresh Token은 TTL이 있는 안전한 저장소로 이전되었고,
자주 조회되는 일정 데이터는 Redis에 캐시되어 성능이 향상되었다.
'프로젝트 > 기업 일정 관리 웹' 카테고리의 다른 글
CI/CD 1 : GithubActions (0) | 2025.04.03 |
---|---|
REST API 에서 Enum 직렬화 문제 (0) | 2025.04.02 |
도메인 별 SSL 인증서 문제 해결 (0) | 2025.04.02 |
CORS 정책 오류 해결 (0) | 2025.04.02 |
Access Token & Refresh Token 설계와 구현 (0) | 2025.04.02 |