热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Redis客户端使用指南与学习笔记

本书基于Redis3.0版本编写,虽然与后续版本存在一些差异,但仍详细介绍了Redis服务器的一对多客户端连接机制。书中不仅涵盖了基本的安装配置和命令操作,还深入探讨了数据结构、持久化策略及性能优化等高级主题,适合初学者和进阶用户参考学习。

参考&#xff1a;<>


  • 注&#xff1a;这本书是基于Redis3.0版本写的&#xff0c;和后面的版本有点差异

Redis服务器是一对多服务器程序&#xff1a;一个服务器可以和多个客户端建立网络连接&#xff0c;每个客户端可以向服务器发送命令请求&#xff0c;而服务器接收并处理客户端发送的命令请求&#xff0c;并向客户端返回命令回复。

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

与服务器连接客户端&#xff0c;Redis服务器使用redisClient结构&#xff08;客户端状态&#xff09;保存客户端当前的状态信息、执行相关功能时需要用到的数据结构。主要包括以下&#xff1a;


  • 客户端的套接字描述符
  • 客户端名称
  • 客户端标志值
  • 指向客户端正在使用的数据库指针、数据库序号
  • 客户端当前要执行的命令、命令参数、参数个数和指向命令实现函数的指针
  • 客户端的输入和输出缓冲区
  • 客户端执行发布订阅用到的数据结构
  • 客户端身份验证标志
  • 客户端的创建时间、最后一次与服务器通信的时间、客户端的输出缓冲区大小超出软性限制&#xff08;soft limit&#xff09;的时间

客户端保存在redisServer结构的clients属性中&#xff0c;该属性是一个链表&#xff0c;保存了所有与服务器连接客户端的状态结构&#xff0c;对客户端执行操作或查找指定客户端&#xff0c;都是通过遍历clients属性完成&#xff1a;

struct redisServer {// ...// 链表&#xff0c;保存了客户端的状态list *clients;// ...
}

客户端链表


一、客户端属性


1.1 套接字描述符

客户端状态的fd属性记录了客户端正在使用的套接字描述符&#xff1a;

type struct redisClient {// ...int fd;// ...
} redisClient;

客户端类型不同&#xff0c;fd取值可以是-1、大于-1的整数&#xff1a;


  • 伪客户端(fake client)&#xff1a;fd属性值为-1。伪客户端处理的命令请求来源于AOF文件或Lua脚本&#xff0c;不是网络&#xff0c;所以这种客户端不需要套接字连接。Redis服务器会在两个地方用到伪客户端&#xff1a;
    • 1.载入AOF文件并还原数据库状态
    • 2.用于执行LUa脚本中包含的Redis命令
  • 普通客户端&#xff1a;fd属性大于-1的整数。普通客户端使用套接字与服务器进行通信&#xff0c;Redis服务器会用fd属性记录客户端套接字的描述符。

执行client list命令可以列出目前所有连接到服务器的普通客户端&#xff1a;
fd属性显示了服务器连接客户端所使用的套接字描述符

redis> client list
id&#61;3 addr&#61;127.0.0.1:53094 fd&#61;9 name&#61; age&#61;914864 idle&#61;0 flags&#61;N db&#61;0 sub&#61;0 psub&#61;0 multi&#61;-1 qbuf&#61;26 qbuf-free&#61;32742 obl&#61;0 oll&#61;0 omem&#61;0 events&#61;r cmd&#61;client

1.2 标志

客户端的标志属性flags记录了客户端的角色&#xff08;role&#xff09;、客户端目前所处的状态&#xff1a;

type struct redisClient {// ...int fd;int flags;// ...
} redisClient;

flags属性的值可以是单个标志&#xff0c;也可以是多个标志的二进制或&#xff0c;如


  • flags &#61;
  • flags &#61; | | …

