Redis从入门到入坑13——管道

2023年 8月 21日 45.2k 0

Redis从入门到入坑13——管道

Redis管道

前言

Redis 是一种基于客户端-服务端模型以及请求/响应协议的TCP服务。一个请求会遵循以下步骤:

  • 客户端向服务端发送命令,并监听socket返回,通常以阻塞模式等待服务端响应
  • 服务端处理命令,并将结果返回给客户端
  • 即 发送命令 ——> 命令排队 ——> 命令执行 ——> 返回结果

    交互模型如图所示,每一次的命令执行命令都需要发送数据和执行返回数据,这其中 数据包往返于两端的时间 称为Round Trip Time(简称RTT)

    image.png

    问题:
    如果同时需要执行大量的命令,那么就要等待上一条命令应答后再执行,这中间不仅仅多了RTT(Round Time Trip),而且还频繁调用系统IO,发送网络请求,同时需要redis调用多次read()和write()系统方法,系统方法会将数据从用户态转移到内核态,这样就会对进程上下文有比较大的影响了,影响Redis性能。

    如何优化频繁命令造成的性能瓶颈?

    解决思路:通过批处理命令来优化往返时间

    管道简介(官网原文)

    Redis pipelining is a technique for improving performance by issuing multiple commands at once without waiting for the response to each individual command. Pipelining is supported by most Redis clients.

    Redis管道是一种通过一次发出多个命令而不等待对每个命令的响应来提高性能的技术。大多数 Redis 客户端都支持管道

    管道的作用

    管道(pipeline)可以一次性发送多条命令给服务端,服务端依次处理完完毕后,通过一条响应一次性将结果返回,通过减少客户端与redis的通信次数来实现降低往返延时时间。

    pipeline实现的原理是队列,先进先出特性就保证数据的顺序性。模型如图所示

    image.png

    pipeline不仅能降低客户端与服务端的往返时间,而且大大提高了 Redis 服务器中每秒执行的操作次数 。 这是因为在不使用管道,单从访问数据结构和服务器响应来看,消耗比较少,但是从客户端和服务端的I/O 操作来看,性能的消耗成本是巨大的,这意味着从用户域到内核域。上下文切换是一个巨大的速度损失

    当使用pipeline时,通常通过单个read()系统调用读取许多命令,并且通过单个write()系统调用传递多个应答。因此,随着pipeline的延长,每秒执行的查询总数最初几乎呈线性增长,最终达到没有pipeline的基线的10倍,如图所示

    image.png

    如何使用管道

    1.管道中的命令都是能正常执行不会报错的情况

    --- 新建一个 需要执行的命令文本
    [root@gone data]# vim exec_pipe.txt 
    
    set k1 v1
    set k2 v2
    hset k3 m1 v1
    rpush list1 v1    
    
    [root@gone data]# cat exec_pipe.txt 
    set k1 v1
    set k2 v2
    hset k3 m1 v1 m2 v2 
    rpush list1 v1
    --- 使用管道执行文本中的命令
    [root@gone data]# cat exec_pipe.txt |redis-cli --pipe
    All data transferred. Waiting for the last reply...
    Last reply received from server.
    errors: 0, replies: 4
    
    --- 验证
    127.0.0.1:6379> keys *
    1) "k3"
    2) "k1"
    3) "k2"
    4) "list1"
    127.0.0.1:6379> hget k3 m1
    "v1"
    127.0.0.1:6379> hmget k3 m1 m2
    1) "v1"
    2) "v2"
    
  • 管道中执行的命令存在错误的情况
  • [root@gone data]# vim exec_pipe.txt 
    
    set k1 v1
    set k2 v2
    hset k3 ---------这个命令是错误的
    rpush list1 v1    
    
    [root@gone data]# cat exec_pipe.txt 
    set k1 v1
    set k2 v2
    hset k3  
    rpush list1 v1
    --- 使用管道执行文本中的命令
    [root@gone data]# cat exec_pipe.txt |redis-cli --pipe
    All data transferred. Waiting for the last reply...
    ERR wrong number of arguments for 'hset' command
    Last reply received from server.
    errors: 1, replies: 4
    
    --- 验证
    127.0.0.1:6379> keys *
    1) "k1"
    2) "k2"
    3) "list1"
    127.0.0.1:6379> hget k3 m1
    (nil)
    

    总结

    pipeline 与原生批量命令对比

    • 原生批量命令是原子性的(如mset,mget); pipeline 是非原子性的
    • 原生批量命令一次只能执行一种命令;pipeline 支持批量执行不同命令
    • 原生命令是服务端实现;pipeline需要服务端和客户端共同完成

    pipeline与事务对比

    • 事务具有原子性; pipeline不具有原子性
    • 事务发送命令是逐条发送,在接收到exec命令后才会执行;pipeline是一次性将多条命令发送到服务器
    • 执行事务时会阻塞其他命令的执行;pipeline中的命令执行不会

    使用pipeline的注意事项

    • pipeline缓冲的指令只是会依次执行,不保证原子性,如果执行中指令发生异常,将会继续执行后续的指令
    • 使用pipeline组装的命令个数不能太多,不然数据量过大客户端阻塞的时间可能过长,同时服务端也在被迫回复一个队列答复,占用很多内存

    相关文章

    JavaScript2024新功能:Object.groupBy、正则表达式v标志
    PHP trim 函数对多字节字符的使用和限制
    新函数 json_validate() 、randomizer 类扩展…20 个PHP 8.3 新特性全面解析
    使用HTMX为WordPress增效:如何在不使用复杂框架的情况下增强平台功能
    为React 19做准备:WordPress 6.6用户指南
    如何删除WordPress中的所有评论

    发布评论