-->

기본적으로 K-V DB인 Redis는 json 형태의 데이터를 저장한다.

이를 protobuf 형식의 바이너리 형태로 넣으면 몇가지 이점이 있다.

  1. 사용량을 크게 줄일 수 있다.
  2. Redis 데이터의 Schema가 생성되므로 명확하게 스펙관리를 할 수 있다.
  3. Redis의 중첩 데이터를 효율적으로 관리할 수 있다.

똑똑한 사람이 이미 만들어 둔 https://github.com/sewenew/redis-protobuf 패키지를 통해 json - protobuf 직렬화, 역직렬화가 가능하다. 아 정확히는 직렬화가 아니라 마샬링이라고 해야한다. 

단점은 우리가 redis 를 직접 조회해서 나오는 데이터는 볼 수 없다. 어차피 서버 통해서 언마샬링 할거니까 괜찮다!

자체적으로 메소드 내에서 ByteArray로 변환하려고 했는데 잘 안되더라. Config에서 RedisTemplate을 설정해줘야 정상 작동했다.

    @Bean
    fun redisTemplate(): RedisTemplate<String, ByteArray> {
        val template = RedisTemplate<String, ByteArray>()

        // Key는 String으로, Value는 ByteArray로 설정
        template.keySerializer = StringRedisSerializer()
        template.valueSerializer = RedisSerializer.byteArray()      

        return template
    }
@Repository
class RedisRepository(
    private val redisTemplate: RedisTemplate<String, ByteArray>,
) {
    // Protobuf 데이터를 불러오는 메서드
    fun <T : com.google.protobuf.Message> getData(
        key: String,
        parser: com.google.protobuf.Parser<T>
    ): T? {
        val redisValue = redisTemplate.opsForValue().get(key)
        return redisValue?.let { parser.parseFrom(redisValue) } // Protobuf 역직렬화
    }

    // Protobuf를 저장할 때 사용하는 메서드
    fun saveData(
        key: String,
        value: com.google.protobuf.Message // Protobuf Message
    ) {
        try {
            val byteArray = value.toByteArray()
            println("Saving key: $key with value size: ${byteArray.size}") // 로그 추가
            redisTemplate.opsForValue().set(key, byteArray) // Protobuf는 byte array로 저장
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }
}

 

서비스 레이어에서는 mapper를 통해 protobuf로 변환해주는 작업이 필요하다.

    // 이벤트 정보 조회 로직
    fun getEventInfo(eventNo: Long): EventMasterDto? {
        val key = getEventKey(eventNo)
        val byteArray = redisRepository.getData(key, RedisEventInfoMessage.parser()) // message
        return byteArray?.let { redisEventMapper.toDto(it) } // Protobuf 역직렬화
    }

    // 이벤트 정보 저장 로직
    fun setEventInfo(eventNo: Long, eventDto: EventMasterDto) {
        val key = getEventKey(eventNo)
        val protobufEvent = redisEventMapper.toProto(eventDto)
        redisRepository.saveData(key, protobufEvent)
    }

 

결과적으로 Redis에는 이런 데이터가 들어간다. 데이터 길이가 304다.

{��Sample Event"���*����2PERIOD:���B�ԡ�JCOUPONP�XdbACTIVEjYrYzSample Global Event (EN)�示例全球事件 (ZH)�AUTO����LIMIT��NO_LIMIT�
�RANDOM�LIMIT�2�N�Y�Y�GMARKET��Y�	VIP Brand�APPROVED�admin�����Y���Y�Y�encryptedString123

 

위 데이터를 언마샬링하면 아래와 같은 데이터가 된다. 요 데이터는 600~650 정도 되는듯

{
  "eventNo": "123",
  "eventGroupNo": "67890",
  "eventName": "Sample Event",
  "eventStartDate": "2024-09-30T12:00:00Z",
  "eventEndDate": "2024-10-10T12:00:00Z",
  "appEnablePeriodType": "PERIOD",
  "appEnablePeriodStartDate": "2024-09-30T00:00:00Z",
  "appEnablePeriodEndDate": "2024-10-10T23:59:00Z",
  "rewardType": "COUPON",
  "rewardPolicyNo": "1111",
  "rewardCnt": 100,
  "status": "ACTIVE",
  "globalShopUseYn": "Y",
  "globalShopMessageUseYn": "Y",
  "globalShopEngEventName": "Sample Global Event (EN)",
  "globalShopChnEventName": "示例全球事件 (ZH)",
  "appWay": "AUTO",
  "appDeductCnt": 1,
  "appRandomCodeMasterNo": "2222",
  "appLimitType": "LIMIT",
  "appLimitCnt": 5,
  "winLimitType": "NO_LIMIT",
  "winLimitCnt": 10,
  "winWay": "RANDOM",
  "winTotalCntLimitType": "LIMIT",
  "winTotalCnt": 50,
  "asyncWinYn": "N",
  "groupRetryEventYn": "Y",
  "myPageExposeYn": "Y",
  "siteType": "GMARKET",
  "rewardValidDay": 7,
  "vipDisplayYn": "Y",
  "vipDisplayBrandName": "VIP Brand",
  "apprStatus": "APPROVED",
  "apprOprt": "admin",
  "apprDate": "2024-09-29T10:00:00Z",
  "simpleJoinCertUseYn": "Y",
  "eventApplyLimitNo": "3333",
  "groupEventYn": "Y",
  "couponpackUseYn": "Y",
  "encStr": "encryptedString123"
}

 

<참고>

https://engineering.ab180.co/stories/thanos-redis

'Back-end' 카테고리의 다른 글

Protobuf와 Map Struct 친해지길 바래  (0) 2024.10.15
[Redis] 나야 조회수  (3) 2024.10.15
[gRPC] Armeria + gRPC 띄워보기  (7) 2024.10.07
[gRPC] gRPC란  (3) 2024.10.02
[Spring/Thymeleaf] option 태그에 enum 동적으로 넣기  (0) 2024.08.10

+ Recent posts