밤빵's 개발일지
[WIL]20240811 Redis 본문
로그인기능을 맡았을 때, Redis에 저장한다고 해서 생전 처음듣는거라 기능구현을 다른 팀원분이 해줬던 경험이 있다. 기능 구현을 하면서 많은 시간이 지났는데 구현해내지 못한게 가장컸고, Redis를 알지도 못 하니 당연한 결과였다. 다른 프로젝트에 참여하게 되서도 심심찮게 Redis가 들려서 며칠 Redis에 대해 틈틈이 공부하기 시작했다.
Redis는 고성능의 인메모리 데이터 저장소로, 다양한 데이터 구조를 지원하는 NoSQL 데이터베이스이다. Redis는 Remote Dictionary Server의 약자로, 키-값(Key-Value) 저장소를 기반으로 빠른 읽기/쓰기 성능을 제공하며, 캐싱, 세션 저장소, 실시간 분석, 메시지 큐 등의 다양한 용도로 사용된다.
🫨Redis?
Redis는 메모리 내에서 데이터를 저장하고 관리하는 오픈 소스 기반의 NoSQL 데이터베이스이다. Redis는 단순한 키-값 저장소를 넘어서, 다양한 데이터 구조(문자열, 해시, 리스트, 세트, 정렬된 세트 등)를 지원하며, 복제, 스냅샷, 퍼시스턴스 등의 기능을 통해 데이터의 일관성과 안정성을 보장한다.
▶Redis의 주요 특징
Redis는 다음과 같은 특징을 가지고 있다:
→ 인메모리 데이터 저장소:
데이터를 메모리에 저장하므로, 디스크 기반의 데이터베이스보다 훨씬 빠른 읽기/쓰기 성능을 제공한다.
→ 다양한 데이터 구조 지원:
문자열(String), 해시(Hash), 리스트(List), 셋(Set), 정렬된 셋(Sorted Set), 비트맵(Bitmap), 하이퍼로그로그(HyperLogLog), 지리공간 인덱스(Geospatial Index) 등을 지원한다.
→ 데이터 영속성:
메모리 내 데이터는 기본적으로 휘발성이지만, Redis는 스냅샷(RDB)와 명령어 로그(AOF) 방식을 통해 데이터의 영속성을 보장할 수 있다.
→ 분산 및 클러스터링:
Redis는 기본적으로 싱글 스레드로 작동하지만, 클러스터링 기능을 통해 여러 서버에 데이터를 분산하여 저장하고 관리할 수 있다.
→ 트랜잭션 지원:
MULTI, EXEC, DISCARD, WATCH 등의 명령어를 통해 트랜잭션을 지원하며, 원자성을 보장할 수 있다.
→ 간편한 사용법:
간단한 명령어 기반으로 동작하며, 다양한 프로그래밍 언어에 대한 클라이언트 라이브러리를 제공하여 손쉽게 사용할 수 있다.
▶ Redis의 장단점
▷장점
→ 빠른 성능:
데이터를 메모리에 저장하므로 빠른 응답 속도를 제공한다. 이는 주로 캐싱, 세션 관리, 실시간 데이터 처리에 적합하다.
→ 다양한 데이터 구조 지원:
Redis는 다양한 데이터 타입을 지원하므로, 복잡한 데이터 모델링을 할 수 있다.
→ 데이터 복제 및 장애 조치:
Redis는 Master-Slave 복제와 Sentinel 모드를 통해 고가용성과 데이터의 안전성을 보장할 수 있다.
→ 확장성:
Redis 클러스터를 통해 수평적 확장이 가능하며, 높은 트래픽과 데이터를 처리할 수 있다.
→ 간편한 설정 및 사용:
Redis는 설정이 간단하고, 명령어 기반으로 쉽게 사용할 수 있다.
▷단점
→ 메모리 의존성:
Redis는 메모리에 데이터를 저장하므로, 메모리 용량이 제한된다. 대규모 데이터 저장에는 적합하지 않을 수 있다.
→ 데이터 영속성 이슈:
기본적으로 메모리 기반이기 때문에 데이터 영속성이 디스크 기반의 데이터베이스만큼 강력하지 않다. 이를 해결하기 위해서는 추가적인 설정과 비용이 필요하다.
→ 싱글 스레드의 한계:
Redis는 기본적으로 싱글 스레드로 작동하므로, CPU 사용률이 높아질 수 있으며, 복잡한 연산을 수행할 때 성능 저하가 발생할 수 있다.
→ 복잡한 데이터 구조 사용 시 주의 필요:
Redis의 고유한 데이터 구조는 다양한 기능을 제공하지만, 잘못된 사용이나 무리한 확장성 요구는 성능 문제를 야기할 수 있다.
▶ Redis 사용 예시: 로그인과 JWT 리프레시 토큰 구현
Spring Boot와 Redis를 활용하여 JWT 기반의 로그인과 리프레시 토큰(Refresh Token) 관리 기능을 구현한 예시이다. Redis를 사용하여 로그인한 사용자 세션과 리프레시 토큰을 관리할 수 있다. 이 방식은 데이터베이스보다 빠른 응답을 제공하고, 서버의 부하를 줄여줄 수 있다.
▽ JWT 및 Redis를 사용한 리프레시 토큰 저장 예시
package com.example.dischord.global.config;
import com.example.dischord.global.filter.JwtFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.repository.configuration.EnableRedisRepositories;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
@Configuration
@EnableWebSecurity
@EnableRedisRepositories
public class SecurityConfig {
private final JwtUtil jwtUtil;
private final UserDetailsService userDetailsService;
public SecurityConfig(JwtUtil jwtUtil, UserDetailsService userDetailsService) {
this.jwtUtil = jwtUtil;
this.userDetailsService = userDetailsService;
}
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
JwtFilter jwtFilter = new JwtFilter(jwtUtil, userDetailsService);
http.csrf(csrf -> csrf.disable())
.formLogin(form -> form.disable())
.httpBasic(httpBasic -> httpBasic.disable())
.authorizeHttpRequests(auth -> auth.anyRequest().permitAll())
.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.addFilterBefore(jwtFilter, UsernamePasswordAuthenticationFilter.class);
return http.build();
}
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(connectionFactory);
return template;
}
@Bean
public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception {
return authenticationConfiguration.getAuthenticationManager();
}
}
→ JwtFilter: JWT 토큰을 검증하는 필터로, 요청이 들어올 때 JWT 토큰의 유효성을 검사한다.
→ SecurityFilterChain: Spring Security의 필터 체인을 정의하는 메서드로, 인증과 인가에 대한 설정을 구성한다.
▶Redis를 사용한 JWT 리프레시 토큰 관리
리프레시 토큰을 Redis에 저장하여, 사용자 인증 상태를 빠르게 관리하고, 토큰의 만료나 갱신 시점을 효과적으로 처리할 수 있다.
▽ Redis를 사용한 리프레시 토큰 저장 예시
@Service
public class JwtService {
private final RedisTemplate<String, Object> redisTemplate;
private final JwtUtil jwtUtil;
public JwtService(RedisTemplate<String, Object> redisTemplate, JwtUtil jwtUtil) {
this.redisTemplate = redisTemplate;
this.jwtUtil = jwtUtil;
}
// 리프레시 토큰 저장 메서드
public void saveRefreshToken(String username, String refreshToken) {
redisTemplate.opsForValue().set(username, refreshToken, 7, TimeUnit.DAYS); // 유효 기간 7일로 설정
}
// 리프레시 토큰 조회 메서드
public String getRefreshToken(String username) {
return (String) redisTemplate.opsForValue().get(username);
}
// 리프레시 토큰 삭제 메서드
public void deleteRefreshToken(String username) {
redisTemplate.delete(username);
}
}
→ getRefreshToken: 저장된 리프레시 토큰을 Redis에서 조회한다.
→ deleteRefreshToken: 사용자가 로그아웃할 때 Redis에 저장된 리프레시 토큰을 삭제한다.
▶Redis 사용 시 주의사항
→ 데이터 유실 가능성:
Redis는 인메모리 데이터베이스이기 때문에, 서버가 다운되면 데이터가 유실될 수 있다. 이를 방지하기 위해 데이터 영속성 설정을 신중히 고려해야 한다.
→ 메모리 관리:
메모리 기반의 데이터 저장소이므로, 저장할 수 있는 데이터의 양이 메모리에 의존적이다. 메모리 사용량을 모니터링하고, 필요에 따라 만료 정책을 설정해야 한다.
→ 네트워크 트래픽:
Redis는 네트워크 기반으로 동작하므로, 네트워크 트래픽이 많아지면 성능에 영향을 줄 수 있다. 이때는 로컬 캐시나 Redis 클러스터링을 고려해야 한다.
→ 보안 설정:
Redis는 기본적으로 인증이 비활성화되어 있으므로, 보안 설정을 강화하고, 필요한 경우 방화벽 규칙을 적용해야 한다.
▶정리
이번 개발일지를 통해 Redis의 개념과 주요 특징, 장단점, 그리고 Redis를 활용한 JWT 리프레시 토큰 구현 예시를 통해 Redis의 유용성을 이해할 수 있었다. Redis는 빠른 성능과 다양한 기능을 제공하지만, 메모리 기반 저장소라는 특성 때문에 데이터 유실과 메모리 관리에 대한 신중한 고려가 필요하다. 이전에 팀 프로젝트에서 Redis를 활용한 기능을 다른 팀원에게 맡기면서 Redis에 대해 아무것도 모르고있던 상태라 꼭 알아야겠다고 느꼈다. 이번 기회를 통해 Redis에 대해 이해하면서 앞으로 개발하는데 활용할 수 있도록 계속 공부해야겠다는 생각이 든다.
'개발Article' 카테고리의 다른 글
[TIL]20240813 Nginx (0) | 2024.08.13 |
---|---|
[TIL]20240812 성능최적화 (0) | 2024.08.12 |
[TIL]20240810 단위테스트란? (0) | 2024.08.10 |
[TIL]20240809 Validation (0) | 2024.08.09 |
[TIL]20240808 SSE와 웹소켓 비교 (0) | 2024.08.08 |