DBMS

(Spring) Lettuce를 활용하여 Redis를 활용하는 방법을 알아보자

너어디사니 2024. 7. 9. 21:36

Spring 에서 Redis를 다루기 위해서는 다양한 라이브러리들이 있는데 나는 그중에서 Lettuce를 활용한 Redis 구현을 해보려고 한다

 

여기서 잠깐 Redis란??

  • Redis는 Key - Value 값을 기반으로 하는 In Memory NOSQL DB 이다

장점

  • 모든 데이터를 메모리에 저장하기 때문에 속도가 굉장히 빠르다
  • 다양한 자료구조를 저장하기 때문에 보다 다양하게 데이터를 관리 할 수 있다
  • 만료 시간을 설정할 수 있고 만료 시간이 지나면 자동으로 지워지기 때문에 보다 효율적인 데이터 관리가 가능하다

단점

  • 용량이 작기 때문에 대용량으로 저장하기 어렵다
  • 휘발성이 있기 때문에 일반 DB와 같이 사용 하는 것이 좋다
  • 싱글 스레드 이기 때문에 하나의 명령어만 처리가 가능하다 즉 크기가 큰 명령을 처리하게 될 경우 성능이 저하 될 수 있다

Redis의 자료구조

  • String : 문자열 데이터를 저장 및 조회할 수 있는 Key - Value 기반의 기본 자료 구조
  • Bitmap : 비트 단위로 데이터를 저장하고 조작할 수 있는 자료구조, 사실상 위의 자료구조와 비슷하다
  • List : 양방향 Linked List 형태로 서로 연결되어 있는 자료 구조 , 양 끝에서 데이터를 빼오거나 삽입하는게 가능하다
  • Hashe : hash 값과 fileld - Value 로 구성된다. 하나의 hash 안에서 여러개의 field - value를 저장할 수 있기 때문에 사용자의 데이터를 저장하는데 용이하다
  • Set : 중복을 허용하지 않는 List와 비슷한 자료 구조
  • Sorted Set(ZSet) : Set과 비슷한 집합 데이터로 정렬 기능을 제공한다. 점수와 값의 쌍으로 저장이 된다 Sorted Set은 점수 값을 사용하여 정렬하고, 점수 값이 중복되면 사전 순으로 정렬한다.
  • Hypperloglog : 대량의 고유 항목 수를 메모리 효율적으로 추정하는 데 사용 하는 자료구조이다
  • Stream : 레디스 5.0 버전부터 제공하는 기능, 로그 및 메시징 시스템에 적합한 고유한 ID가 있는 데이터 스트림.

Lettuce 초기 셋팅

1. application.yml 과 build.gradle.kts 에 셋팅을 해준다

#appcation.yml

spring:
  data:
    redis:
      host: localhost
      port: 6379
//build.gradle.kts

implementation("io.lettuce:lettuce-core:6.3.2.RELEASE")

 

2. Lettuce 환경 구성

  • redis를 설치해준다
brew install redis
  • Class에 기본 설정을 구성해준다
