Redis设计与实现 第 13 章 客户端

2021/6/29 19:24:12

本文主要是介绍Redis设计与实现 第 13 章 客户端,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

第 13 章 客户端

Redis 服务器是典型的一对多服务器程序,通过使用由 I/O 多路复用技术实现的文件事件处理器,服务器使用单线程单进程的方式来处理命令请求,并与多个客户端进行网络通信

redis.h/redisClient 结构保存了客户端当前的状态信息,以及执行相关功能需要用到的数据结构:

  • 客户端的套接字描述符

  • 客户端的名字

  • 客户端的标志值

  • 指向客户端正在使用的数据库的指针,数据库的号码

  • 客户端当前执行的命令、命令的参数、命令参数的个数、指向命令实现函数的指针

  • 客户端的输入缓冲区和输出缓冲区

  • 客户端的复制状态信息、进行复制需要的数据结构

  • 客户端执行 BRPOP、BLPOP 等列表阻塞命令需要的数据结构

  • 客户端的事务状态、执行 WATCH 命令的数据结构

  • 客户端执行发布与订阅功能的数据结构

  • 客户端的身份验证标志

  • 客户端的创建时间、客户端和服务器最后一次通信的时间、客户端的输出缓冲区大小超过软性限制的时间

服务器状态结构的 clients 属性是一个链表,保存了所有与服务器相连接的客户端的状态结构

clients

clients链表

13.1 客户端属性

分为两类:

  • 通用属性
  • 特定功能相关属性
    • 操作数据库的 db 属性、dictid 属性

13.1.1 套接字描述符

客户端状态 fd 属性记录套接字描述符,取值为 -1 或大于 -1 的整数

  • 伪客户端的 fd 属性为 -1:处理的命令请求来源于 AOF 或者 Lua 脚本

  • 普通客户端的 fd 属性为大于 -1 的整数

13.1.2 名字

默认情况下客户端是没有名字的,名字记录在客户端状态的 name 属性,可以使用 clint setname 为当前客户端设置名字

没有名字时 name 属性指向 NULL 指针;设置了名字将指向一个字符串对象

13.1.3 标志

  • flags 记录了客户端的角色及客户端所处的状态

  • 可以是单个标志

  • 也可以是多个二进制或

  • 每个标志使用一个常量表示,一部分标志记录了客户端的角色

    • 主从服务器复制时,各自成为对方的客户端
      • REDIS_MASTER 主服务器
      • REDIS_SLAVE 从服务器
    • REDIS_PRE_PSYNC
      • 版本低于 2.8 的从服务器,服务器不能使用 PSYNC 命令同步,只在 REDIS_SLAVE 打开时使用
    • REDIS_LUA_CLIENT
      • 专门处理 Lua 脚本的伪客户端
    • REDIS_MONITOR:客户端在执行 MONITOR 命令
    • REDIS_UNIX_SOCKET:服务器使用 UNIX 套接字连接客户端
    • REDIS_BLOCKED 客户端被 BRPOP、BLPOP 命令阻塞
    • REDIS_UNBLOKCED 客户端已经从 REDIS_BLOCKED 恢复

    部分标志

    AOF 持续化只会将修改了数据库的命令写入 AOF 文件,但 PUBLIS 命令是向频道的订阅者发送消息,而接收消息的客户端状态会因此改变,需要 REDIS_FORCE_AOF 标志强制写入;SCRIPT LOAD 修改了服务器的状态,同理需要 REDIS_FORCE_AOF 标志

flags属性例子

13.1.4 输入缓冲区

sds querybuf 属性即客户端状态的输入缓冲区,保存客户端发送的命令请求,大小会根据输入内容动态变化,但最大不能超过 1 GB,否则服务器会关闭次客户端

querybuf

13.1.5 命令与命令参数

