Redis学习三:设计与实现之单机数据库

  • 前言
  • 数据库键空间
    • 键空间的结构
    • 读写键空间时的维护操作
  • RDB文件
    • RDB文件结构
    • RDB文件介绍
    • RDB触发规则
    • RDB优点
    • RDB缺点
  • AOF持久化的实现
    • AOF持久化操作
    • AOF文件同步的效率与安全性
    • AOF的还原数据过程
    • AOF优点
    • AOF缺点
  • Redis的文件事件
    • 文件事件处理器的组成部分
  • Redis命令请求的执行过程

前言

本文来源于《Redis的设计与实现》第二章节的学习,是这本书的简要读书笔记,仅作为记录所用,希望以后能常常温故知新~~~

数据库键空间

Redis 是一个键值对(key-value pair)数据库服务器, 服务器中的每个数据库都由一个 redis.h/redisDb 结构表示, 其中, redisDb 结构的dict 字典保存了数据库中的所有键值对, 我们将这个字典称为键空间(key space):

键空间的结构

typedef struct redisDb { // ... // 数据库键空间,保存着数据库中的所有键值对 dict *dict; // ...
} redisDb;

键空间中的键:字符串对象
键空间中的值:字符串对象 / 列表对象 / 哈希表对象 / 集合对象 / 有序集合对象 中的任意一种

例如:

redis> SET message "hello world"
OK
redis> RPUSH alphabet "a" "b" "c"
(integer) 3
redis> HSET book name "Redis in Action"
(integer) 1
redis> HSET book author "Josiah L. Carlson"
(integer) 1
redis> HSET book publisher "Manning"
(integer) 1

它所对应的键空间结构如下:

读写键空间时的维护操作

当使用Redis命令对数据库进行读写时,服务器不仅会对键空间执行指定的读写操作,还会执行一些额外的维护操作,其中包括:

  • 在读取一个键之后(读操作和写操作都要对键进行读取), 服务器会根据键是否存在, 以此来更新服务器的键空间命中(hit)次数或键空间不命中(miss)次数, 这两个值可以在 INFO stats 命令的 keyspace_hits 属性和 keyspace_misses 属性中查看;
  • 在读取一个键之后, 服务器会更新键的 LRU (最后一次使用)时间, 这个值可以用于计算键的闲置时间, 使用命令 OBJECT idletime 命令可以查看键 key 的闲置时间。
  • 如果服务器在读取一个键时, 发现该键已经过期, 那么服务器会先删除这个过期键, 然后才执行余下的其他操作;
  • 如果有客户端使用 WATCH 命令监视了某个键, 那么服务器在对被监视的键进行修改之后, 会将这个键标记为脏(dirty), 从而让事务程序注意到这个键已经被修改过;
  • 服务器每次修改一个键之后, 都会对脏(dirty)键计数器的值增一, 这个计数器会触发服务器的持久化以及复制操作执行;
  • 如果服务器开启了数据库通知功能, 那么在对键进行修改之后, 服务器将按配置发送相应的数据库通知。

RDB文件

RDB文件结构

REDIS | db_version | databases | EOF | check_sum

  • REDIS : 5字节,保存着 “REDIS” 五个字符,检查是否为RDB文件的标识;
  • db_version : 4字节,值是字符串表示的整数,表示RDB文件的版本号,例如“0006”;
  • databases 包含0或者多个数据库,以及各个数据库中的键值对数据;
  • EOF 常量的长度为 1 字节, 这个常量标志着 RDB 文件正文内容的结束;
  • check_sum 是一个 8 字节长的无符号整数, 保存着一个校验和,这个校验和是程序通过对 REDIS 、 db_version 、 databases 、 EOF 四个部分的内容进行计算得出的。

