前言

本文基于 黄建宏-《Redis设计与实现》总结。第二部分为Redis 数据库,RDB持久化,AOF持久化,事件,客户端,服务器

目录

  • 前言
  • 数据库
    • 服务器中的数据库
      • 服务器数据库示例
    • 切换数据库
    • 数据库键空间
      • 数据库键空间示例
      • 读写键空间时的维护操作
    • 设置键的生存时间/过期时间
      • 过期时间
    • 过期键删除策略
      • 定时删除
        • 优点
        • 缺点
      • 惰性删除
        • 优点
        • 缺点
        • 实现
      • 定期删除
        • 实现
          • activeExpireCycle工作模式
    • AOF,RDB和复制功能对过期键的处理
      • RDB
        • 生成RDB文件
        • 载入RDB文件
      • AOF
        • AOF文件写入
        • AOF重写
      • 复制
    • 数据库通知
      • 键空间通知
      • 键事件通知
      • 通知类型
  • RDB持久化
    • RDB文件的创建与载入
      • 创建
        • 服务器状态
          • 执行SAVE命令
          • 执行BGSAVE命令
      • 载入
    • 自动间隔保存
    • RDB文件结构
      • RDB完整结构
      • database完整结构
      • key_value_pairs完整结构
        • 不带过期时间的键值对
        • 带过期时间的键值对

数据库

服务器中的数据库

Redis服务器将所有数据库都保存在服务器状态redis.h/redisServer结构的db数组中,db数组的每个项都是一个redis.h/redisDb结构,每个redisDb结构代表一个数据库。
在初始化服务器时,会根据redisServer的dbnum属性来创建多少个数据库,默认值为16

服务器数据库示例

切换数据库

 默认情况下,Redis客户端的目标数据库为0号数据库,可以通过select命令来切换目标数据库,如 SELECT 1 OR SELECT 2### 客户端状态与服务器状态之间的关系


在不同语言的客户端中,没有都一直显示目标数据库的号码,为了避免对数据库进行误操作,在执行Redis命令之前,先执行SELECT命令,切换到指定数据库再执行别的命令。

数据库键空间

Redis服务器中每个数据库redis.h/redisDb结构的dict字典保存了该数据库的所有键值对,这个字典称为键空间

数据库键空间示例

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命令可以查看键的闲置时间
  • 如果服务器读取键时发现该键已经过期,那么会先删除这个过期键,再执行余下操作
  • 如果客户端使用WATCH命令监视了某个键,那么服务器再对该键进行修改后,会将其标记为dirty,从而让事务程序注意到该键已经被修改过
  • 服务器每次修改一个键,都会对dirty键计数器的值加一,这个计数器会触发服务器的持久化以及复制操作
  • 如果服务器开启了数据库通知功能,对键修改后,服务器会按配置发送响应的数据库通知

设置键的生存时间/过期时间

通过EXPIRE(设置秒)或PEXPIRE(设置毫秒)可以给键设置生存时间TTL,过后服务器会自动删除生存时间为0的键

EXPIRE key 5

通过EXPIREAT或PEXPIREAT可以给键设置过期时间,过期时间时一个UNIX时间戳,过后服务器会自动删除这个键

EXPIREAT key 1377257300

TTL或PTTL命令可以接收一个带有生存时间/过期时间的键,返回这个键的剩余生存时间

redis>TTL key
(integer) 997

PERSIST可以移除一个键的过期时间

redis>PERSIST message
(integer)-1

过期时间

redisDb结构的expires字典保存了所有键的过期时间,也称为过期字典


在实际中,键空间的键和过期字典的键都指向同一个键对象,上图只是为了展示方便

过期键删除策略

之前提到服务器会自动删除生存时间为0的键以及过期的键,那么这个自动是怎么自动的呢?
有三种删除策略
- 定时删除
- 定期删除
- 惰性删除

定时删除

在设置键的过期时间的同时,创建一个Timer,让Timer在键的过期时间到了,对键立即执行删除操作。

优点

  • 对内存最友好:能及时释放过期键所占的内存

缺点

  • 对CPU时间最不友好:过期键比较多时,删除过期键这一行为可能会占用相当一部分CPU时间,影响服务器的响应时间和吞吐量
  • 创建Timer需要用到Redis服务器的时间事件,时间事件的实现方式是无序链表,查找一个事件的时间复杂度为O(N),并不能高效处理大量时间事件

