개요
프로젝트를 MSA로 구성할 때 RDB만 사용하는 것보다 NoSQL DB나 InMemory DB도 같이 사용하는 것이 성능 상으로 더 좋을 것이라고 생각되기 때문에 대표적인 Redis의 RedisTemplate에 대해 정리해 볼 것이다.
Redis?
Redis
Redis란? dictionary 구조(key-value) 형태로 데이터를 저장하고 관리하는 서버 핵심 기능 Redis는 데이터베이스, 캐시, 메시지 브로커 및 스트리밍 엔진으로 사용되는 오픈 소스(BSD 라이선스), 인메모리
eleunadeu.tistory.com
- Redis에 대한 간단한 정리는 예전에 했기 때문에 이번에는 Redis의 사용 방법에 대해서만 정리할 것이다.
Redis 사용 준비
컴퓨터 저장 용량을 고려해 로컬 환경에 Redis를 설치하지 않고 Docker의 이미지를 사용해 Redis를 설치해 실습을 진행한다.
Docker Hub - Redis 검색 결과
- redis: Redis 서버의 Core
- redis/redis-stack-server: 여러 플러그인이 추가된 Redis Stack 서버 이미지. 확률형 데이터, JSON 문서 등을 사용할 수 있음
- redis/redis-stack: redis/redis-stack-server에 Redis Insight가 추가된 이미지. Redis Insight를 같이 사용할 수 있다.
Redis를 사용하면서 Redis Insight도 같이 쓸 수 있는 redis/redis-stack 이미지를 사용했다.
docker-compose.yml로 Redis 설치
실습을 위한 빈 스프링부트 프로젝트 루트 폴더에 docker-compse.yml 파일을 생성 후 인텔리제이 터미널을 사용해 docker 명령어를 실행한다.
services:
redis-stack:
image: redis/redis-stack
container_name: redis-stack-compose
restart: always
environment:
REDIS_ARGS: "--requirepass systempass"
ports:
- 6379:6379
- 8001:8001
- REDIS_ARGS를 사용해 사용자 비밀번호를 설정
docker compose up -d
docker compose ps
- Redis를 설치하고 명령어를 통해 정상적으로 실행되었는지 확인
docker-compose 도중 발생한 에러 및 해결
Error response from daemon: Ports are not available: exposing port TCP 0.0.0.0:6379 -> 0.0.0.0:0: listen tcp4 0.0.0.0:6379: bind: Only one usage of each socket address (protocol/network address/port) is normally permitted.
- 다른 프로젝트에서 Redis를 사용했던 적이 있었는데 해당 프로세스가 아직 실행되고 있어서 docker-compose를 통해 6379 포트를 사용하도록 Redis를 설치할 수 없었다.
netstat -ano | findstr :6379
taskkill /PID {PID} /F
- Window Powershell에서 해당 명령어를 통해 6379를 사용하고 있는 포트의 프로세스를 종료했다.
- 해당 포트가 다른 작업에 사용 중이라면 위 명령어를 사용하지 말고 docker-compose의 redis 포트 설정을 변경해야 된다.
Redis 인텔리제이에 연결
인텔리제이 DB 탭 → + → DatatSource → Redis
기본 유저 default와 yml에서 설정한 패스워드를 입력 후 Test Connection이 성공하면 OK를 누른다.
Redis Insight 접속 방법
docker-compose.yml로 설정한 8001 포트로 웹에서 접속하면 Redis Insight에 접속할 수 있다.
- Username과 Password 입력 후 Test Connection을 통과하면 Apply Changes를 누르고 Open 버튼을 눌러 접속할 수 있다.
- Redis에 대한 간단한 연습을 진행할 수 있다.
RedisTemplate 사용
Redis와 상호작용하기 위한 Spring Boot의 핵심 클래스.
Spring Data Redis 라이브러리를 통해 제공되며, Redis 서버에 데이터 저장 및 조회를 쉽게 해주는 다양한 메서드 제공.
주요 특징
- Reids의 데이터 타입 지원
- RedisTemplate은 Redis의 다양한 데이터 구조(예: String, List, Set, Hash 등)를 쉽게 다룰 수 있도록 메서드를 제공
- 직렬화 지원
- 데이터를 Redis에 저장할 때와 조회할 때, 직렬화/역직렬화를 처리, String, JSON, Protobuf 등의 직렬화 방식 설정 가능
- 유연한 확장성
- 키와 값의 타입을 지정할 수 있어 다양한 데이터 구조에 맞게 사용할 수 있음
주요 메서드 (opsFor...)
- opsForValue(): 문자열(Value) 작업 (Key-Value 저장소)
- opsForList(): 리스트(List) 작업
- opsForSet(): 집합(Set) 작업
- opsForHash(): 해시(Hash) 작업
- opsForZSet(): 정렬된 집합(Sorted Set) 작업
주요 메서드 (opsFor...)
- opsForValue(): 문자열(Value) 작업 (Key-Value 저장소)
- opsForList(): 리스트(List) 작업
- opsForSet(): 집합(Set) 작업
- opsForHash(): 해시(Hash) 작업
- opsForZSet(): 정렬된 집합(Sorted Set) 작업
사용 방법
1. 의존성 추가 및 yml 설정
implementation 'org.springframework.boot:spring-boot-starter-data-redis'
spring:
data:
redis:
host: localhost
port: 6379
username: default
password: systempass
2. RedisConfig 생성
@Configuration
public class RedisConfig {
@Bean
public RedisTemplate<String, ItemDto> rankTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<String, ItemDto> template = new RedisTemplate<>();
template.setConnectionFactory(redisConnectionFactory);
template.setKeySerializer(RedisSerializer.string());
template.setValueSerializer(RedisSerializer.json());
return template;
}
}
- RedisTemplate을 Bean을 생성하고 Key와 Value에 대한 직렬화 방식 설정
3. RedisTemplate 사용
@Slf4j
@Service
public class ItemService {
private final ItemRepository itemRepository;
private final OrderRepository orderRepository;
private final ZSetOperations<String, ItemDto> rankOps;
public ItemService(
ItemRepository itemRepository,
OrderRepository orderRepository,
RedisTemplate<String, ItemDto> rankTemplate
) {
this.itemRepository = itemRepository;
this.orderRepository = orderRepository;
this.rankOps = rankTemplate.opsForZSet();
}
public void purchase(Long id) {
Item item = itemRepository.findById(id)
.orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND));
orderRepository.save(ItemOrder.builder()
.item(item)
.count(1)
.build());
// incrementScore 외에도 상황에 맞는 메서드 호출하는 것이 중요
rankOps.incrementScore("soldRanks", ItemDto.fromEntity(item), 1);
}
public List<ItemDto> getMostSold() {
Set<ItemDto> ranks = rankOps.reverseRange("soldRanks", 0, 9);
if (ranks == null) return Collections.emptyList();
return ranks.stream().toList();
}
}
- RedisTemplate을 사용해 물품 구매시 ItemDto를 Redis Sorted에 저장하는 메서드와 구매된 상품을 순위 별로 조회하는 메서드를 만들었다.
- Post Man을 사용해 구매 요청을 보낸다.
- 각 구매 항목이 Score 값과 함께 Redis에 저장된 것을 확인할 수 있다.
- 조회 API 호출 시 많이 구매한 순서대로 조회 되는 것을 확인할 수 있다.
Redis Session Clustering
Session Clustering?
웹 애플리케이션에서 사용자의 세션 데이터를 여러 서버 간에 공유하거나 복제하여 가용성과 안정성을 높이는 기술.
필요성
- 로드 밸런싱
- 클라이언트 요청이 여러 서버로 분산되므로, 특정 서버에만 세션이 저장되면 문제가 발생할 수 있다.
- 고가용성
- 서버 장애 시에도 세션이 유지되며, 사용자는 중단 없는 서비스를 경험할 수 있다.
세션 클러스터링 방식
- 세션 복제
- 세션 데이터를 클러스터에 있는 모든 서버에 복제한다.
- 단점: 서버 수가 많아질수록 성능 저하 우려.
- 공유 세션 저장소
- 세션 데이터를 중앙의 저장소(Redis, Memcached, Database 등)에 저장하여 모든 서버가 공유하도록 설정.
- 장점: 서버 간 동기화가 필요 없으므로 확장성 우수.
- 단점: 저장소가 병목이 될 수 있음.
- 스티키 세션 (Sticky Session)
- 로드 밸런서가 특정 사용자의 요청을 항상 같은 서버로 보내도록 설정.
- 장점: 구현이 간단함.
- 단점: 서버 장애 시 세션 데이터 손실 가능.
장단점
- 장점:
- 고가용성, 장애 복구 용이.
- 확장성: 서버 추가 시에도 세션 손실 없음.
- 단점:
- 추가적인 저장소나 네트워크 비용 발생.
- 구현 복잡성 증가 (특히 복제 방식).
Redis와 세션 클러스터링
Redis는 세션 클러스터링의 중앙 저장소로 많이 사용된다.
1. 설정
implementation 'org.springframework.boot:spring-boot-starter-data-redis'
implementation 'org.springframework.session:spring-session-data-redis'
- Redis와 Session 의존성 추가
spring:
data:
redis:
host: localhost
port: 6379
username: default
password: systempass
- Redis를 사용하기 위한 yml 설정 추가
@Configuration
public class RedisConfig {
@Bean
public RedisSerializer<Object> springSessionDefaultRedisSerializer() {
// security 추가되면 변경 필요함
return RedisSerializer.json();
}
}
- Redis Config로 springSessionDefaultRedisSerializer Bean 설정
- Spring Security 또는 세션 데이터를 저장할 대 사용하는 기본 직렬화 방식 정의
@RestController
public class SessionController {
// localhost:8080/set?q=
@GetMapping("/set")
public String set(@RequestParam("q") String q, HttpSession session) {
session.setAttribute("q", q);
return "Saved: " + q;
}
// localhost:8080/get
@GetMapping("/get")
public String get(HttpSession session) {
return String.valueOf(session.getAttribute("q"));
}
}
- Session Clustering이 제대로 동작하는지 확인하기 위해 간단한 Controller 구성
2. Port 설정
인텔리제이 상단의 Run Debug 버튼 옆의 실행 파일을 선택하는 메뉴의 Edit Configuration 클릭
- Copy Configuration을 눌러 Application의 Configuration을 복사 후 Modify options의 add VM options 선택
- -Dserver.port=8081 을 입력해 애플리케이션을 8081 포트로 실행할 수 있도록 변경.
3. 애플리케이션 실행 및 API 호출 및 Session 확인
- SESSION이 정상적으로 생성되는 것을 확인할 수 있다.
- Session을 생성한 8080 포트 외에도 Redis에 저장된 Session 정보를 8081 포트에서도 정상적으로 확인할 수 있다.
정리
- Redis의 RedisTemplate과 Session Clustering 기능에 대해 실습하면서 Redis의 편리성을 느꼈다.
- Cache 등의 다른 기능도 배워서 애플리케이션을 만들 때 다양하게 활용하면 좋을 것 같다.
'자바 심화 > TIL' 카테고리의 다른 글
대규모 스트림 처리 (2) | 2024.12.04 |
---|---|
Redis - Cache (0) | 2024.12.02 |
Docker - 기본 사용 및 Cl / CD (5) | 2024.11.28 |
MSA - 기초 5 (0) | 2024.11.27 |
MSA - 기초 4 (0) | 2024.11.26 |