RDB文件介绍

  1. 用于保存和还原 Redis 服务器所有数据库中的所有键值对数据;
  2. SAVE 命令由服务器进程直接执行保存操作,所以该命令会阻塞服务器;
  3. BGSAVE 命令由子进程执行保存操作,所以该命令不会阻塞服务器;
  4. 服务器状态中会保存所有用 save 选项设置的保存条件,当任意一个保存条件被满足时,服务器会自动执行 BGSAVE 命令;
  5. RDB 文件是一个经过压缩的二进制文件,由多个部分组成;
  6. 对于不同类型的键值对, RDB 文件会使用不同的方式来保存它们;

RDB触发规则

  • save 规则满足的情况下,会自动触发RDB规则;
  • 执行 flushall 命令,也会触发RDB规则;
  • 退出redis,也会产生RDB文件;

备份的时候自动会生成一个dump.rdb;如果需要恢复rdb文件,只需要将rdb文件放在redis启动目录下面就可以了,redis启动的时候会自动恢复;

RDB优点

适合大规模的数据恢复!对数据的完整性要求不高!

RDB缺点

需要一定的时间间隔进程操作! 如果redis意外宕机了,最后一次修改数据就没有了!fork进程的时候,会占用一定的内存空间;

AOF持久化的实现

AOF持久化操作

AOF持久化功能的实现可以分为 : 命令追加 、 文件写入 、 文件同步 三个步骤:

struct redisServer { // ... // AOF 缓冲区 sds aof_buf; // ...
};
  • 命令追加: 当 AOF 持久化功能处于打开状态时, 服务器在执行完一个写命令之后, 会以协议格式将被执行的写命令追加到服务器状态的 aof_buf 缓冲区的末尾;
  • 写入与同步:由于可能aof_buf缓冲区有内容追加,所以服务器每次结束一个事件循环前会调用 flushAppendOnlyFile 函数, 考虑是否需要将 aof_buf 缓冲区中的内容写入和保存到 AOF 文件里面;

为了提高文件的写入效率, 在现代操作系统中, 当用户调用 write 函数, 将一些数据写入到文件的时候, 操作系统通常会将写入数据暂时保存在一个内存缓冲区里面, 等到缓冲区的空间被填满、或者超过了指定的时限之后, 才真正地将缓冲区中的数据写入到磁盘里面,这里需要将 写入 与 同步 区分开来;

AOF文件同步的效率与安全性

AOF文件同步的效率与安全性主要由服务器配置appendfsync来决定:

  • appendfsync = always
    服务器在每个事件循环都要将 aof_buf 缓冲区中的所有内容写入到 AOF 文件, 并且同步 AOF 文件, 所以 always 的效率是 appendfsync 选项三个值当中最慢的一个,但也是最安全的;
  • appendfsync = everysec
    服务器在每个事件循环都要将 aof_buf 缓冲区中的所有内容写入到 AOF 文件, 并且每隔超过一秒就要在子线程中对 AOF 文件进行一次同步;效率快,并且就算故障停机,数据库仅丢失1s的命令数据;
  • appendfsync = no
    服务器在每个事件循环都要将 aof_buf 缓冲区中的所有内容写入到 AOF 文件, 至于何时对 AOF 文件进行同步, 则由操作系统控制。这个模式下AOF写入速度是最快的,但该模式会在系统缓存中积累一段时间的写入数据;

AOF的还原数据过程

AOF 模式默认是不开启的,默认是使用RDB方式持久化的,我们需要手动配置,只需要将appendonly由no 修改为 yes 就开启了 AOF,重启,redis就生效了,如果 AOF文件有错位,redis是无法启动的,这时候我们可以通过redis-check-aof --fix appendonly.aof 来修复AOF文件;

AOF 文件通过保存所有修改数据库的写命令请求来记录服务器的数据库状态,所有命令都以Redis命令请求协议的格式保存,服务器只要载入并重新执行保存在 AOF 文件中的命令, 就可以还原数据库本来的状态。

在执行 BGREWRITEAOF 命令时, Redis 服务器会维护一个 AOF 重写缓冲区, 该缓冲区会在子进程创建新 AOF 文件的期间, 记录服务器执行的所有写命令。 当子进程完成创建新 AOF 文件的工作之后, 服务器会将重写缓冲区中的所有内容追加到新 AOF 文件的末尾, 使得新旧两个 AOF 文件所保存的数据库状态一致。 最后, 服务器用新的 AOF 文件替换旧的 AOF 文件, 以此来完成 AOF 文件重写操作。

