《Redis设计与实现》读书笔记(十八) ——Redis客户端属性设计与原理

《Redis设计与实现》读书笔记(十八) ——Redis客户端属性设计与原理

(原创内容,转载请注明来源,谢谢)

一、概述

redis服务器是一对多服务器,多个客户端可以与一个服务器建立连接,并且分别发送请求,服务器接收请求并分别回复。通过使用I/O多路复用技术实现的文件事件处理器,redis服务器使用单线程单进程的方式来处理请求,并与多个客户端建立网络通信。

1、单个客户端状态结构存储

每个与服务器建立连接的客户端,服务器都为这些客户端建立相应的redis.h/redisClient结构,用于分别存储每个客户端的状态,这个结构保存客户端当前的信息,以及执行相关功能时候需要用到的数据结构,主要包括:

1)客户端信息

客户端套接字描述符,客户端名字,客户端标志值,客户端身份验证标志,客户端创建时间、最后一次与服务器通信时间、客户端输出缓冲区以及缓冲区大小超出服务器软性限制的时间。

2)客户端状态

客户端当前使用的数据库指针及数据库号码,客户端当前要执行的命令、命令参数、参数个数、实现命令的指针。

3)客户端用到的数据结构

客户端复制状态信息及复制所需的数据结构,客户端执行brpop、blpop等阻塞列表命令时用到的数据结构,客户端事务及watch用到的数据结构,客户端执行发布订阅功能用到的数据结构。

2、所有客户端存储

redis通过redisServer结构的clients属性,将所有的客户端结构进行存储,存储是采用链表的方式。如下:

         struct redisServer{
         //…其他内容
         list *clients;
         }

clients属性,以链表的形式,存储了所有的客户端状态,里面的每个元素都代表一个客户端,包含该客户端的诸如客户端信息、状态、使用的数据结构等全部信息。如下图所示:

二、客户端属性

客户端属性分为通用的和特定操作下的属性,特定操作如切换数据库、执行事务、watch等。这里重点学习通用属性。

主要用到的类型如下:

         typedef struct redisClient{
         //..其他内容
         int fd;
         robj *name;
         int flags;
         sds querybuf;
         robj **argv;
         int argc;
         struct redisCommand*cmd;
         char buf[REDIS_REPLY_TRUNK_BYTES];
         int bufpos;
         list *reply;
         int authenticated;
         time_t ctime;
         time_tlastinteraction;
         time_t obuf_soft_limit_reached_time;
         }redisClient;

1、套接字描述符

在redisClient里面,用int的方式记录当前使用的套接字描述符,属性名称是fd。

fd的值是-1或者大于-1的整数。当客户端是来自AOF文件或者Lua脚本,需要生成的临时的伪客户端,则值是-1,表示其不需要网络;正常的客户端值是大于-1的整数,这个值是redis客户端和redis服务器进行通信的描述符。

2、名字

客户端的名字属性名称是name,类型是redis的字符串对象。

默认情况下客户端没有名字,可以通过client setname设置名字,通过client list命令查看当前所有客户端的信息,如下是设置名字之后的:

如果没有设置名字,name是指向null的指针,设置之后则是redis字符串对象。

3、标志

客户端的标志记录客户端的角色,和当前客户端所处的状态,用int类型存储,属性名是flags。标志可以是单个的也可以是多个的二进制“或”。如flags = flag1 或者flags = flag1 | flag2 |flag3。

每个标志是一个常量,主要的如下:

1)主从复制期间,主服务器会成为从服务器的客户端,REDIS_MASTER表示客户端是主服务器,REDIS_SLAVE表示客户端是从服务器。

2)REDIS_PRE_PSYNC表示客户端是redis版本低于2.8的从服务器,主服务器不能用psync命令才进行复制。

3)REDIS_LUA_CLIENT表示lua脚本创建的伪客户端。

4)还有其他标志,最重要的是REDIS_UNBLOCKED,这标志标记redis已经从阻塞状态脱离出来,只有这样的客户端才会接收到服务器发送的信息。

5)REDIS_FORCE_AOF,这个标志也很特殊,默认情况下只有“写”相关的命令才会计入aof文件,但是存在个别命令,虽然不会影响到数据库的数据,但是会产生副作用,则需要用此标记,强制将结果写入aof。例如pubsub命令,会给所有订阅者发送信息;script load命令,加载脚本。

flags例子如下:

4、输入缓冲区

输入缓冲区保存客户端发送的命令请求,采用redis的sds类型存储,名称是querybuf。sds是简单动态字符串,是redis用来存储字符串对象值的结构。

输入缓冲区会根据输入的内容动态扩大或减小,但是不能超过1gb,否则redis会自动关闭该客户端。

输入命令set key value,querybuf的结果(缩略)如下:

5、命令与命令参数

当发送请求道querybuf后,redis会对命令进行分析,将命令参数保存到**argv,命令个数保存到argc。

