第4章 客户端-客户端管理

发布于:2024-06-28 ⋅ 阅读:(19) ⋅ 点赞:(0)

1. 客户端API
1.1client list
client list命令能列出与Redis服务端相连的所有客户端连接信息。

127.0.0.1:6379> client list
id=254487 addr=10.2.xx.234:60240 fd=1311 name= age=8888581 idle=8888581 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=0 qbuf-free=0 obl=0 oll=0 omem=0 events=r cmd=get
id=300210 addr=10.2.xx.215:61972 fd=3342 name= age=8054103 idle=8054103 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=0 qbuf-free=0 obl=0 oll=0 omem=0 events=r cmd=get
id=5448879 addr=10.16.xx.105:51157 fd=233 name= age=411281 idle=331077 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=0 qbuf-free=0 obl=0 oll=0 omem=0 events=r cmd=ttl
id=2232080 addr=10.16.xx.55:32886 fd=946 name= age=603382 idle=331060 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=0 qbuf-free=0 obl=0 oll=0 omem=0 events=r cmd=get
id=7125108 addr=10.10.xx.103:33403 fd=139 name= age=241 idle=1 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=0 qbuf-free=0 obl=0 oll=0 omem=0 events=r cmd=del
id=7125109 addr=10.10.xx.101:58658 fd=140 name= age=241 idle=1 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=0 qbuf-free=0 obl=0 oll=0 omem=0 events=r cmd=del
...

在这里插入图片描述
下面将选择几个重要的属性进行说明:
(1)标识:id、addr、fd、name 这四个属性属于客户端的标识:

  • id:客户端连接的唯一标识,这个id是随着Redis的连接自增的,重启Redis后会重置为0。
  • addr:客户端连接的ip和端口。
  • fd:socket的文件描述符,与lsof命令结果中的fd是同一个,如果fd=-1代表当前客户端不是外部客户端,而是Redis内部的伪装客户端。
  • name:客户端的名字,后面的client setName和client getName两个命令会对其进行说明。
    (2)输入缓冲区:qbuf、qbuf-free
    Redis为每个客户端分配了输入缓冲区,它的作用是将客户端发送的命令临时保存,同时Redis会从输入缓冲区拉取命令并执行。client list中qbuf和qbuf-free分别代表这个缓冲区的总容量和剩余容量,Redis没有提供相应的配置来规定每个缓冲区的大小,输入缓冲区会根据输入内容大小的不同动态调整,只是要求每个客户端缓冲区的大小不能超过1G,超过后客户端将被关闭。
    输入缓冲使用不当会产生两个问题:
  • 一旦某个客户端的输入缓冲区超过1G,客户端将会被关闭。
  • 输入缓冲区不受maxmemory控制,假设一个Redis实例设置了maxmemory为4G,已经存储了2G数据,但是如果此时输入缓冲区使用了3G,已经超过maxmemory限制,可能会产生数据丢失、键值淘汰、OOM等情况。
    造成输入缓冲区过大的原因有哪些?
  • 输入缓冲区过大主要是因为Redis的处理速度跟不上输入缓冲区的输入速度,并且每次进入输入缓冲区的命令包含了大量bigkey,从而造成了输入缓冲区过大的情况。
  • Redis发生了阻塞,短期内不能处理命令,造成客户端输入的命令积压在了输入缓冲区,造成了输入缓冲区过大。
    那么如何快速发现和监控呢?监控输入缓冲区异常的方法有两种:
  • 通过定期执行client list命令,收集qbuf和qbuf-free找到异常的连接记录并分析,最终找到可能出问题的客户端。
  • 通过info命令的info clients模块,找到最大的输入缓冲区,例如下面命令中的其中client_biggest_input_buf代表最大的输入缓冲区,例如可以设置超过10M就进行报警:
    在这里插入图片描述
    输入缓冲区问题出现概率比较低,但是也要做好防范,在开发中要减少bigkey、减少Redis阻塞、合理的监控报警。
    (3)输出缓冲区:obl、oll、omem
    Redis为每个客户端分配了输出缓冲区,它的作用是保存命令执行的结果返回给客户端,为Redis和客户端交互返回结果提供缓冲,与输入缓冲区不同的是,输出缓冲区的容量可以通过参数client-output-buffer-limit来进行设置,并且输出缓冲区做得更加细致,按照客户端的不同分为三种:普通客户端、发布订阅客户端、slave客户端。
    在这里插入图片描述
    对应的配置规则是:
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:如果客户端使用的输出缓冲区超过了soft limit并且持续了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

