Redis Pipelining - round-trip time (RTT), 네트워크 요청횟수 감소

taehee kim·2023년 6월 6일
0

redis

목록 보기
4/4

0. round-trip time (RTT)

round-trip time (RTT)이란 클라이언트가 서버로 요청하고 응답을 받기까지 걸리는 시간을 의미합니다.

Redis Server와 서버와 통신할때에도 당연히 RTT를 가지게 될텐데 이를 줄일 수 있는 방법들에 대해서 알아보려고 합니다.

  1. Redis Pipelining
  2. Redis Lua Scripting
  3. Redis Transaction

1. Redis Pipelining

1-1. Redis Pipelining이란?

한마디로 Redis Command들을 Redis Server로 전송할때 한번에 묶어서 하나의 네트워크 전송으로 보내는 기술을 말합니다.

1-2. Redis Command를 모아서 보내야 하는 이유

RTT


일반적으로 네트워크 통신은 다음과 같이 Blocking하게 이루어집니다. 따라서 각각의 command를 따로 보낼 경우 RTT가 크게 증가합니다.

인터넷에 설명들을 보면 3 handwayshake를 command개수마다 한다는 설명도 있지만 보통 Redis Client에서 Connection pool을 사용하기 때문에 이는 맞지 않는 설명이라고 생각합니다.

read, write 시스템 호출 수

매 Command호출 시 개별적으로 네트워크 통신을 하게 되면 read, write 시스템콜을 여러번 호출해야합니다. 따라서 RTT의 시간 관점 뿐만 아니라 커널 레벨의 자원 소모 관점에서도 비효율적입니다.

1-3. Redis Pipelining과 Redis Transaction, Lua Scripting과 차이점

  1. Pipelining은 각각의 Batch들을 Atomic 하게 실행하지 않습니다. 따라서 동시성 문제가 발생할 수 있습니다.(하지만 atomic하지 않기 때문에 더 효율적으로 실행될 수 있는 가능성도 존재합니다.)
  2. Transaction, Pipelining은 read Command로 부터의 결과를 반환받을 수 없습니다. 이를 원할 경우 Lua Scripting을 사용해야합니다.

Redis 공식문서를 보면서 느끼는 점은 Redis에서 Scripting방식을 Transaction과 Pipeline의 상위 호환으로 보는 관점이 있다는 점입니다. Transaction과 Pipeline은 deprecated될 것 같다고 이야기 하는 경우도 있습니다. 실제로 scripting은 이 둘이 할 수 있는 기능을 거의 모두 할 수 있으며 못하는 부분도 할 수 있습니다.

1-4. SpringBoot에서 Pipelining적용

private void setKeyAndDeltaWithPipeline(Integer ttl, String key, Object data, long computationTime) {
        redisTemplate.executePipelined((RedisCallback<Object>) connection -> {
            RedisSerializer<String> serializer = redisTemplate.getStringSerializer();
            byte[] keyBytes = serializer.serialize(key);
            byte[] deltaKeyBytes = serializer.serialize(getDeltaKey(key));
            RedisSerializer<Object> valueSerializer = (RedisSerializer<Object>) redisTemplate.getValueSerializer();
            byte[] dataBytes = valueSerializer.serialize(data);
            byte[] computationTimeBytes = valueSerializer.serialize(computationTime);

            connection.set(keyBytes, dataBytes);
            connection.set(deltaKeyBytes, computationTimeBytes);

            long ttlLong = Long.parseLong(ttl.toString());
            Duration duration = Duration.of(ttlLong, ChronoUnit.SECONDS);
            connection.expire(keyBytes, duration.getSeconds());
            connection.expire(deltaKeyBytes, duration.getSeconds());

            return null;
        });
    }

1-5. Cluster mode일때 주의점

Pipelining, Transaction, Pipelining 모두 같은 node의 key만을 지정해야합니다.

profile
Fail Fast

0개의 댓글