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不会有调用失败的风险)。





  • 相关阅读:
    A1143. Lowest Common Ancestor
    三个loading小动画实例
    CSS之圣杯布局与双飞翼布局
    sublime个人快捷键
    响应式之表格
    CSS之column语法
    使用column简单实现瀑布流效果
    Flex 布局教程:实例篇(转)
    Flex 布局教程:语法篇(转)
    简单实现瀑布流效果
  • 原文地址:https://www.cnblogs.com/caoxiaojian/p/5633447.html
Copyright © 2011-2022 走看看