Redis的数据持久化功能详解(2)—— RDB持久化实践

RDB持久化是通过快照完成的,当符合一定条件时Redis会自动将内存中的所有数据进行快照并存储到磁盘上。默认存储在Redis安装目录的data子目录的dump.rdb文件中。

一、环境描述

  1. 主机配置
    CPU:单核
    内存:2 GB
    IP:10.24.16.87

  2. 操作系统
    CentOS 6.6 x86_64 Minimal

  3. Redis版本
    Redis server v=3.2.4 sha=00000000:0 malloc=jemalloc-4.0.3 bits=64 build=431d8e4a684c794b

  4. Redis安装方式
    按照《在CentOS上安装Redis缓存系统

二、相关命令

1. SAVE命令

SAVE命令会将Redis内存中的数据集同步保存至磁盘上,产生一个包含所有数据的时间点快照,以RDB文件的形式存储。

你几乎不会在生产环境中调用SAVE命令,因为这个命令会阻塞所有其他的客户端。相反,你通常可以使用BGSAVE命令。然而,如果要防止Redis创建在后台保存数据的子进程(例如,调用fork(2)系统调用时发生错误),那么SAVE命令可能是用于持久化最近数据集的比较好的最后手段了。

若想了解更详细的信息,请参考《Redis的数据持久化功能详解(1)—— 两种持久化方式》。

SAVE命令会返回一个简单的字符串,如果执行成功,则返回OK

2. BGSAVE命令

这个命令可以在后台保存数据库,运行之后会立即返回OK代码。Redis会创建子进程,父进程会持续为客户端提供服务,而子进程则会将数据库保存在磁盘上,然后退出。如果想要检查子进程的操作是否成功,那么你可以在客户端中运行LASTSAVE命令。

若想了解更详细的信息,请参考《Redis的数据持久化功能详解(1)—— 两种持久化方式》。

BGSAVE命令总是会立即返回OK代码。

3. LASTSAVE命令

LASTSAVE命令会返回最后一次成功执行RDB持久化的时间,以UNIX TIME的格式返回结果。你可以在客户端中运行LASTSAVE命令,检查前一次运行的BGSAVE命令是否运行成功。然后,再次运行BGSAVE命令,你可以每隔一段时间(例如,每隔N秒)检查一次LASTSAVE命令的运行结果是否改变。

LASTSAVE命令的返回值是一个整数,表示UNIX格式的时间戳。

三、相关配置选项

在本文使用的Redis服务器中,所有配置项都存放在/usr/local/Redis/etc/redis.conf配置文件中。RDB持久化涉及的配置项包括保存点、数据压缩、数据校验等等。

1. 保存点

这个配置项会将Redis内存中的数据保存至磁盘,格式如下所示:

  1. save <秒数> <修改次数>

如果时间达到给定的秒数,并且对数据库的写操作也达到给定的次数,那么Redis便会将数据保存至磁盘。

在Redis的默认配置中,RDB持久化的行为如下所示:

  • 当时间达到900秒(15分钟),并且对数据库的写操作至少达到1次时,Redis便会持久化数据。
  • 当时间达到300秒(5分钟),并且对数据库的写操作至少达到10次时,Redis便会持久化数据。
  • 当时间达到60秒(1分钟),并且对数据库的写操作至少达到10000次时,Redis便会持久化数据。

注意:如果你想要完全禁用保存点,那么你可以注释所有的“save”配置行。

如果你想要移除所有先前配置的保存点,那么你可以添加一个用空字符串作为参数的save指令,如下所示:

  1. save ""

保存点的默认配置如下所示:

  1. save 900 1
  2. save 300 10
  3. save 60 10000

2. 出错停止写入

在默认情况下,如果启用RDB快照功能(至少有一个保存点),并且最近一次后台持久化数据失败,那么Redis将会停止接受所有的写入操作请求。

这将会使用户注意到,Redis并没有将数据正确地持久化至磁盘上。否则,用户不会注意到已经发生的错误,这样便不能预防某些灾害的发生。

如果后台保存数据的进程再次开始工作,那么Redis将会自动地再次允许执行写入操作。

然而,如果你已经为Redis服务器和持久化建立了完善的监控机制,那么你可能想要禁用这个特性,即使Redis服务器的磁盘、权限或其他部分发生问题,Redis也能够像平时一样持续提供服务。

出错停止写入的默认配置如下所示:

  1. stop-writes-on-bgsave-error yes

3. 数据压缩

当Redis将数据保存为.rdb文件时,可以使用LZF算法压缩字符串类型的对象。

这个配置项的默认值为yes,因为这项功能总是能带来好处的。

如果你想要在保存数据的子进程运行时节省一些CPU性能开销,那么你可以将这个配置项设置为no。但是,如果你的数据中有很多可压缩的值或键,那么保存的数据文件可能会比较大。

数据压缩的默认配置如下所示:

  1. rdbcompression yes

4. 数据校验

从Redis 2.5版本至今,Redis会在持久化文件的末尾添加一个CRC64校验和。

这使得RDB持久化能够最大程度的避免文件损坏。但是,当保存和加载RDB文件时,也会额外消耗一些性能(大约10%左右)。如果想要获得最大化的性能,那么你可以禁用这项功能。

在不使用校验和功能的RDB文件中,Redis会将校验和设为0,这就告诉加载代码跳过数据校验过程。

数据校验的默认配置如下所示:

  1. rdbchecksum yes

5. 转储文件名

这项配置用于指定RDB文件的名称。

