Redis是经典C/S架构,一个服务器可以与多个客户端进行通信。Redis服务器工作在单进程单线程模式,但它通过I/O多路复用技术处理客户端请求实现了高并发。
1. 客户端定义
Redis客户端作为与服务器通信的媒介,保存了其必要的一些属性,要操作Redis服务器存储的内容,必须通过客户端与服务端进行通信才能修改。
1 | /** |
1.1 套接字文件描述符 - fd
根据客户端类型的不同,fd的值可以是-1或真实文件描述符。
- 伪客户端:fd值为-1,这种客户端用于本地执行命令,如AOF文件加载或Lua脚本执行。
- 普通客户端:fd值为真实描述符值,这种客户端通过网络套接字与服务端通信,用于执行一般的命令。
1.2 客户端名称 - name
默认情况下,连接到服务端的客户端没有名称,我们通过CLIENT SETNAME命令可以设置当前客户端的名称。
1 | # 通过CLIENT list命令获取当前服务器连接的客户端 |
1.3 标志 - flags
客户端标志属性flags记录了客户端的角色,每一位都记录客户端的一种属性或状态。
第N位 | 标志 | 描述 |
---|---|---|
0 | CLIENT_SLAVE | 客户端是从节点 |
1 | CLIENT_MASTER | 客户端是主节点 |
2 | CLIENT_MONITOR | 客户端是监控从节点 |
3 | CLIENT_MULTI | 客户端正在执行事务 |
4 | CLIENT_BLOCKED | 客户端正在被BRPOP等命令阻塞 |
5 | CLIENT_DIRTY_CAS | WATCH命令监控的键已经改变,EXEC将会失败 |
6 | CLIENT_CLOSE_AFTER_REPLY | 回复完成后关闭客户端 |
7 | CLIENT_UNBLOCKED | 客户端非阻塞,存储在server.unblocked_clients链表中 |
8 | CLIENT_LUA | 指向Lua脚本的客户端 |
9 | CLIENT_ASKING | 客户端发出了ASKING命令 |
10 | CLIENT_CLOSE_ASAP | 客户端需要尽快关闭 |
11 | CLIENT_UNIX_SOCKET | 通过unix domain连接的客户端 |
12 | CLIENT_DIRTY_EXEC | 事务命令入队时出错,EXEC将会失败 |
13 | CLIENT_MASTER_FORCE_REPLY | 主从服务器命令通信时,从节点要发送REPLICATION ACK给主节点,但主节点必须打开该标识强制回复 |
14 | CLIENT_FORCE_AOF | 默认情况下,AOF不会记录PUB/SUB等命令,该标志表示AOF也会记录PUBSUB命令和SCRIPT LOAD |
15 | CLIENT_FORCE_REPL | 强制主节点将当前执行的命令复制给所有从节点。执行PUBSUB命令会打开客户端CLIENT_FORCE_AOF标志,执行SCRIPT LOAD命令会打开CLIENT_FORCE_AOF,CLIENT_FORCE_REPL两个标志 |
16 | CLIENT_PRE_PSYNC | 客户端代表的是低于Redis2.8版本的从节点,主节点不能使用PSYNC命令与该从节点同步 |
17 | CLIENT_READONLY | 集群客户端处于只读状态 |
18 | CLIENT_PUBSUB | 客户端处于PUB/SUB模式 |
19 | CLIENT_PREVENT_AOF_PROP | 客户端执行的命令不存储到AOF |
20 | CLIENT_PREVENT_REPL_PROP | 客户端执行的命令不复制给从节点 |
19+20 | CLIENT_PREVENT_PROP | 客户端执行的敏力不存储到AOF且不复制给从节点 |
21 | CLIENT_PENDING_WRITE | 客户端有要发送的内容,但并未设置写处理程序 |
22 | CLIENT_REPLY_OFF | 不要发送回复给客户端 |
23 | CLIENT_REPLY_SKIP_NEXT | 跳过下一跳命令的回复 |
24 | CLIENT_REPLY_SKIP | 不要发送这条命令的回复 |
25 | CLIENT_LUA_DEBUG | debug模式执行Lua脚本 |
26 | CLIENT_LUA_DEBUG_SYNC | debug模式执行Lua脚本,但并不fork()子进程 |
27 | CLIENT_MODULE | 无连接的模块客户端 |
1.4 输入缓冲区 - querybuf
客户端的输入缓冲区用于保存客户端发送的命令请求,输入缓冲区的大小根据输入内容动态地扩大或缩小,最大不能超过client_max_querybuf_len(默认1G),可以通过配置文件进行配置。
1 | # 输入命令 |
pending_querybuf缓冲区是存储主节点将接收到的命令复制给从节点的数据
1.5 输出缓冲区 - list & buf
服务端给客户端的回复会保存在客户端的输出缓冲区中,每个客户端有两个输出缓冲区,一个是固定的缓冲区,一个是可变的缓冲区:
- 固定缓冲区-buf字节数组:保存长度较小的回复信息
- 可变缓冲区-list链表:保存长度较大的回复
固定缓冲区buf的默认大小为16KB,当该空间用完或回复内容太多无法放进buf中,则会使用list可变缓冲区。
2. 源码剖析
- TCP连接处理程序
1 | // TCP链接处理程序,创建一个客户端的连接状态 |
- 创建客户端
1 | client *createClient(int fd) { |
- 释放客户端
1 | void freeClient(client *c) { |
- 输出缓冲区写给客户端
1 | int writeToClient(int fd, client *c, int handler_installed) { |