Redis 是如何执行的?

文章目录

  • 命令执行流程
    • 步骤一:用户输入一条命令
    • 步骤二:客户端先将命令转换成 Redis 协议,然后再通过 socket 连接发送给服务器端
    • 步骤三:服务器端接收到命令
    • 步骤四:执行前准备
    • 步骤五:执行最终命令,调用 redisCommand 中的 proc 函数执行命令。
    • 步骤六:执行完后相关记录和统计
    • 步骤七:返回结果给客户端
  • 扩展知识:I/O 多路复用
  • 小结

Redis 是如何执行的?收到的答案往往是:客户端发命令给服务器端,服务端收到执行之后再返回给客户端。

然而对于执行细节却「避而不谈」 ,当继续追问服务器端是如何执行的?能回答上来的人更是寥寥无几,这未免让人有些遗憾,一个我们每天都在用的技术,知道原理的人却寥若晨星。

对于任何一门技术,如果你只停留在「会用」的阶段,那就很难有所成就。

命令执行流程

一条命令的执行过程有很多细节,但大体可分为:

  • 客户端先将用户输入的命令,转化为 Redis 相关的通讯协议
  • 再用 socket 连接的方式将内容发送给服务器端,服务器端在接收到相关内容之后,
  • 先将内容转化为具体的执行命令,再判断用户授权信息和其他相关信息,当验证通过之后会执行最终命令
  • 命令执行完之后,会进行相关的信息记录和数据统计
  • 然后再把执行结果发送给客户端,这样一条命令的执行流程就结束了
  • 如果是集群模式的话,主节点还会将命令同步至子节点

在这里插入图片描述

步骤一:用户输入一条命令

步骤二:客户端先将命令转换成 Redis 协议,然后再通过 socket 连接发送给服务器端

客户端和服务器端是基于 socket 通信的,服务器端在初始化时会创建了一个 socket 监听,用于监测链接客户端的 socket 链接,源码如下:

void initServer(void) {//......// 开启 Socket 事件监听if (server.port != 0 &&listenToPort(server.port,server.ipfd,&server.ipfd_count) == C_ERR)exit(1);//......
}

socket 小知识:每个 socket 被创建后,会分配两个缓冲区,输入缓冲区和输出缓冲区。 写入函数并不会立即向网络中传输数据,而是先将数据写入缓冲区中,再由 TCP 协议将数据从缓冲区发送到目标机器。一旦将数据写入到缓冲区,函数就可以成功返回,不管它们有没有到达目标机器,也不管它们何时被发送到网络,这些都是 TCP 协议负责的事情。 注意:数据有可能刚被写入缓冲区就发送到网络,也可能在缓冲区中不断积压,多次写入的数据被一次性发送到网络,这取决于当时的网络情况、当前线程是否空闲等诸多因素,不由程序员控制。 读取函数也是如此,它也是从输入缓冲区中读取数据,而不是直接从网络中读取。

当 socket 成功连接之后,客户端会先把命令转换成 Redis 通讯协议(RESP 协议,REdis Serialization Protocol)发送给服务器端,这个通信协议是为了保障服务器能最快速的理解命令的含义而制定的,如果没有这个通讯协议,那么 Redis 服务器端要遍历所有的空格以确认此条命令的含义,这样会加大服务器的运算量,而直接发送通讯协议,相当于把服务器端的解析工作交给了每一个客户端,这样会很大程度的提高 Redis 的运行速度。例如,当我们输入 set key val 命令时,客户端会把这个命令转换为 *3\r\n$3\r\nSET\r\n$4\r\nKEY\r\n$4\r\nVAL\r\n 协议发送给服务器端。 更多通讯协议,可访问官方文档:https://redis.io/topics/protocol

步骤三:服务器端接收到命令

服务器会先去输入缓冲中读取数据,然后判断数据的大小是否超过了系统设置的值(默认是 1GB),如果大于此值就会返回错误信息,并关闭客户端连接。 默认大小如下图所示:

