长春亚泰,详解Redis 管道技能,上海迪士尼乐园

Redis 管道技能

Redis是一种根据客户端-服务端模型(C/S模型)以及恳求/呼应协议的TCP服务。

这意味着一般情况下一个恳求会遵从以下过程:

  • 客户端向服务端发送一个查询恳求,并监听Socket回来,一般是以堵塞形式,等候服务端呼应。
  • 服务端处理指令,并将成果回来给客户端。

这便是一般恳求模型。



所谓RTT(Round-Trip Time),便是往复时延,在计算机网络中它是一个重要的功能指标,表明从发送端发送数据开端,到发送端收到来自接纳端的承认(接纳端收到数据后便当即发送承认),一共阅历的时延。

一般以为,单向时延 = 传输时延t1 + 传达时延t2 + 排队时延t3

为了处理这个问题,Redis支撑经过管道,来到达削减RTT的意图。



SpringDataRedis 运用管道

SpringDataRedis供给了executePipelined办法对管道进行支撑。

下面是一个Redis行列的操作,放到了管道中进行操作。

package net.ijiangtao.tech.framework.spring.ispringboot.redis.pipelining;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.ListOperations;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.test.context.junit4.SpringRunner;
import java.time.Duration;
import java.time.Instant;
/**
* Redis Pipelining
*
* @author ijiangtao
* @create 2019-04-13 22:32
**/
@RunWith(SpringRunner.class)
@SpringBootTest
@Slf4j
public class RedisPipeliningTests {
@Autowired
private RedisTemplate redisTemplate;
private static final String RLIST = "test_redis_list";
@Test
public void test() {
Instant beginTime2 = Instant.now();
redisTemplate.executePipelined(new RedisCallback() {
@Override
public Object doInRedis(RedisConnection connection) throws DataAccessException {
for (int i = 0; i < (10 * 10000); i++) {
connection.lPush(RLIST.getBytes(), (i + "").getBytes());
}
for (int i = 0; i < (10 * 10000); i++) {
connection.rPop(RLIST.getBytes());
}
return null;
}
});
log.info(" ***************** pipeling time duration : {}", Duration.between(beginTime2, Instant.now()).getSeconds());
}
}

留意executePipelined中的doInRedis办法回来总为null。

Redis 管道的功能测试

上面简略演示了管道的运用方法,那么管道的功能终究怎么呢?

下面咱们一起来验证一下。

首要,redis供给了redis-benchmark东西测试功能,我在自己的电脑上经过cmd翻开指令行,不运用管道,进行了一百万次set和get操作,作用如下:

$ redis-benchmark -n 1000000 -t set,get -q
SET: 42971.94 requests per second
GET: 46737.71 requests per second

均匀每秒处理4万屡次操作恳求。

经过-P指令运用管道,作用如下:

$ redis-benchmark -n 1000000 -t set,get -P 16 –q
SET: 198098.27 requests per second
GET: 351988.72 requests per second

运用管道今后,set和get的速度变成了每秒将近20万次和35万次。

然后我在服务器上,测试了运用SpringDataRedis进行rpop出队2000次的功能。

别离运用单线程出队、32个线程并宣布队和单线程管道出队。下面是测试的成果:



从计算成果来看,出队2000次,在单线程下大约需求6秒;32个线程并发恳求大约需求2秒;而单线程下运用管道只需求70毫秒左右。

运用管道技能的留意事项

当你要进行频频的Redis恳求的时分,为了到达最佳功能,下降RTT,你应该运用管道技能。

但假如经过管道发送了太多恳求,也会形成Redis的CPU运用率过高。

下面是经过循环向Redis发送出队指令来监听行列的CUP运用情况:



当管道中累计了很多恳求今后,CUP运用率敏捷升到了100%,这是十分危险的操作。

关于监听行列的场景,一个简略的做法是当发现行列回来的内容为空的时分,就让线程休眠几秒钟,等行列中累积了一定量数据今后再经过管道去取,这样就既能享用管道带来的高功能,又避免了CPU运用率过高的危险。

Thread.currentThread().sleep(10 * 1000);