Redis pipeline
什么是Redis pipeline
Redis 中的 Pipeline 指的是管道技术,指的是客户端允许将多个请求依次发给服务器,过程中而不需要等待请求的回复,在最后再一并读取结果即可。
为什么需要pipeline
redis 客户端执行一条命令分 4 个过程:
这个过程称为 Round trip time(简称 RTT, 往返时间),Redis 中的 mget 和 mset 有效节约了 RTT,但大部分命令(如 hgetall,并没有 mhgetall)不支持批量操作,需要消耗 N 次 RTT ,这个时候需要 pipeline 来解决这个问题。
pipeline管道性能
如果我们使用正常的一次发送一条命令,具体的流程如下图所示:
Redis 通过 TCP 来对外提供服务,Client 通过 Socket 连接发起请求,每个请求在命令发出后会阻塞等待 Redis 服务器进行处理,处理完毕后将结果返回给 client。
Redis 的 Client 和 Server 是采用一问一答的形式进行通信,请求一次给一次响应。而这个过程在排除掉 Redis 服务本身做复杂操作时的耗时的话,可以看到最耗时的就是这个网络传输过程。每一个命令都对应了发送、接收两个网络传输,假如一个流程需要 0.1 秒,那么 1 秒最多只能处理 10 个请求,将严重制约 Redis 的性能。
在很多场景下,我们要完成一个业务,可能会对 redis 做连续的多个操作,譬如库存减一、订单加一、余额扣减等等,这有很多个步骤是需要依次连续执行的。
如果我们使用 Redis 的管道 pipeline 来优化上述流程,那么具体的流程图如下图所示:
在未使用管道 pipeline 技术时,一个请求会遵循两个步骤,即首先客户端向服务端发送一个查询请求,并监听 Socket 返回,通常是以阻塞模式,等待服务端响应。 最后服务端处理命令,并将结果返回给客户端。
Redis 管道技术可以在服务端未响应时,客户端可以继续向服务端发送请求,并最终一次性读取所有服务端的响应。这样可以最大限度的利用 Redis 的高性能并节省不必要的网络 IO 开销。
原生批命令与Pipeline对比
- 原生批命令是原子性,pipeline 是非原子性(原子性概念:一个事务是一个不可分割的最小工作单位,要么都成功要么都失败。原子操作是指你的一个业务逻辑必须是不可拆分的,处理一件事情要么都成功,要么都失败,原子不可拆分。)
- 原生批命令一命令多个 key, 但 pipeline 支持多命令(存在事务),非原子性。
- 原生批命令是服务端实现,而 pipeline 需要服务端与客户端共同完成。
pipeline原理
管道(pipeline)可以一次性发送多条命令并在执行完后一次性将结果返回,pipeline 通过减少客户端与 redis 的通信次数来实现降低往返延时时间,而且 Pipeline 实现的原理是队列,而队列的原理是时先进先出,这样就保证数据的顺序性。
Pipeline 的默认的同步的个数为 53 个,也就是说 arges 中累加到 53 条数据时会把数据提交。其过程可以理解为 client 可以将多个命令放到一个 tcp 报文一起发送,server 则可以将多条命令的处理结果放到一个 tcp 报文返回。
pipeline “打包命令” 客户端将多个命令缓存起来,缓冲区满了就发送(将多条命令打包发送);有点像 “请求合并”。服务端接受一组命令集合,切分后逐个执行并一起返回。
Pipeline使用注意
不过在编码时请注意,pipeline 期间将 “独占” 链接,此期间将不能进行非 “管道” 类型的其他操作,直到 pipeline 关闭;如果你的 pipeline 的指令集很庞大,为了不干扰链接中的其他操作,你可以为 pipeline 操作新建 Client 链接,让 pipeline 和其他正常操作分离在 2 个 client 中。
不过 pipeline 事实上所能容忍的操作个数,和 socket-output 缓冲区大小/返回结果的数据尺寸都有很大的关系;同时也意味着每个 redis-server 同时所能支撑的 pipeline 链接的个数,也是有限的,这将受限于 server 的物理内存或网络接口的缓冲能力。
同时,使用 pipeline 方式打包命令发送,redis 必须在处理完所有命令前先缓存起所有命令的处理结果。打包的命令越多,缓存消耗内存也越多。所以并不是打包的命令越多越好。具体多少合适需要根据具体情况测试。
pipeline的局限性
pipeline 只能用于执行连续且无相关性的命令,当某个命令的生成需要依赖于前一个命令的返回时(或需要一起执行时),就无法使用 pipeline 了。通过 scripting 功能,可以规避这一局限性。
有些系统可能对可靠性要求很高,每次操作都需要立马知道这次操作是否成功,是否数据已经写进 redis 了,如 Redis 实现分布式锁等,那这种场景就不适合了。
更多
原文链接:链接
其他:目录
更多文章,可以关注下方公众号: