본문 바로가기
Spring

Redis 부숴버리기

by windy7271 2024. 5. 12.
728x90
반응형

이번 harbor 프로젝트를 진행하면서 사용한 기술들의 대해서 모두 다 정리를 해보려고 한다.

https://github.com/beyond-sw-camp/be03-fin-4team-HarboR

 

GitHub - beyond-sw-camp/be03-fin-4team-HarboR: 🥴 송보석 🫠 이원태 😮 이창선 🤪 손정민

🥴 송보석 🫠 이원태 😮 이창선 🤪 손정민. Contribute to beyond-sw-camp/be03-fin-4team-HarboR development by creating an account on GitHub.

github.com

 

자세한 내용은 여기서 확인할 수 있다.

 

 

Redis는 Remote(원격)에 위치하고 프로세스로 존재하는 In-Memory 기반의 Dictionary(key-value) 구조 데이터 관리 Server 시스템이다.

 

관계형 데이터베이스와 같이 쿼리 연산을 지원하지 않지만, 대신 데이터의 고속 읽기와 쓰기에 최적화 되어 있다. 그래서 Redis는 일종의 NoSQL 로 분류되기도 한다.

 

NoSQL: NoSQL은 Not Only SQL의 약자로써 기존 관계형 데이터베이스(RDBMS)보다 더 융통성 있는 데이터 모델을 사용하고 데이터의 저장 및 검색을 위한 특화된 메커니즘을 제공하는 데이터 저장기술을 의미한다.NoSQL 데이터베이스는 단순 검색 및 추가 작업에 있어서 매우 최적화된 키-값 저장 기법을 사용하여 응답속도나 처리 효율 등에 있어서 매우 뛰어난 성능을 보여준다.

 

 

1. Look aside Cache 패턴

 

 

레디스의 데이터 존재유무를 확인하고 있으면 그것을 돌려주고 없으면 db에 들렸다 와서 돌려주는 형식이다.

 

 

1.  write back 패턴

 

 

레디스는 설계 구조상 단점이 존재한다.

Redis는 Single Thread로 동작한다. 그래서 한 사용자 오래걸리는 커맨드를 실행하면 나머지 요청은 수행할 수 없고 대기하게 되어 장애가 빈번하게 발생한다. 참고로 단순한 get/set의 경우, 초당 10만 TPS 이상이 가능하다. (CPU 속도 영향받음) 그런데 만약 하나의 명령어가 1초가 걸리는 작업을 해버리면 9만 9999개의 명령어는 1초동안 대기하게 되는데 모두 timout이 발생하면서 서비스가 터진다. (보통 timeout = 200~300ms)

 

 즉 한 번에 하나의 명령어를 실행하기 때문에 O(N) 의 명령어를 가진

KEYS, FLUSHALL, FLUSHDB, Delete COlLECTIONS, Get All Collections

 

는 주의 해줘야한다. 

keys  (x) → scan (o)

모든 키를 보여주는 커맨드인데 데이터가 많을수록 조회가 매우 오래 걸린다. 이 커맨드는 재귀적으로 key를 호출할 수 있는 scan으로 대체하여 사용하는 게 좋다.

키 나누기

Hash나 Sorted Set 자료구조는 내부에 여러 아이템을 저장할 수 있는데 내부 아이템이 많아질수록 성능이 저하된다. 그래서 적절하게 최대 100만개 정도만 저장해주는 게 좋다.

delete (x) → unlink (o)

키에 많은 데이터가 들어있을 때 delete로 지우면 그 키를 지우는 동안 아무런 동작을 할 수 없다. unlink를 사용하면 백그라운드로 키를 지울 수 있기 때문에 이를 사용하는 게 좋다. 

 

이 외에도 Get All Collections와 같은 O(n) 명령어들도 최대한 사용하면 안된다. FLUSHALL, FLUSHDB도 마찬가지인데 이 명령어들은 모든 데이터를 삭제하는 거라 꼭 필요한 경우에는 어쩔 수 없이 사용해야 한다.

 

 