惰性删除

放任键过期不管,每次从键空间获取键时,都检查键是否过期,过期则删除该键

优点

  • 对CPU时间最友好:保证删除过期键的操作只在非做不可的情况下进行

缺点

  • 对内存最不友好:只要不再次获取这个过期键,所占用的内存就不会被释放

实现

所有读写数据库的Redis命令在执行之前都会调用expireIfNeeded函数对输入键检查

定期删除

每隔一段时间,程序对数据库进行一次检查,删除过期键。删除多少过期键以及检查多少隔数据库由算法决定
定期删除策略是对前两种策略的折中”

  • 每隔一段时间删除一次过期键,并通过限制删除操作的执行时长和频率来减少对CPU时间的影响

  • 定期删除过期键,有效减少了因为过期键带来的内存浪费
    其难点在于确定删除操作的执行时长和频率:

  • 删除操作太频繁或执行时间太长,会退化为定时删除策略

  • 删除操作执行太少或执行时间太短,会和惰性删除策略一样,浪费内存

实现

每当Redis服务器周期性操作serverCron函数执行时,调用activeExpireCycle函数在规定时间内,分多次遍历服务器的各个数据库,从数据库的expire字典中随机检查一部分键的过期时间,并删除其中的过期键

  • 默认每次检查的数据库数量:16
  • 默认的每个数据库检查的键数量:20
activeExpireCycle工作模式
  • 函数每次运行都从一定数量的数据库中取一定数量的随机键检查,并删除其中的过期键
  • 全局变量current_db会记录检查进度,并在下次调用activeExpireCycle时,接着上次的进度处理
  • 随着该函数不断执行,服务器中所有数据库都会被检查一遍,current_db重置为0,开始新一轮的检查

AOF,RDB和复制功能对过期键的处理

RDB

生成RDB文件

在执行SAVE或者BGSAVE命令创建一个新的RDB文件时,程序会对数据库中的键检查,过期的键不会被保存到新创建的RDB文件中

载入RDB文件

  • 主服务器模式运行:过期键不会被载入到数据库中
  • 从服务器模式运行:过期键会被载入到数据库中,主从服务器在数据同步时,从服务器的数据库会被清空,所以过期键对载入RDB文件的从服务器也不会有影响

AOF

AOF文件写入

当服务器以AOF持久化模式运行时,如果键已经过期,但是还没被惰性删除或定期删除,那么AOF文件不会因为过期键产生影响
当过期键被惰性删除或定期删除后,程序会向AOF文件append一条DEL命令,来显示记录该键已被删除

AOF重写

在执行AOF重写的过程中,程序会对数据库中的键进行检查,已过期的键不会被保存到重写后的AOF文件中

复制

当服务器运行在复制模式下时,从服务器的过期键删除动作,通过由主服务器来控制从服务器统一删除过期键,可以保证主从服务器数据的一致性

  • 主服务器在删除一个过期键后,会向所有从服务器发送一个DEL命令,告知从服务器删除这个过期键
  • 从服务器在执行客户端放的读命令时,碰到过期键也不会删除,而是像处理未过期键一样来处理过期键

数据库通知

数据库通知是Redis 2.8 新增的功能,可以让客户端通过订阅给定的频道或模式,来获取数据库中键的变化,以及数据库中命令的执行情况

键空间通知

关注“某个键执行了什么命令”

键事件通知

关注“某个命令被什么键执行了”

通知类型

服务器配置的notify-keyspace-events选项决定了服务器所发送通知的类型

  • AKE:发送所有类型的键空间通知和键事件通知
  • AK:发送所有类型的键空间通知
  • AE:发送所有类型的键事件通知
  • K$:发送字符串键有关的键空间通知
  • EI:发送列表键相关的键事件通知

RDB持久化

Redis是一个键值对数据库服务器,我们将服务器中的非空数据库以及它们的键值对统称为数据库状态
因为Redis是内存数据库,为了解决服务器进程退出,服务器中的数据库状态消失不见的问题,Redis提供了RDB持久化功能,可以将Redis在内存中的数据库状态保存到磁盘中,避免数据丢失。RDB持久化可以手动执行,也可以根据服务器配置选项定期执行,该功能可以将某个时间点的数据库状态保存到一个RDB文件中。

