Redis | 第7章 Redis 服务器《Redis设计与实现》
创始人
2024-09-25 08:20:27
0

前言

参考资料:《Redis设计与实现 第二版》;

第二部分为单机数据库的实现,主要由以下模块组成:数据库持久化事件客户端服务器

本篇将介绍 Redis 的服务器端,从服务器接收客户端的命令请求serverCron 函数 以及初始化服务器三个角度介绍;

与本章相关的 Redis 命令总结在下篇文章,欢迎点击收藏,本篇将不再重复:

《Redis常用命令及示例总结(API)》 :https://www.jianshu.com/p/f8eb9afaa908


  1. 命令请求的执行过程
    ============

1.1 发送命令请求

  • 用户在客户端键入一个命令请求 { SET KEY VALUE };
  • 客户端将命令请求转换成协议格式 { *3\r\n3\r\nSET\r\n3\r\nKEY\r\n$5\r\nVALUE\r\n };
  • 通过连接到服务器的套接字,将协议格式的命令请求发送给服务器;


发送命令请求过程.png

1.2 读取命令请求

  • 读取套接字中协议格式的命令请求,并将其保存到客户端状态的输入缓冲区里面;

  • 分析协议格式的命令请求,提取参数命令以及参数个数,存进客户端状态的 argvargc 属性;

  • 调用命令执行器,执行客户端指定命令;



    读取命令请求.png


解析出的协议格式内容.png

1.3 命令执行器(1):查找命令实现

  • 根据客户端的 argv[0] 参数,在命令表中查找参数所指定的命令,并将找到的命令 redisCommand 保存到客户端状态的 cmd 属性里;


命令表示例.png

设置客户端状态的 cmd 指针.png

  • redisCommand 的主要参数:name(名字),proc(函数指针),arity(命令参数个数),sflags(命令属性标识),flags(sflags的二进制标识),calls(服务器总共执行了多少次这个命令),milliseconds(执行该命令的总耗时);


sflags属性的标识.png

1.4 命令执行器(2):执行预备操作

  • 检查客户端状态的 cmd 指针是否指向 NULL,是则返回错误;

  • 根据 cmd 指向的 redisCommand 结构的 arity 属性检查参数个数是否正确,不正确则返回错误;

  • 检查客户端是否通过身份验证,未通过的只能执行 AUTH 命令;

  • 若服务器打开了 maxmemory 功能,则在执行命令之前先检查服务器内存占用情况,在需要时回收内存。内存回收失败返回错误;

  • 等等…

1.5 命令执行器(3):调用命令的实现函数

  • 执行以下语句:client->cmd->proc(client)

  • 被调用的命令实现函数执行指定操作,返回相应命令回复;



    执行前客户端状态.png


执行后客户端状态.png.png

1.6 命令执行器(4):执行后续工作

  • 如果服务器开启了慢查询功能,慢查询日志模块会检查是否需要为刚刚执行完的命令请求添加一条新的慢查询日志;
  • 根据执行命令耗费时长更新 redisCommand 结构的 milliseconds 属性,同时将 calls 属性加一;
  • 如果服务器开启了 AOF 持久化功能,会将命令写入 AOF 缓冲期里;
  • 如果有从服务器正则复制当前服务器,服务器会将命令传播给所有从服务器;

1.7 将命令回复发送给客户端

  • 当客户端套接字变为可写状态时,服务器会执行命令回复处理器,将保存在客户端输出缓冲区中的命令回复发送给客户端 {+OK\r\n};

  • 当命令发送完毕后,回复处理器会清空客户端状态的输出缓冲区,为处理下一个命令请求最准备;

1.8 客户端接收并打印命令回复

  • 客户端接收协议格式的命令回复后,会将回复转成易读格式;