和输入缓冲区相同的是,输出缓冲区也不会受到maxmemory的限制,如果使用不当同样会造成maxmemory用满产生的数据丢失、键值淘汰、OOM等情况。
实际上输出缓冲区由两部分组成:固定缓冲区(16KB)和动态缓冲区,其中固定缓冲区返回比较小的执行结果,而动态缓冲区返回比较大的结果,例如大的字符串、hgetall、smembers命令的结果等,
固定缓冲区使用的是字节数组,动态缓冲区使用的是列表。当固定缓冲区存满后会将Redis新的返回结果存放在动态缓冲区的队列中,队列中的每个对象就是每个返回结果
在这里插入图片描述
client list中的obl代表固定缓冲区的长度,oll代表动态缓冲区列表的长度,omem代表使用的字节数。
监控输出缓冲区的方法依然有两种:

  • 通过定期执行client list命令,收集obl、oll、omem找到异常的连接记录并分析,最终找到可能出问题的客户端。
  • 通过info命令的info clients模块,找到输出缓冲区列表最大对象数。其中,client_longest_output_list代表输出缓冲区列表最大对象数。
127.0.0.1:6379> info clients
# Clients
connected_clients:502
client_longest_output_list:4869
client_biggest_input_buf:0
blocked_clients:0

相比于输入缓冲区,输出缓冲区出现异常的概率相对会比较大,那么如何预防呢?

  • 进行上述监控,设置阀值,超过阀值及时处理。
  • 限制普通客户端输出缓冲区的,把错误扼杀在摇篮中,例如可以进行如下设置:
client-output-buffer-limit normal 20mb 10mb 120
  • 适当增大slave的输出缓冲区的,如果master节点写入较大,slave客户端的输出缓冲区可能会比较大,一旦slave客户端连接因为输出缓冲区溢出被kill,会造成复制重连。
  • 限制容易让输出缓冲区增大的命令,例如,高并发下的monitor命令就是一个危险的命令。
  • 及时监控内存,一旦发现内存抖动频繁,可能就是输出缓冲区过大。
    (4)客户端的存活状态
    client list中的age和idle分别代表当前客户端已经连接的时间和最近一次的空闲时间:
    例如上面这条记录代表当期客户端连接Redis的时间为8888581秒,其中空闲了8888581秒,实际上这种就属于不太正常的情况,当age等于idle时,说明连接一直处于空闲状态。
 id=254487 addr=10.2.xx.234:60240 fd=1311 name= age=8888581 idle=8888581 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=0 qbuf-free=0 obl=0 oll=0 omem=0 events=r cmd=get

(5)客户端的限制maxclients和timeout
Redis提供了maxclients参数来限制最大客户端连接数,一旦连接数超过maxclients,新的连接将被拒绝。maxclients默认值是10000,可以通过info clients来查询当前Redis的连接数:
可以通过config set maxclients对最大客户端连接数进行动态设置,config get maxclients获取最大客户端连接数。
一般来说maxclients=10000在大部分场景下已经绝对够用,但是某些情况由于业务方使用不当(例如没有主动关闭连接)可能存在大量idle连接,无论是从网络连接的成本还是超过maxclients的后果来说都不是什么好事,因此Redis提供了timeout(单位为秒)参数来限制连接的最大空闲时间,一旦客户端连接的idle时间超过了timeout,连接将会被关闭,例如设置timeout为30秒:config set timeout 30。Redis的默认配置给出的timeout=0,表示客户端永远不会超时,即Redis会一直保持与客户端的连接不断开。这是基于对客户端开发的一种保护。例如很多开发人员在使用JedisPool时不会对连接池对象做空闲检测和验证,如果设置了timeout>0,可能就会出现上面的异常,对应用业务造成一定影响,但是如果Redis的客户端使用不当或者客户端本身的一些问题,造成没有及时释放客户端连接,可能会造成大量的idle连接占据着很多连接资源,一旦超过maxclients;后果也是不堪设想。
在实际开发和运维中,需要将timeout设置成大于0,例如可以设置为300秒,同时在客户端使用上添加空闲检测和验证等等措施。
(6)客户端类型
client list中的flag是用于标识当前客户端的类型,例如flag=S代表当前客户端是slave客户端、flag=N代表当前是普通客户端,flag=O代表当前客户端正在执行monitor命令。
在这里插入图片描述
1.2client setName和client getName