在这里插入图片描述
当数据大小验证通过之后,服务器端会对输入缓冲区中的请求命令进行分析,提取命令请求中包含的命令参数,存储在 client 对象(服务器端会为每个链接创建一个 Client 对象)的属性中。

步骤四:执行前准备

  1. 判断是否为退出命令,如果是则直接返回;

  2. 非 null 判断,检查 client 对象是否为 null,如果是返回错误信息;

  3. 获取执行命令,根据 client 对象存储的属性信息去 redisCommand 结构中查询执行命令;

  4. 用户权限效验,未通过身份验证的客户端只能执行 AUTH(授权) 命令,未通过身份验证的客户端执行了 AUTH 之外的命令则返回错误信息;

  5. 集群相关操作,如果是集群模式,把命令重定向到目标节点,如果是 master(主节点) 则不需要重定向;

  6. 检查服务器端最大内存限制,如果服务器端开启了最大内存限制,会先检查内存大小,如果内存超过了最大值会对内存进行回收操作;

  7. 持久化检测,检查服务器是否开启了持久化和持久化出错停止写入配置,如果开启了此配置并且有持久化失败的情况,禁止执行写命令;

  8. 集群模式最少从节点(slave)验证,如果是集群模式并且配置了 replminslavestowrite(最小从节点写入),当从节点的数量少于配置项时,禁止执行写命令;

  9. 只读从节点验证,当此服务器为只读从节点时,只接受 master 的写命令;

  10. 客户端订阅判断,当客户端正在订阅频道时,只会执行部分命令(只会执行 SUBSCRIBE、PSUBSCRIBE、UNSUBSCRIBE、PUNSUBSCRIBE,其他命令都会被拒绝)。

  11. 从节点状态效验,当服务器为 slave 并且没有连接 master 时,只会执行状态查询相关的命令,如 info 等;

  12. 服务器初始化效验,当服务器正在启动时,只会执行 loading 标志的命令,其他的命令都会被拒绝;

  13. lua 脚本阻塞效验,当服务器因为执行 lua 脚本阻塞时,只会执行部分命令;

  14. 事务命令效验,如果执行的是事务命令,则开启事务把命令放入等待队列;

  15. 监视器 (monitor) 判断,如果服务器打开了监视器功能,那么服务器也会把执行命令和相关参数发送给监视器 (监视器是用于监控服务器运行状态的)。

当服务器经过以上操作之后,就可以执行真正的操作命令了

步骤五:执行最终命令,调用 redisCommand 中的 proc 函数执行命令。

步骤六:执行完后相关记录和统计

  1. 检查慢查询是否开启,如果开启会记录慢查询日志;
  2. 检查统计信息是否开启,如果开启会记录一些统计信息,例如执行命令所耗费时长和计数器(calls)加1;
  3. 检查持久化功能是否开启,如果开启则会记录持久化信息; ④ 如果有其它从服务器正在复制当前服务器,则会将刚刚执行的命令传播给其他从服务器。

步骤七:返回结果给客户端

命令执行完之后,服务器会通过 socket 的方式把执行结果发送给客户端,客户端再把结果展示给用户,至此一条命令的执行就结束了。

扩展知识:I/O 多路复用

Redis 使用的是 I/O 多路复用功能来监听多 socket链接的,这样就可以使用一个线程链接来处理多个请求,减少线程切换带来的开销,同时也避免了 I/O 阻塞操作,从而大大提高了 Redis 的运行效率。

在这里插入图片描述
综合来说,此步骤的执行流程如下:

  • 与服务器端以 socket 和 I/O 多路复用的技术建立链接;
  • 将命令转换为 Redis 通讯协议,再将这些协议发送至缓冲区。

小结

当用户输入一条命令之后,客户端会以 socket 的方式把数据转换成 Redis 协议,并发送至服务器端,服务器端在接受到数据之后,会先将协议转换为真正的执行命令,在经过各种验证以保证命令能够正确并安全的执行,但验证处理完之后,会调用具体的方法执行此条命令,执行完成之后会进行相关的统计和记录,然后再把执行结果返回给客户端,整个执行流程,如下图所示:

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/305438.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

docker学习(二十一、network使用示例container、自定义)