每个标志使用一个常量表示&#xff0c;一部分记录了客户端的角色、一部分记录了客户端目前所处的状态。


  • 客户端角色&#xff1a;
    • REDIS_MASTER、REDIS_SLAVE&#xff1a;表示客户端代表的是一个主服务器、从服务器。在主从服务器进行复制操作时&#xff0c; 主服务器会成为从服务器的客户端&#xff0c;从服务器成为抓服务器的客户端。
    • REDIS_PRE_PSYNC&#xff1a;表示客户端代表是一个版本低于Redis2.8的从服务器&#xff0c;主服务器不能使用PSYNC命令与这个从服务器进行同步。这个标志只能在REDIS_SLAVE标志打开状态使用。
    • REDIS_LUA_CLINET&#xff1a;表示客户端用于处理Lua脚本里包含的Redis命令的伪客户端。
  • 客户端所处的状态&#xff1a;
    • REDIS_MONITOR&#xff1a;表示客户端正在执行MONITOR命令。
    • REDIS_UNIX_SOCKET&#xff1a;表示服务器使用UNIX套接字来连接客户端。

1.3 输入缓冲区

客户端状态的输入缓冲区用于保存客户端发送的命令请求&#xff1a;

type struct redisClient {// ...int fd;int flags;sds querybuf;// ...
} redisClient;

注&#xff1a;输入缓冲区的大小根据输入内容动态地缩小或扩大&#xff0c;但最大不能超过1GB&#xff0c;否则服务器将会关闭这个客户端。

示例&#xff1a;

如果客户端向服务器发送了set key value命令请求&#xff0c;那么客户端状态的querybuf属性是一个包含以下内容的SDS值&#xff1a;

*3\r\n$3\r\nSET\r\n$3\r\nkey\r\n$5\r\nvalue\r\n

如下图所示&#xff1a;
querybuf属性


1.4 命令与命令参数

在服务器将客户端发送的命令请求保存到客户端的querybuf属性后&#xff0c;服务器会对命令请求的内容进行分析&#xff0c;然后将得出的命令参数以及参数个数分别保存到客户端状态的argv属性和argc属性&#xff1a;

type struct redisClient {// ...int fd;int flags;sds querybuf;robj **argv;int argc;// ...
} redisClient;

  • argv属性&#xff1a;一个数组&#xff0c;数组中每一项是字符串&#xff0c;argv[0]是要执行的命令&#xff0c;其他项是传给命令的参数。
  • argc属性&#xff1a;记录argv数组的长度

示例&#xff1a;

如1.3的querybuf属性值&#xff0c;服务器将分析、创建下图的argv属性和argc属性&#xff1a;
argv属性和argc属性
注&#xff1a;SET命令本身也是一个参数。


1.5 命令的实现函数

服务器从协议内容中分析得出argv属性和argc属性的值后&#xff0c;服务器根据argv[0]的值&#xff0c;在命令表中查找命令所对应的命令实现函数。

命令表是一个字典&#xff0c;字典的键是SDS结构&#xff0c;保存了命令的名字&#xff0c;字典的值是命令对应的redisCommand结构。该结构保存了命令的实现函数、命令的标志、命令应该给定的参数个数、命令的总执行次数和总耗时等统计信息。命令表如下图所示&#xff1a;
命令表

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

type struct redisClient {// ...int fd;int flags;sds querybuf;robj **argv;int argc;struct redisCommand *cmd;// ...
} redisClient;

之后服务器使用cmd属性指向的redisCommand结构、argv、argc属性的值调用相关命令实现函数&#xff0c;执行客户端指定的命令。

示例&#xff1a;

当argv[0]为"SET"时&#xff0c;查找命令表并将客户端状态的cmd指针指向redisCommand结构的过程如下图所示&#xff1a;
查找命令并设置cms属性
注&#xff1a;命令表的查找操作不区分大小写。


1.6 输出缓冲区

