1 编写本文的初衷
因为目前实习工作需求,需要把服务器环境中所有Redis数据进行初步简单分析,即统计其中存储的每一个key所占内存的大小,以便作出清理不重要缓存数据的决策。
但是,由于从线上环境获得持久化文件为AOF文件,而不是RDB文件。RDB文件可以通过Rdbtools工具,来分析具体数据。但是AOF文件不能这样操作。
因此,就给我带来一个问题:如何通过AOF文件获取指定的RDB持久化文件呢?
于是,我通过查阅网上文章,获取的一个解决思路:单独在Redis中开启一个未使用过的端口服务,使用已得到的AOF文件替换该端口服务下自动生成的AOF文件;然后,重启该端口指定的Redis服务,即可把新的AOF文件中数据加载到Redis数据库中,最后在该端口服务客户端执行save或者bgsave命令,即可在指定路径下得到对应的RDB持久化文件。
2 具体实施
2.1 Redis持久化概念简介
Redis数据库进行持久化有两种方式:RDB持久化和AOF持久化。
那么,什么是RDB持久化呢?
RDB(Redis Database)持久化:可以将Redis在内存中的数据库状态保存到磁盘里面,避免数据意外丢失。RDB持久化既可以手动执行,也可以根据服务器配置选项定期执行,该功能可以将某个时间点上的数据库状态保存到一个RDB文件中。(PS:手动执行保存时,在客户端执行SAVE命令或者BGSAVE即可把当前所有数据保存到dump.rdb文件中,如果在线上执行,建议使用BGSAVE命令)
RDB文件具体功能:用于保存和还原Redis服务器所有数据库中的所有键值对数据。
那么,什么是AOF持久化呢?
AOF(Append Only File)持久化:与RDB持久化通过保存数据库中的键值对来记录数据库状态不同,AOF持久化是通过保存Redis服务器所执行的写命令来记录数据库状态的。AOF持久化功能的实现可以分为命令追加(append)、文件写入、文件同步(sync)三个步骤。
AOF文件具体功能:通过保存所有修改数据库的写命令请求来记录服务器的数据库状态。
2.2 获取指定Redis的AOF持久化文件
一般情况,都是获取限制环境的AOF文件,那么如何在线上环境找到AOF文件呢?(PS:因为时间原因,可能忘记存储在哪里,所以以下提供一个搜索命令,方便操作)
sudo find / -name '*.aof' # 此命令用于查找系统上所有以aof为后缀的文件
通过该命令,查看具体文件的路径信息,即可确认自己需要获取的AOF文件。
确定后,通过一下命令把指定AOF文件拷贝到本地主机上:
scp liuzhen@172.160.12.16:/home/liuzhen/prod_redis_data/redis/redis-appendonly.aof . # 从服务器复制远程文件到本地当前所在根目录
2.3 把Redis的持久化AOF文件转换为RDB文件
关于redis.conf文件中配置aof持久化操作信息简单介绍:
(1)找到redis.conf文件,设置其中的字段属性:
appendonly no ——> appendonly yes
此处也可以在redis客户端,使用指令来完成修改:
redis 127.0.0.1:6379> config set appendonly yes OK redis 127.0.0.1:6379> BGREWRITEAOF # 用于重写生成aof文件Background append only file rewriting started
此选项为aof功能的开关,默认为“no”,可以通过“yes”来开启aof功能
只有在“yes”下,aof重写/文件同步等特性才会生效
(2)在redis.conf文件中,指定aof文件的名称
appendfilename "appendonly.aof" # 这是文件中默认的配置名称,也可以自己修改指定的文件名称
(3)在redis.conf文件中,确认 aof操作中文件同步策略
配置默认结果:
# appendfsync alwaysappendfsync everysec# appendfsync no
即选用everysec,具体意思:
1. no:表示等操作系统进行数据缓存同步到磁盘.
2. always:表示每次更新操作后手动调用fsync() 将数据写到磁盘.
3. everysec:表示每秒同步一次.一般用everysec
(4)在redis.conf文件中,确认 aof-rewrite期间,appendfsync是否暂缓文件同步
配置默认结果:
no-appendfsync-on-rewrite no
具体意思:
"no"表示“不暂缓”,“yes”表示“暂缓”,默认为“no”
(5)在redis.conf文件中,确认 aof文件rewrite触发的最小文件尺寸(mb,gb),以及 相对于“上一次”rewrite,本次rewrite触发时aof文件应该增长的百分比
配置默认结果:
auto-aof-rewrite-percentage 100auto-aof-rewrite-min-size 64mb
具体实施步骤:
(1) 创建一个新的redis.conf文件,该文件命名可采用redis_port.conf形式,例如:redis_6391.conf。该文件中内容起初完全何Redis默认的redis.conf文件中内容一致
(2) 修改redis_6391.conf指定的port值,在文件中搜索port把默认的6379修改为6391
(3) 修改redis_6391指定的dir值,在文件中搜索dir把默认的".\"改为自己要存放文件的具体路径。该路径用于存放RDB文件和AOF文件
(4) 修改redis_6391指定的appendfilename值,在文件中搜索appendfilename把默认的"appendonly.aof"改为自己想要定义的文件名称,该文件即为AOF文件的最终名称
(5) 修改redis_6391指定的dbfilename值,在文件中搜索dbfilename把默认的"dump.rdb"改为自己想要定义的文件名称,该文件即为RDB文件的最终名称
(6) 此步骤最重要,修改redis_6391指定的appendonly值,在文件中搜索appendonly把默认的"no"改为"yes"。这句配置意思是Redis服务重启后,默认不加载AOF持久化文件恢复数据,而是去找RDB持久化文件恢复;如果修改为"yes"后,发现有AOF文件,会首先加载AOF文件恢复数据
以下给出我本机修改后的redis_6391.conf文件中具体配置代码:
redis_6391.conf源码
(7) 重启指定端口的服务,例如此处在Redis按照src目录下,运行./redis-server redis_6391.conf即可启动服务,待服务完成启动成功后,即可把指定的AOF文件数据加载进去(PS:此步骤需要先确认指定目录下的AOF文件已被替换成目标AOF文件,期间可以多次重启实现具体AOF文件加载)
以下给出我本机使用Redis加载启动大小为1.7G的aof文件,由于文件比较大,所以加载的时间有点长,此处是加载了60秒。
liuzhen@liuzhen-ubuntu:~/redis-2.8.17/src$ ./redis-server redis_6391.conf [68180] 19 Jul 15:02:07.997 * Increased maximum number of open files to 10032 (it was originally set to 1024). _._ _.-``__ ''-._ _.-`` `. `_. ''-._ Redis 2.8.17 (00000000/0) 64 bit .-`` .-```. ```\/ _.,_ ''-._ ( ' , .-` | `, ) Running in stand alone mode |`-._`-...-` __...-.``-._|'` _.-'| Port: 6391 | `-._ `._ / _.-' | PID: 68180 `-._ `-._ `-./ _.-' _.-' |`-._`-._ `-.__.-' _.-'_.-'| | `-._`-._ _.-'_.-' | http://redis.io `-._ `-._`-.__.-'_.-' _.-' |`-._`-._ `-.__.-' _.-'_.-'| | `-._`-._ _.-'_.-' | `-._ `-._`-.__.-'_.-' _.-' `-._ `-.__.-' _.-' `-._ _.-' `-.__.-' [68180] 19 Jul 15:02:08.011 # Server started, Redis version 2.8.17[68180] 19 Jul 15:05:12.843 * DB loaded from append only file: 184.831 seconds [68180] 19 Jul 15:05:12.843 * The server is now ready to accept connections on port 6391[68180] 19 Jul 15:05:13.008 * 10000 changes in 60 seconds. Saving... [68180] 19 Jul 15:05:13.084 * Background saving started by pid 68228[68228] 19 Jul 15:05:47.548 * DB saved on disk [68228] 19 Jul 15:05:47.613 * RDB: 23 MB of memory used by copy-on-write [68180] 19 Jul 15:05:47.717 * Background saving terminated with success [68180] 19 Jul 15:07:54.064 * DB saved on disk [68180] 19 Jul 15:08:58.096 * Asynchronous AOF fsync is taking too long (disk is busy?). Writing the AOF buffer without waiting for fsync to complete, this may slow down Redis. [68180] 19 Jul 16:49:14.515 * Background saving started by pid 90980[90980] 19 Jul 16:56:56.883 * DB saved on disk [90980] 19 Jul 16:56:56.966 * RDB: 4 MB of memory used by copy-on-write [68180] 19 Jul 16:56:57.418 * Background saving terminated with success
(8)打开Redis客户端,运行./redis-cli -p 6391,客户端启动成功后,运行命令save,等待命令运行成功后,即可得到本步骤最终目标的RDB持久化文件(PS:此处如果是在线上环境尝试,建议采用bgsave命令)
此处给出,使用AOF文件还原数据后,查看具体数据信息的结果:
liuzhen@liuzhen-ubuntu:~/redis-2.8.17/src$ ./redis-cli -p 6391 127.0.0.1:6391> info# Serverredis_version:2.8.17redis_git_sha1:00000000redis_git_dirty:0 redis_build_id:4ba260b6ab802599 redis_mode:standalone os:Linux 4.13.0-39-generic x86_64 arch_bits:64multiplexing_api:epoll gcc_version:5.4.0 process_id:68180run_id:97cddc494e3924885bacb03776dfe09e8fa055f9 tcp_port:6391uptime_in_seconds:9400uptime_in_days:0 hz:10lru_clock:5266472config_file:/home/liuzhen/redis-2.8.17/src/redis_6391.conf # Clientsconnected_clients:1client_longest_output_list:0 client_biggest_input_buf:0 blocked_clients:0 # Memoryused_memory:2239514040used_memory_human:2.09G used_memory_rss:330895360used_memory_peak:2272377648used_memory_peak_human:2.12G used_memory_lua:38912mem_fragmentation_ratio:0.15mem_allocator:jemalloc-3.6.0 # Persistenceloading:0 rdb_changes_since_last_save:0 rdb_bgsave_in_progress:0 rdb_last_save_time:1531990617rdb_last_bgsave_status:ok rdb_last_bgsave_time_sec:463rdb_current_bgsave_time_sec:-1aof_enabled:1aof_rewrite_in_progress:0 aof_rewrite_scheduled:0 aof_last_rewrite_time_sec:-1aof_current_rewrite_time_sec:-1aof_last_bgrewrite_status:ok aof_last_write_status:ok aof_current_size:1700508277aof_base_size:1699947297aof_pending_rewrite:0 aof_buffer_length:0 aof_rewrite_buffer_length:0 aof_pending_bio_fsync:0 aof_delayed_fsync:1 # Statstotal_connections_received:2total_commands_processed:281instantaneous_ops_per_sec:0 rejected_connections:0 sync_full:0 sync_partial_ok:0 sync_partial_err:0 expired_keys:9290evicted_keys:0 keyspace_hits:1065050keyspace_misses:0 pubsub_channels:0 pubsub_patterns:0 latest_fork_usec:101807 # Replicationrole:master connected_slaves:0 master_repl_offset:0 repl_backlog_active:0 repl_backlog_size:1048576repl_backlog_first_byte_offset:0 repl_backlog_histlen:0 # CPUused_cpu_sys:46.01used_cpu_user:189.71used_cpu_sys_children:134.11used_cpu_user_children:79.12 # Keyspacedb1:keys=1146336,expires=51965,avg_ttl=276142509 127.0.0.1:6391>
备注:在Redis指定端口服务加载给定的AOF文件时,如果AOF文件过大,系统可能会报如下错误:
Can't save in background: fork: Cannot allocate memory
解决办法:
修改系统/etc/sysctl.conf文件,并添加以下内容:
vm.overcommit_memory=1
在 FreeBSD上:
sudo /etc/rc.d/sysctl reload
在 Linux上:
sudo sysctl -p /etc/sysctl.conf
参考资料:
1.redis中的数据快照、AOF、数据恢复、主从复制介绍及使用(https://blog.csdn.net/zhu_xun/article/details/16806697)
2.redis如何利用appendonly.aof恢复数据(https://blog.csdn.net/sanbingyutuoniao123/article/details/50484674)
3.Redis持久存储(AOF/Snapshot)(http://shift-alt-ctrl.iteye.com/blog/1878716)
4.redis dump.rdb appendonly.aof 文件路径修改(https://blog.csdn.net/yangxujia/article/details/51010222)
5.超大数据快速导入MySQL(https://blog.csdn.net/dingding_12345/article/details/78646484)
6.redis Can’t save in background: fork: Cannot allocate memory 解决及原理(https://blog.csdn.net/zqz_zqz/article/details/53384854)
7.redis bgsave failed because fork Cannot allocate memory(https://stackoverflow.com/questions/11752544/redis-bgsave-failed-because-fork-cannot-allocate-memory)
8.《Redis设计与实现 第二版》 黄健宏 著