client setName xx
client getName

client getName和setName命令可以做为标识客户端来源的一种方式,但是通常来讲,在Redis只有一个应用方使用的情况下,IP和端口作为标识会更加清晰。当多个应用方共同使用一个Redis,那么此时client setName可以作为标识客户端的一个依据。
1.3.client kill

client kill ip:port

此命令用于杀掉指定IP地址和端口的客户端。

127.0.0.1:6379> client kill 127.0.0.1:52343
OK

由于一些原因(例如设置timeout=0时产生的长时间idle的客户端),需要手动杀掉客户端连接时,可以使用client kill命令。
1.4.client pause

client pause timeout(毫秒)

client pause命令用于阻塞客户端timeout毫秒数,在此期间客户端连接将被阻塞。
在这里插入图片描述
例如在一个客户端执行:

127.0.0.1:6379> client pause 10000
OK

在另一个客户端执行ping命令,发现整个ping命令执行了9.72秒(手动执行redis-cli,只为了演示,不代表真实执行时间):

127.0.0.1:6379> ping
PONG
(9.72s)

该命令可以在如下场景起到作用:

  • client pause只对普通和发布订阅客户端有效,对于主从复制(从节点内部伪装了一个客户端)是无效的,也就是此期间主从复制是正常进行的,所以此命令可以用来让主从复制保持一致。
  • client pause可以用一种可控的方式将客户端连接从一个Redis节点切换到另一个Redis节点。
  • 需要注意的是在生产环境中,暂停客户端成本非常高。
    1.5.monitor
    monitor命令用于监控Redis正在执行的命令,如图4-11所示,我们打开了两个redis-cli,一个执行set get ping命令,另一个执行monitor命令。可以看到monitor命令能够监听其他客户端正在执行的命令,并记录了详细的时间戳。
    在这里插入图片描述
    monitor的作用很明显,如果开发和运维人员想监听Redis正在执行的命令,就可以用monitor命令,但事实并非如此美好,每个客户端都有自己的输出缓冲区,既然monitor能监听到所有的命令,一旦Redis的并发量过大,monitor客户端的输出缓冲会暴涨,可能瞬间会占用大量内存,下图展示了monitor命令造成大量内存使用。
    在这里插入图片描述
    2.客户端统计片段
    例如下面就是一次info clients的执行结果:
127.0.0.1:6379> info clients
# Clients
connected_clients:1414
client_longest_output_list:0
client_biggest_input_buf:2097152
blocked_clients:0

说明如下:
1)connected_clients:代表当前Redis节点的客户端连接数,需要重点监控,一旦超过maxclients,新的客户端连接将被拒绝。
2)client_longest_output_list:当前所有输出缓冲区中队列对象个数的最大值。
3)client_biggest_input_buf:当前所有输入缓冲区中占用的最大容量。
4)blocked_clients:正在执行阻塞命令(例如blpop、brpop、brpoplpush)的客户端个数。除此之外info stats中还包含了两个客户端相关的统计指标,如下:

127.0.0.1:6379> info stats
# Stats
total_connections_received:80
...
rejected_connections:0

参数说明:
·total_connections_received:Redis自启动以来处理的客户端连接数总数。
·rejected_connections:Redis自启动以来拒绝的客户端连接数,需要重点监控。


网站公告

今日签到

点亮在社区的每一天
去签到