RedisTemplate 의 구조와 동작원리 Deep dive

jonghyun.log·2026년 6월 28일

deep-dive

목록 보기
2/3
post-thumbnail

N줄요약

  • RedisTemplate은 Spring Data Redis 에서 제공하는 추상화 계층
  • 내부적으로 Operator 객체, Serializer, Redis Connection 객체를 포함함
  • Jvm 객체는 Redis가 저장하지 못하고 네트워크 통신을 하지못해 직렬화가 필요
  • RedisTemplate 사용중 문제가 생기면 직렬화 옵션과 레디스 클라이언트 옵션을 신경쓰는것이 필요

해당 글을 작성한 이유

스프링으로 레디스를 통신하다보면 RedisTempalte을 통해 주로 레디스를 다루곤하는데,
관련해서 RedisTemplate이 어떻게 레디스를 다루고 내부적인 동작에 대한 고찰이 부족하다고 생각해 알아보고자 한다.

RedisTemplate 이란?

RedisTemplate은 spring data redis에서 제공하는 레디스와 상호작용하기 위한 템플릿 클래스이다.

가령, 명시적으로 Redis에 접근해서 데이터를 저장한다고 생각해보자. 그러면 보통 아래와 같이 코드를 작성하게 될것이다.

@RequiredArgsConstructor
@Service
public class RedisTemplateService {

    private final RedisTemplate<String, Object> redisTemplate;

    public void save(String key, String value) {
        redisTemplate.opsForValue().set(key, value);
    }
}

redisTemplate.opsForValue().set(key, value);

해당 코드를 보면 다음과 같은 패턴으로 구성된다.

  1. RedisTemplate 에서 opsFor~() 메서로드 Operation 객체를 꺼낸다.
  2. 1의 Operation 객체로 get(), set(), mget(),... 같은 명령어 실행

나는 이 코드를 쓸때 아래와 같은 궁금증이 들었다.

  • 왜 바로 set() 메서드를 쓰지않고 opsFor~() 를 먼저 호출하고 set()을 호출하지?
  • set() 메서드를 호출하면 어떻게 redis와 통신해서 데이터를 저장하는거지?

이 질문에 한번 대답해 보고자 한다.

redisTemplate.opsForValue().set(key, value) 한줄의 동작

redisTemplate.opsForValue().set(key, value);

한줄은 사실 내부적으로 세가지로 동작한다.

  1. 어떤 Redis 명령을 실행할지 고른다.
  2. Jvm 상의 Java/Koltin 객체를 Redis와 통신하기 위한 바이너리 값으로 바꾼다.
  3. Redis 서버에 바이너리를 보내서 명령어 실행 요청을 보낸다.

RedisTemplate의 핵심 구성요소 3가지

redisTemplate 내부 코드를 보면 크게 세가지 요소로 구성된다.

  1. Serializer : jvm 인스턴스 <-> 네트워크 바이너리간의 직렬화/역직렬화 객체
  2. Operation : Redis 자료구조별 명령어 정의 객체
  3. Connection : Redis 커넥션 객체

Redis 로 요청을 보내는 경우의 RedisTemplate 내부 동작

내부적으로 어떻게 동작하길래 위의 세가지 구성요소로 이루어진걸까?

/**  
 * redisTemplate 을 통한 cache write */
fun saveProductInCache(name: String) {  
    val productDto = ProductDto(id = 0, name = name, price = 10000L)  
    val productKey = cacheKey(name = productDto.name)  
    val opsForValue = redisTemplate.opsForValue()  
    opsForValue.set(productKey, productDto)  
}

이런 메서드를 실행시켜보자.
productDto는 jvm 기반의 인스턴스는
바로 네트워크를 통해 보낼 수 없기 때문에 직렬화가 필요하다.

opsForVaule.set() 메서드는 내부적으로 DefaultValueOperations.set() 메서드를 호출하게 되며, 여기서 Redis에 저장할 key, value를 각각 byte 배열로 변환하여 rawKey, rawValue로 변환한다.

위 사진은 serializer 를 통해 key 값을 바이트 배열로 변환하는 로직이며, 변환 이후에는 아래처럼 바이트 배열로 직렬화를 거친다.

