向Redis发出一条命令,会发生什么?
mhr18 2024-10-21 05:42 28 浏览 0 评论
天下皆知美之为美,斯恶已;皆知善之为善,斯不善已。
故有无相生,难易相成,长短相形,高下相倾,音声相和,前后相随,恒也。
是以圣人处无为之事,行不言之教。万物作焉而不辞,生而不有,为而不恃,功成而弗居。夫唯弗居,是以不去。
文章导航
日常工作中,我们经常在Redis中设置值和取值,那么一条命令发出去之后,都经历了什么呢?
127.0.0.1:6379> SET key value
OK
一条命令,从发送到得到回复的过程,客户端和服务端需要完成一系列的操作。以上面代码为例,客户端和服务端共需要经历下面的步骤:
- 客户端向服务端发送SET key value命令。
- 服务端接收客户端请求,并处理。在数据库中进行设置操作,并产生命令回复OK。
- 服务端将命令回复OK发送给客户端
- 客户端接收服务端返回命令并回复OK,并将该回复显示给用户
本文关于Redis 源码部分,源于Redis 7.0
客户端发送命令请求
将用户在客户端输入一个命令后,客户端会将命令请求转成协议格式,并发送给服务端。
客户端向服务端发送命令
比如在客户端输入下面命令:
127.0.0.1:6379> SET key value
OK
客户端会将该命令转成协议格式,并发送给服务端。
*3\r\n$3\r\nSET\r\n$3\r\nkey\r\n$5\r\nvalue\r\n
为了使文章结构清晰,关于协议格式不再赘述,文末详细介绍!
服务端读取命令请求
当客户端向服务端发送完命令请求后,服务端会调用命令请求处理器进行下面操作:
- 读取协议格式的命令请求,并保存到客户端缓冲区(Client )。
- 对命令请求解析,提取出命令参数及参数个数。
- 调用命令执行器,执行命令。
redis-server client.drawio.png
上图是Redis将命令请求保存到客户端缓冲区后的结构。
client是客户端缓冲区结构体,其中将协议格式的命令请求保存在client的querybuf中。argc保存命令请求的个数。参数保存到argv中。后文我们用client来替代客户端缓冲区
接下来Redis Server会调用命令执行器完成执行命令的后续部分。
命令执行器之查找命令
首先命令执行器要根据客户端缓冲区的argv[0]在redisCommandTable中查找参数指定的命令,并保存到client的cmd字段中。
redisCommandTable是一个全局变量,定义了所有 Redis 命令,值为redisCommand结构,包括命令的名称、实现函数、所需参数数量以及其他属性。它用于存储和管理 Redis 的命令信息。
以下是redisCommand结构体的主要字段整理出来,完整描述详见源码server.h/redisCommand:
字段名 | 类型 | 描述 |
declared_name | char* | 命令的声明名称 |
summary | char* | 命令的摘要 |
complexity | char* | 复杂度描述 |
since | char* | 命令引入的版本号 |
proc | redisCommandProc* | 命令实现函数指针 |
arity | int | 参数数量 |
flags | uint64_t | 命令标志 |
acl_categories | uint64_t | ACL分类 |
getkeys_proc | redisGetKeysProc* | 获取键参数的函数指针 |
microseconds | long long | 命令执行时间(微秒) |
calls | long long | 命令调用次数 |
rejected_calls | long long | 被拒绝的命令调用次数 |
failed_calls | long long | 失败的命令调用次数 |
redisCommandTable采用与大小写无关的查找策略,因此命令名字的大小写不影响查找。
命令执行器之预执行
现在我们已经准备好执行命令了,但是在执行前还需要一些预备检查,以便命令可以正确、顺利的执行。
- 客户端身份验证:如果Redis服务器启用了身份验证机制,首先会验证客户端是否已成功通过身份验证。只有通过身份验证的客户端才能继续执行后续的命令。
- 命令权限检查:根据ACL(访问控制列表)配置,检查当前连接的客户端是否具有执行该命令的权限。ACL可以限制每个用户或用户组能够执行的特定命令。
- 命令存在性检查:检查客户端请求的命令是否存在于Redis服务器的命令字典中。如果命令不存在,则向客户端返回错误响应。
- 参数数量检查:根据命令定义的参数数量要求(arity字段),检查客户端请求的参数数量是否满足要求。如果参数数量不正确,则向客户端返回错误响应。
- 参数格式检查:对于某些命令,进一步检查参数的格式是否符合预期。例如,对于SET命令,会检查键和值参数的类型是否正确。
- 服务器状态检查:在执行某些命令之前,可能会检查服务器的状态是否允许执行该命令。例如,在主从复制模式下,只有主节点允许执行写操作。
命令执行器之执行
到这一步,所有的前置准备工作已经就绪,接下来要真正执行了!
前面我们知道客户端缓冲区保存了命令的参数和参数个数,分别保存在client的argv、argc属性中,当执行命令的时候,运行下面语句即,代码位于service.c/call
c->cmd->proc(c); //setCommand(client)
client结构
被调用的命令实现函数执行响应的操作,并产生对应的命令回复,保存在客户端缓冲区(client的reply和buf属性中)。
命令回复结构
命令执行器之善后
命令执行结束后,命令执行器还需要执行一些善后工作:
- 释放资源:在命令执行完毕后,命令执行器需要释放相关的资源,包括临时数据结构、数据库锁等。这样可以避免资源泄露和浪费,保持系统的稳定性和高效性。
- 日志记录:根据配置和需求,命令执行器可能需要记录命令执行的日志。这包括成功执行的命令、出现错误的命令、重要事件等。日志记录有助于故障排查、性能优化和监控。
- 统计和计数:命令执行器可能需要对命令执行过程中的统计数据进行更新和计数。例如,命令调用次数、执行时间、失败次数等。这些统计信息可以用于性能分析和监控系统健康状态。
- 处理事务回滚:如果命令执行过程中发生了错误,导致事务无法完成,命令执行器可能需要执行相应的回滚操作,撤销之前已执行的命令。这保证了事务的一致性和可靠性。
将命令回复发送给客户端,并打印
Redis Server 执行命令回复处理器,将客户端缓冲区中的命令回复发送给客户端。
客户端在收到命令回复后,将协议格式转换为人类可读模式,并打印出来。
到这里,客户端和服务端的整个请求过程已经结束了。有同学开始问了,集群下是如何运行的?客户端怎么知道key所在节点的呢?
在集群模式下,服务端在接收到命令请求后,会先根据key判断命令请求中的key所在槽是否在当前节点,如果不是,会向客户端返回一个MOVED错误,客户端根据MOVED错误信息转向正确的节点重新发送命令请求并执行上述操作。
redis cluster check
Redis协议格式
Redis 协议是一种用于与 Redis 数据库进行通信的简单而高效的文本协议。它使用 TCP/IP 进行传输,并以行为单位进行交互。
在 Redis 协议中,每个请求和响应都由多个字符组成。我们可以将协议的格式分为请求格式和响应格式:
请求格式:
- *<参数数量> CR LF:表示参数数量的前缀,用于指定请求中的参数个数。
- $<参数长度> CR LF:表示参数长度的前缀,用于指定接下来的参数的长度。如果参数为空,则长度为 -1。
- <参数值> CR LF:参数的实际内容。
举个例子,如果我们要设置一个键值对,请求可以如下所示:
*3 // 参数数量为 3
$3 // 第一个参数长度为 3
SET // 第一个参数值为 SET
$5 // 第二个参数长度为 5
mykey // 第二个参数值为 mykey
$7 // 第三个参数长度为 7
myvalue // 第三个参数值为 myvalue
响应格式:
Redis 的响应也由多个字符组成,有以下几种可能的类型:
- 状态回复(Status Reply):以 "+" 开头,后面跟着状态信息。
- 错误回复(Error Reply):以 "-" 开头,后面跟着错误信息。
- 整数回复(Integer Reply):以 ":" 开头,后面跟着一个整数。
- 批量回复(Bulk Reply):以 "$" 开头,后面跟着回复的长度和内容。如果长度为 -1,则表示空值。
- 多条批量回复(Multi Bulk Reply):以 "*" 开头,后面跟着回复的数量和内容。
举个例子,如果我们要获取一个键的值,响应可以如下所示:
$7 // 响应内容的长度为 7
myvalue // 响应内容为 myvalue
完整的协议格式参考:https://redis.io/docs/reference/protocol-spec/
相关推荐
- 订单超时自动取消业务的 N 种实现方案,从原理到落地全解析
-
在分布式系统架构中,订单超时自动取消机制是保障业务一致性的关键组件。某电商平台曾因超时处理机制缺陷导致日均3000+订单库存锁定异常,直接损失超50万元/天。本文将从技术原理、实现细节、...
- 使用Spring Boot 3开发时,如何选择合适的分布式技术?
-
作为互联网大厂的后端开发人员,当你满怀期待地用上SpringBoot3,准备在项目中大显身手时,却发现一个棘手的问题摆在面前:面对众多分布式技术,究竟该如何选择,才能让SpringBoot...
- 数据库内存爆满怎么办?99%的程序员都踩过这个坑!
-
你的数据库是不是又双叒叕内存爆满了?!服务器监控一片红色警告,老板在群里@所有人,运维同事的电话打爆了手机...这种场景是不是特别熟悉?别慌!作为一个在数据库优化这条路上摸爬滚打了10年的老司机,今天...
- springboot利用Redisson 实现缓存与数据库双写不一致问题
-
使用了Redisson来操作Redis分布式锁,主要功能是从缓存和数据库中获取商品信息,以下是针对并发时更新缓存和数据库带来不一致问题的解决方案1.基于读写锁和删除缓存策略在并发更新场景下,...
- 外贸独立站数据库炸了?对象缓存让你起死回生
-
上周黑五,一个客户眼睁睁看着服务器CPU飙到100%——每次页面加载要查87次数据库。这让我想起2024年Pantheon的测试:Redis缓存能把WooCommerce查询速度提升20倍。跨境电商最...
- 手把手教你在 Spring Boot3 里纯编码实现自定义分布式锁
-
为什么要自己实现分布式锁?你是不是早就受够了引入各种第三方依赖时的繁琐?尤其是分布式锁这块,每次集成Redisson或者Zookeeper,都得额外维护一堆配置,有时候还会因为版本兼容问题头疼半...
- 如何设计一个支持百万级实时数据推送的WebSocket集群架构?
-
面试解答:要设计一个支持百万级实时数据推送的WebSocket集群架构,需从**连接管理、负载均衡、水平扩展、容灾恢复**四个维度切入:连接层设计-**长连接优化**:采用Netty或Und...
- Redis数据结构总结——面试最常问到的知识点
-
Redis作为主流的nosql存储,面试时经常会问到。其主要场景是用作缓存,分布式锁,分布式session,消息队列,发布订阅等等。其存储结构主要有String,List,Set,Hash,Sort...
- skynet服务的缺陷 lua死循环
-
服务端高级架构—云风的skynet这边有一个关于云风skynet的视频推荐给大家观看点击就可以观看了!skynet是一套多人在线游戏的轻量级服务端框架,使用C+Lua开发。skynet的显著优点是,...
- 七年Java开发的一路辛酸史:分享面试京东、阿里、美团后的心得
-
前言我觉得有一个能够找一份大厂的offer的想法,这是很正常的,这并不是我们的饭后谈资而是每个技术人的追求。像阿里、腾讯、美团、字节跳动、京东等等的技术氛围与技术规范度还是要明显优于一些创业型公司...
- mysql mogodb es redis数据库之间的区别
-
1.MySQL应用场景概念:关系型数据库,基于关系模型,使用表和行存储数据。优点:支持ACID事务,数据具有很高的一致性和完整性。缺点:垂直扩展能力有限,需要分库分表等方式扩展。对于复杂的查询和大量的...
- redis,memcached,nginx网络组件
-
1.理解阻塞io,非阻塞io,同步io,异步io的区别2.理解BIO和AIO的区别io多路复用只负责io检测,不负责io操作阻塞io中的write,能写多少是多少,只要写成功就返回,譬如准备写500字...
- SpringBoot+Vue+Redis实现验证码功能
-
一个小时只允许发三次验证码。一次验证码有效期二分钟。SpringBoot整合Redis...
- AWS MemoryDB 可观测最佳实践
-
AWSMemoryDB介绍AmazonMemoryDB是一种完全托管的、内存中数据存储服务,专为需要极低延迟和高吞吐量的应用程序而设计。它与Redis和Memcached相似,但具有更...
- 从0构建大型AI推荐系统:实时化引擎从工具到生态的演进
-
在AI浪潮席卷各行各业的今天,推荐系统正从幕后走向前台,成为用户体验的核心驱动力。本文将带你深入探索一个大型AI推荐系统从零起步的全过程,揭示实时化引擎如何从单一工具演进为复杂生态的关键路径。无论你是...
你 发表评论:
欢迎- 一周热门
- 最近发表
- 标签列表
-
- oracle位图索引 (74)
- oracle批量插入数据 (65)
- oracle事务隔离级别 (59)
- oracle主从同步 (56)
- oracle 乐观锁 (53)
- redis 命令 (83)
- php redis (97)
- redis 存储 (67)
- redis 锁 (74)
- 启动 redis (73)
- redis 时间 (60)
- redis 删除 (69)
- redis内存 (64)
- redis并发 (53)
- redis 主从 (71)
- redis同步 (53)
- redis结构 (53)
- redis 订阅 (54)
- redis 登录 (62)
- redis 面试 (58)
- redis问题 (54)
- 阿里 redis (67)
- redis的缓存 (57)
- lua redis (59)
- redis 连接池 (64)