redis pipeline
“redis pipeline” why pipeline ? Redis 客户端与 server 的请求/响应模型 前面的文章 Redis 底层协议RESP详解 ,介绍到 redis 客户端与 redis-server 交互通信,采用的 TCP 请求/响应模型; 我们通过 Redis 客户端执行命令,如set key value,客户端遵循RESP协议,将命令的协议串发送给redis-server执行,redis-server执行完成后再同步返回结果。 手写Redis客户端-实现自己的Jedis 对这一过程进行了重点分析,并遵循RESP实现了自己简易版的Redis客户端。 Redis客户端与server通信,使用的是客户端-服务器 (CS) 模式;每次交互,都是完整的请求/响应模式。 这意味着通常情况下一个请求会遵循以下步骤: 客户端连接服务端,基于特定的端口,发送一个命令,并监听Socket返回,通常是以阻塞模式,等待服务端响应。 服务端处理命令,并将结果返回给客户端。 很显然,我们使用jedis或lettuce执行Redis命令,每次都是建立socket连接,并等待返回。 每个命令底层建立TCP连接的时间是省不掉的,即使我们都是在内网使用Redis,内网快但请求/响应的往返时间是不会减少的。 当需要对一组kv进行批量操作时,这组命令的耗时=sum(N*(建立连接时间+发送命令、返回结果的往返时间RTT)),随批量操作的key越多,时间累加呈线性增长。 顺理成章的,就出现了像数据库连接池等池化思想的衍生,redis连接也进行“池化”,如JedisPool。 JedisPool就足够了? 池化connection后,每次执行命令都从池子里“借”,用完之后再将connection“还”到池子。只是节省了创建TCP连接的时间; 当需要对一组kv进行批量操作时,JedisPool池子里的connection连接、极端情况都被用完了,怎么办? ——需要等待JedisPool池里有可复用的connection才能继续执行; redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool … Caused by: java.util.NoSuchElementException: Timeout waiting for idle object at org.apache.commons.pool2.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:449) 如果在指定的等待时间内没有等到idle空闲连接,就报异常了。 尽管使用了池化、将connection进行复用,但不可避免的带来其他问题: https://jjlu521016.github.io/2018/12/09/JedisPool常见问题.html 除了池化的connection会被瞬间用完,Redis官网还给出了另外一个性能损耗的原因: It’s not just a matter of RTT https://redis.io/topics/pipelining 虽然池化的connection,节省了建立连接的时间,但多条命令(发送命令到sever、server返回结果)分别执行多次socket网络IO,涉及到read()和write() syscall系统调用,这意味着从用户态到内核态。上下文切换是巨大的速度损失。 ...