2024.07.07 - [Spring/대용량 트래픽] - Reactive Redis란?
Reactive Redis란?
2024.07.07 - [Spring/대용량 트래픽] - Spring Webflux R2DBC 여러가지 기능들 Spring Webflux R2DBC 여러가지 기능들2024.07.06 - [Spring/대용량 트래픽] - Spring Webflux R2DBC 사용해보기 Spring Webflux R2DBC 사용해보기2024.0
lsdiary.tistory.com
준비물
- Redis 6(Docker Container)
- Gradle
- spring-boot-starter-data-redis-reactive
혹여나 Docker와 Redis가 설치되어 있지 않다면 이 글을 참고 하길바란다. https://lsdiary.tistory.com/55
Redis,Docker 설치하기와 수많은 에러
도커 컨테이너 기반으로 Redis를 설치해보겠다. https://hub.docker.com/_/redis redis - Official Image | Docker Hub Quick reference Supported tags and respective Dockerfile links 7.2.4, 7.2, 7, latest, 7.2.4-bookworm, 7.2-bookworm, 7-bookworm,
lsdiary.tistory.com
모두 설치가 되었다면 다음과 같은 명령으로 Redis 컨테이너를 실행한다.
docker run -it -p 6379:6379 redis:6.2
실행되었다면 다음 명령으로 cli를 들어간다.
docker exec -it [containerID] redis-cli
그리고, monitor 명령으로 redis에 어떠한 상호작용이 일어나는지 모니터링 해주면 준비는 끝이다.
본인은 InteliJ로 돌아와서 다음과 같은 의존성을 추가해줬다.
implementation 'org.springframework.boot:spring-boot-starter-data-redis-reactive'
이렇게 잘 추가가 되었다면 제대로 된것이다.
다음은 .yml 파일설정이다.
data:
redis:
host: 127.0.0.1
port: 6379
이렇게 설정을 해주면 연결 끝~? R2DBC와 마찬가지로 lazy로 연결을 시도하기 때문에 port번호를 틀리게 해도 실패하는 메세지가 뜨지 않는다.(물론 R2DBC에서는 비밀번호를 틀리게 했었음)
-> 검증 로직을 넣어줘야한다.
RedisConfig.java
@Configuration
@RequiredArgsConstructor
@Slf4j
public class RedisConfig implements ApplicationListener<ApplicationReadyEvent> {
private final ReactiveRedisTemplate<String, String> reactiveRedisTemplate;
@Override
public void onApplicationEvent(ApplicationReadyEvent event) {
reactiveRedisTemplate.opsForValue().get("1")
.doOnSuccess(i -> log.info("initialize to redis connection"))
.doOnError((err) -> log.error("failed to initialize redis connection: {}", err.getMessage()))
.subscribe();
}
}
마찬가지로 강제로 어플리케이션이 실행될때, Redis에 "1"인 키값을 요청해서 실패시 에러를 발생시키도록 해줬다.
성공시에는 위와같은 화면이 나와야한다.
Redis-cli 모니터링화면에서도 확인할 수있다.
reactiveRedisTemplate.opsForList().leftPush("list1", "hello").subscribe();
reactiveRedisTemplate.opsForValue().set("sampleKey1", "sample", Duration.ofSeconds(60)).subscribe();
작성한 config파일에 위와같은 코드를 추가해서 Redis에 데이터를 저장할수 있다.
Cache로 사용
기존에 생성해두었던 로직에 더해서(사용자 아이디로 사용자를 찾음) -> 이걸 캐시로 사용하는 코드를 작성해보겠다.
ReactiveRedisTemplate을 이용할 것인데, 위의 설정파일에서 만들어준 다음과 같은 코드(String, String 형식)는ReactiveRedis가 실행하면서 default로 만들어주는 Bean이다.
private final ReactiveRedisTemplate<String, String> reactiveRedisTemplate;
하지만 우리가 원하는 로직은 사용자를 찾는 것이기 때문에 <String, User> 형식이 필요하다. -> 커스텀하게 만들어주는건 원하는 형식에 맞춰 따로 설정이 필요하다.
RedisConfig.java
@Bean
public ReactiveRedisTemplate<String, User> reactiveRedisTemplate(ReactiveRedisConnectionFactory connectionFactory){
ObjectMapper objectMapper = new ObjectMapper()
// 모르는 속성에 실패처리 안함
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
// created_at, updated_at 등 시간에 관한 처리
.registerModule(new JavaTimeModule())
.disable(SerializationFeature.WRITE_DATE_KEYS_AS_TIMESTAMPS);
Jackson2JsonRedisSerializer<User> jsonRedisSerializer = new Jackson2JsonRedisSerializer<>(objectMapper, User.class);
RedisSerializationContext<String, User> serializationContext = RedisSerializationContext
.<String, User>newSerializationContext()
.key(RedisSerializer.string())
.value(jsonRedisSerializer)
.hashKey(RedisSerializer.string())
.hashValue(jsonRedisSerializer)
.build();
return new ReactiveRedisTemplate<>(connectionFactory, serializationContext);
}
위와 같이 설정파일에 빈으로 등록해주자.
UserSevcie.java
public Mono<User> findById(Long id){
return reactiveRedisTemplate.opsForValue()
.get(getUserCacheKey(id))
.switchIfEmpty(
userR2dbcRepository.findById(id)
.flatMap(u -> reactiveRedisTemplate.opsForValue()
.set(getUserCacheKey(id), u)
.then(Mono.just(u)))
);
// return userR2dbcRepository.findById(id);
}
기존 Spring Data Redis와의 차이점은 Mono, Flux로 감싸느냐의 차이이다.
- 그렇다면 User에 대해서 업데이트를 해주는 경우는 어떨까?
Redis에 저장되어있는 값도 변경을 해줘야할것이다. 다음과 같이 unlink() 메서드(비동기 삭제)로 Redis에 저장되어있는 데이터를 삭제하고 DB에 저장하는식으로 Service로직을 수정해준다.
public Mono<User> update(Long id, String name, String email){
return userR2dbcRepository.findById(id)
.flatMap(u -> {
u.setName(name);
u.setEmail(email);
return userR2dbcRepository.save(u);
})
.flatMap(u -> reactiveRedisTemplate.unlink(getUserCacheKey(id)).then(Mono.just(u)));
}
- 삭제
public Mono<Void> deleteById(Long id){
return userR2dbcRepository.deleteById(id)
.then(reactiveRedisTemplate.unlink(getUserCacheKey(id)))
.then(Mono.empty());
}
- TTL설정 : set인자에 Duration.ofxxx(원하는 시간)
2024.07.13 - [Spring/대용량 트래픽] - Spring MVC vs Webflux 성능 비교(with Jmeter)
Spring MVC vs Webflux 성능 비교(with Jmeter)
2024.07.12 - [Spring/대용량 트래픽] - Reactive Redis 사용법 Reactive Redis 사용법2024.07.07 - [Spring/대용량 트래픽] - Reactive Redis란? Reactive Redis란?2024.07.07 - [Spring/대용량 트래픽] - Spring Webflux R2DBC 여러가지
lsdiary.tistory.com
'Spring > 대용량 트래픽' 카테고리의 다른 글
Blockhound로 디버깅하기 (0) | 2024.07.13 |
---|---|
Spring MVC vs Webflux 성능 비교(with Jmeter) (0) | 2024.07.13 |
Reactive Redis란? (0) | 2024.07.07 |
Spring Webflux R2DBC 여러가지 기능들 (0) | 2024.07.07 |
Spring Webflux R2DBC 사용해보기 (0) | 2024.07.06 |