임도현의 성장
Spring-Boot Redis에 저장 조회 해보기 본문
🥕 Redis 란?
Redis는 Remote Dictionary Server의 약자로 빠른 오픈 소스 인메모리(Key-Value) 데이터 저장소입니다. Redis는 Key - value 구조를 기반으로 비정형 데이터를 저장하고 관리하는 시스템으로 비관계형 데이터 베이스(NoSQL)의 일종입니다. Redis는 주로 메모리 내 In- memory에서 데이터를 저장하고 관리하지만 데이터를 디스크에 지속적으로 저장 할 수 있는 영속성 기능도 지원합니다. 이를 통해 빠른 읽기 쓰기를 제공하며 복잡한 데이터 구조를 지원합니다.
Redis 주요 타입
- String: 가장 기본적인 데이터 타입으로, 텍스트나 숫자 등의 데이터를 저장합니다.
- List: 리스트 형태로 순차적인 데이터를 저장합니다.
- Set: 고유한 값을 저장하는 집합형 데이터 타입입니다.
- Hash: 여러 필드를 가진 데이터 객체를 저장합니다.
📚 In- memory 란?
컴퓨터의 주기억장이친 RAM에 데이터를 올려서 사용하는 방법 RAM에 데이터를 저장하게 되면 메모리 내부에서 처리가 되므로 데이터를 저장 조회할 때 하드디스크를 오고가는 과정을 거치지 않아도 되어 속도가 매우 빠릅니다. 이처럼 In-memory는 RAM을 사용하여 빠른 데이터 처리를 가능하게 만드는 방식입니다.
📰 DB놯두고 왜 Redis에 저장 해?
데이터베이스는 데이터를 물리디스크에 직접 사용하기 때문에 서버에 장애가 발생해 다운되더라도 데이터가 손실되지 않지만, 매 번 디스크에 접근해야 해서, 사용자가 많아질수록 부하가 심해지고 느려진다. 하지만 Redis는 같은 요청이 여러번 들어올 때 Redis를 사용함으로써 매번 DB를 거치지 않고 서버에서 저장해놨던 값을 바로 가져와 DB의 부하를 줄이고 서비스의 속도도 느려지지 않게 할 수 있다. 하지만 우리는 작은 서비스이니깐 Web Server-WAS-DB 의 구조로도 DB에 무리가 가지 않는다.. 🤣
😏 내 생각 정리
기존에 로그인 성공을 하면 DB에 토큰들을 저장 했하는 로직에서 그냥 Redis에 저장하면 되서 간편한거 같다. 또한 관리도 하기 쉽다는 장점이있다. 토큰 검증이 왔을 때 DB까지 가서 조회하고 오는데 많은 시간이 걸렸는데 이제는 매우 빠르게 토큰을 검증할 수 있게 되었다. 한마디로 인증과 같은 빈번한 요청이 필요한 시스템에서 큰 성능 향상을 가져올 수 있게되었다. 단점으로는 휘발성이다. 서버가 종료되거나 재시작되면 데이터가 모두 사라진다 하지만 우리는 Token을 저장할꺼여서 사라지면 재로그인 하라고 요청을 보내면 된다.
🐳Redis는 도커로 다운받아서 실행하는 방식으로 하였다.🐳
docker pull redis
🌳 Spring-Boot에 연결
Redis 연결을 위해서 build.gradle에 등록해주고
implementation 'org.springframework.boot:spring-boot-starter-data-redis'
application.properties에 port번호와 host를 작성해 주어야 한다. port는 기본적으로 6379가 기본이며 변경 할 수 있다.
spring.data.redis.host=localhost
spring.data.redis.port=6379
🍅 Config 설정
Redis 연결을 위해 RedisConnectionFactory를 사용하였다. 요기에 LettuceConnectionFactory객체를 생성해서 host와 port로 connection 에 대한 정보를 추가해줬습니다. RedisTemplate을 설정하여 Redis 서버와의 연결을 설정하고 Redis에 저장되는 데이터의 Key는 String으로 Value는 JSON 형식으로 직렬화하여 처리하도록 설정 해 주었습니다.
@Configuration
public class RedisConfig {
@Value("${spring.data.redis.host}")
private String host;
@Value("${spring.data.redis.port}")
private int port;
@Bean
public RedisConnectionFactory redisConnectionFactory() {
return new LettuceConnectionFactory(host, port);
}
@Bean
public RedisTemplate<?, ?> redisTemplate() {
RedisTemplate<?, ?> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory());
redisTemplate.setKeySerializer(new StringRedisSerializer()); // Key를 String으로 직렬화
redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer()); // Value를 JSON으로 직렬화
return redisTemplate;
}
}
🍙 RedisTemplate 으로 AccessToken 저장
Redis는 Key - value형태로 저장이 되기때문에 Key 값으로 accessToken:{userId}식으로 들어가고 value값으로 진짜 토큰 값이 들어가진다. Redis는 저장할때 TTL을 설정하여 시간이 만료되면 자동으로 키값을 삭제 해준다. 나는 하나씩 저장을 했지만 객체 형식으로 저장을 해도 된다. Redis에 저장하는 방식은 밑에 코드 처럼 RedisTemplate으로 저장하는 방식이 있고 CrudRepository를 상속받아 JPA처럼 저장하는 방식이있다.
@Autowired
private RedisTemplate<String, Object> redisTemplate;
@Transactional
public TokenRedis token(CustomUser customUser) {
String accessToken = jwtInterface.getAccess(customUser.getName());
saveAccessToken(customUser.getName(), accessToken, 1000 * 60 * 60); // accessToken 저장
String getValue = getAccessToken(customUser.getName()); // 키값 정보 조회
Long getTTL = getTTLAccess(customUser.getName()); // TTL 시간 확인
return new TokenRedis(customUser.getName(), accessToken);
}
// accessToken 저장
public void saveAccessToken(String userId, String accessToken, long accessTokenTTL) {
redisTemplate.opsForValue().set("accessToken:" + userId, accessToken, Duration.ofSeconds(accessTokenTTL));
}
// accessToken 조회
public String getAccessToken(String userId) {
return (String) redisTemplate.opsForValue().get("accessToken:" + userId);
}
// accessToken TTL 조회
public Long getTTLAccess(String key) {
return redisTemplate.getExpire("accessToken:" + key);
}
// accessToken TTL 갱신
public void setTTLAccess(String key, long ttlInSeconds) {
redisTemplate.expire("accessToken:" + key, Duration.ofSeconds(ttlInSeconds));
}
// accessToken 삭제
public void deleteDataAccess(String key) {
redisTemplate.delete("accessToken:" + key);
}
🗿 Redis확인 해보기
도커로 Redis를 실행하고 docker exec -it redis-server redis-cli 명령어를 사용하면 된다.
- KEYS * : 모든 키들을 보여줌
- GET 이름:ID : value 값을 보여줌
- TTL 이름:ID : 만료 시간을 보여줌
- EXPIRE 이름:ID seconds : 만료 시간을 갱신해줌
- DEL 이름:ID : 지정한 key를 삭제함
- FLUSHDB : 현제 서버의 key들을 다 삭제함
- FLUSHALL : Redis서버의 모든 Key 삭제
👻CrudRepository 상속받아서 저장하기
@RedisHash 어노테이션을 사용하여 value는 token timeToLive는 TTL로 만료시간을 설정 해주었다. 이렇게 저장을 하면 key가 token:{id} 형식으로 저장이 된다. CrudRepository는 set 타입으로 정이 된다. 이 방식도 TTL을 설정 해줬기때문에 만료 시간이 지나면 자동으로 삭제가 된다. 하지만 다른 key들도 같이 생겨 일일히 삭제해주어야 해서 나는 RedisTemplate방식을 추천한다.
@Data
@RedisHash(value = "token", timeToLive = 1000 * 60 * 60)
public class TokenRedisEntity {
@Id
private String id;
@Indexed
private String accessToken;
}
저장하는 방식과 조회하는 방식은 JPA랑 똑같다.
@Autowired
private final TokenRedisRepository tokenRedisRepository;
public void getRedis(String userId){
String accessToken = jwtTokenProvider.createAccessToken(userId);
tokenRedisRepository.save(new TokenRedisEntity(userId, accessToken));
Optional<TokenRedisEntity> token = tokenRedisRepository.findByAccessToken(accessToken);
}
CrudRepository를 상속받아 JPA형식으로 저장을 할 수 있다.
public interface TokenRedisRepository extends CrudRepository<TokenRedisEntity, String> {
Optional<TokenRedisEntity> findByAccessToken(String accessToken);
}
'Spring Boot' 카테고리의 다른 글
Spring-Boot Cross-Origin Resource Sharing (0) | 2024.12.25 |
---|---|
Spring-Boot JWT Access Token Refresh Token (1) | 2024.12.24 |
Spring-Boot Spring Security 스프링 시큐리티 (0) | 2024.10.28 |
Spring-Boot AOP개념 @Aspect Advisor (0) | 2024.10.03 |
Spring-Boot @Transactional 트랜잭션 전파 (0) | 2024.09.15 |