argv是一个数组,每一项都是一个redis字符串对象,其中argv[0]是要执行的命令,后面的下标是传入的参数。argc则是记录数组argv的长度。

输入命令set key value,argc和argv的结果如下:

6、命令实现函数

分析完querybuf,并生成argc和argv后,redis将根据argv[0]的内容,确定相应的要实现的函数。

redis保存着一个数据字典,该字典存储着每个命令与其对应的redisCommand结构,键是sds结构的命令,值是对应的redisCommand结构。该字典也成为redis的命令表。

客户端的cmd属性,即分析完argv[0]后,从上述redis命令表中找到对应的结构,并用指针指向该结构。命令表的键不区分大小写,因此redis的命令也是不区分大小写的。

7、输出缓冲区

执行命令得到的回复,会保存在输出缓冲区中,每个客户端都有两个缓冲区,一个是固定大小的,另一个可变大小的。

固定大小的缓冲区由buf和bufpos两个属性组成,buf是一个数组,用于存储固定大小的返回值,默认大小是16kb;bufpos记录目前buf已经使用的字节数。固定大小缓冲区通常用于记录长度比较短的元素,如OK、短的字符串返回值、整数、错误回复等。

可变大小的缓冲区由链表组成,属性名是reply,链表内是一个或多个字符串对象组成。当回复的长度太长,则用可变大小缓冲区。另外,如果一开始用固定大小缓冲区,当记录过程中大小超过16kb,则会转换成可变大小缓冲区。

8、身份验证

redis用int记录是否验证身份,属性名是authenticated,0表示未通过验证,1表示已经通过验证。

当未验证身份,除了auth以外的命令,都会被redis服务器拒绝。

9、时间

redis共有3个属性记录客户端的时间相关的内容:ctime、lastinteraction、obuf_soft_limit_reached_time,类型都是time_t。

ctime记录客户端与redis服务器创建连接的时间,clientlist命令可以查看客户端连接的秒数,用age表示,单位是秒。

lastinteraction表示客户端与redis服务器最后一次交互的时间,可以是服务器发送信息给客户端的时间,也可以是客户端发送信息给服务器的时间。这个时间主要用来判断空转时间,即连接后没有操作的时间,client list可以查看空转时间,用idle表示,单位是秒。

obuf_soft_limit_reached_time表示输出缓冲区第一次达到软性限制的时间。

——written by linhxx 2017.09.08

原文发布于微信公众号 - 决胜机器学习(phpthinker)

原文发表时间:2017-09-08

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏林欣哲

ISA指令集

今天的内容来源于《计算机系统概论》的第4章,介绍的指令是作者根据x86指令简化设计的一个自称为LC-3(Little Computer-3 edition)的指...

3957
来自专栏决胜机器学习

《Redis设计与实现》读书笔记(十一) ——Redis数据库与键空间

《Redis设计与实现》读书笔记(十一) ——Redis数据库与键空间 (原创内容,转载请注明来源,谢谢) 一、redis数据库 redis服务器将所有数据库都...

3406
来自专栏开发与安全

linux系统编程之基础必备(五):Linux进程地址空间和虚拟内存

一、虚拟内存 先来看一张图(来自《Linux内核完全剖析》),如下: ? 分段机制:即分成代码段,数据段,堆栈段。每个内存段都与一个特权级相关联,即0~...

1887
来自专栏智能合约

PHP性能分析之Xhprof数据说明

986
来自专栏玩转JavaEE

Spring Cloud Stream使用细节

上篇文章我们看了Spring Cloud Stream的基本使用,小伙伴们对Spring Cloud Stream应该也有了一个基本的了解,但是上篇文章中的消息...

2996
来自专栏pangguoming

Redis快速入门

Redis是一个开源,先进的key-value存储,并用于构建高性能,可扩展的Web应用程序的完美解决方案。 Redis从它的许多竞争继承来的三个主要特点: ...

3215
来自专栏前端架构

程序是如何执行的(一)a=a+1

1、计算机中有两个主要的核心部件:CPU和内存,其中CPU负责运算而内存负责存储程序和相关的变量,每一条程序语句和变量都在内存中有对应的内存地址。

792
来自专栏决胜机器学习

《Redis设计与实现》读书笔记(十二) ——Redis键的生存时间与过期时间

《Redis设计与实现》读书笔记(十二) ——Redis键的生存时间与过期时间 (原创内容,转载请注明来源,谢谢) 1、设置方式 在redis客户端,可以通过e...

2464
来自专栏转载gongluck的CSDN博客

Boost asio 官方教程

7.1. 概述 本章介绍了 Boost C++ 库 Asio,它是异步输入输出的核心。 名字本身就说明了一切:Asio 意即异步输入/输出。 该库可以让 ...

4435
来自专栏奔跑的蛙牛技术博客

java 读写二进制数据与java序列化

zip文档以压缩格式存储一个和多个文件,每个ZIP文件都有一个头,包含每个文件的名字和压缩方法等信息

542

扫描关注云+社区