客户端接收并打印命令回复.png


  1. serverCron 函数
    ================
  • serverCron 函数默认每隔 100ms 执行一次,负责管理服务器资源与保持服务器自身良好运转;

  • 下面是 serverCron 函数所做操作的介绍:

    • 更新服务器时间缓存 :更新服务器状态的 unixtime(秒级) 属性和 mstime(毫秒级) 属性。精度不高,用于:打印日志、更新 LRU 时钟、决定是否执行持久化任务、服务器上线时间等;

    • 更新 LRU 时钟 :更新服务器状态的 lruclock(10秒更新一次) 和 lru 属性。前者用于计算键的空转时间,后者保存了对象最后一次被命令访问的时间。空转时间=lruclock-lru;

    • 更新服务器每秒执行命令次数 :调用 trackOperationsPerSecond 函数。以抽样计算的方式,估算并记录服务器在最近 1s 处理的命令请求数量;

  • 更新服务器内存峰值函数 :更新stat_peak_memory 属性。该属性记录了服务器的内存峰值大小;

  • 处理 SIGTERM 信号:在启动服务器时,Redis 会为服务器进程的 SIGTERM 信号关联处理器 sigtermHandler 函数,信号处理器负责在服务器接到 SIGTERM 信号时,打开服务器状态的 shutdown_asap 标识;

  • 管理客户端资源 :调用 clientsCron 函数。如果客户端与服务器之间的连接已经超时,则释放客户端。如果客户端输入缓冲区大小超过一定长度,则释放客户端当前的输入缓冲区,并创建一个默认大小的输入缓冲区;

  • 管理数据库资源 :调用 databasesCron 函数,删除过期键,对字典进行收缩操作;

  • 执行被延迟的 BGREWRITEAOF :检查在执行 BGSAVE 命令期间,是否有 BGREWRITEAOF 命令被延迟执行;

  • 检查持久化操作的运行状态 :检查 rdb_child_pid(记录 BGSAVE 命令的子进程 ID) 属性与 aof_child_pid(记录执行 BGREWRITEAOF 命令的子进程 ID) 属性。值为 -1 说明服务器没有进行持久化操作;


持久化检查过程.png

  • 将 AOF 缓冲区中的内容写入 AOF 文件:如果服务开启 AOF 功能,并且 AOF 缓冲区里有待写入数据,则将 AOF 缓冲区中的内容写入 AOF 文件里;

  • 关闭异步客户端:关闭输出缓冲区大小超过限制的客户端;

  • 增加 cronloops 计数器的值 :对服务器状态的 cronloops 属性增 1;

  1. 初始化服务器
    =========

3.1 初始化服务器状态结构

  • 即创建使用默认值一个 struct redisServer 结构体;
  • 负责初始化一般属性;
  • 初始化的工作由 redis.c/initServerConfig 函数完成,该函数的主要工作有:
    • 设置服务器的运行 ID;
    • 设置服务器的默认运行频率;
    • 设置服务器的默认配置文件路径;
    • 设置服务器的运行架构;
    • 设置服务器的默认端口号;
    • 设置服务器的默认 RDB 持久化条件和 AOF 持久化条件;
    • 初始化服务器的 LRU 时钟;
    • 创建命令表;

3.2 载入配置选项

  • 载入用户给定的配置参数和配置文件,并对 server 变量相关属性的值进行修改;

  • 指定端口号:redis-server --port 10086

  • 修改数据库数量与 RDB 文件压缩功能:redis-server redis.conf。并且 redis.conf 文件里包含以下内容:

    # 将数据库数量设置为32个 database 32 # 关闭 RDB 文件的压缩功能 rdbcompression no 

3.3 初始化服务器数据结构

  • 负责初始化数据结构

    • 调用 initServer 函数,初始化下列数据库:
    • 设置数据库:server.clients 链表(存客户端)、server.db 数组(存数据库)、server.pubsub_channels 字典(保存频道订阅信息)、server.lua(用于执行 Lua 脚本的 Lua 环境)、server.slowlog(用于保存慢查询日志)
  • 进行一些重要设置

    • 为服务器设置进程信号处理器;
    • 创建共享对象(如 OK、整数 0-9999);
    • 打开服务器的监听端口,为监听套接字关联连接应答事件处理器,等待服务器正式运行时接受客户端的连接;
    • serverCron 函数创建时间事件;
    • 当 AOF 持久化功能打开时,打开现有 AOF 文件或创建并打开一个新的 AOF 文件,为 AOF 写入做准备;
    • 初始化服务器的后台 I/O 模块,为将来 I/O 操作做准备;

3.4 还原数据库状态

  • 载入 RDB 文件或 AOF 文件(优先),并根据文件记录的内容还原服务器的数据库状态;
  • 成功还原的日志信息:
    [8040] 01 Dec 20:12:41.758 * DB loaded from disk: 0.001 seconds

3.5 执行事件循环

  • 在打印下列日志后执行事件循环(loop函数);
    [8040] 01 Dec 20:12:41.758 * The server is now ready to accept connections on port 6379