AOF优点

每一次修改都会同步,文件的完整性会更加好;

AOF缺点

相对于数据文件量而言,aof远远大于rdb,修复速度也会慢;aof运行效率慢,因此redis默认的配置是rdb;

Redis的文件事件

Redis基于Reactor模式开发了网络事件处理器——文件事件处理器,使用 I/O 多路复用(multiplexing)程序来同时监听多个套接字, 并根据套接字目前执行的任务来为套接字关联不同的事件处理器。虽然文件事件处理器以单线程方式运行, 但通过使用 I/O 多路复用程序来监听多个套接字, 文件事件处理器既实现了高性能的网络通信模型, 又可以很好地与 Redis 服务器中其他同样以单线程方式运行的模块进行对接, 这保持了 Redis 内部单线程设计的简单性。

文件事件处理器的组成部分


文件事件是对套接字操作的抽象, 每当一个套接字准备好执行连接应答(accept)、写入、读取、关闭等操作时, 就会产生一个文件事件。 因为一个服务器通常会连接多个套接字, 所以多个文件事件有可能会并发地出现。

I/O多路复用程序总是会将所有产生事件的套接字入队到一个队列中,通过这个队列,有序、同步、一次一个套接字的方式向文件事件分派器传送套接字;

Redis服务事件分为:文件事件 与 时间事件,其中,服务器一般仅执行 serverCron函数 这一个时间事件,而文件事件分为 读事件 与 写事件;

Redis命令请求的执行过程

例如 客户端发送set key value到获取回复OK的过程中:

  • 客户端向服务器发送命令请求 SET KEY VALUE 。
  • 服务器接收并处理客户端发来的命令请求 SET KEY VALUE , 在数据库中进行设置操作, 并产生命令回复 OK 。
  • 服务器将命令回复 OK 发送给客户端。
  • 客户端接收服务器返回的命令回复 OK , 并将这个回复打印给用户观看。

而服务器从启动到能够处理客户端的命令请求需要执行以下步骤:

  • 初始化服务器状态;
  • 载入服务器配置;
  • 初始化服务器数据结构;
  • 还原数据库状态;
  • 执行事件循环;

serverCron 函数默认每隔 100 毫秒执行一次, 它的工作主要包括更新服务器状态信息, 处理服务器接收的 SIGTERM 信号, 管理客户端资源和数据库状态, 检查并执行持久化操作, 等等。