执行命令所得的命令回复会被保存在客户端状态的输出缓冲区里&#xff0c;每个客户端都有两个输出缓冲区可用&#xff1a;


  • 固定大小缓冲区&#xff1a;保存那些长度比较小的回复&#xff0c;如OK、简短的字符串值、整数值、错误回复等。
  • 可变大小缓冲区&#xff1a;保存那些长度较大的回复&#xff0c;如非常长的字符串值、很多项组成的列表、包含很多元素的集合等。

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


  • buf&#xff1a;数组长度为REDIS_REPLY_CHUNK_BYTES&#xff0c;默认值是16*1024&#xff0c;也就是16KB
  • bufpos&#xff1a;记录了数组目前已经使用的字节数量

type struct redisClient {// ...int fd;int flags;sds querybuf;robj **argv;int argc;struct redisCommand *cmd;char buf[REDIS_REPLY_CHUNK_BYTES];int bufpos;// ...
} redisClient;

示例&#xff1a;

一个固定大小缓冲区保存&#43;OK\r\n&#xff0c;如下图所示&#xff1a;
固定大小缓冲区

当buf数组空间用完或回复太大无法放进buf数组里&#xff0c;服务器就会使用可变大小的缓冲区。

可变大小的缓冲区由reply链表和一个或多个字符串对象组成&#xff1a;

type struct redisClient {// ...int fd;int flags;sds querybuf;robj **argv;int argc;struct redisCommand *cmd;char buf[REDIS_REPLY_CHUNK_BYTES];int bufpos;list *reply;// ...
} redisClient;

示例&#xff1a;

一个包含三个字符串对象的reply链表如下图所示&#xff1a;
可变大小缓冲区

为了避免发送给客户端回复过大&#xff0c;占用过多服务器资源&#xff0c;服务器会时刻检查客户端的输出缓冲区大小&#xff0c;并在缓冲区的大小超出范围时&#xff0c;执行相应的限制操作。

服务器使用两种模式限制客户端输出缓冲区的大小&#xff1a;


  • 硬性限制&#xff08;hard limit&#xff09;&#xff1a;如果输出缓冲区大小超过了硬性限制所设置的大小&#xff0c;服务器立即关闭客户端
  • 软性限制&#xff08;soft limit&#xff09;&#xff1a;
    • 如果缓冲区大小超过软性限制所设置的大小&#xff0c;但没超过硬性限制&#xff0c;那么服务器将使用客户端状态结构的 obuf_soft_limit_reached_time 属性记录下客户端到达软性限制的起始时间&#xff1b;之后服务器会继续监视客户端&#xff0c;如果输出缓冲区的大小一致超过软性限制&#xff0c;且持续时间超过服务器设置的时长&#xff0c;那么服务器将关闭客户端&#xff1b;
    • 如果输出缓冲区的大小在指定时间之内不再超过软性限制&#xff0c;那么客户端不会给关闭&#xff0c;且obuf_soft_limit_reached_time属性值被清零。

使用 client-output-buffer-limit 选项可以为普通客户端、从服务器客户端、执行发布订阅的客户端分别设置不同的软性限制和硬性限制。

三个设置示例&#xff1a;

# 将普通客户端的硬性限制和软性限制都设置为0&#xff0c;表示不限制客户端的输出缓冲区大小
client-output-buffer-limit normal 0 0 0
# 将从服务器客户端的硬性限制设置为256mb&#xff0c;软性限制设置为64mb&#xff0c;软性限制时长为60s
client-output-buffer-limit slave 256mb 64mb 60
# 将执行发布订阅的客户端硬性限制设置为32mb&#xff0c;软性限制为8mb&#xff0c;软性限制时长为60s
client-output-buffer-limit pubsub 32mb 8mb 60

1.7 身份验证

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

