zoukankan      html  css  js  c++  java
  • Redis客户端

    客户端通信协议

    Redis制定了RESP(REdis Serialization Protocol, Redis序列化协议) 实现客户端与服务端的正常交互, 这种协议简单高效, 既能够被机器解析, 又容易被人类识别。

    示例:客户端发送一条set hello world命令给服务端。按照RESP的标准, 客户端需要将其封装为如下格式(每行用 分隔):

    *3
    $3
    SET
    $5
    hello
    $5
    world

    返回:

    +OK

    RESP格式说明:
    发送命令格式

    RESP的规定一条命令的格式如下, CRLF代表"
    "
    *<参数数量> CRLF
    $<参数1的字节数量> CRLF
    <参数1> CRLF
    ...
    $<参数N的字节数量> CRLF
    <参数N> CRLF

    示例解说:以set hello world为例

    *3         参数数量为3个,第一行为*3
    $3         set有3个字节,第二行为$3
    SET        第一个参数set
    $5         hello有5个字节,第三行为$5
    hello      第二个参数hellot
    $5         world有5个字节,第五行为$5
    world      第三个参数world

    上面只是格式化显示的结果, 实际传输格式为如下代码:

    *3
    $3
    SET
    $5
    hello
    $5
    world
    

    返回结果格式
    Redis的返回结果类型分为以下五种

    ·状态回复: 在RESP中第一个字节为"+"。
    ·错误回复: 在RESP中第一个字节为"-"。
    ·整数回复: 在RESP中第一个字节为""。
    ·字符串回复: 在RESP中第一个字节为"$"。
    ·多条字符串回复: 在RESP中第一个字节为"*"

    redis-cli只能看到最终的执行结果, 那是因为redis-cli本身就是按照RESP进行结果解析的, 所以看不到中间结果。
    例如执行set hello world, 返回结果是OK, 并不能看到加号:

    127.0.0.1:6379> set hello world
    OK

    为了看到Redis服务端返回的“真正”结果, 可以使用nc命令、 telnet命令、 甚至写一个socket程序进行模拟。
    示例:

    使用nc命令连接redis:nc 127.0.0.1 6379
    set hello world
    +OK
    
    sethx
    -ERR unknown command 'sethx'
    
    incr counter
    :1
    
    get hello
    $5
    world
    
    mget java python
    *2
    $5
    jedis
    $8
    redis-py


    无论是字符串回复还是多条字符串回复, 如果有nil值, 那么会返回$-1

    对一个不存在的键执行get操作, 返回结果为:
    get not_exist_key
    $-1
    
    如果批量操作中包含一条为nil值的结果, 那么返回结果如下:
    mget hello not_exist_key java
    *3
    $5
    world
    $-1
    $5
    jedis

    客户端API


    client list

    id=5020789 addr=172.19.8.172:36962 fd=516 name= age=24621 idle=24621 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=0 qbuf-free=0 obl=0 oll=0 omem=0 events=r cmd=cluster
    
    标识:id、 addr、 fd、 name
    id:客户端连接的唯一标识,这个id是随着Redis的连接自增的,重启Redis后会重置为0。
      addr:客户端连接的ip和端口。
      fd:socket的文件描述符,与lsof命令结果中的fd是同一个,如果fd=-1代表当前客户端不是外部客户端,而是Redis内部的伪装客户端。
      name:客户端的名字 后面的client setName和client getName两个命令会对其进行说明。
    
    
    输入缓冲区: qbuf、 qbuf-free
      qbuf、 qbuf-free 分别代表这个缓冲区的总容量和剩余容量。


    输出缓冲区: obl、 oll、 omem
    obl代表固定缓冲区的长度
    oll代表动态缓冲区列表的长度
    omem代表使用的字节数
    注:输出缓冲区由两部分组成: 固定缓冲区(16KB)和动态缓冲区,其中固定缓冲区返回比较小的执行结果,而动态缓冲区返回比较大的结果。固定缓冲区使用的是字节数组, 动态缓冲区使用的是列表。 当固定缓冲区存满后会将Redis新的返回结果存放在动态缓冲区的队列中。


      客户端的存活状态: age、idle
        age表示当前客户端已经连接的时间
        idle表示最近一次的空闲时间


      客户端类型: flag

        N 普通客户端
        M 当前客户端是master节点
        S 当前客户端是slave节点
        O 当前客户端正在执行monitor命令
        X 当前客户端正在执行事务
        b 当前客户端正在等待阻塞事件
        i 当前客户端正在等待VM I/O,此状态目前已弃用
        d 一个受监视的键被修改,EXEC命令将失败
        u 客户端未被阻塞
        c 回复完整输出后,关闭连接
        A 尽可能快的关闭连接

    输入缓冲区说明:

    Redis为每个客户端分配了输入缓冲区,它的作用是将客户端发送的命令临时保存,同时Redis从会输入缓冲区拉取命令并执行, 输入缓冲区为客户端发送命令到Redis执行命令提供了缓冲功能。
    注:输入缓冲区会根据输入内容大小的不同动态调整,只是要求每个客户端缓冲区的大小不能超过1G,超过后客户端将被关闭。

    输入缓冲使用不当会产生两个问题:

    ·一旦某个客户端的输入缓冲区超过1G, 客户端将会被关闭。
    ·输入缓冲区不受maxmemory控制, 假设一个Redis实例设置了maxmemory为4G, 已经存储了2G数据, 但是如果此时输入缓冲区使用了3G, 已经超过maxmemory限制, 可能会产生数据丢失、 键值淘汰、 OOM等情况

    造成输入缓冲区过大的原因有哪些?

    1、Redis的处理速度跟不上输入缓冲区的输入速度,并且每次进入输入缓冲区的命令包含了大量bigkey, 从而造成了输入缓冲区过大的情况。 
    2、还有一种情况就是Redis发生了阻塞,短期内不能处理命令,造成客户端输入的命令积压在了输入缓冲区,造成了输入缓冲区过大。

    监控输入缓冲区异常的方法有两种:

    1、通过定期执行client list命令,收集qbuf和qbuf-free找到异常的连接记录并分析,最终找到可能出问题的客户端。
    2、通过info命令的info clients模块,找到最大的输入缓冲区。

    对比client list和info clients监控输入缓冲区的优劣势

    输出缓冲区说明:

    Redis为每个客户端分配了输出缓冲区,它的作用是保存命令执行的结果返回给客户端,为Redis和客户端交互返回结果提供缓冲。
    注:输出缓冲区的容量可以通过参数client-outputbuffer-limit来进行设置,并且输出缓冲区做得更加细致,按照客户端的不同分为三种: 普通客户端、 发布订阅客户端、 slave客户端。

    client-outputbuffer-limit配置:

    client-output-buffer-limit <class> <hard limit> <soft limit> <soft seconds>
    ·<class>: 客户端类型, 分为三种。 
        a) normal: 普通客户端; 
        b) slave: slave客户端,用于复制; 
        c) pubsub: 发布订阅客户端。
    ·<hard limit>: 如果客户端使用的输出缓冲区大于<hard limit>, 客户端会被立即关闭。
    ·<soft limit>和<soft seconds>: 如果客户端使用的输出缓冲区超过了<softlimit>并且持续了<soft limit>秒, 客户端会被立即关闭。

    redis默认配置:

    client-output-buffer-limit normal 0 0 0
    client-output-buffer-limit slave 256mb 64mb 60
    client-output-buffer-limit pubsub 32mb 8mb 60

    其他:

    client setName xx               给客户端设置名字,这样比较容易标识出客户端的来源。
    client getName                  查看当前客户端的name
    client kill ip:port             杀掉指定IP地址和端口的客户端
    client pause timeout(毫秒)       阻塞客户端timeout毫秒数,在此期间客户端连接将被阻塞(对主从复制的客户端无效)
    monitor                         监控Redis正在执行的命令
  • 相关阅读:
    再谈 Devstack(Rocky)
    记一次性能测试与优化经历
    Nova rebuild for boot from volume issue
    OpenStack RPM Sample 解析
    [Cinder] 存储 Qos
    Octavia Rocky UDP 负载均衡功能试验
    Keepalived + LVS-NAT 实现高可用四层 TCP/UDP 负载均衡器
    LVS 四层 TCP/UDP 负载均衡器
    集群的定义以及类别定义
    对程序员又了解了一些
  • 原文地址:https://www.cnblogs.com/MacoLee/p/14066842.html
Copyright © 2011-2022 走看看