服务器对命令请求的内容分析后得出的命令参数及个数将被保存到客户端状态的 argv、argc 属性

  • argv:
    • 数组,每个项都是字符串对象,argv[0] 是要执行的命令,其他项是传给命令的参数
  • argc:
    • 记录 argv 数组的长度

argv、argc例子

13.1.6 命令的实现函数

服务器根据 argv[0] 的值在命令表中查找命令对应的命令实现函数

命令表

一个字典,键是 SDS 结构,保存名字,值是命令对应的 redisCommand 结构,保存了实现函数、命令标志等等的统计信息

程序在命令表中找到 argv[0] 所对应的 redisCommand 结构,则将 cmd 指针指向这个结构

查找命令并设置cmd属性

针对命令表的查找操作不区分输入字母的大小写

13.1.7 输出缓冲区

执行命令所得的回复保存在客户端状态的输出缓冲区,每个客户端都有两个输出缓冲区可用,一个固定一个变化

  • 固定:保存长度比较小的回复,如 OK、简短字符串值、整数值、错误回复等
  • 可变:非常长字符串、多项列表、多元素集合

固定大小缓冲区由 buf、bufpos 组成

  • buf:大小为 REDIS_REPLY_CHUNK_BYTES 字节数组
  • bufpos:buf 数组已使用字节数量

REDIS_REPLY_CHUNK_BYTES 默认为 16 * 1024 ,即 16 KB

固定

当 buf 数组使用完或者回复太大而没办法放进 buf 数组时,服务器则使用可变大小缓冲区

可变缓冲区由 reply 链表和一个或多个字符串组成,通过链表来连接多个字符串对象

可变大小

13.1.8 身份验证

客户端状态的 authenticated 属性记录了客户端是否通过身份验证

  • 0:未通过
    • 除了 AUTH 命令其余拒绝
  • 1:通过

如果服务器没有启用身份验证,即使 authenticated 为 0 也不会拒绝,由 requirepass 设置

13.1.9 时间

时间有关属性

  • ctime:创建客户端的时间,Client list 的 age 域记录

  • lastinteraction:客户端与服务器最后一次进行互动的时间,可以指某一方对另一方的行为,不特定客户端或者服务器

    • 可以计算空转时间
    • client list 的 idle 记录
  • obuf_soft_limit_reached_time:记录输出缓冲区第一次到软性限制的时间

13.2 客户端的创建与关闭

13.2.1 创建普通客户端

如果客户端是通过网络连接与服务器进行连接的普通客户端,则在客户端使用 connect 函数连接到服务器时,服务器会调用连接事件处理器为客户端创建客户端状态,并加入到服务器状态 clients 链表末尾

13.2.2 关闭普通客户端

关闭原因:

  • 客户端进程退出或被杀死

  • 客户端发送带有不符合协议格式的命令请求

  • 客户端成为 client kill 命令的目标

  • 服务器配置了 timeou 选项,空转时间超过则关闭

    • 例外:客户端是主服务器,被命令阻塞或者执行订阅命令超过时间则不会
  • 命令请求大小超过输出缓冲区限制

  • 回复超过输出缓冲区限制

可变大小缓冲区理论上任意长,但为了避免回复过大,会时刻检查客户端的输出缓冲区大小,超过时执行限制

  • 硬性限制:超过硬性限制大小则则关闭
  • 软性限制:超过软性限制大小但没到达影响限制,记录下 obuf_soft_limit_reached_time 时间,服务器继续监控,如果一直超过的持续时间超过设置时间则关闭;否则不会关闭,obuf_soft_limit_reached_time 也归 0

进行设置

设置

13.2.3 Luau 脚本的伪客户端

lua_client 关联负责执行 Lua 脚本中的 Redis 命令的伪客户端,直到服务器关闭此客户端才会被关闭

13.2.4 AOF 文件的伪客户端

在载入 AOF 文件创建,载入完成后关闭



这篇关于Redis设计与实现 第 13 章 客户端的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程