type struct redisClient {// ...int fd;int flags;sds querybuf;robj **argv;int argc;struct redisCommand *cmd;char buf[REDIS_REPLY_CHUNK_BYTES];int bufpos;list *reply;int authenticated;// ...
} redisClient;

  • authenticated&#xff1a;
    • 0&#xff1a;表示客户端未通过身份验证。此时除了AUTH命令&#xff0c;其他命令都会被服务器拒绝执行&#xff08;服务器需要开启身份验证功能&#xff0c;参考配置文件里的requirepass选项&#xff09;
    • 1&#xff1a;表示客户端通过了身份验证

1.8 时间

客户端中与时间有关的几个属性&#xff1a;ctime、lastinteraction、obuf_soft_limit_reached_time。

type struct redisClient {// ...int fd;int flags;sds querybuf;robj **argv;int argc;struct redisCommand *cmd;char buf[REDIS_REPLY_CHUNK_BYTES];int bufpos;list *reply;int authenticated;time_t ctime;time_t lastinteraction;time_t obuf_soft_limit_reached_time;// ...
} redisClient;

  • ctime&#xff1a;记录了客户端创建的时间&#xff0c;用来记算客户端与服务器连接的时间&#xff0c;client list命令中的age选项记录了这个时间。
  • lastinteraction&#xff1a;记录了客户端与服务器最后一次交互的时间。如客户端向服务端发送命令请求、服务器向客户端发送命令回复。
    • 该属性还可以用来计算客户端空转&#xff08;idle&#xff09;时间&#xff0c;即距离客户端与服务器最后一次进行交互过去的时间。 client list命令中的idle选项记录了这个时间。
  • obuf_soft_limit_reached_time&#xff1a;记录了输出缓冲区第一次到达软性限制&#xff08;soft limit&#xff09;的时间。

二、客户端的创建与关闭


2.1 普通客户端


2.1.1 创建普通客户端

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

示例&#xff1a;

如已有客户端c1、c2&#xff0c;新的客户端c3连接到服务器后&#xff0c;就会将新创建的c3客户端状态添加到clients链表末尾&#xff1a;
服务器状态结构的clients链表


2.1.2 关闭普通客户端

一个普通客户端会因为多种原因被关闭&#xff1a;


  • 客户端进程退出或被杀死&#xff0c;客户端与服务器之间的网络连接将被关闭
  • 客户端向服务器发送了带有不符合协议格式的命令请求
  • 客户端成为了CLIENT KILL目标
  • 用户为服务器设置了timeout配置选项&#xff0c;当客户端的空转时间超过timeout选项设置的值。一些例外情况&#xff0c;
    • 客户端是主服务器&#xff08;打开了REDIS_MASTER标志&#xff09;&#xff0c;从服务器&#xff08;打开了REDIS_SLAVE标志&#xff09;&#xff0c;正在被BLOOP等命令阻塞&#xff08;打开了REDIS_BLOCKED标志&#xff09;&#xff0c;或者正在执行发布订阅等命令&#xff0c;即使超过了timeout设置的值也不会被关闭
  • 客户端发送的命令请求大小超过输入缓冲区的限制&#xff08;默认1GB&#xff09;
  • 要发送给客户端的命令回复大小超过了输出缓冲区的限制大小



2.2 Lua脚本伪的客户端

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

struct redisServer {// ...redisClient *lua_client;// ...
} redisClient;

注&#xff1a;lua_client伪客户端在服务器运行整个生命周期会一直存在&#xff0c;只有服务器关闭&#xff0c;这个客户端才会被关闭。


2.3 AOF文件的伪客户端

服务器在载入AOF文件时会创建用于执行AOF文件包含的Redis命令的伪客户端&#xff0c;在载入完成之后&#xff0c;关闭这个伪客户端。


