一, Redis 数据库
我们都知道 Redis 是基于内存的数据库, 数据是以 key-value 键值对的方式存储的, 那么 key-value 键值对是随意放在内存中的么, 其实 Redis 的服务会创建很多的数据库空间, 这些 key-value 键值对都是在各个数据库空间中存储的.
当我们使用客户端工具链接 Redis 服务时, 会在客户端中看到一系列的 db * 命名的项 (如图), 这些就是一个个数据库, Redis 初始化创建 16 个数据库, 数据库创建个数可以在配置文件中修改.
而在命令行模式中是看不到这些数据库的具体数量的, 但在命令行提示符的右侧会提示我们当前处于哪个数据库 (如图), 并且可以用上一章说到的 SELECT 命令进行数据库的切换; 客户端默认连接第一个数据库, 即 0 号数据库.
(1) 数据库键空间
key-value 键值对存储在各个数据库中, 而每个数据库内部都是由一个 redisDb 结构, 结构中有若干个属性, 最主要的有两个属性 dict,expires.
- typedef struct redisDb {
- // ...
- // 数据库键空间, 保存着数据库中的所有键值对
- dict *dict;
- // 过期字典, 保存着键的过期时间
- dict *expires;
- // ...
- } redisDb;
dict 是字典结构, 存储我们的 key-value 键值对, 这个字典称为数据库键空间, 字典的键就是数据库的键, 每个键都是一个字符串, 存储 key 值; 字典的值就是数据库的值, 每个值都可以是五大对象中任意一种, 存储 value 值; 所以我们存储的 key-value 最终是在数据库中以字典的结构存储的.
expires 同样是字典结构, 但其存储的是 key-value 过期时间; 当我们设置了 key-value 的过期时间, 那么 key-value 存储在 dict 字典中, 而过期时间则存储在 expires 中; 字典的键存储 key, 字典的值存储过期时间; 这里需要注意的是, 无论设置的过期时间是秒还是毫秒, 最终存储时都会转换为 unix 毫秒时间戳.
图中是带有过期字典的数据库例子
(2) 持久化
上面说道的无论是数据库还是期内的数据都是存储在服务器内内存中的, 如果服务器一旦发生掉电, 进程退出等情况, 那么其内存中的数据就都消失不见了, 在我们大规模并发的项目下, 显然这是灾难性的, 所以应对这种情况的办法之一, 就是持久化, 把内存中的数放到磁盘中, 意外发生后, 能够从磁盘上进行数据恢复到内存中, 这样就避免了数据丢失.
Redis 提供了两种持久化方式 RDB 持久化和 AOF 持久化.
2,RDB 持久化
RDB 持久化是最直接的持久化方式, 直接将内存中的数据保存到 RDB 文件中, 当恢复时也是直接从 RDB 文件中恢复;
RDB 文件是经过压缩的二进制文件, 这里对文件结构不做详解.
RDB 持久化可以手动执行, 也可以设置定期执行.
RDB 持久化命令有两个 SAVE(同步) 和 BGSAVE(异步), 同步持久化过程中, 会拒绝客户端的所有请求; 异步则是创建子进程执行, 不会对客户端产生影响, 具体可以看上一章的命令介绍.
自动间隔性保存
因为 BGSAVE 命令是异步执行, 不会阻塞服务器, 所以 Redis 允许用户自行配置 SAVE 选项, 当选项触发时自动执行 BGSAVE 命令.
当用户开启了触发自动 BGSAVE 后, 如果不配置 save 选项, 服务器会使用默认设置, 如下:
(1) 在 900 秒内, 对数据库进行了至少 1 次修改.
(2) 在 300 秒内, 对数据库进行了至少 10 次修改.
(3) 在 60 秒内, 对数据库进行了至少 10000 次修改.
以上三个条件, 满足任意一条, 就会进行 BGSAVE 操作
3,AOF 持久化
AOF 持久化与 RDB 不同, AOF 持久化是通过记录服务器所执行的命令来保存数据的.
被写入 AOF 文件的所有命令都是以 Redis 请求协议格式保存的.
数据的还原, 就是通过读取 AOF 文件的这些命令进行的.
执行的命名并不是直接写入 AOF 文件的, 而是先写入缓冲区, 没执行一条命令就会追加到缓冲区的末尾, 当一条命令执行完成后, 返回数据前, 会将缓冲区的数据写入到 AOF 文件中.
AOF 文件的载入与还原
AOF 持久化的数据还原过程就是读取 AOF 中命令重新执行命令的过程.
(1)Redis 会创建一个伪客户端, 伪客户端与真实的客户端执行命令的效果是一样的, 只是不带网络连接.
(2) 从 AOF 文件分析并读取一条命令.
(3) 伪客户端执行这条命令.
(4) 重复 2 和 3 过程, 知道 AOF 文件中的所有命令处理完成.
AOF 文件重写
AOF 文件的持久化是记录被执行对的命令, 这样随着时间越来越长, AOF 文件中的内容会越来越多, 体积也会越来越大, 文件越大恢复数据的时间也越多.
在命令执行的过程中有些键值对被删除了, 有些被修改了, 而这些过程命令是完全没有必要再执行一遍的, 所以 Redis 提供了 AOF 文件的重写功能对 AOF 进行重建, 使用重建后的文件要比元 AOF 文件体积小很多.
AOF 文件重写, 并不需要对原 AOF 文件进行任何访问改动, 他是通过对数据库内的数据读取来操作的, 即查看数据库内有什么数据, 然后根据数据类型进行创建这些数据的写入命令.
AOF 文件重写过程中, 创建写入命令时会先检查元素数量, 如果数量超过了 Redis.h/REDIS_AOF_REWRITE_ITEMS_PER_CMD=64 常量的值, 就会分成多条命令,
AOF 文件重写是有子进程进行的, 并不影响主进程处理命令; 子进程而不是线程, 因为进程带有数据副本, 不锁数据的情况下, 能保证安全.
AOF 文件子进程重写过程中, 主进程仍然在处理数据, 这样造成了子进程和主进程的数据不一致, 子进程数据少了一部分, 这种情况下 Redis 会创建一个 AOF 重写缓冲区; 这样少的那部分命令会写到 AOF 重写缓冲区中, 重写完成后, 再把缓冲区这些命令写进新的 AOF 文件中, 然后用新的 AOF 文件替换就得 AOF 文件.
4, 总结
Redis 初始化会创建一批数据库, 每个数据库的内部数据结构都是字典, key-value 的最终存储也会落到字典上.
AOF 持久化比 RDB 持久化频率更高, 速度更快; 当有 AOF 持久化时, RDB 持久化命令不会再执行; 但当 RDB 持久化命令执行时, AOF 命令会等待其执行完成后再执行, 而其他 RDB 命令不会执行.
AOF 文件重写过程不会影响旧的 AOF 文件, 即便 AOF 重写过程失败, 也不会干扰原来的 AOF 恢复数据, 只有在成功之后才会替换原来的文件.
参考:
《Redis 设计与实现》黄健宏著, 网上对 Redis 的详解等
此博客为笔者使用 Redis 很久之后, 参考网络上各类文章总结性书写, 原创手打, 如有错误欢迎指正.
来源: https://www.cnblogs.com/MouseDong/p/11134066.html