Redis服务器是典型的一对多服务器程序:一个服务器可以与多个客户端建立网络连接,每个客户端可以向服务器发送命令请求,而服务器则接收并处理客户端发送的命令请求,并向客户端返回命令回复。

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

每个与服务器进行连接的客户端,服务端都为这些客户端建立相应的redisClient结构(客户端状态),保存客户端当前的状态信息,以及执行相关功能时需要用到的数据结构。

Redis服务器状态结构的clients属性是一个链表,这个链表保存了所有与服务器连接的客户端的状态结构,对客户端执行批量操作,或者查找某个指定的客户端,都可以通过遍历clients链完成。

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

1、客户端状态的fd属性记录了客户端正在使用的套接字描述符

typedef struct redisClient{
int fd;
} redisClient;

根据客户端的类型不同fd的属性值可以是-1,或者是大于-1的整数:伪客户端fd属性为-1;普通客户端的fd属性值为大于-1的整数。

2、默认情况下一个连接到服务器的客户端是没有名称的, 可以使用Client setname 命令为客户端设置一个名称。

3、客户端的标志属性flags记录了客户端角色(role),以及客户端状态

typedef struct redisClient{
int flag;
} redisClient;

在主从服务器进行复制操作时,主服务器会成为从服务器的客户端,而从服务器也会成为主服务器的客户端。

REDIS_MASTER 客户端是一个主服务器

REDIS_BLOCKED 客户端正在被列表命令阻塞

REDIS_MULTI | REDIS_DIRTY_CAS 客户端正在执行事务,但事务的安全性已经被破坏

REDIS_SLAVE | REDOS_PRE_PSYNC 客户端是一个从服务器,并且版本低于REDIS2.8

REDIS_LUA_CLIENT | REDIS_FORCE_AOF | REDIS_FORCE_REPL 这是专门执行Lua脚本包含的redis命令的伪客户端 ,它强制服务器将当前执行的命令写入到AOF文件,并复制给从服务器。

4、客户端状态的输入缓冲区用户保存客户端发送的命令请求:

typedef struct redisClient {
sds querybuf;
} redisClient;

5、在服务器将客户端发送的命令请求保存在客户端状态的querybuf属性后,服务器将对命令请求的内容进行分析,并将得出的命令参数以及命令参数的个数分别保存到客户端状态的argv属性和argc属性

typedef struct redisClient{
robj **argv;
int argc;
} redisClient;

argv属性是一个数组,数组的每个项都是一个字符串队形,其中avgv[0]是要执行的命令,其之后的其他项都是传给命令的参数。

6、当服务器从协议内容中分析并得出argv属性和argc属性的值之后,服务器将根据项argv[0]的值,在命令表中查找命令所对应的实现函数。

命令表是一个字典表,字典的键是一个SDS结构,保存了命令的名字,字典值是命令的名字,字典值是命令所对应的redisCommand结构,这个结构保存了命令的实现函数、命令的标志、命令应该给定的参数个数、命令的总执行次数和总耗时长等统计信息。

当程序在命令表中成功找到argv[0]所对应的redisCommand结构时,它会将客户端状态的cmd指针指向这个结构:

typedef struct redisClient{
struct redisCommand *cmd;
} redisClient;

之后,服务器就可以使用cmd属性所指向的redisCommand结构,以及argv、argc属性中保存的命令参数信息,调用命令实现函数,执行客户端指定的命令。

7、执行命令所得的命令回复会被保存在客户端状态的输出缓冲区里面,每个客户端有两个输出缓冲区可以用,一个缓冲区的大小是固定的,一个大小是可变的。

固定大小的缓冲区用于保存那些长度比较小的回复,可变大小的缓冲区用于保存耐饿长度比较大的回复。

客户端的固定大小缓冲区由buf和bufpos两个属性组成

typedef struct redisClient{
char buf[REDIS_REPLY_CHUNK_BYTES];//REDIS_REPLY_CHUNK_BYTES 默认16 *1024 也就是说固定缓冲区默认 16k
int bufpos;//记录已使用的字节数量
} redisClient;

8、身份认证

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

typedef struct redisClient{
int authenticated;
} redisClient;

authenticated属性仅在服务器启用了身份验证功能的时候使用,如果服务器没有启用的话,即使为0也不会拒绝客户端的命令请求。

9、时间

typedef struct redisClient{
time_t ctime;//创建客户端的时间 连接服务器时长(秒)
time_t lastinteraction;//最后一次与服务器互动时间,计算客户端空转时间
//记录缓冲区第一次到达软性限制的时间
time_t obuf_soft_limit_reached_time;
} redisClient;

如果客户端是通过网络连接于服务器进行连接的普通客户端,那么客户端使用connect函数连接到服务器时,服务器就会调用连接事件处理器,为客户端创建相应的客户端状态,并将这个新的客户端状态添加到服务器状态结构clients链表的末尾。

普通客户端可以因为多种原因而被关闭:

客户端进程退出或者被杀死,那么客户端与服务端的网络连接被关闭。

如果客户端向服务端发送了带有不符合协议的命令请求,那么这个客户端也会被关闭。

如果客户端成为了CLIENT KILL命令的目标,那么它也会被关闭。

如果服务端设置了timeout配置项,那么客户端的空转事件超过timeout现象设置的值时,客户端被关闭。

如果客户端发送的命令请求的大小超过了输入缓冲区的限制大小(默认1G),那么客户端会被服务器关闭。

如果要发送给客户端的命令回复的大小超过了输出缓冲区的限制大小,那么这个客户端会被服务器关闭。

服务器使用两种模式来限制客户端输出缓冲区的大小:

