前言

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

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

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


1. 命令请求的执行过程

1.1 发送命令请求

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

1.2 读取命令请求

  • 读取套接字中协议格式的命令请求,并将其保存到客户端状态的输入缓冲区里面;
  • 分析协议格式的命令请求,提取参数命令以及参数个数,存进客户端状态的 argvargc 属性;
  • 调用命令执行器,执行客户端指定命令;



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

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

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

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

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

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

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

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

  • 等等……

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

  • 执行以下语句:client->cmd->proc(client)
  • 被调用的命令实现函数执行指定操作,返回相应命令回复;

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

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

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

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

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

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

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

2. 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 说明服务器没有进行持久化操作;

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

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

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

3. 初始化服务器

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 文件里包含以下内容:
    1. # 将数据库数量设置为32个
    2. database 32
    3. # 关闭 RDB 文件的压缩功能
    4. 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

最后

新人制作,如有错误,欢迎指出,感激不尽!
欢迎关注公众号,会分享一些更日常的东西!
如需转载,请标注出处!

Redis | 第7章 Redis 服务器《Redis设计与实现》的更多相关文章

  1. 【redis】Java连接云服务器redis之JedisConnectionException的异常问题

    代码很简单: public static void main(String[] args) { Jedis jedis = new Jedis("116.85.10.216",63 ...

  2. Redis | 第11章 服务器的复制《Redis设计与实现》

    目录 前言 1. 旧版复制功能的实现 1.1 同步与命令传播 1.2 旧版复制功能的缺陷 2. 新版复制功能的实现 2.1 部分重同步的实现原理 3. PSYNC 命令的实现 4. 复制的详细步骤 4 ...

  3. Redis | 第5章 Redis 中的持久化技术《Redis设计与实现》

    目录 前言 1. RDB 持久化 1.1 RDB 文件的创建与载入 1.2 自动间隔性保存 1.2.1 设置保存条件 1.2.2 dirty 计数器和 lastsave 属性 1.2.3 检查保存条件 ...

  4. Redis | 第8章 发布订阅与事务《Redis设计与实现》

    目录 前言 1. 发布订阅 1.1 频道的订阅与退订 1.2 模式的订阅与退订 1.3 发送消息 1.4 查看订阅消息 2. 事务 2.1 事务的实现 2.2 WATCH 命令的实现 2.3 事务的 ...

  5. Redis | 第9章 Lua 脚本与排序《Redis设计与实现》

    目录 前言 1. Lua 脚本 1.1 Redis 创建并修改 Lua 环境的步骤 1.2 Lua 环境协作组件 1.3 EVAL 命令的实现 1.4 EVALSHA 命令的实现 1.5 脚本管理命令 ...

  6. Redis | 第10章 二进制数组、慢查询日志和监视器《Redis设计与实现》

    目录 前言 1. 二进制位数组 1.1 位数组的表示 1.2 GETBIT 命令的实现 1.3 SETBIT 命令的实现 1.4 BITECOUNT 命令的实现 1.5 BITOP 命令的实现 2. ...

  7. Redis | 第12章 Sentinel 哨兵模式《Redis设计与实现》

    目录 前言 1. 启动并初始化 Sentinel 2. Sentinel 与服务器间的默认通信 2.1 获取主服务器信息 2.2 获取从服务器信息 2.3 向主服务器和从服务器发送信息 3. 接受来自 ...

  8. Redis | 第4章 Redis中的数据库《Redis设计与实现》

    目录 前言 1. Redis中的数据库 2. 数据库的键空间 3. 键的生成时间与过期时间 4. Redis中的过期键删除策略 5. AOF.RDB和复制功能对过期键的处理 5.1 生成 RDB 文件 ...

  9. 探索Redis设计与实现13:Redis集群机制及一个Redis架构演进实例

    本文转自互联网 本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github.com/h2pl/Java-Tutorial ...

随机推荐

  1. python常用功能

    1. 获取昨天日期 引入datetime模块 import datetime def getYesterday(): today = datetime.date.today() #返回当前本地日期 # ...

  2. 4.7 80--删除排序数组中的重复项 II

    因为python的list可以直接del List[index],因此直接使用了暴力方法,判断是否重复了两次,是的话直接使用del. 在转向使用Java时,因为暴力方法的局限,一直在找怎样对Java的 ...

  3. BUAA_2020_软件工程_个人博客作业

    项目 内容 这个作业属于哪个课程 2020春季计算机学院软件工程(罗杰 任健) 这个作业的要求在哪里 个人博客作业 我在这个课程的目标是 了解软件工程的技术,掌握工程化开发的能力 这个作业在哪个具体方 ...

  4. OO第二单元——多线程(电梯)

    OO第二单元--多线程(电梯) 综述 第二单元的三次联系作业都写电梯,要求逐步提高,对于多线程的掌握也进一步加深.本次作业全部都给出了输入输出文件,也就避免了正则表达式判断输入输出是否合法的问题. 第 ...

  5. zuul过滤器filter 的编写

    通过上一节(zuul的各种配置)的学习,我们学会了zuul路由的各种配置,这一节我们来实现一下zuul的过滤器功能.那么为什么需要用到zuul的过滤器呢?我们知道zuul是我们实现外部系统统一访问的入 ...

  6. 算法:杨辉三角(Pascal's Triangle)

    一.杨辉三角介绍 杨辉三角形,又称帕斯卡三角形.贾宪三角形.海亚姆三角形.巴斯卡三角形,是二项式系数的一种写法,形似三角形,在中国首现于南宋杨辉的<详解九章算法>得名,书中杨辉说明是引自贾 ...

  7. VMware Workstation 16.2 Pro for Linux SLIC 2.6 & Unlocker

    请访问原文链接:https://sysin.org/blog/vmware-workstation-16-linux-slic/,查看最新版.原创作品,转载请保留出处. 作者:gc(at)sysin. ...

  8. linux下创建文件的文件权限问题

    今天发现创建文件的权限和自己规定的权限不一致,了解到了权限掩码的问题,这里总结一下. 首先权限掩码umask是chmod配套的,总共为4位(gid/uid,属主,组权,其它用户的权限),不过通常我们都 ...

  9. 为什么IDEA不推荐你使用@Autowired ?

    @Autowired注解相信每个Spring开发者都不陌生了!在DD的Spring Boot基础教程和Spring Cloud基础教程中也都经常会出现. 但是当我们使用IDEA写代码的时候,经常会发现 ...

  10. C语言图书管理借阅系统——ncurses库的使用

    一.前言 作为一只大四狗,最近还跟着大二同学修了一门课(当然不是之前没通过啦),课程是高级语言课程设计,高级语言指的是C语言 :),内容是做一个XX管理系统,我选择了图书管理系统,先介绍下我做的系统: ...