zoukankan      html  css  js  c++  java
  • Redis 请求应答模式和往返延时 Pipelining

    Redis是一个CS结构的TCP服务器,使用”请求-应答”的模式。,客户端发起一个请求是这样的步骤:

    • 客户端发送一个请求给服务器,然后等待服务器的响应,一般客户端使用阻塞模式来等待服务器响应。
    • 服务器收到请求并处理完毕后,发送结果给客户端。

     

      举个例子,发送下面4个命令大概就是这样的顺序:

    • 客户端发送: INCR X
    • 服务器响应: 1
    • 客户端发送: INCR X
    • 服务器响应: 2
    • 客户端发送: INCR X
    • 服务器响应: 3
    • 客户端发送: INCR X
    • 服务器响应: 4

      客户端和服务器通过网络连接,网速可以非常快, 也可以非常慢。不管是快还是慢,消息包从客户端到服务器,再从服务器返回到客户端,总是要需要时间的。这个时间被称之为RTT(Round Trip Time,往返延时)。显然,当客户端需要发送多条请求时(比如往一个list中加很多元素,或者往一个数据库中填充很多keys),这个往返延时会影响到性能。假设网络非常慢,往返延时达到250毫秒,就算服务器每秒可以处理10万个请求,客户端也只能每秒处理4个请求。就算使用环回接口,往返延时非常小,如果需要执行很多写的操作, 也是要浪费许多时间的。

      幸好我们有办法改进这种情况。

    Redis Pipelining

          “请求-响应”模式的服务器在处理完一个请求后就开始处理下一个请求,不管客户端是否读取到前一个请求的响应结果。这让客户端不需要发一个请求等一个响应的串行,可以一次发送多个请求,再最后一次性读取所有响应。这就叫pipelining(管道化),这种技术几十年来广泛的使用。比如很多POP3协议支持这个特性,大大的加速了从服务器上下载新邮件的速度。

        Redis在很早的版本就支持pipeling,所以无论你用的是什么版本的redis,都可以用pipelining。下面是一个使用netcat的演示例子:

    $ (printf "PING
    PING
    PING
    "; sleep 1) | nc localhost 6379
    +PONG
    +PONG
    +PONG

      我们的第一个例子,如果使用pipeline,客户端的请求和服务器的响应顺序就是如下:

    • 客户端发送: INCR X
    • 客户端发送: INCR X
    • 客户端发送: INCR X
    • 客户端发送: INCR X
    • 服务器响应: 1
    • 服务器响应: 2
    • 服务器响应: 3
    • 服务器响应: 4

      注意:当客户端使用pipelining发送很多请求时,服务器将在内存中使用队列存储这些指令的响应。所以批量发送的指令数量,最好在一个合理的范围内,比如每次发1万条指令,读取完响应后再发送另外1万条指令。2万条指令,一次性发送和分2次发送,对客户端来说速度是差不多的,但是对服务器来说,内存占用差了1万条响应的大小。

    性能测试

      下面是我们用Redis Ruby客户端测试使用pipelining带来的性能改进:

    require 'rubygems'
    require 'redis'
    
    def bench(descr)
        start = Time.now
        yield
        puts "#{descr} #{Time.now-start} seconds"
    end
    
    def without_pipelining
        r = Redis.new
        10000.times {
            r.ping
        }
    end
    
    def with_pipelining
        r = Redis.new
        r.pipelined {
            10000.times {
                r.ping
            }
        }
    end
    
    bench("without pipelining") {
        without_pipelining
    }
    bench("with pipelining") {
        with_pipelining
    }

        在我的Mac OS X系统中运行上面的脚本,由于使用环回接口往返延时非常小,这样pipeling带来的优化非常小。可以得到下面的结果:

    without pipelining 1.185238 seconds
    with pipelining 0.250783 seconds
    

      从结果可以看到,使用pipelining技术,我们的传输速度提高了5倍。

    管道化 VS 脚本

        大部分使用pipelining的情况都可以用Redis脚本(2.6或高于2.6的版本才支持)来代替,使之更高效的在服务器端执行。使用脚本的最大好处是,在最小的延迟下可以读和写,比如可以:让“读,计算,写”这样一个流程非常快(pipeling不能处理这种情景,因为客户端需要得到响应之后才能计算和写)。有时候,应用程序可能需要在一个pipeline中发送多个EVAL或EVALSHA指令,redis的SCRITP LOAD指令能很好的满足这种需求(它保证了EVALSHA不会有调用失败的风险)。





  • 相关阅读:
    sublime text 4 vim 插件配置
    ssh-keygen 的使用
    distribution transaction solution
    bilibili 大数据 视频下载 you-get
    Deepin 20.2.1 安装 MS SQL 2019 容器版本
    【转】使用Linux下Docker部署MSSQL并加载主机目录下的数据库
    【转】You Can Now Use OneDrive in Linux Natively Thanks to Insync
    dotnet 诊断工具安装命令
    Linux 使用 xrandr 设置屏幕分辨率
    【转】CentOS 7.9 2009 ISO 官方原版镜像下载
  • 原文地址:https://www.cnblogs.com/caoxiaojian/p/5633447.html
Copyright © 2011-2022 走看看