round-trip time (RTT)이란 클라이언트가 서버로 요청하고 응답을 받기까지 걸리는 시간을 의미합니다.
Redis Server와 서버와 통신할때에도 당연히 RTT를 가지게 될텐데 이를 줄일 수 있는 방법들에 대해서 알아보려고 합니다.
한마디로 Redis Command들을 Redis Server로 전송할때 한번에 묶어서 하나의 네트워크 전송으로 보내는 기술을 말합니다.
일반적으로 네트워크 통신은 다음과 같이 Blocking하게 이루어집니다. 따라서 각각의 command를 따로 보낼 경우 RTT가 크게 증가합니다.
인터넷에 설명들을 보면 3 handwayshake를 command개수마다 한다는 설명도 있지만 보통 Redis Client에서 Connection pool을 사용하기 때문에 이는 맞지 않는 설명이라고 생각합니다.
매 Command호출 시 개별적으로 네트워크 통신을 하게 되면 read, write 시스템콜을 여러번 호출해야합니다. 따라서 RTT의 시간 관점 뿐만 아니라 커널 레벨의 자원 소모 관점에서도 비효율적입니다.
Redis 공식문서를 보면서 느끼는 점은 Redis에서 Scripting방식을 Transaction과 Pipeline의 상위 호환으로 보는 관점이 있다는 점입니다. Transaction과 Pipeline은 deprecated될 것 같다고 이야기 하는 경우도 있습니다. 실제로 scripting은 이 둘이 할 수 있는 기능을 거의 모두 할 수 있으며 못하는 부분도 할 수 있습니다.
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;
});
}
Pipelining, Transaction, Pipelining 모두 같은 node의 key만을 지정해야합니다.