여기서 주목할 점은 valueSerializerProductDto를 그대로 Redis에 넘기지 않고 byte[](바이트 배열) 로 변환한다는 점이다.
RedisTemplateset() 은 단순히 Redis SET 명령을 호출하는 것이 아니라,
명령 실행 전에 Java 객체를 Redis가 저장할 수 있는 형태로 바꾸는 과정을 포함한다.

그리고 마지막으로, RedisTemplate.execute() 메서드 내부의 actions.doInRedis() 메서드에서 위에서 콜백으로 전달한 connection -> connection.set(rawKey, rawValue) 로직을 실행하게 된다.
여기서 connection 객체는 내부적으로 실제 Redis와 통신하기 위한 클라이언트 객체를 래핑한 레디스 커넥션 객체다. (Lettuce, Jedis 등)

get()은 set()과 반대로 동작한다.
key를 rawKey로 직렬화한 뒤 RedisConnection.get(rawKey)을 호출하고,
Redis에서 받은 byte[]를 valueSerializer로 역직렬화해서 ProductDto로 반환한다.

위의 처리 과정을 정리한 다이어그램

왜 이런 구조로 설계했을까?

  • Operation 이 필요한 이유
    • Redis는 String, Hash, List, Set 등 여러 자료구조를 제공하는데, 해당 자료구조별로 명령어가 다름
  • Serializer 가 필요한 이유
    • Redis에 데이터를 저장하려면 Jvm 상의 인스턴스를 네트워크 통신을 통해 Redis에 저장해야하기 때문
    • 이 과정에서 저장하려는 객체는 json 혹은 bytes 배열 등으로 변환하여 redis 메모리상에 저장됨
  • Connection 이 필요한 이유
    • 내부적으로 Lettuce/Jedis 같은 실제 클라이언트를 통해 커넥션을 맺고 요청을 주고 받는데, 이러한 세부 구현을 숨기고 추상화를 통해 구현 편의성을 제공하기 위해

참고 : 객체 직렬화란?

객체 직렬화를 설명하는 이유는 이 과정을 제대로 이해하고 있어야
RedisTemplate의 구성요소에 대해 이해할 수 있기 때문이다.

객체 직렬화를 요약하면

  • JVM 기반 힙 공간에 존재하는 인스턴스의 데이터는 메모리상에 데이터가 참조형태를 통해 유기적으로 연결되어 존재
  • 네트워크 상에서 데이터는 바이너리 형태의 문자열만 통신 가능
  • 즉, JVM 위의 인스턴스를 직렬화/역직렬화를 통해 바이너리 문자열로 변환하여 네트워크로 보내기 위한 과정

이는 Redis <-> Spring 뿐만 아니라 Spring 에서 네트워크 통신을 수행하는 모든 작업에 직렬화/역직렬화 과정이 포함된다.

여기까지 이해했다면, RedisTemplate 역시 내부적으로 레디스 명령어를 수행하면 직렬화/역직렬화 과정이 필요하다는것을 이해할것이다.

관련 참고 아티클

실무적으로 가져갈 점

  • RedisTemplate을 볼 때는 "명령어 API" 만 보지 말고 serializer 설정을 같이 봐야 한다.
  • 저장된 값이 깨지거나 타입 캐스팅 문제가 나면 serializer를 먼저 의심할 수 있다.
  • RedisTemplate은 편의 API가 아니라 Redis 통신 과정을 추상화한 Template 클래스이다.

레슨런

RedisTemplate는 Redis 와 통신하기 위해 직렬화하는 과정과 redis 클라이언트 사용법을 추상화하여 해당 과정을 신경쓰지 않고도 편하게 사용하기 위한 템플릿 클래스를 제공하는 것을 알았습니다.

이 편의를 제공하기 위해 내부적으로 serializer, operation 객체, Redis Client(Redis Connection) 객체를 가지고 있다는것을 배웠습니다.

개인적으로는 RedisTemplate이 이런 구조를 가지고 있는지에 대한 물음표가 있었는데,
이번에 관련 내용을 공부하며 궁금증을 어느정도 해소하게 되어 기분이 좋습니다.

0개의 댓글