Redis学习三:设计与实现之单机数据库的实现相关推荐

  1. java计算机毕业设计BS架构考研交流学习平台设计与实现源码+数据库+系统+lw文档

    java计算机毕业设计BS架构考研交流学习平台设计与实现源码+数据库+系统+lw文档 java计算机毕业设计BS架构考研交流学习平台设计与实现源码+数据库+系统+lw文档 本源码技术栈: 项目架构:B ...

  2. c++ 多线程 类成员函数_为什么我说C/C++程序员都要阅读Redis源码之:通过Redis学习事件驱动设计

    0. 为什么我说C/C++程序员都要阅读Redis源码 主要原因就是『简洁』.如果你用源码编译过Redis,你会发现十分轻快,一步到位.其他语言的开发者可能不会了解这种痛,作为C/C++程序员,如果你 ...

  3. 《Redis学习三之面试》

    文章转载自:https://juejin.im/post/5ad6e4066fb9a028d82c4b66 就我个人而言,我觉得Redis的基本使用是我们每个Java程序员都应该会的.另外,如果需要面 ...

  4. 简述事件接口与事件适配器的联系与区别_通过Redis学习事件驱动设计

    01 为什么我说C程序员都要阅读Redis源码 主要原因就是『简洁』.如果你用源码编译过Redis,你会发现十分轻快,一步到位.其他语言的开发者可能不会了解这种痛,作为C/C++程序员,如果你源码编译 ...

  5. 为什么C/C++程序员都要阅读Redis源码之:Redis学习事件驱动设计

    0. 为什么我说C/C++程序员都要阅读Redis源码 主要原因就是『简洁』.如果你用源码编译过Redis,你会发现十分轻快,一步到位.其他语言的开发者可能不会了解这种痛,作为C/C++程序员,如果你 ...

  6. redis学习(三) 使用redis构建文章投票,发布后端

    1.需求 1.首先设计数据库 2.代码 Redis.php <?php//评分是将文章的到的支持票数乘以一个常量,然后加上文章的发布时间,得出的结果就是文章的评分 const ONE_WEEKS ...

  7. redis学习--三种特殊数据类型,GEO地理位置,HyperLogLog,BitMap

    三种特殊数据类型,GEO地理位置,HyperLogLog,BitMap GEO地理位置 简介 Redis 的 GEO 特性在 Redis 3.2 版本中推出, 这个功能可以将用户给定的地理位置信息储存 ...

  8. centos7安装mysql5.7.16_Linux学习三Centos7安装mysql5.7.16数据库的详细教程

    这篇文章主要为大家详细介绍了Linux学习第三篇,Centos7安装mysql5.7.16数据库,具有一定的参考价值,感兴趣的小伙伴们可以参考一下 如果您有服务器咨询问题.购买问题.可以联系我们客服 ...

  9. Redis学习总结(13)——分布式之数据库和缓存双写一致性方案解析!

    一.为什么写这篇文章? 首先,缓存由于其高并发和高性能的特性,已经在项目中被广泛使用.在读取缓存方面,大家没啥疑问,都是按照下图的流程来进行业务操作: 但是在更新缓存方面,对于更新完数据库,是更新缓存 ...

  10. Redis学习笔记(八)redis之lua脚本学习

    redis系列文章目录 使用spring-data-redis实现incr自增 Redis 利用Hash存储节约内存 Redis学习笔记(九)redis实现时时直播列表缓存,支持分页[热点数据存储] ...

最新文章

  1. SQL SERVER中ROLLUP的用法
  2. thinkphp模型中的获取器和修改器(根据字段名自动调用模型中的方法)
  3. golang struct 切片数组去重
  4. bim推荐计算机配置,BIM建模推荐电脑配置清单 适合Revit软件的BIM建模电脑主机配置(2)...
  5. 看美女有助于男士长寿
  6. js取消气泡事件、阻止浏览器的默认行为
  7. 数据结构之栈的应用:表达式求值
  8. Java内存与垃圾回收调优
  9. UI基础--烟花动画
  10. 2017软件构造3.3
  11. JRebel过期激活
  12. iSlide(PPT增强插件)官方正式版V5.6.1 | islide插件下载ppt插件在哪里下载?
  13. cad连接不同线段的端点_CAD中怎么把几个线断连接成一个整体
  14. 【TensorFlow】【数字货币】【单词记忆】【微信运营】【DIY电脑】 | Chat · 预告
  15. 淘宝搜索上传图片获得上传sid
  16. java rrd 读取_rrd4j的使用详解1–数据保存入rrd文件 | 学步园
  17. Windows7 VS2015 下编译 PythonQt3.2
  18. 穷与焦虑。文/江湖一剑客
  19. 【CF85D】 Sum of Medians
  20. 第六章 Wi-Fi扫描流程

热门文章

  1. 国二c语言和南开100题,全国计算机二级C语言题库_南开100题.doc
  2. 实验二 预测分析算法的设计与实现
  3. Matlab三位曲线之plot3函数
  4. [渝粤教育] 中山大学 地理信息系统概论 参考 资料
  5. matlab单边指数信号傅里叶变换,第三章3典型信号傅里叶变换性质1讲解.ppt
  6. .NET程序员我是如何通过一个产品在2年内买车买房
  7. IP城域网遇到的总结
  8. 计算机控制系统——导论
  9. Android与iPhone的对比(水木上看到的,不清楚原文来源)
  10. Java新手小白入门篇 Java面向对象(一)