推荐阅读
  • 深入理解Redis的数据结构与对象系统
    本文详细探讨了Redis中的数据结构和对象系统的实现,包括字符串、列表、集合、哈希表和有序集合等五种核心对象类型,以及它们所使用的底层数据结构。通过分析源码和相关文献,帮助读者更好地理解Redis的设计原理。 ... [详细]
  • 深入解析Nginx中的Location指令及其属性
    本文将详细探讨Nginx配置文件中关键的location指令,包括其三种匹配方式(精准匹配、普通匹配和正则匹配),以及如何在实际应用中灵活运用这些匹配规则。此外,还将介绍location下的重要子元素如root、alias和proxy_pass,并解释相关参数的使用方法。 ... [详细]
  • 本文深入探讨了HTTP请求和响应对象的使用,详细介绍了如何通过响应对象向客户端发送数据、处理中文乱码问题以及常见的HTTP状态码。此外,还涵盖了文件下载、请求重定向、请求转发等高级功能。 ... [详细]
  • 本文将详细探讨Linux pinctrl子系统的各个关键数据结构,帮助读者深入了解其内部机制。通过分析这些数据结构及其相互关系,我们将进一步理解pinctrl子系统的工作原理和设计思路。 ... [详细]
  • PHP 过滤器详解
    本文深入探讨了 PHP 中的过滤器机制,包括常见的 $_SERVER 变量、filter_has_var() 函数、filter_id() 函数、filter_input() 函数及其数组形式、filter_list() 函数以及 filter_var() 和其数组形式。同时,详细介绍了各种过滤器的用途和用法。 ... [详细]
  • 深入解析Redis内存对象模型
    本文详细介绍了Redis内存对象模型的关键知识点,包括内存统计、内存分配、数据存储细节及优化策略。通过实际案例和专业分析,帮助读者全面理解Redis内存管理机制。 ... [详细]
  • 作者:守望者1028链接:https:www.nowcoder.comdiscuss55353来源:牛客网面试高频题:校招过程中参考过牛客诸位大佬的面经,但是具体哪一块是参考谁的我 ... [详细]
  • 本题旨在通过给定的评级信息,利用拓扑排序和并查集算法来确定全球 Tetris 高手排行榜。题目要求判断是否可以根据提供的信息生成一个明确的排名表,或者是否存在冲突或信息不足的情况。 ... [详细]
  • 数据结构入门:栈的基本概念与操作
    本文详细介绍了栈这一重要的数据结构,包括其基本概念、顺序存储结构、栈的基本操作(如入栈、出栈、清空栈和销毁栈),以及如何利用栈实现二进制到十进制的转换。通过具体代码示例,帮助读者更好地理解和应用栈的相关知识。 ... [详细]
  • 本文详细介绍了C语言中的指针,包括其基本概念、应用场景以及使用时的优缺点。同时,通过实例解析了指针在内存管理、数组操作、函数调用等方面的具体应用,并探讨了指针的安全性问题。 ... [详细]
  • 本文介绍了Linux系统中的文件IO操作,包括文件描述符、基本文件操作函数以及目录操作。详细解释了各个函数的参数和返回值,并提供了代码示例。 ... [详细]
  • 本文详细介绍了 iBatis.NET 中的 Iterate 元素,它用于遍历集合并重复生成每个项目的主体内容。通过该元素,可以实现类似于 foreach 的功能,尽管 iBatis.NET 并未直接提供 foreach 标签。 ... [详细]
  • Hybrid 应用的后台接口与管理界面优化
    本文探讨了如何通过优化 Hybrid 应用的后台接口和管理界面,提升用户体验。特别是在首次加载 H5 页面时,为了减少用户等待时间和流量消耗,介绍了离线资源包的管理和分发机制。 ... [详细]
  • 目录一、salt-job管理#job存放数据目录#缓存时间设置#Others二、returns模块配置job数据入库#配置returns返回值信息#mysql安全设置#创建模块相关 ... [详细]
  • 深入解析Java枚举及其高级特性
    本文详细介绍了Java枚举的概念、语法、使用规则和应用场景,并探讨了其在实际编程中的高级应用。所有相关内容已收录于GitHub仓库[JavaLearningmanual](https://github.com/Ziphtracks/JavaLearningmanual),欢迎Star并持续关注。 ... [详细]
author-avatar
夫妇郭_390
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有