转储文件名的默认配置如下所示:

  1. dbfilename dump.rdb

6. 转储文件目录

这项配置用于指定RDB文件的存放目录。

Redis将会在这个目录中将内存数据保存为RDB文件,使用的文件名由dbfilename配置项指定。

Redis也会在这个目录中创建只增文件(AOF)。

注意,你必须为这项配置指定一个目录路径,而不是一个文件名。

转储文件目录的默认配置如下所示:

  1. dir /usr/local/Redis/data

四、RDB持久化实践

下面将通过实际操作演示RDB持久化的使用方法,本文不会修改redis.conf配置文件,而是使用redis-cli config set命令,临时修改Redis的配置,重新启动主机或服务之后,Redis的配置就会还原。

1. 设置RDB文件名和目录

在Redis服务器的Shell中运行以下命令:

  1. redis-cli config set dir /root/Downloads
  2. redis-cli config set dbfilename redisdb.rdb

Redis会将持久化生成的RDB文件保存在/root/Downloads目录中,文件名为redisdb.rdb

2. 导入测试数据集

运行以下Java代码,生成测试数据集文件:

  1. import java.io.File;
  2. import java.io.FileWriter;
  3. import java.io.IOException;
  4. import java.io.PrintWriter;
  5. import java.util.UUID;
  6. import org.apache.commons.lang.StringUtils;
  7. public class RedisDataGenerator {
  8. public static void main(String[] args) {
  9. // 设置KEY条数
  10. long count = 10000;
  11. int len = 4;
  12. if (args.length > 0 && StringUtils.isNumeric(args[0])) {
  13. count = Long.parseLong(args[0]);
  14. len = args[0].length();
  15. }
  16. // 生成数据导入脚本
  17. FileWriter fw = null;
  18. try {
  19. File f = new File("E:\\RedisData.txt");
  20. fw = new FileWriter(f, true);
  21. PrintWriter pw = new PrintWriter(fw);
  22. for (long i = 0; i < count; i++) {
  23. String key = "key_" + String.format("A" + "%0" + len + "d", i).substring(1);
  24. String value = UUID.randomUUID().toString();
  25. String command = "SET" + " " + key + " " + value;
  26. pw.println(command);
  27. }
  28. pw.flush();
  29. fw.flush();
  30. pw.close();
  31. fw.close();
  32. } catch (IOException e) {
  33. e.printStackTrace();
  34. }
  35. }
  36. }

上述程序默认生成10000条数据,但本文运行这个程序时,会将运行参数指定为10000000条。

将生成的RedisData.txt数据文件上传至Redis服务器的/root/Downloads目录。然后,登录Redis服务器,在Shell中运行以下命令:

  1. cd /root/Downloads/
  2. cat RedisData.txt | redis-cli --pipe

上述命令会利用Redis的管道机制导入测试数据,运行成功之后,返回信息如下图所示:

导入测试数据

在Shell中运行以下命令,查看测试数据占用的内存大小:

  1. redis-cli info memory

上述命令的运行结果如下图所示:

查看测试数据占用的内存大小

从上图中可以看出,测试数据占用了1.02GB的内存空间。

3. 手动执行RDB相关命令

在Redis服务器的Shell中运行以下命令,保存内存中的所有数据:

  1. redis-cli bgsave

Redis会启动一个后台进程持久化内存中的所有数据,可以不断运行以下命令,查看持久化进程是否结束:

  1. redis-cli lastsave

当上述命令的返回值发生变化时,表示数据持久化已经完成,查看是否已经生成RDB文件,如下图所示:

持久化所有数据

由上图可知,持久化生成的RDB文件就是/root/Downloads/redisdb.rdb文件,文件大小为487MB。

4. 配置保存点

在Redis服务器的Shell中运行以下命令,清除默认的保存点,然后设置新的保存点:

  1. redis-cli config set save ""
  2. redis-cli config set save "30 1000"

新保存点会在时间经过30秒,并且写入操作至少有1000次时,执行RDB持久化操作。

5. 配置数据压缩

在Redis服务器的Shell中运行以下命令,启用数据压缩功能:

  1. redis-cli config set rdbcompression yes

如果启用数据压缩功能,那么每次执行持久化的时间就会延长,因为会耗费更多的CPU性能。

6. 配置数据校验

数据校验必须修改redis.conf配置文件,然后重新启动Redis服务才能生效。在Redis服务器的Shell中运行以下命令,查看是否启用数据校验功能:

  1. redis-cli config get rdbchecksum

如果启用数据校验功能,那么每次执行持久化的时间就会延长,因为会耗费更多的CPU性能。

7. 重建缓存

在Redis服务器的Shell中运行以下命令,将RDB文件拷贝至默认目录,然后清除Redis中的所有数据:

  1. cp /root/Downloads/redisdb.rdb /usr/local/Redis/data/dump.rdb
  2. redis-cli flushall

查看Redis中的数据是否被清除,如下图所示:

检查数据是否被清除

运行以下命令,重新启动Redis服务:

  1. service redis_6379 restart

重启服务之后,Redis存放RDB文件的目录会恢复为默认值/usr/local/Redis/data/,RDB文件名会恢复为默认值dump.rdb。从RDB文件恢复数据时,可以通过redis-cli运行ping命令,若返回错误信息,则表示数据恢复尚未完成,如下图所示:

数据恢复尚未完成

若返回PONG,则表示数据恢复已经完成,如下图所示:

数据恢复已经完成

数据恢复完成之后,检查恢复后的数据是否完整,如下图所示:

检查数据完整性