最后

\color{blue}{\rm\small{新人制作,如有错误,欢迎指出,感激不尽!}}

\color{blue}{\rm\small{欢迎关注我,并与我交流!}}

\color{blue}{\rm\small{如需转载,请标注出处!}}
最后编辑于:2024-08-25 14:36:26
© 著作权归作者所有,转载或内容合作请联系作者

喜欢的朋友记得点赞、收藏、关注哦!!!

相关内容

热门资讯

安卓出厂系统和最新系统,全面升... 亲爱的数码控们,你是否也像我一样,对手机系统的新鲜玩意儿充满好奇?今天,咱们就来聊聊安卓出厂系统和最...
掌上医院安卓系统,智慧医疗新时... 掌上医院安卓系统:你的私人健康小助手想象你正躺在床上,手机轻轻一滑,就能预约挂号、查看报告、了解医生...
安卓系统如何冻结程序,提升手机... 手机里那些占内存、耗电快的应用,是不是让你头疼不已?别急,今天就来教你怎么用安卓系统冻结这些“捣蛋鬼...
手机变身安卓系统,探索系统转换... 哇塞,你有没有想过,你的手机竟然可以变身成为安卓系统的小能手?没错,就是那个我们日常离不开的智能手机...
window平板转安卓系统,转... 亲爱的平板用户们,你是否曾想过,你的Windows平板电脑也能变身成为安卓小精灵呢?没错,今天我要跟...
安卓系统qq离线设置,畅享无打... 亲爱的安卓手机用户们,你们是不是也有过这样的烦恼:明明想安静地放松却总是被QQ消息打扰得心烦意乱?别...
安卓刷win系统体验,刷机攻略... 哇塞,你有没有想过,你的安卓手机也能变身成Windows系统的超级英雄?没错,就是那个我们熟悉的Wi...
安卓设备的系统刷写,操作步骤、... 你有没有想过,你的安卓手机其实就像一个等待你发挥创意的画布呢?没错,就是那个你每天捧在手心里的宝贝—...
安卓系统双开的软件,实现多账号... 你有没有想过,在手机上同时运行两个相同的APP,是不是就像拥有两个超级英雄一样酷炫呢?没错,这就是安...
安卓系统绘画app推荐,全方位... 你有没有想过,在手机上也能画出美轮美奂的作品呢?没错,现在科技这么发达,安卓系统上的绘画app可是五...
安卓系统看广告视频,智能播放与... 你有没有发现,现在手机上那些安卓系统的应用,动不动就弹出来广告视频?真是让人又爱又恨啊!今天,就让我...
安卓系统安装歌曲软件,热门歌曲... 你有没有想过,手机里没有喜欢的歌曲,那感觉就像是没有了灵魂?别急,今天就来给你支个招,教你在安卓系统...
如何退出安卓升级系统,实用技巧... 手机突然弹出一个升级提示,你心里是不是有点小紧张呢?别担心,今天就来手把手教你如何退出安卓升级系统,...
安卓平板系统克隆软件,轻松实现... 你有没有想过,把你的安卓平板上的系统,像变魔术一样克隆到另一台平板上?听起来是不是很神奇?别急,今天...
小米8 是安卓系统,安卓系统下... 你有没有想过,手机的世界里,安卓系统就像是个万能的魔法师,而小米8就是那个挥舞魔杖的勇敢少年!今天,...
安卓系统的职业选手,职业选手的... 职场高手,安卓战场上的风云人物 ?亲爱的游戏迷们,你是否曾在王者荣耀的战场上,目睹过那些如风似电的操...
安卓系统后台耗电高,高效管理策... 亲爱的手机控们,你们是不是也和我一样,每天对着手机,却总是担心电量不够用呢?尤其是安卓系统的小伙伴们...
小米3安装安卓系统,操作指南与... 亲爱的手机控们,你是否曾对自家的小米3手机心生厌倦,渴望给它换一副新颜?别急,今天就来手把手教你如何...
警察恢复安卓手机系统,警察如何... 手机突然卡成“龟速”,应用动不动就闪退,是不是感觉自己的安卓手机被“诅咒”了?别急,警察叔叔来帮你恢...
安卓手机有双系统,安装、设置与... 你有没有想过,你的安卓手机其实是个“变形金刚”,可以瞬间变身成两个不同的世界?没错,就是安卓手机有双...