728x90
반응형
1. 작성하게 된 이유
- Redis는 무엇이냐, 이것에 대해 설명하기 전에 내가 이것을 사용해야 하는 이유에 대해 알아보겠습니다.
- 때는 24년 1월... 팀 결성과 기획 결정의 때, 우리는 프로젝트의 기획을 논의했고 실시간성이 중요하다고 판단했습니다.
- 그래서 메시지 브로커에 대해 공부하고 적용하기로 했습니다.
- 그리고 혹시 필요하시거나 까먹을 경우에 대비할 목적이기도 합니다.
2. 메시지큐? 메시지 브로커?
- 메시지 큐와 메시지 브로커는 모두 애플리케이션간 메시지를 비동기적으로 전송하는데 사용되는 메시지 기반 미들웨어입니다.
- 메시지 큐는 생성자와 소비자 사이에서 메시지를 일시적으로 저장하는 큐라는 구조를 통해 메시지를 전달합니다. 주로 단일 메시지 처리 패턴에 초점을 맞춥니다.
- 메시지 브로커는 기본적으로 메시지 큐의 기능을 포함한 추가 패턴과 프로토콜을 지원하여 고급 메시지 기능을 제공합니다.
- 단순한 비동기 메시지 처리가 필요한 경우 메시지 큐를, 복잡한 통신 패턴과 고급 메시지 처리 기능이 필요한 경우 메시지 브로커를 선택할 수 있습니다.
- https://ko.wikipedia.org/wiki/%EB%A9%94%EC%8B%9C%EC%A7%80_%ED%81%90
메시지 큐 - 위키백과, 우리 모두의 백과사전
위키백과, 우리 모두의 백과사전. 메시지 큐 메시지 큐(message queue)는 키보드나 마우스를 통해 발생하는 사용자의 입력을 메시지로 전달하는 윈도우즈 시스템에서 어떤 프로세스에 대한 메시지
ko.wikipedia.org
메시지 브로커 - 위키백과, 우리 모두의 백과사전
위키백과, 우리 모두의 백과사전. 메시지 브로커 패턴을 설명하는 시퀀스 다이어그램 메시지 브로커(message broker), 인터페이스 엔진(interface engine[1])은 송신자의 메시지 프로토콜 형식으로부터의
ko.wikipedia.org
3. Redis란 무엇인가?
- Redis는 "Remote Dictionary Server"의 약자로, 고성능의 키-값 구조 데이터 저장소입니다.
- 메시지 브로커로 사용할 수 있습니다.
- 메모리 기반의 데이터 저장소로서, 데이터를 메모리에 저장하여 빠른 데이터 읽기 및 쓰기를 제공합니다.
- 메모리 기반이라 빠르다는 의미는 데이터를 저장하고 처리할 때 주로 컴퓨터의 메인 메모리(RAM)를 사용한다는 의미입니다.
- 하드 디스크나 SSD와 같은 영구 저장 장치에 데이터를 읽고 쓰는 것보다 훨씬 빠른 성능을 제공합니다.
- 하지만 대량의 데이터를 사용할 경우 주의가 필요합니다.
4. 사용법
- 저는 도커를 사용해서 spring에 redis를 연결했습니다.
1. 도커 이미지 생성
docker pull redis
2. 생성된 이미지 확인
docker images
3. 실행
docker run -p 6379:6379 redis
- d: 컨테이너를 백그라운드 모드로 실행합니다.
- p 6379:6379: 호스트 머신의 포트 6379를 컨테이너의 포트 6379로 매핑합니다.
- redis: 실행할 이미지 이름으로, 여기서는 Redis 이미지를 사용합니다.
docker run -d -p 6379:6379 redis
403bd6c5d849c03b0036a09c131dd3d8a6346f1f82c0abadf7c04be1f78a42f4
4. 컨테이너 종료
docker rm -f 40
5. 실행중인 도커 컨테이너 찾기
docker ps
6. redis cli 실행
redis-cli
이 부분은 저장된 것을 확인하거나 임의로 삭제해야 할 경우를 위해 사용했다.
5. 실제 사용 예시
- 제일 처음 redis를 실행하고 터미널로 현재 redis에 있는것 확인했을 때 아무 값도 없는 것을 알 수 있습니다.
- 문자열과 객체로 나눠서 입출력하도록 코드를 작성하였습니다.
- spring 설정
더보기
implementation 'org.springframework.boot:spring-boot-starter-data-redis'
build.gradle
spring.data.redis.host=localhost
spring.data.redis.port=6379
application.properties
@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<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory);
// 범용적으로 사용할 수 있는 직렬화 방식 설정
Jackson2JsonRedisSerializer<Object> serializer = new Jackson2JsonRedisSerializer<>(Object.class);
redisTemplate.setValueSerializer(serializer);
redisTemplate.setKeySerializer(new StringRedisSerializer());
return redisTemplate;
}
}
redis config
- 작성 코드
더보기
@AllArgsConstructor
@NoArgsConstructor
@Getter
public class RequestDto {
int num;
String s;
}
RequestDto
@Service
public class RedisService {
@Autowired
RedisTemplate<String, Object> redisTemplate; // JSON 형태로 저장 가능
public List<String> getString() {
redisTemplate.setValueSerializer(new Jackson2JsonRedisSerializer<>(String.class));
List<String> list = new ArrayList<>();
String pattern = "string*";
Cursor<byte[]> cursor = redisTemplate.getConnectionFactory().getConnection().scan(ScanOptions.scanOptions().match(pattern).build());
while (cursor.hasNext()) {
String key = new String(cursor.next());
if (redisTemplate.opsForValue().get(key) != null) {
System.out.println(redisTemplate.opsForValue().get(key));
String string = (String) redisTemplate.opsForValue().get(key);
list.add(string);
}
}
return list;
}
public List<RequestDto> getObject() {
redisTemplate.setValueSerializer(new Jackson2JsonRedisSerializer<>(RequestDto.class));
List<RequestDto> list = new ArrayList<>();
String pattern = "object*";
Cursor<byte[]> cursor = redisTemplate.getConnectionFactory().getConnection().scan(ScanOptions.scanOptions().match(pattern).build());
while (cursor.hasNext()) {
String key = new String(cursor.next());
if (redisTemplate.opsForValue().get(key) != null) {
RequestDto dto = (RequestDto) redisTemplate.opsForValue().get(key);
list.add(dto);
}
}
return list;
}
public boolean setString(String s) {
redisTemplate.opsForValue().set("string" + s, s);
return true;
}
public boolean setObject(RequestDto dto) {
redisTemplate.opsForValue().set("object" + dto.getNum(), dto);
return true;
}
}
Service
@RestController
@RequestMapping("/api/redis")
public class RedisController {
@Autowired
RedisService redisService;
@GetMapping("/string")
public List<String> getString() {
return redisService.getString();
}
@GetMapping("/object")
public List<RequestDto> getObject() {
return redisService.getObject();
}
@PostMapping("/string")
public boolean setString(@RequestBody Map<String, String> string) {
String s = string.get("String");
return redisService.setString(s);
}
@PostMapping("/object")
public boolean setObject(@RequestBody RequestDto dto) {
return redisService.setObject(dto);
}
}
Controller
- PostMan을 통해 테스트 해본 결과 : 문자열
- PostMan을 통해 테스트 해본 결과 : 객체
6. 후기및 느낀점
- 메시지 브로커로 사용할 수 있습니다!
- 라고 했지만 저는 메모리 저장소로 사용했습니다.
- 아무래도 메모리 기반이라 빠르기 때문에 자주 쓰는 데이터를 꺼내 쓰거나 변화가 없는 데이터를 꺼내 쓸 때 좋았습니다.
- 한번 쓰고 버릴 데이터를 저장하고 사용하는데 사용했습니다.
- 그리고 저는 랭킹 갱신용으로도 썼는데 jpa로 유저 점수를 받아다가 redis에 저장하고 불러올 때 redis에서 꺼내도록 했습니다.
- 현재는 소량의 데이터를 사용할 목적으로 사용했지만 추후에 메모리 브로커의 용도로도 사용할 수 있도록 정리 할 필요성을 느꼈습니다.
728x90
반응형