第 13 章 客户端
Redis服务器是典型的一对多服务器程序:一个服务器可以与多个客户端建立网络连接。
通过使用由I/O多路复用技术实现的文件事件处理器,Redis服务器使用单线程单进程的方式来处理命令请求,并与多个客户端进行网络通信。
对于每个与服务器进行连接的客户端,服务器都为这些客户端建立了相应的redis.h/redisclient
结构(客户端状态),这个结构保存了客户端当前的状态信息,以及执行相关功能时需要用到的数据结构,具体属性本节稍后会介绍
Redis服务器结构中存储了一个redisClient
类型的链表,它保存了所有与服务器连接的客户端状态结构
13.1 客户端属性
redisClient
结构的源码如下
1 | typedef struct redisClient { |
13.1.1 套接字描述符
客户端状态的fd
属性记录了客户端正在使用的套接字描述符
若fd = -1
则说明这个客户端是用来执行Lua脚本或者AOF操作的伪客户端
可以通过CLIENT list
命令列出目前所有连接到服务器的普通客户端
1 | CLIENT list |
13.1.2 名字
使用CLIENT setname
命令可以为客户端设置名字,让客户端身份更加清晰
13.1.3 标志
客户端的标记属性flags
记录了客户端的角色和当前所处的状态
flags
属性的值可以是多个标志的二进制或,例如
1 | flags = <flag1> | <flag2> | ... |
一部分标志记录了客户端的角色
-
在主从服务器进行复制操作时,主服务器会成为从服务器的客户端,而从服务器也会成为主服务器的客户端。
REDIS_MASTER
标志表示客户端代表的是一个主服务器,REDIS SLAVE
标志表示客户端代表的是一个从服务器。 -
REDIS_PRE_PSYNC
标志表示客户端代表的是一个版本低于Redis2.8的从服务器 -
REDIS_LUA_CLIENT
标识表示客户端是专门用于处理Lua脚本里面包含的Redis命令的伪客户端。
另外一部分标志记录了客户端目前所处的状态
REDIS_MONITOR
标志表示客户端正在执行MONITOR
命令。REDIS_UNIX_SOCKET
标志表示服务器使用UNIX
套接字来连接客户端。REDIS_BLOCKED
标志表示客户端正在被BRPOP
、BLPOP
等命令阻塞。- 等等
13.1.4 输入缓冲区
输入缓冲区是querybuf
属性,它是一个Redis字符串结构,用于保存客户端发送的命令请求,大小可以根据输入内容动态地扩大和缩小。例子如下图
13.1.5 命令与命令参数
在服务器将客户端发送的命令请求保存到客户端状态的querybuf属性之后,服务器将对命令请求的内容进行分析,并将得到的命令参数以及命令参数的个数分别存储在客户端状态的argv
和argc
中。
例如下图,假如客户端发送的命令为SET key "value"
,那么将这样保存
13.1.6 命令的实现函数
当服务器从协议内容中分析并得出argv
属性和argc
属性的值之后,服务器将根据项argv[0]
的值,在命令表中查找命令所对应的命令实现函数。
命令表是一个字典,字典的键是一个SDS结构(Redis定义的字符串结构),保存了命令的名字,而字典的值是命令所对应的redisCommand结构,这个结构保存了命令的实现函数、命令的标志、命令应该给定的参数个数等信息。
当程序成功的找到了argv[0]
对应的redisCommand
结构时,它会将客户端状态(redisClient
)中的cmd
指针指向这个命令
例如下图,我们在命令表中查找SET
命令,并将cmd
指针指向它
13.1.7 输出缓冲区
执行命令得到的命令回复将保存在客户端状态的输出缓冲区中,它有定长和变长两种选择
13.1.8 身份验证
略
13.1.9 时间
略
13.2 客户端的创建与关闭
服务器使用不同的方式来创建和关闭不同类型的客户端
13.2.1 创建普通客户端
如果客户端是通过网络连接与服务器进行连接的普通客户端,那么在客户端使用connect
函数连接到服务器时,服务器就会调用连接事件处理器,为客户端创建相应的客户端状态,并将这个新的客户端状态添加到服务器状态结构client
链表的尾部
如下图所示,当客户端c3连接时
13.2.2 关闭普通客户端
一个普通客户端可以因为多种原因而关闭
- 客户端进程退出或者被杀死
- 客户端向服务器发送了不符合协议格式的数据
- 如果客户端成为
CLIENT KILL
命令的目标,它也会被关闭 - 如果设置了timeout配置项,当客户端的空转时间超过了timeout时就会被关闭
- 如果客户端发送的命令请求超过了输入缓冲区的限制大小,则它会被关闭
- 如果客户端发送的命令请求超过了输出缓冲区的限制大小,则它会被关闭
13.2.3 Lua脚本的伪客户端
服务器在初始化时创建负责执行Lua脚本的伪客户端,并将这个伪客户端关联在服务器状态结构(redisServer
)的lua_client
属性中
1 | typedef struct redisServer{ |
lua_client
伪客户端在服务器运行的整个生命周期中都会存在
13.2.4 AOF文件的伪客户端
服务器在载入AOF文件时,会创建用于执行存储于AOF中的写命令的伪客户端,当载入完成时,这个伪客户端就会关闭。