Redis 연동

 

## build.gradle

implementation 'org.springframework.boot:spring-boot-starter-data-redis'

 

## application.yml

spring:
  application:
    name: redis
  datasource:
    driver-class-name: org.mariadb.jdbc.Driver
    url: jdbc:mariadb://localhost:3306/redis
    username: root
    password: 1234
  redis:
    host: localhost
    port: 6379

 

 

# RedisConfig

@Configuration
@EnableRedisRepositories
@Slf4j
public class RedisConfig{
    @Value("${spring.redis.host}")
    private String redisHost;
    @Value("${spring.redis.port}")
    private int redisPort;

    @Bean
    public RedisConnectionFactory redisConnectionFactory() {
        log.info("redisConnectionFactory : 등록");
        return new LettuceConnectionFactory(redisHost, redisPort);
    }

    @Bean
    public RedisTemplate<?, ?> redisTemplate() {
        RedisTemplate<byte[], byte[]> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(redisConnectionFactory());
        return redisTemplate;
    }
}

 

RedisConncetionFactory 는 

redis 를 등록하는 역할을 한다.

 

여기서 깊게 파고 들어갈수 있는 부분이 있다.

 

return new LettuceConnectionFactory(redisHost, redisPort);

 

바로 이 부분인데, 일단 가장 기본적인 설정을 하기때문에 지금은 그냥 넘어가고 이따 아래에서 설명을 해보도록하겠다.

 

 

 

 

RedisTemplate 는 Redis 와의 상호작용을 위한 RedisTemplate 빈을 생성한다. 이 빈은 Redis 데이터 저장소와의 통신을 추상화 하고 단순화 하는데 사용된다. 

 

@Service
public class RedisUtil {

    private final StringRedisTemplate template;

    public RedisUtil(StringRedisTemplate template) {
        this.template = template;
    }

    public String getData(String key) {
        ValueOperations<String, String> valueOperations = template.opsForValue();
        return valueOperations.get(key);
    }

    public void setDataExpire(String key, String value) {
        ValueOperations<String, String> valueOperations = template.opsForValue();
        valueOperations.set(key, value);
    }

    public void deleteData(String key) {
        template.delete(key);
    }
}

 

기본적인 레디스 기본 기능을 만들어 보겠다.

 

redis의 기본 키를 등록하고, 키를 얻고, 키를 지우는 것이다.

## Controller

@RestController
@RequiredArgsConstructor
public class RedisConrtoller {
    private final RedisService redisService;

    @GetMapping("/set")
    public void redissetTest() {
        redisService.setRedisKey();
    }
    @GetMapping("/get")
    public String redisgetTest() {
        return redisService.getRedisKey();
    }
    @GetMapping("/delete")
    public String redisdeleteTest() {
        return redisService.deleteRedisKey();
    }
}




## Service


@Service
@RequiredArgsConstructor
public class RedisService {

    private final RedisRepository repository;
    private final RedisUtil redisUtil;
    public void setRedisKey() {
        redisUtil.setDataExpire("1", "hi redis");
    }

    public String getRedisKey() {
        return redisUtil.getData("1");

    }
    public String deleteRedisKey() {
        redisUtil.deleteData("1");
        return "bye reids";
    }
}

 

 

http://localhost:8080/set

http://localhost:8080/get

http://localhost:8080/delete

http://localhost:8080/delete

 

 

이것들을 잘 요리조리 사용하면 될 것 같다. 

하지만 얼마전에 IBK 개발하시는 분이 Redis 에 대해  말씀해 주셨는데 레디스를 데이터 저장용으로 쓰지는 않는다고하니 그 부분을 유의해서 사용하면 된다.

 

다음 장에서는 좀더 심화해서 사용해 보도록 하겠다.

http://redisgate.kr/redis/cluster/cluster.php

 

 

반응형

댓글