@Configuration
class LettuceRedis(
){
    private val redisClient = RedisClient.create("redis://localhost:6379") // 여기서 Redis 주소를 지정
    private val connection: StatefulRedisConnection<String, String> = redisClient.connect() // Redis 주소 연결
    private val command = connection.sync()  // Redis 싱크 후 사용

 

3. 이 후 사용하면 끝

  • 환경 설정이 까다로운 RedisTemplete과는 달리 환경설정이 굉장히 간편하다는 장점이 있다

4. 각 자료구조 별 입출력 메서드

  • String
commands.set("key", "value") //Set 메서드로 String 자료구조 저장
commands.get("key") //Get 메서드로 String 자료구조 저장
commands.incr("count") // incr 메서드로 키의 값을 1만큼 증가
commands.decr("count") // decr 메서드로 키의 값을 1만큼 감소
  • Bitmap
// bitmap에서 특정 위치에 비트맵을 설정 true는 특정 비트를 1 false는 0으로 설정
commands.setbit("Key", 10, true) 
// bitmap에서 특정 위치의 비트를 가져온다
commands.getbit("bitmapKey", 10)

// bitmap에서 1로 설정된 비트의 수를 계산
commands.bitcount("bitmapKey")
  • List
// List 왼쪽에 값을 추가
commands.lpush("Key", "value1")

// List 오른쪽에 값을 추가
commands.rpush("Key", "value2")

// List 왼쪽에 값을 가져오고 제거
commands.lpop("Key")

// List 오른쪽에 값을 가져오고 제거
commands.rpop("Key")

// List 특정 범위의 값을 가져온다
commands.lrange("Key", 0, -1)

// List 길이를 가져온다
commands.llen("Key")
  • Hash
//hash field에 값을 설정한다
commands.hset("Key", "field", "value")

//hash field에 맞는 값을 가져온다
commands.hget("Key", "field")

//hash에 맞는 값을 모두 가져온다
commands.hgetall("Key")

//hash field를 삭제한다
commands.hdel("Key", "field")

//hash field의 수를 가져온다
commands.hlen("Key")
  • Set
// Set에 값을 추가
commands.sadd("key", "value1")

// Set에 값을 제거
commands.srem("key", "value1")

// Set에 모든 값을 가져온다
commands.smembers("key")

// Set에 값이 존재하는지 확인
commands.sismember("key", "value1")
  • Sorted Set
// 정렬된 Set에 점수와 함께 값을 추가
commands.zadd("Key", 1.0, "value1")

// 정렬된 Set에 특정 범위의 값을 가져온다
commands.zrange("Key", 0, -1)

// 정렬된 Set에 값의 순위를 가져온다
commands.zrank("Key", "value1")

// 정렬된 Set에서 값을 제거
commands.zrem("Key", "value1")

// 정렬된 Set에서 값의 점수를 가져온다
commands.zscore("Key", "value1")
  • Hypperloglog
// HyperLogLog에 값을 추가
commands.pfadd("Key", "value1", "value2")

// HyperLogLog의 고유 항목 수를 계산한다
val uniqueCount: Long = commands.pfcount("Key")

// 여러 HyperLogLog를 병합
commands.pfmerge("MergedKey", "Key1", "Key2")
  • Stream
// Stream 에 새 항목을 추가
commands.xadd("Key", mapOf("id" to "1234", "temperature" to "19.8"))

// Stream 에 항목을 가져온다
commands.xread(XReadArgs.StreamOffset.from("Key", "0"))

// Stream 그룹을 관리한다
commands.xgroupCreate(StreamOffset.from("Key", "0"), "groupName")

// Stream 메시지를 확인한다
commands.xack("Key", "groupName", "messageId")

 

5. RedisEviction 

  • Redis가 사용하는 메모리가 maxMemory 에 지정한 크기보다 커지면 Redis는 사용자가 지정한 Eviction 정책에 따라 저장되어 있는 데이터를 제거한 후, 새로운 데이터를 저장하게 되는데 이 때 사용할 수 있는 방법이다
  • RedisEviction 정책은 아래와 같으며 필자는 ENUM 타입으로 해당 정책을 상수화 해서 관리하고 있다
NO_EVICTION("noeviction"),  //메모리 부족 시 새로운 키를 추가하려는 작업이 실패한다
ALL_KEYS_LRU("allkeys-lru"), //사용 빈도가 낮은 모든 키를 제거한다
VOLATILE_LRU("volatile-lru"), //사용 빈도가 낮은 만료 키를 제거한다
ALL_KEYS_RANDOM("allkeys-random"), //임의의 모든 키를 제거한다
VOLATILE_RANDOM("volatile-random"), //임의의 만료 키를 제거한다
VOLATILE_TTL("volatile-ttl") //만료 시간이 짧은 키를 제거한다
  • RedisEviction 정책 사용 방법
    • init 블록에서 사용하는 방법과 메서드 내부에서 사용하는 방법이 있는데 전체적인 Redis 정책을 설정해주는 것과 세부적인 Redis 정책을 설정하는 차이점이 있으니 프로젝트에 맞춰서 사용하면 될 것 같다
    init {
        command.configSet("maxmemory-policy", RedisEviction.VOLATILE_TTL.policy)
    }