Redis
Redis는 Key, Value 구조의 비정형 데이터를 저장하고 관리하기 위한 오픈 소스 기반의 비관계형 데이터 베이스 관리 시스템이다
데이터베이스, 캐시, 메세지 브로커로 사용되며 인메모리 데이터 구조를 가진 저장소입니다
장점 및 특징
- 다양한 자료 구조를 지원한다. (Strings, Hash, List, Set 등)
- 영속성을 지원하는 인 메모리 데이터 저장소
- 싱글 스레드 방식으로 인해 연산을 원자적으로 수행 (Race condition 방지)
- 데이터를 메모리에 저장하기 때문에 매우 빠른 응답 시간 제공
- Master-slave 복제 지원 → 데이터 가용성 높일 수 있음, 클러스터링을 통해 수평적 확장 가능 (높은 가용성 및 확장성)
- Expires → 데이터에 만료시간을 설정하여 일정 시간 후 데이터를 자동으로 없앨 수 있다
단점
- 데이터를 메모리에 저장하기 때문에 메모리 사용량이 큰 데이터일 경우 추가적인 메모리 비용 발생
- 단일 스레드 모델이기 때문에 다중 CPU 코어를 활용하지 못한다 → 많은 동시 요청이 발생하는 경우 처리 성능 한계
간단하게 Redis에 대해서 알아보았다.
그런데 우리는 DB를 사용하기 위해서 보통 관계형 데이터베이스를 사용한다.
그렇다면 언제 Redis를 사용하면 좋을까??
- 캐싱 → 다른 시스템의 쿼리 결과 및 계산 결과 등을 캐싱하여 중복 계산을 피하고 빠른 데이터 접근 가능
- 세션 저장 → 사용자의 세션을 저장하여 관리를 효율적으로 할 수 있다.
- 실시간 데이터 분석 및 처리
- 인증 토큰 저장
아래 예제를 통해 Spring Boot에서 Redis를 사용해보자
Spring Boot + Redis
build.gradle
implementation 'org.springframework.boot:spring-boot-starter-data-redis'
application.yml
spring:
redis:
host: localhost
port: 6379
RedisConfig.java
@Configuration
public class RedisConfig {
@Value("${spring.redis.host}")
private String redisHost;
@Value("${spring.redis.port}")
private int redisPort;
// Redis 연결
@Bean
public RedisConnectionFactory redisConnectionFactory(){
return new LettuceConnectionFactory(redisHost,redisPort);
}
// Redis에서 넘겨준 byte 값 객체 직렬화
@Bean
public RedisTemplate<?,?> redisTemplate(){
RedisTemplate<byte[], byte[]> redisTemplate=new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory());
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(new StringRedisSerializer());
return redisTemplate;
}
}
config 파일에서 Seraializer가 나오는데 이것은 직렬화를 의미한다.
Serializer에 대해서 알아보자
Serializer
Redis에 객체를 저장하기 위해서는 해당 객체를 직렬화를 해주어야한다.
Serializer에는 3가지 종류가 있다.
GenericJackson2JsonRedisSerializer
- 해당 Serializer는 객체의 클래스 지정없이 직렬화할 수 있다.
- 하지만 Object의 Class 및 Package까지 전부 함께 저장하게 되어 다른 프로젝트에서 Redis에 있는 값을 사용하려면 package까지 일치시켜줘야해서 번거롭다.
- MSA 관점의 프로젝트에서는 사용하지 않고, 프로젝트의 변경사항이 자주 발생할 경우 문제가 생길 수 있으니 추천하지 않는다.
Jackson2JsonRedisSerializer
- 해당 Serializer는 클래스를 지정하기 때문에 Redis에 저장할 때 class 값을 저장하지 않는다.
- GenericJackson2JsonRedisSerializer는 다르게 package 가 일치할 필요가 없다.
- Class 타입을 지정하기 때문에 RedisTemplate를 여러 쓰레드에서 접근하게 될 때 serializer 타입의 문제가 발생한다.
StringRedisSerializer
- String 값을 그대로 저장하는 Serializer
- JSON 형태로 직접 encoding, decoding을 해줘야하지만 위의 serializer에서 발생할 수 있는 문제가 발생하지 않는다.
- Class 타입 지정이 필요하지 않음
- Package까지 일치할 필요가 없다.
RedisUtils.java
@Slf4j
@Component
@RequiredArgsConstructor
public class RedisUtils {
private final RedisTemplate<String, Object> redisTemplate;
public void initRedis() {
redisTemplate.execute((RedisCallback<? extends Object>)connection -> {
connection.flushDb();
return null;
});
}
public <T> void saveDataList(String key, List<T> data) {
for (T datum : data) {
try {
ObjectMapper mapper = new ObjectMapper();
String value = mapper.writeValueAsString(datum);
redisTemplate.opsForList().rightPush(key, value);
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
}
}
public <T> boolean saveData(String key, T data) {
try {
ObjectMapper mapper = new ObjectMapper();
String value = mapper.writeValueAsString(data);
redisTemplate.opsForValue().set(key, value);
return true;
} catch (Exception e) {
log.error(e.getMessage());
return false;
}
}
public <T> boolean saveDataWithTimeout(String key, T data, long timeout) {
try {
ObjectMapper mapper = new ObjectMapper();
String value = mapper.writeValueAsString(data);
redisTemplate.opsForValue().set(key, value, timeout, TimeUnit.MICROSECONDS);
return true;
} catch (Exception e) {
log.error(e.getMessage());
return false;
}
}
public <T> T getData(String key, Class<T> classType) throws JsonProcessingException {
String value = (String)redisTemplate.opsForValue().get(key);
if (StringUtil.isNullOrEmpty(value)) {
return null;
} else {
ObjectMapper mapper = new ObjectMapper();
T obj = mapper.readValue(key, classType);
return obj;
}
}
}
참조
'Spring' 카테고리의 다른 글
| Spring Boot JPA 영속성 컨텍스트 (0) | 2023.07.27 |
|---|---|
| Querydsl에서 Cross Join이 발생할 경우 (0) | 2023.07.23 |
| [SpringBoot] Scheduler & 동적 Scheduler (0) | 2023.06.05 |
| Intellij 네이버 Java 코딩 컨벤션 및 Checkstyle 적용 (1) | 2023.06.01 |
| Mock Test 중 발생한 오류 (0) | 2023.06.01 |