RDB文件的创建与载入

创建

有两个Redis命令可以用于生成RDB文件,一个是SAVE,一个是BGSAVE。创建RDB文件是由rdbSave函数完成的

  • SAVE命令:会阻塞Redis服务器进程,直到RDB文件创建完,在服务器进程阻塞期间,服务器不能处理任何命令请求
  • BGSAVE命令:会派生出一个子进程,然后由子进程负责创建RDB文件,服务器进程继续处理命令请求

服务器状态

执行SAVE命令

当SAVE命令正在执行时,客户端发送的所有请求都会被拒绝

执行BGSAVE命令

当BGSAVE命令正在执行时,Redis服务器仍然可以继续处理客户端的请求,但是客户端发送的

  • SAVE命令会被服务器拒绝,避免服务器进程和子进程同时执行两个rdbSave调用
  • BGSAVE命令也会被服务器拒绝,避免同时执行两个BGSAVE命令
  • BGREWRITEAOF命令会在BGSAVE执行完再执行。如果正在执行BGREWRITEAOF,客户端发送的BGSAVE会被服务器拒绝

载入

RDB文件的载入工作是在服务器启动时自动执行的,只要Redis服务器在启动时检测到RDB文件存在,它就会自动载入RDB文件。载入工作是由rdbLoad函数完成的
因为AOF文件的更新频率通常比RDB文件的更新频率高,所以

  • 服务器开启AOF持久化功能:服务器会优先使用AOF文件来还原数据库状态
  • 服务器关闭AOF持久化功能:服务器会使用RDB文件来还原数据库状态

自动间隔保存

因为BGSAVE命令可以在不阻塞服务器进程的情况下执行,所以Redis允许用户通过设置服务器配置的save选项,让服务器每隔一段时间自动执行一次BGSAVE命令。 可以设置多个保存条件,但是只要其中一个条件满足,服务器就会执行BGSAVE命令。

Redis服务器周期性操作函数serverCron默认每隔100毫秒执行一次,它的其中一项工作就是检查save选项所设置的保存条件是否满足,如果满足,就执行BGSAVE。

def serverCron():# ...#遍历所有保存条件for saveparam in server.saveparams:#计算距离上次执行保存操作有多少秒save_interval = unixtime_now() - server.lastsave# 如果数据库状态的修改次数超过条件所设置的次数# 并且距离上次保存的时间超过条件所设置的时间# 那么执行保存操作if server.dirty >= saveparam.changes and save_interval > saveparam.seconds:BGSAVE()# ...

RDB文件结构

RDB完整结构

  • REDIS 这部分长度为5字节,保存着"REDIS"五个字符,程序在载入文件时,通过这五个字符来检查是否是RDB文件
  • db_version 长度为4字节,记录了RDB文件的版本号,如"0006"
  • databases 部分包含零哥或任意多个数据库,以及各个数据库中的键值对数据
  • EOF 常量的长度为1字节,标志着RDB文件正文内容结束
  • check_sum 长度为8字节,保存着一个根据前四个部分计算出的校验和,服务器在载入RDB文件时,会根据载入数据计算的校验和与该校验和进行对比,来检查RDB文件是否出错或损坏

database完整结构

  • SELECTDB 常量的长度为1字节,当读入程序遇到这个值,知道接下来要读入的是一个数据库号码
  • db_number 保存数据库号码,根据号码大小,可以是1字节,2字节或5字节,当程序读入这部分,会调用SELECT命令来切换数据库
  • key_value_pairs 保存了数据库所有键值对数据

key_value_pairs完整结构

不带过期时间的键值对

  • TYPE 记录了value的类型,长度为1字节,程序会根据TYPE的值来决定如何读入和解释value的数据
  • key 是一个字符串对象
  • value 根据TYPE类型不同以及保存内容长度不同,其结构和长度也不同

带过期时间的键值对

  • EXPIRETIME_MS 常量的长度为1字节,告诉读入程序,接下来要读入是一个以毫秒为单位的过期时间
  • ms 是一个8字节的带符号整数,记录UNIX时间戳,也就是键值对的过期时间