1、硬性限制,如果输出缓冲区的大小超过了硬性限制所设置的大小,那么服务器立即关闭客户端。

2、软性限制,如果输出缓冲区的大小超过了软性限制设置的大小,但没有超过硬性设置的大小,obuf_soft_limit_reached_time属性记录下客户端达到软性限制的起始事件,之后服务器会继续监视客户端,如果输出缓冲区的大小一直超出软性限制,并且持续时间超过服务器设置的时长,那么服务器将关闭客户端。

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

struct redisServer{
redisClient *lua_client;
}

lua_client 伪客户端在服务器运行的整个声明周期中会一直存在,只有服务器关闭时,这个客户端才会关闭。

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


每天学一点,总会有收获。

说明:尊重作者知识产权,文中内容参考《Redis设计与实现》,仅在此做学习与大家分享。


Redis学习笔记(十) 客户端的更多相关文章

  1. Redis学习笔记十:独立功能之监视器

    通过执行 monitor 命令可以让客户端自己变成一个监视器,实时接收并打印当前处理的命令请求的相关信息. 127.0.0.1:6379> monitor OK 1451752646.83727 ...

  2. redis 学习笔记(6)-cluster集群搭建

    上次写redis的学习笔记还是2014年,一转眼已经快2年过去了,在段时间里,redis最大的变化之一就是cluster功能的正式发布,以前要搞redis集群,得借助一致性hash来自己搞shardi ...

  3. redis 学习笔记-cluster集群搭建

    一.下载最新版redis 编译 目前最新版是3.0.7,下载地址:http://www.redis.io/download 编译很简单,一个make命令即可,不清楚的同学,可参考我之前的笔记: red ...

  4. Redis学习笔记~目录

    回到占占推荐博客索引 百度百科 redis是一个key-value存储系统.和Memcached类似,它支持存储的value类型相对更多,包括string(字符串).list(链表).set(集合). ...

  5. Redis学习笔记4-Redis配置详解

    在Redis中直接启动redis-server服务时, 采用的是默认的配置文件.采用redis-server   xxx.conf 这样的方式可以按照指定的配置文件来运行Redis服务.按照本Redi ...

  6. Redis学习笔记7--Redis管道(pipeline)

    redis是一个cs模式的tcp server,使用和http类似的请求响应协议.一个client可以通过一个socket连接发起多个请求命令.每个请求命令发出后client通常会阻塞并等待redis ...

  7. (转)redis 学习笔记(1)-编译、启动、停止

    redis 学习笔记(1)-编译.启动.停止   一.下载.编译 redis是以源码方式发行的,先下载源码,然后在linux下编译 1.1 http://www.redis.io/download 先 ...

  8. Redis 学习笔记4: Redis 3.2.1 集群搭建

    在CenOS 6.7 linux环境下搭建Redis 集群环境 1.下载最新的Redis版本 本人下载的Redis版本是3.2.1版本,下载之后,解压,编译(make): 具体操作可以参考我的博文:R ...

  9. Redis学习笔记(2)——Redis的下载安装部署

    一.下载Redis Redis的官网下载页上有各种各样的版本,如图 但是官网下载的Redis项目不正式支持Windows.如果需要再windows系统上部署,要去GitHub上下载.我下载的是Redi ...

  10. Redis学习笔记(1)- CentOS 6.4 安装Redis

    Redis学习笔记(1)- CentOS 6.4 安装Redis 2013.10.13     学习环境 vm 10.1 + 默认.新装的干净 CentOS 6.4  64BIT系统     准备 1 ...

随机推荐

  1. 理解java容器底层原理--手动实现ArrayList

    为了照顾初学者,我分几分版本发出来 版本一:基础版本 实现对象创建.元素添加.重新toString() 方法 package com.xzlf.collection; /** * 自定义一个Array ...

  2. 通过纯css实现图片居中的多种实现方式

    html结构: <div class="demo" style="width: 800px;height: 600px; border:1px solid #ddd ...

  3. Qt 与 .Net 为何不兼容

    哪怕是非Qt的静态库里用了 .Net 也不行.

  4. 谷歌提高Google Assistant中Voice Match的准确性

    谷歌正在提高 Google Assistant 中 Voice Match 的准确性,使其变得更加完善.谷歌表示一旦用户在 Google Assistant 中启用 Voice Match 功能,那么 ...

  5. HTML中使用CSS样式(上)

    在每一个标签上都可以设置style属性,这就是CSS样式: <div style="height:48px;border: 1px solid red;text-align:cente ...

  6. 在线图片资源转换成Base64格式

    function getBase64Image(img) { var canvas = document.createElement("canvas"); canvas.width ...

  7. 已有项目接入git远程仓库

    1.项目根目录初始化git仓库 git init 2.将本地项目与远程仓库关联(首先得在远程创建一个代码仓库) git remote add origin 远程仓库地址 诺,仓库地址就是这个玩意 3. ...

  8. 《JavaScript和jQuery实战手册(原书第2版)》——2.1节语句

    2.1 语句JavaScript语句是基本的编程单元,通常表示JavaScript程序中的单个步骤.可以把一条语句看做一个句子一样,就好像成串的句子一起组成一个段落(或一章,或一本书)一样,把语句组合 ...

  9. java的基础知识01

    来自<head first java>书籍的摘录

  10. mysql查询语句中like 的用法

    1.常见用法: (1)搭配%使用 %代表一个或多个字符的通配符,譬如查询字段name中以大开头的数据: (2)搭配_使用 _代表仅仅一个字符的通配符,把上面那条查询语句中的%改为_,会发现只能查询出一 ...