文章目录 一、container应用示例1.需要共用同一个端口的服务,不适用container方式2.可用示例3.停掉共享源的容器,其他容器只有本地回环lo地址 总结 二、自定义网络应用示例默认bridge,容器间ip通信默认bridge,容器间服务名不通 自…

关于设计模式、Java基础面试题

前言 之前为了准备面试,收集整理了一些面试题。 本篇文章更新时间2023年12月27日。 最新的内容可以看我的原文:https://www.yuque.com/wfzx/ninzck/cbf0cxkrr6s1kniv 设计模式 单例共有几种写法? 细分起来就有9种:懒汉&#x…

常见算法(java版)

冒泡排序 每次从数组中找出最大值放在数组的后面去。 关键步骤 确定总共需要做几轮: 数组的长度-1。 每轮比较几次:数组的长度 - 第i轮。 当前位置大于后一个位置则交换数据。 选择排序 每轮选择当前位置,开始找出后面的较小值与该位置交换。 关键…

Keras多分类鸢尾花DEMO

完整的一个小demo: pandas1.2.4 numpy1.19.2 python3.9.2 import numpy as np import pandas as pd import matplotlib.pyplot as plt from pandas import DataFrame from scipy.io import loadmat from sklearn.model_selection import train_test_split impor…

【精选】vulnhub CTF5 NanoCMS漏洞 (青铜门笔记)

🍬 博主介绍👨‍🎓 博主介绍:大家好,我是 hacker-routing ,很高兴认识大家~ ✨主攻领域:【渗透领域】【应急响应】 【python】 【VulnHub靶场复现】【面试分析】 🎉点赞➕评论➕收藏…

关于StartAI生图下载问题

最近小编常常收到一些小伙伴对StartAI生图的问题反馈,今天为大家同一解答吧! Q1:小编小编,为什么我生图后下载图片在文件夹中显示空白呀? 小编:当前我们StartAI版本0.4.5在下载图片时还未添加保存类型&…

Apache Commons Pool的对象池技术

第1章:引言 咱们今天来聊聊一个在Java开发中超级实用,但又经常被忽视的技术——对象池技术。可能你们已经听说过“对象池”这个名词,但对它的具体作用和重要性还有些模糊。别急,小黑带你们一步步深入了解。 想象一下&#xff0c…

产品经理如何培养思维模式和创新能力?

作为一名产品经理,我们需要具备一定的思维模式和创新能力,以应对不断变化的市场和技术环境。在本文中,我将分享一些培养产品经理思维模式和创新能力的方法。 一、培养市场洞察力 作为产品经理,我们需要深入了解市场和用户需求&a…

9种卷积注意力机制创新方法汇总,含2024最新

今天咱们来聊聊卷积注意力机制。 相信各位在写论文的时候都苦恼过怎么更好地改模型,怎么更高效地提高模型的性能和泛化能力吧?我的建议是,不妨考虑考虑卷积注意力。 卷积注意力机制是一种通过关注输入数据中的不同部分来改进模型性能的方法…

前端子项目共用node_modules

项目目录结构如下 首先按上面的结构新建三个项目,有一定前端经验的都知道怎么处理,我就不多介绍了。 1,子项目1 package.json如下,我只安装了vue index.js如下 2,子项目2 package.json如下,我安装了…

MLILY梦百合荣获巨量引擎“2023 Home M³ 年度内容种草奖”

12月27日,由巨量引擎主办的2024未来空间大会在海南三亚举办,本届大会以“全域驱动破界增长”为主题,汇聚家居家装行业优秀企业,共同探讨在产业调整期中,家居家装企业如何利用抖音平台做好全域营销、实现逆势增长。大会颁发了巨量引擎“Home M”系列奖项,MLILY梦百合与亚朵星球、…

【Fastadmin】通用排序weigh不执行model模型的事件

在model模型类支持的before_delete、after_delete、before_write、after_write、before_update、after_update、before_insert、after_insert事件行为中,我们可以快捷的做很多操作,如删除缓存、逻辑判断等 但是在fastadmin的通用排序weigh拖动中无法触发…