Redis设计与实现:第十三章 - 客户端

参考:《Redis设计与实现》

1、客户端定义

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

       对于每个与服务端进行连接的客户端,服务器都是为这些客户端建立对应的redis.h/redisClient结构来保存客户端当前的状态信息,以及相关功能需要用到的数据结构。

       Redis服务器状态结构的clients属性是一个链表,保存了与服务器连接的客户端的状态结构。数据结构如下:

	struct redisServer{
		list *clients //一个保存所有客户端状态的链表
	}

       假设一个服务端与三个客户端对接,他的数据结构是这样的:
在这里插入图片描述
       

2、客户端属性

1、套接字描述符、名字、标志

数据结构标识:

	typedef struct redisClient{
		int fd;//套接字描述符
		robj *name;//名字
		int flags; //标识
	}

套接字描述符
       伪客户端的套接字描述符字段值为-1,伪客户端的处理命令来源于AOF文件或者Lua脚本,而不是网络。普通客户端的套接字标识符为大于-1的整数

名字
       默认情况下,连接到服务端的客户端是没有名字的,但是可以通过设置name字段让客户端的身份更明确。

标志
       客户端的标志属性记录了客户端的角色信息

       flags属性可以是单个标志,也可以是多个标志的二进制或。
       

2、命令

       命令参数与执行程序对应数据结构

	typedef struct redisClient{
		robj **argv //字符串数组,用来保存相应的命令内容
		int argc //字符串数组的大小

		struct redisCommand *cmd //命令所对应的redisCommand结构
	}

       服务器将客户端发送的命令请求存储到客户端状态的query_buf属性之后,服务器会对命令的内容进行分析,将分析的结果保存到 argv和argc属性上,具体的如果是像set key value这样的命令他的存储如下:
在这里插入图片描述

       服务器进行命令的解析时,会从argv[0]获取值并与命令数据字典dict进行匹配,找到对应的命令信息,存储到cmd属性。这个属性包含给定的参数个数、命令的总执行次数,命令的总耗时等统计信息。服务端通过调用cmd这个参数进行命令的执行。

3、缓冲区

       输入缓冲区与输出缓冲区的结构表示:

	typedef struct redisClient{
		sds querybuf; //输入缓冲区

		//固定大小输出缓冲区
		char buf[REDIS_REPLY_CHUNK_BYTES]
		int bufpos

		list *reply; //可变大小输出缓冲区
	}

       输入缓冲区是保存客户端输入的命令信息,所以用sds的结构进行存储,它的大小会根据内容动态的缩小或者扩大,但是最大大小如果超过1GB,服务端就会关闭这个客户端。

       每个客户端都会有两个输出缓冲区,一个缓冲区大小是固定的,一个缓冲区大小是可变的。

       固定大小缓冲区,通过buf数组bufpos,两个属性组合,buf数组的大小是固定的,bufpos则记录了buf数组目前已经使用的字节数量。固定大小缓冲区主要用来保存长度较小的回复。

       当固定大小缓冲区空间使用殆尽或者回复消息过大,则会开始启用可变长大小的输出缓冲区,它的数据结构是通过链表来连接一个或者多个的字符串对象,具体结构如下:
在这里插入图片描述

4、身份验证

       身份验证的数据结构是:

	typedef struct redisClient{
		int authenticated;//身份验证
	}

       如果该字段的值为0表示客户端未通过身份验证,如果该值为1表示客户端通过身份验证。

       

5、时间

ctime: 记录了创建客户端的时间,这个时间可以用来计算客户端和服务端已经连接了多少秒

lastinteraction:记录客户端和服务端最后一次进行互动的时间,可以用来计算客户端空转时长

obuf_soft_limit_reached_time:记录输出缓冲区第一次到达软性限制的时间。
       

3、客户端创建与关闭

1、普通客户端

       通过网络与服务器连接的普通客户端,在客户端使用connect函数连接到服务器的时候,服务器就会调用连接事件处理器为客户端创建相应的客户端状态,将它添加到clients链表的末尾。

       客户端被服务端关闭有很多种情况,具体查看原书。

服务器会采用两种模式来限制客户端缓冲区大小:

  • 硬性限制:如果缓冲区大小超出硬性限制的大小,服务端会主动关闭客户端
  • 软性限制:如果客户端没有超出硬性限制,但是在配置的软性限制时长中,持续超出软性限制大小,则服务端会自动关闭客户端,否则不关闭

具体的设置可查看原书。

2、Lua脚本的伪客户端

       服务器会在初始化时,创建负责执行Lua脚本的中包含Redis命令的伪客户端,将这个伪客户端关联到服务器状态结构中的lua_client属性中。

       lua_client伪客户端在服务器运行的整个生命周期都会一直存在,只有服务器被关闭的时候,这个客户端才会关闭。

3、AOF的伪客户端

       服务器在载入AOF文件的时候,会创建用于执行AOF文件的Redis命令伪客户端,并在载入完成之后,关闭这个伪客户端。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章