공부/Spring (1)

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
반응형
1