【Redis-基础】客户端

Redis是用单线程来处理多个客户端的访问,因此作为Redis的开发和运维人员需要了解Redis服务端和客户端的通信协议,以及主流编程语言的Redis客户端使用方法,同时还需要了解客户端管理的相应API以及开发运维中可能遇到的问题。

客户端API

client list

client list命令能列出与Redis服务端相连的所有客户端连接信息,输出结果的每一行代表一个客户端的信息,它们是每个客户端的一些执行状态,下面选择几个重要的属性进行说明。

标识:id、addr、fd、name
  • id:客户端连接的唯一标识,这个id是随着Redis的连接自增的,重启Redis后会重置为0。
  • addr:客户端连接的ip和端口。
  • fd:socket的文件描述符,与lsof命令结果中的fd是同一个,如果fd=-1代表当前客户端不是外部客户端,而是Redis内部的伪客户端。
  • name:客户端的名字。
输入缓冲区:qbuf、qbuf-free

Redis为每个客户端分配了输入缓冲区,它的作用是将客户端发送的命令临时保存,同时Redis从会输入缓冲区拉取命令并执行。

qbuf和qbuf-free分别代表这个缓冲区的总容量和剩余容量,Redis没有提供相应的配置来规定每个缓冲区的大小,输入缓冲区会根据输入内容大小的不同动态调整。

输入缓冲有两点需要注意:

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

输入缓冲区使用不当造成的危害非常大,那么造成输入缓冲区过大的原因有哪些?

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

那么如何快速发现和监控呢?监控输入缓冲区异常的方法有两种:

  • 通过定期执行client list命令,收集qbuf和qbuf-free找到异常的连接记录并分析,最终找到可能出问题的客户端。
  • 通过info命令的info clients模块,找到最大的输入缓冲区,例如可以设置超过10M就进行报警。

【Redis-基础】客户端_第1张图片

输出缓冲区:obl、oll、omem

Redis为每个客户端分配了输出缓冲区,它的作用是保存命令执行的结果返回给客户端,为Redis和客户端交互返回结果提供缓冲。

与输入缓冲区不同的是,输出缓冲区的容量可以通过参数client-output-buffer-limit来进行设置,并且输出缓冲区做得更加细致,按照客户端的不同分为三种:普通客户端、发布订阅客户端、slave客户端。对应的配置规则是:

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

输出缓冲区也不受maxmemory的限制,如果使用不当同样会造成maxmemory用满产生的数据丢失、键值淘汰、OOM等情况。

实际上输出缓冲区由两部分组成:固定缓冲区(16KB)和动态缓冲区,其中固定缓冲区返回比较小的执行结果,而动态缓冲区返回比较大的结果。固定缓冲区使用的是字节数组,动态缓冲区使用的是列表。当固定缓冲区存满后会将Redis新的返回结果存放在动态缓冲区的队列中,队列中的每个对象就是每个返回结果。

client list中的obl代表固定缓冲区的长度,oll代表动态缓冲区列表的长度,omem代表使用的字节数。监控输出缓冲区的方法和监控输入缓冲区的方法一致。

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

  • 进行上述监控,设置阀值,超过阀值及时处理。
  • 限制普通客户端输出缓冲区的 ,把错误扼杀在摇篮中。
  • 适当增大slave的输出缓冲区的 ,如果master节点写入较大,slave客户端的输出缓冲区可能会比较大,一旦slave客户端连接因为输出缓冲区溢出被kill,会造成复制重连。
  • 限制容易让输出缓冲区增大的命令,例如,高并发下的monitor命令就是一个危险的命令。
  • 及时监控内存,一旦发现内存抖动频繁,可能就是输出缓冲区过大。
客户端的存活状态

client list中的age和idle分别代表当前客户端已经连接的时间和最近一次的空闲时间。

客户端的限制maxclients和timeout

Redis提供了maxclients参数来限制最大客户端连接数,一旦连接数超过maxclients,新的连接将被拒绝。maxclients默认值是10000,可以通过info clients来查询当前Redis的连接数。

Redis同时提供了timeout(单位为秒)参数来限制连接的最大空闲时间,一旦客户端连接的idle时间超过了timeout,连接将会被关闭。

客户端类型

client list中的flag是用于标识当前客户端的类型,见下表:

【Redis-基础】客户端_第2张图片

其他

下表列出之前介绍过以及一些比较简单或者不太重要的属性:

【Redis-基础】客户端_第3张图片

【Redis-基础】客户端_第4张图片

monitor

monitor命令用于监控Redis正在执行的命令,monitor的作用很明显,如果开发和运维人员想监听Redis正在执行的命令,就可以用monitor命令,但事实并非如此美好,每个客户端都有自己的输出缓冲区,既然monitor能监听到所有的命令,一旦Redis的并发量过大,monitor客户端的输出缓冲会暴涨,可能瞬间会占用大量内存。

客户端相关配置

tcp-keepalive

检测TCP连接活性的周期,默认值为0,也就是不进行检测,如果需要设置,建议为60,那么Redis会每隔60秒对它创建的TCP连接进行活性检测,防止大量死连接占用系统资源。

tcp-backlog

TCP三次握手后,会将接受的连接放入队列中,tcp-backlog就是队列的大小,它在Redis中的默认值是511。通常来讲这个参数不需要调整,但是这个参数会受到操作系统的影响,例如在Linux操作系统中,如果/proc/sys/net/core/somaxconn小于tcp-backlog,那么在Redis启动时会看到警告日志,并建议将/proc/sys/net/core/somaxconn设置更大。

客户端统计片段

info clients和info status中可以查看Redis中的客户端相关统计指标,其中有:

  • connected_clients:代表当前Redis节点的客户端连接数,需要重点监控,一旦超过maxclients,新的客户端连接将被拒绝。
  • client_longest_output_list:当前所有输出缓冲区中队列对象个数的最大值。
  • client_biggest_input_buf:当前所有输入缓冲区中占用的最大容量。
  • blocked_clients:正在执行阻塞命令(例如blpop、brpop、brpoplpush)的客户端个数。
  • total_connections_received:Redis自启动以来处理的客户端连接数总数。
  • rejected_connections:Redis自启动以来拒绝的客户端连接数,需要重点监控。

客户端常见异常

客户端读写超时

造成该异常的原因也有以下几种:

  • 读写超时时间设置得过短。
  • 命令本身就比较慢。
  • 客户端与服务端网络不正常。
  • Redis自身发生阻塞。
客户端连接超时

造成该异常的原因也有以下几种:

  • 连接超时设置得过短。
  • Redis发生阻塞,造成tcp-backlog已满,造成新的连接失败。
  • 客户端与服务端网络不正常。
客户端连接数过大

这个问题可能会比较棘手,因为此时无法执行Redis命令进行问题修复,一般来说可以从两个方面进行着手解决:

客户端

如果maxclients参数不是很小的话,应用方的客户端连接数基本不会超过maxclients,通常来看是由于应用方对于Redis客户端使用不当造成的。此时如果应用方是分布式结构的话,可以通过下线部分应用节点(例如占用连接较多的节点),使得Redis的连接数先降下来。从而让绝大部分节点可以正常运行,此时再通过查找程序bug或者调整maxclients进行问题的
修复。

服务端

如果此时客户端无法处理,而当前Redis为高可用模式(例如Redis Sentinel和Redis Cluster),可以考虑将当前Redis做故障转移。

此问题不存在确定的解决方式,但是无论从哪个方面进行处理,故障的快速恢复极为重要,当然更为重要的是找到问题的所在,否则一段时间后客户端连接数依然会超过maxclients。

你可能感兴趣的:(redis)