Redis (二) 数据库相关推荐

  1. Redis与数据库缓存一致性问题

    一.Redis 数据一致性问题产生的原因 对 Redis和数据库的操作有 2 种方案: 1.先操作(删除) Redis,再操作数据库 2.先操作数据库,再操作(删除) Redis 上述二种方案,都希望 ...

  2. 虹科干货|Redis企业版数据库为企业「数据安全」叠加最强Buff!

    虹科干货|Redis企业版数据库为企业「数据安全」叠加最强Buff! "这是一场可预见的噩梦!" 近期,黑客通过攻击亚洲最大两家数据中心-万国数据和新科电信媒体,获取国际巨头企业的 ...

  3. Redis缓存数据库

    目录 NoSQL NoSQL特点 常见的NoSQL数据库 redis MongoDB 行式存储数据库 列式存储数据库 redis简介 安装redis redis启动服务 前台启动 提取信息 后台启动 ...

  4. Redis二:redis-cli操作各种数据类型

    Redis二:redis-cli操作各种数据类型 1. redis-cli的登录与常用数据类型 2. 各种数据类型的操作 2.1 String(数值在这里也被视为字符串) 2.3 Hash(可以将一个 ...

  5. Redis二次小结(2020-11-29)

    一.Redis是单线程的(Maven仓库更新慢) 安装 Redis的安装不难,w10下就是下载下来,然后解压,在命令窗口cd到安装路径下,启动: redis-server.exe redis.wind ...

  6. Redis高性能数据库

    经常用redis做什么? 在公司中经常用redis来做数据库的缓存,用来缓存一些经常被客户端访问到的数据,从而减轻后端数据库的压力 常见的缓存数据库有哪些? Redis     Memcache    ...

  7. php redis 切换数据库,Laravel Redis数据库切换以及laravel缓存/Session使用不同的Redis数据库 - Laravel学习网...

    Redis Select命令用于切换到指定的数据库,数据库索引号index用数字值指定,以0作为起始索引值. 比如我们要使用db10数据库,只需要使用如下命令即可: redis 127.0.0.1:6 ...

  8. android数据库降级_Android SQLite (二.数据库创建,升级及降级)

    上篇文章简介和常用语法介绍了SQLite数据库的基本信息和一些常用的语法操作,本篇文章主要介绍Android开发过程中SQLite数据库的创建使用和常见问题处理. 一.SQLiteOpenHelper ...

  9. Redis 缓存数据库

    Redis 缓存数据库 第1章 Redis简介: redis是使用C语言编写的开源的,支持网络,基于内存,可持久性的键值对存储数据库,2013年5月之前,Redis是最流行的键值对存储数据库 Redi ...

最新文章

  1. 在线等!同事扔需求,不会写代码躲在厕所怎么办 | 每日趣闻
  2. WPF入门:数据绑定
  3. 2020年十大机器学习框架
  4. array_merge
  5. php生成网页,php – 网页生成(CMS喜欢)
  6. SAP CRM产品主数据里的七种ID
  7. 任务调度及远端管理(基于Quartz.net)
  8. 每个人对工作都会有自己的想法
  9. JavaRabbitmq笔记-Rabbitmq自定义头(Properties中的headers)
  10. Docker快速搭建JIRA缺陷管理平台
  11. php 利用csv导,php 导入/导出 csv 文件
  12. Linux软件万花筒
  13. JqGrid常用示例
  14. ie6下margin间距是两倍的解决办法
  15. MATLAB读取nc文件
  16. 抖音短视频数据抓取实战系列(九)——自动化Appium的环境与参数配置
  17. python:pygame小游戏(三)—— 打字游戏
  18. python爬歌词生成词云图_Python爬虫摇滚网易云音乐歌词生成词云图
  19. selenium实现高校班级打卡-石墨文档每日一报自动化
  20. 想不到验证码背后的故事这么有意思

热门文章

  1. 权限管理需要哪几张表
  2. 互联网思维(三)——产业思维
  3. 小猴吃桃matlab,幼儿园小班水墨画教案《小猴吃桃》
  4. Mysql5.7 windows 下压缩包方式安装以及环境配置
  5. 纸质的报销单错了就得重新来,可不可以填写电子报销单?
  6. vnc却显示 failed to connect:操作成功完成。(0)
  7. mysql 1677_MySQL之数据库主从复制配置报错Last_Errno: 1677
  8. 连目标管理都不会,还谈什么目标?
  9. 2017年年终总结 韩俊强的博客
  10. 港科夜闻|全国政协副主席梁振英一行到访香港科技大学(广州)