redis持久化

12次阅读

共计 2966 个字符,预计需要花费 8 分钟才能阅读完成。

## # Redis 持久化介绍

所有的数据都存在内存中,从内存当中同步到硬盘上,这个过程叫做持久化过程。持久化操作,两种方式:rdb 方式、aof 方式,可以单独使用或者结合使用。

rdb 持久化方法:在指定的时间间隔写入硬盘  aof 方式:将以日志,记录每一个操作,服务器启动后就构建数据库。

RDB 方式 Redis 是默认支持的

优势:只有一个文件,时间间隔的数据,可以归档为一个文件,方便压缩转移(就一个文件)

## #Redis 的持久化之 RDB 方式 **

劣势:如果宕机,数据损失比较大,因为它是每一个时间段进行持久化操作的。也就是积攒的数据比较多,一旦懵逼,就彻底懵逼了

[root@hdp-01 redis]# vi redis.conf

往下拉:

这里 save 900 1 表示 每 900 秒内至少有 1 个 kery 发生变化 就持久化

save 300 10 表示 每 300 秒内至少有 10 个 key 发生变化 就持久化

save 60 10000 表示 每 60 秒内至少有 10000 个 key 发生变化 就持久化

再往下拉

这里有个 dbfilename 配置 是保存的持久化的文件名 默认是 dump.rdb

dir ./ 表示文件存储路径是当前路径

退出

[root@hdp-01 redis]# ll 总用量 64drwxr-xr-x. 2 root root   134 9 月   1 16:30 bin-rw-r–r–. 1 root root   109 9 月   1 17:30dump.rdb-rw-r–r–. 1 root root 58767 9 月   3 07:04 redis.conf

当前路径里确实是有这个文件的

## # RDB 备份和恢复数据

假如遇到断电或者宕机或者自然灾害 需要恢复数据 我们模拟下 先重置下数据

shutdown 关闭下 redis

127.0.0.1:6379> shutdown

not connected> exit

[root@hdp-01redis]# ll

总用量 52

drwxr-xr-x. 2 root root   bin-rw-r–r–. 1 root root  dump.rdb-rw-r–r–. 1 root root  redis.conf

删掉 rdb 文件 再启动 redis  这时候启动 是没数据的

[root@hdp-01]# rm -rf dump.rdb [root@hdp-01redis]# ./bin/redis-server ./redis.conf [root@hdp-01redis]# ./bin/redis-cli127.0.0.1:6379> keys *(empty list or set)

搞几个 key 然后 shutdown save 保存退出

[url=]

[/url]
127.0.0.1:6379> set n1 1OK127.0.0.1:6379> set n2 2OK127.0.0.1:6379> set n3 3OK127.0.0.1:6379> shutdown savenot connected> exit[url=]

[/url]

假如这时候 我们再重启 redis 这时候启动过程会进程 rdb check 验证 然后加载 redis 目录下 rdb 文件 加载数据

验证下:我们再次启动

[url=]

[/url]
[root@hdp-01 redis]# ./bin/redis-server ./redis.conf [root@hdp-01 redis]# ./bin/redis-cli127.0.0.1:6379> keys *1) “n1″2) “n3″3) “n2″[url=]

[/url]

说明是数据加载进来了

这里我们把 redis 下的 rdb 文件剪切到其他地方去 然后再启动试下

[root@hdp-01 redis]# mv dump.rdb /root/

剪切到 root 下

这时候再启动下

[root@hdp-01 redis]# ./bin/redis-server ./redis.conf [root@hdp-01 redis]# ./bin/redis-cli127.0.0.1:6379> keys *(empty list or set)

发现所有数据都没了 恢复数据的话 我们只需要把备份文件搞到 redis 下即可

[url=]

[/url]
[root@hdp-01 redis]# cp /root/dump.rdb /usr/local/redis/cp:是否覆盖 ”/usr/local/redis/dump.rdb”?y[root@hdp-01 redis]# ./bin/redis-server ./redis.conf [root@hdp-01 redis]# ./bin/redis-cli127.0.0.1:6379> keys *1) “n2″2) “n1″3) “n3″[url=]

[/url]

## #Redis 的持久化之 AOF 方式 **

AOF 方式:将以日志,记录每一个操作

优势:安全性相对 RDB 方式高很多

劣势:效率相对 RDB 方式低很多

## # AOF 备份和恢复数据

AOF 方式:将以日志,记录每一个操作

优势:安全性相对 RDB 方式高很多;劣势:效率相对 RDB 方式低很多;

配置:

[root@hdp-01 redis]# vi redis.conf

编辑 redis.conf

appendonly no 默认关闭 aof 方式 我们修改成 yes 就开启

下面那个是默认的 aof 文件名

再往下拉:

这里是三种同步策略:

always 是 只要发生修改 立即同步(推荐实用 安全性最高)

everysec 是 每秒同步一次

no 是不同步

修改成 always

重新启动 redis 随便加几个 key

这里就有一个 appendonly.aof 文件

重置数据

[root@hdp-01 redis]# rm -rf dump.rdb

启动 redis

[root@hdp-01 redis]# ./bin/redis-server ./redis.conf [root@hdp-01 redis]# ./bin/redis-cli127.0.0.1:6379> keys *(empty list or set)

目前数据库是空 添加数据

[url=]

[/url]
127.0.0.1:6379> set n1 1OK127.0.0.1:6379> set n2 2OK127.0.0.1:6379> set n3 3OK127.0.0.1:6379> shutdown nosavenot connected> exit[url=]

[/url]

把 aof 文件剪切到其他地方 启动

[root@hdo-01 redis]# mv appendonly.aof /root/[root@hdo-01 redis]# ./bin/redis-server ./redis.conf [root@hdp-01 redis]# ./bin/redis-cli127.0.0.1:6379> keys *(empty list or set)

我们再把 aof 文件复制回来

[url=]

[/url]
[root@hdp-01 redis]# cp /root/appendonly.aof /usr/local/redis/cp:是否覆盖 ”/usr/local/redis/appendonly.aof”?y[root@hdp-01 redis]# ./bin/redis-server ./redis.conf [root@hdp-01 redis]# ./bin/redis-cli127.0.0.1:6379> keys *1) “n1″2) “n3″3) “n2″[url=]

[/url]

正文完
 0

redis-持久化

12次阅读

共计 11329 个字符,预计需要花费 29 分钟才能阅读完成。

介绍

  1. 首先,我们应该明确持久化的数据有什么用,答案是用于重启后的数据恢复。
  2. Redis 是一个内存数据库,无论是 RDB 还是 AOF,都只是其保证数据恢复的措施。
  3. 所以 Redis 在利用 RDB 和 AOF 进行恢复的时候,都会读取 RDB 或 AOF 文件,重新加载到内存中。

Redis 持久化的方式

  1. RDB
  2. AOF

RDB

  1. RDB 就是 Snapshot 快照存储,是默认的持久化方式。

可理解为半持久化模式,即按照一定的策略周期性的将数据保存到磁盘。
对应产生的数据文件为 dump.rdb,通过配置文件中的 save 参数来定义快照的周期。

  1. 下面是默认的快照设置:

    • save 900 1 #当有一条 Keys 数据被改变时,900 秒刷新到 Disk 一次
    • save 300 10 #当有 10 条 Keys 数据被改变时,300 秒刷新到 Disk 一次
    • save 60 10000# 当有 10000 条 Keys 数据被改变时,60 秒刷新到 Disk 一次

Redis 的 RDB 文件不会坏掉,因为其写操作是在一个新进程中进行的。
当生成一个新的 RDB 文件时,Redis 生成的子进程会先将数据写到一个临时文件中,然后通过原子性 rename 系统调用将临时文件重命名为 RDB 文件。
这样在任何时候出现故障,Redis 的 RDB 文件都总是可用的。
同时,Redis 的 RDB 文件也是 Redis 主从同步内部实现中的一环。

第一次 Slave 向 Master 同步的实现是:

* Slave 向 Master 发出同步请求,Master 先 dump 出 rdb 文件,然后将 rdb 文件全量传输给 slave,然后 Master 把缓存的命令转发给 Slave,初次同步完成。

第二次以及以后的同步实现是:

* Master 将变量的快照直接实时依次发送给各个 Slave。但不管什么原因导致 Slave 和 Master 断开重连都会重复以上两个步骤的过程。

Redis 的主从复制是建立在内存快照的持久化基础上的,只要有 Slave 就一定会有内存快照发生。

可以很明显的看到,RDB 有它的不足,就是一旦数据库出现问题,那么我们的 RDB 文件中保存的数据并不是全新的。

从上次 RDB 文件生成到 Redis 停机这段时间的数据全部丢掉了。

AOF

AOF(Append-Only File) 比 RDB 方式有更好的持久化性。

由于在使用 AOF 持久化方式时,Redis 会将每一个收到的写命令都通过 Write 函数追加到文件中,类似于 MySQL 的 binlog。

当 Redis 重启是会通过重新执行文件中保存的写命令来在内存中重建整个数据库的内容。

对应的设置参数为:
$ vim /opt/redis/etc/redis_6379.conf

  • appendonly yes 启用 AOF 持久化方式
  • appendfilename appendonly.aof #AOF 文件的名称,默认为 appendonly.aof
  • appendfsync always 每次收到写命令就立即强制写入磁盘,是最有保证的完全的持久化,但速度也是最慢的,一般不推荐使用。
  • appendfsync everysec 每秒钟强制写入磁盘一次,在性能和持久化方面做了很好的折中,是受推荐的方式。
  • appendfsync no #完全依赖 OS 的写入,一般为 30 秒左右一次,性能最好但是持久化最没有保证,不被推荐。

AOF 的完全持久化方式同时也带来了另一个问题,持久化文件会变得越来越大。

比如我们调用 INCR test 命令 100 次,文件中就必须保存全部的 100 条命令,但其实 99 条都是多余的。

因为要恢复数据库的状态其实文件中保存一条 SET test 100 就够了。

为了压缩 AOF 的持久化文件,Redis 提供了 bgrewriteaof 命令。

收到此命令后 Redis 将使用与快照类似的方式将内存中的数据以命令的方式保存到临时文件中,最后替换原来的文件,以此来实现控制 AOF 文件的增长。

由于是模拟快照的过程,因此在重写 AOF 文件时并没有读取旧的 AOF 文件,而是将整个内存中的数据库内容用命令的方式重写了一个新的 AOF 文件。

对应的设置参数为:
$ vim /opt/redis/etc/redis_6379.conf

  • no-appendfsync-on-rewrite yes

在日志重写时,不进行命令追加操作,而只是将其放在缓冲区里,避免与命令的追加造成 DISK IO 上的冲突。
auto-aof-rewrite-percentage 100

当前 AOF 文件大小是上次日志重写得到 AOF 文件大小的二倍时,自动启动新的日志重写过程。
auto-aof-rewrite-min-size 64mb #当前 AOF 文件启动新的日志重写过程的最小值,避免刚刚启动 Reids 时由于文件尺寸较小导致频繁的重写。

选择

到底选择什么呢?下面是来自官方的建议:

  • 通常,如果你要想提供很高的数据保障性,那么建议你同时使用两种持久化方式。

如果你可以接受灾难带来的几分钟的数据丢失,那么你可以仅使用 RDB。
很多用户仅使用了 AOF,但是我们建议,既然 RDB 可以时不时的给数据做个完整的快照,并且提供更快的重启,所以最好还是也使用 RDB。
因此,我们希望可以在未来(长远计划)统一 AOF 和 RDB 成一种持久化模式。

在数据恢复方面

RDB 的启动时间会更短,原因有两个:

  • 是 RDB 文件中每一条数据只有一条记录,不会像 AOF 日志那样可能有一条数据的多次操作记录。所以每条数据只需要写一次就行了。

另一个原因是 RDB 文件的存储格式和 Redis 数据在内存中的编码格式是一致的,不需要再进行数据编码工作,所以在 CPU 消耗上要远小于 AOF 日志的加载。

  • 灾难恢复模拟

既然持久化的数据的作用是用于重启后的数据恢复,那么我们就非常有必要进行一次这样的灾难恢复模拟了。
据称如果数据要做持久化又想保证稳定性,则建议留空一半的物理内存。因为在进行快照的时候,fork 出来进行 dump 操作的子进程会占用与父进程一样的内存,真正的 copy-on-write,对性能的影响和内存的耗用都是比较大的。
目前,通常的设计思路是利用 Replication 机制来弥补 aof、snapshot 性能上的不足,达到了数据可持久化。

即 Master 上 Snapshot 和 AOF 都不做,来保证 Master 的读写性能,而 Slave 上则同时开启 Snapshot 和 AOF 来进行持久化,保证数据的安全性。

  1. 首先,修改 Master 上的如下配置:

    • sudo vim /opt/redis/etc/redis_6379.conf
    • save 900 1 #禁用 Snapshot
    • save 300 10
    • save 60 10000
    • appendonly no #禁用 AOF
  2. 接着,修改 Slave 上的如下配置:

    • sudo vim /opt/redis/etc/redis_6379.conf
    • save 900 1 #启用 Snapshot
    • save 300 10
    • save 60 10000

appendonly yes #启用 AOF

appendfilename appendonly.aof #AOF 文件的名称

appendfsync always

appendfsync everysec #每秒钟强制写入磁盘一次

appendfsync no

no-appendfsync-on-rewrite yes #在日志重写时,不进行命令追加操作

auto-aof-rewrite-percentage 100 #自动启动新的日志重写过程

auto-aof-rewrite-min-size 64mb #启动新的日志重写过程的最小值

分别启动 Master 与 Slave

$ /etc/init.d/redis start

启动完成后在 Master 中确认未启动 Snapshot 参数

redis 127.0.0.1:6379> CONFIG GET save

1) “save”
2) “”

然后通过以下脚本在 Master 中生成 25 万条数据:

dongguo@redis:/opt/redis/data/6379$ cat redis-cli-generate.temp.sh

#!/bin/bash

REDISCLI="redis-cli -a slavepass -n 1 SET"
ID=1

while(($ID<50001))
do
  INSTANCE_NAME="i-2-$ID-VM"
  UUID=`cat /proc/sys/kernel/random/uuid`
  PRIVATE_IP_ADDRESS=10.`echo "$RANDOM % 255 + 1" | bc`.`echo "$RANDOM % 255 + 1" | bc`.`echo "$RANDOM % 255 + 1" | bc`\
  CREATED=`date "+%Y-%m-%d %H:%M:%S"`

  $REDISCLI vm_instance:$ID:instance_name "$INSTANCE_NAME"
  $REDISCLI vm_instance:$ID:uuid "$UUID"
  $REDISCLI vm_instance:$ID:private_ip_address "$PRIVATE_IP_ADDRESS"
  $REDISCLI vm_instance:$ID:created "$CREATED"

  $REDISCLI vm_instance:$INSTANCE_NAME:id "$ID"

  ID=$(($ID+1))
done

dongguo@redis:/opt/redis/data/6379$ ./redis-cli-generate.temp.sh

在数据的生成过程中,可以很清楚的看到 Master 上仅在第一次做 Slave 同步时创建了 dump.rdb 文件,之后就通过增量传输命令的方式给 Slave 了。
dump.rdb 文件没有再增大。

dongguo@redis:/opt/redis/data/6379$ ls -lh

total 4.0K

-rw-r–r– 1 root root 10 Sep 27 00:40 dump.rdb

而 Slave 上则可以看到 dump.rdb 文件和 AOF 文件在不断的增大,并且 AOF 文件的增长速度明显大于 dump.rdb 文件。

dongguo@redis-slave:/opt/redis/data/6379$ ls -lh

total 24M

-rw-r–r– 1 root root 15M Sep 27 12:06 appendonly.aof

-rw-r–r– 1 root root 9.2M Sep 27 12:06 dump.rdb

等待数据插入完成以后,首先确认当前的数据量。

redis 127.0.0.1:6379> info

    redis_version:2.4.17
    redis_git_sha1:00000000
    redis_git_dirty:0
    arch_bits:64
    multiplexing_api:epoll
    gcc_version:4.4.5
    process_id:27623
    run_id:e00757f7b2d6885fa9811540df9dfed39430b642
    uptime_in_seconds:1541
    uptime_in_days:0
    lru_clock:650187
    used_cpu_sys:69.28
    used_cpu_user:7.67
    used_cpu_sys_children:0.00
    used_cpu_user_children:0.00
    connected_clients:1
    connected_slaves:1
    client_longest_output_list:0
    client_biggest_input_buf:0
    blocked_clients:0
    used_memory:33055824
    used_memory_human:31.52M
    used_memory_rss:34717696
    used_memory_peak:33055800
    used_memory_peak_human:31.52M
    mem_fragmentation_ratio:1.05
    mem_allocator:jemalloc-3.0.0
    loading:0
    aof_enabled:0
    changes_since_last_save:250000
    bgsave_in_progress:0
    last_save_time:1348677645
    bgrewriteaof_in_progress:0
    total_connections_received:250007
    total_commands_processed:750019
    expired_keys:0
    evicted_keys:0
    keyspace_hits:0
    keyspace_misses:0
    pubsub_channels:0
    pubsub_patterns:0
    latest_fork_usec:246
    vm_enabled:0
    role:master
    slave0:10.6.1.144,6379,online
    db1:keys=250000,expires=0
    

当前的数据量为 25 万条 key,占用内存 31.52M。

然后我们直接 Kill 掉 Master 的 Redis 进程,模拟灾难。

dongguo@redis:/opt/redis/data/6379$ sudo killall -9 redis-server

我们到 Slave 中查看状态:

redis 127.0.0.1:6379> info

redis_version:2.4.17
redis_git_sha1:00000000
redis_git_dirty:0
arch_bits:64
multiplexing_api:epoll
gcc_version:4.4.5
process_id:13003
run_id:9b8b398fc63a26d160bf58df90cf437acce1d364
uptime_in_seconds:1627
uptime_in_days:0
lru_clock:654181
used_cpu_sys:29.69
used_cpu_user:1.21
used_cpu_sys_children:1.70
used_cpu_user_children:1.23
connected_clients:1
connected_slaves:0
client_longest_output_list:0
client_biggest_input_buf:0
blocked_clients:0
used_memory:33047696
used_memory_human:31.52M
used_memory_rss:34775040
used_memory_peak:33064400
used_memory_peak_human:31.53M
mem_fragmentation_ratio:1.05
mem_allocator:jemalloc-3.0.0
loading:0
aof_enabled:1
changes_since_last_save:3308
bgsave_in_progress:0
last_save_time:1348718951
bgrewriteaof_in_progress:0
total_connections_received:4
total_commands_processed:250308
expired_keys:0
evicted_keys:0
keyspace_hits:0
keyspace_misses:0
pubsub_channels:0
pubsub_patterns:0
latest_fork_usec:694
vm_enabled:0
role:slave
aof_current_size:17908619
aof_base_size:16787337
aof_pending_rewrite:0
aof_buffer_length:0
aof_pending_bio_fsync:0
master_host:10.6.1.143
master_port:6379
master_link_status:down
master_last_io_seconds_ago:-1
master_sync_in_progress:0
master_link_down_since_seconds:25
slave_priority:100
db1:keys=250000,expires=0

可以看到 master_link_status 的状态已经是 down 了,Master 已经不可访问了。

而此时,Slave 依然运行良好,并且保留有 AOF 与 RDB 文件。

下面我们将通过 Slave 上保存好的 AOF 与 RDB 文件来恢复 Master 上的数据。

首先,将 Slave 上的同步状态取消,避免主库在未完成数据恢复前就重启,进而直接覆盖掉从库上的数据,导致所有的数据丢失。

redis 127.0.0.1:6379> SLAVEOF NO ONE

OK

确认一下已经没有了 master 相关的配置信息:

redis 127.0.0.1:6379> INFO

redis_version:2.4.17
redis_git_sha1:00000000
redis_git_dirty:0
arch_bits:64
multiplexing_api:epoll
gcc_version:4.4.5
process_id:13003
run_id:9b8b398fc63a26d160bf58df90cf437acce1d364
uptime_in_seconds:1961
uptime_in_days:0
lru_clock:654215
used_cpu_sys:29.98
used_cpu_user:1.22
used_cpu_sys_children:1.76
used_cpu_user_children:1.42
connected_clients:1
connected_slaves:0
client_longest_output_list:0
client_biggest_input_buf:0
blocked_clients:0
used_memory:33047696
used_memory_human:31.52M
used_memory_rss:34779136
used_memory_peak:33064400
used_memory_peak_human:31.53M
mem_fragmentation_ratio:1.05
mem_allocator:jemalloc-3.0.0
loading:0
aof_enabled:1
changes_since_last_save:0
bgsave_in_progress:0
last_save_time:1348719252
bgrewriteaof_in_progress:0
total_connections_received:4
total_commands_processed:250311
expired_keys:0
evicted_keys:0
keyspace_hits:0
keyspace_misses:0
pubsub_channels:0
pubsub_patterns:0
latest_fork_usec:1119
vm_enabled:0
role:master
aof_current_size:17908619
aof_base_size:16787337
aof_pending_rewrite:0
aof_buffer_length:0
aof_pending_bio_fsync:0
db1:keys=250000,expires=0

在 Slave 上复制数据文件:

dongguo@redis-slave:/opt/redis/data/6379$ tar cvf /home/dongguo/data.tar *

appendonly.aof

dump.rdb

将 data.tar 上传到 Master 上,尝试恢复数据:

可以看到 Master 目录下有一个初始化 Slave 的数据文件,很小,将其删除。

dongguo@redis:/opt/redis/data/6379$ ls -l

total 4

-rw-r–r– 1 root root 10 Sep 27 00:40 dump.rdb

dongguo@redis:/opt/redis/data/6379$ sudo rm -f dump.rdb

然后解压缩数据文件:

dongguo@redis:/opt/redis/data/6379$ sudo tar xf /home/dongguo/data.tar

dongguo@redis:/opt/redis/data/6379$ ls -lh

total 29M

-rw-r–r– 1 root root 18M Sep 27 01:22 appendonly.aof

-rw-r–r– 1 root root 12M Sep 27 01:22 dump.rdb

启动 Master 上的 Redis;

dongguo@redis:/opt/redis/data/6379$ sudo /etc/init.d/redis start

Starting Redis server…

查看数据是否恢复:

redis 127.0.0.1:6379> INFO

redis_version:2.4.17
redis_git_sha1:00000000
redis_git_dirty:0
arch_bits:64
multiplexing_api:epoll
gcc_version:4.4.5
process_id:16959
run_id:6e5ba6c053583414e75353b283597ea404494926
uptime_in_seconds:22
uptime_in_days:0
lru_clock:650292
used_cpu_sys:0.18
used_cpu_user:0.20
used_cpu_sys_children:0.00
used_cpu_user_children:0.00
connected_clients:1
connected_slaves:0
client_longest_output_list:0
client_biggest_input_buf:0
blocked_clients:0
used_memory:33047216
used_memory_human:31.52M
used_memory_rss:34623488
used_memory_peak:33047192
used_memory_peak_human:31.52M
mem_fragmentation_ratio:1.05
mem_allocator:jemalloc-3.0.0
loading:0
aof_enabled:0
changes_since_last_save:0
bgsave_in_progress:0
last_save_time:1348680180
bgrewriteaof_in_progress:0
total_connections_received:1
total_commands_processed:1
expired_keys:0
evicted_keys:0
keyspace_hits:0
keyspace_misses:0
pubsub_channels:0
pubsub_patterns:0
latest_fork_usec:0
vm_enabled:0
role:master
db1:keys=250000,expires=0

可以看到 25 万条数据已经完整恢复到了 Master 上。

此时,可以放心的恢复 Slave 的同步设置了。

redis 127.0.0.1:6379> SLAVEOF 10.6.1.143 6379

OK

查看同步状态:

redis 127.0.0.1:6379> INFO

redis_version:2.4.17
redis_git_sha1:00000000
redis_git_dirty:0
arch_bits:64
multiplexing_api:epoll
gcc_version:4.4.5
process_id:13003
run_id:9b8b398fc63a26d160bf58df90cf437acce1d364
uptime_in_seconds:2652
uptime_in_days:0
lru_clock:654284
used_cpu_sys:30.01
used_cpu_user:2.12
used_cpu_sys_children:1.76
used_cpu_user_children:1.42
connected_clients:2
connected_slaves:0
client_longest_output_list:0
client_biggest_input_buf:0
blocked_clients:0
used_memory:33056288
used_memory_human:31.52M
used_memory_rss:34766848
used_memory_peak:33064400
used_memory_peak_human:31.53M
mem_fragmentation_ratio:1.05
mem_allocator:jemalloc-3.0.0
loading:0
aof_enabled:1
changes_since_last_save:0
bgsave_in_progress:0
last_save_time:1348719252
bgrewriteaof_in_progress:1
total_connections_received:6
total_commands_processed:250313
expired_keys:0
evicted_keys:0
keyspace_hits:0
keyspace_misses:0
pubsub_channels:0
pubsub_patterns:0
latest_fork_usec:12217
vm_enabled:0
role:slave
aof_current_size:17908619
aof_base_size:16787337
aof_pending_rewrite:0
aof_buffer_length:0
aof_pending_bio_fsync:0
master_host:10.6.1.143
master_port:6379
master_link_status:up
master_last_io_seconds_ago:0
master_sync_in_progress:0
slave_priority:100
db1:keys=250000,expires=0

master_link_status 显示为 up,同步状态正常。

在此次恢复的过程中,我们同时复制了 AOF 与 RDB 文件,那么到底是哪一个文件完成了数据的恢复呢?

实际上,当 Redis 服务器挂掉时,重启时将按照以下优先级恢复数据到内存:

  • 如果只配置 AOF, 重启时加载 AOF 文件恢复数据;
  • 如果同时 配置了 RDB 和 AOF, 启动是只加载 AOF 文件恢复数据;
  • 如果只配置 RDB, 启动是将加载 dump 文件恢复数据。

也就是说,AOF 的优先级要高于 RDB,这也很好理解,因为 AOF 本身对数据的完整性保障要高于 RDB。

在此次的案例中,我们通过在 Slave 上启用了 AOF 与 RDB 来保障了数据,并恢复了 Master。

但在我们目前的线上环境中,由于数据都设置有过期时间,采用 AOF 的方式会不太实用,过于频繁的写操作会使 AOF 文件增长到异常的庞大,大大超过了我们实际的数据量,这也会导致在进行数据恢复时耗用大量的时间。
因此,可以在 Slave 上仅开启 Snapshot 来进行本地化,同时可以考虑将 save 中的频率调高一些或者调用一个计划任务来进行定期 bgsave 的快照存储,来尽可能的保障本地化数据的完整性。

在这样的架构下,如果仅仅是 Master 挂掉,Slave 完整,数据恢复可达到 100%。
如果 Master 与 Slave 同时挂掉的话,数据的恢复也可以达到一个可接受的程度。

如希望了解更多,请关注微信公众号

正文完
 0

Redis持久化

12次阅读

共计 1755 个字符,预计需要花费 5 分钟才能阅读完成。

 这节介绍 Redis 的持久化,包括 RDB 和 AOF 两种方式。

1.RDB 持久化

 Redis 能够将内存中的数据持久化到 RDB 文件中,避免数据丢失。RDB 文件的格式如下示:

 第一部分是开头的 5 个字节,值为 REDIS,第二部分是长度为 4 个字节的版本号,值为一个字符串表示的整形。database 部分包含零个或任意多个数据库,以及各个数据库中的键值对数据,database 的结构如下示:

 EOF 为 1 字节的结束符号,check_sum 为 8 字节长的校验和,这个校验和是通过前面 4 个部分计算出来的。

 可以使用 SAVE 或者 BGSAVE 命令生成 RDB 文件。SAVE 命令会阻塞 Redis 服务器进程,直到 RDB 文件创建完毕为止,在服务器进程阻塞期间,服务器不能处理任何命令请求。BGSAVE 命令则会派生出一个子进程,然后由子进程负责创建 RDB 文件,父进程继续处理命令请求。

 BGSAVE 除了可以通过命令来手动执行外,还可以通过配置项来定期执行,该功能可以将某个时间点上的数据库状态保存到一个 RDB 文件中。配置格式为:

    save N M

 表示服务器在 N 秒内对数据进行了至少 M 次修改。该配置可以有多个,只要满足其中一个条件就会触发 BGSAVE。当 BGSAVE 命令执行时,父进程会 fork 一个子进程,子进程会将当前内存中的数据写到磁盘上的一个临时文件。当临时文件写完后会将原来的 RDB 文件替换掉,这样的好处是可以使用 copy-on-write。

 RDB 文件只是服务器在某个时刻的快照,潜在的风险就是会丢失两次备份之间的数据,同时在服务器出现问题时也可能丢失最新的数据。

 RDB 文件生成的文件名默认为 dump.rbd,在文件会在服务器启动时自动载入。注意,如果开启了 AOF 持久化,则服务器优先加载 AOF 文件。只有在 AOF 持久化关闭的状态下,才会加载 RDB 文件。

2.AOF 持久化

 不同于 RDB 文件以保存数据库中键值对值的方式,AOF 文件以追加的方式,将所有的写命令以请求协议的格式保存到文件中来记录数据库的状态,因而文件内容是可识别的纯文本,可以直接查看。

 当有写命令到达时,服务器会执行客户端发来的命令,然后将执行后的写命令追加到 AOF 缓冲区中。追加完数据后服务器会判断是否需要执行文件写入和文件同步动作,当判断结果为需要时会将缓冲区中的内容写入到磁盘中,由于操作系统的特性,在没有调用 fsync 或者 fdataasync 同步函数时,操作系统通常会将写入数据暂时保存在一个内存缓冲区里面,等到缓冲区的空间被填满或者过了指定的时间后,才真正的将缓冲区中的数据写入到磁盘里面。AOF 文件的持久化策略由 appendfsync 选项的值控制,包括 always,everysec 和 no,分别为:

  1. 每一次写操作都会调用一次 fsync;每隔一秒进行一次 fsync;
  2. 不主动调用 fsync,依赖于操作系统。

 Redis 提供了 AOF 重写功能,来应对文件过大的情况。执行 AOF 重写时,父进程会 fork 一个子进程,让子进程来处理数据的持久化。子进程会遍历内存中的所有键值对,对于每一个键值对,会转为一条写操作,并将对应类型的请求协议写入到临时文件中。比如,在一段时间内,服务器处理了客户端的如下请求:

    SADD    key“val1”SADD    key“val2”SREM    key“val1”SADD    key“val3”

 则原来的 4 条命令,在重写后等同于 1 条命令:

    SADD     key“val2””val3”

 由于使用了 fork 命令,为了解决在重写的过程中,因为新的写请求命令到来而导致父子进程的数据不一致的情况,Redis 服务器设置了一个 AOF 重写缓冲区,这个缓冲区在服务器创建子进程之后开始使用。当 Redis 服务器执行完一个写命令后,它会同时将该命令发送给 AOF 缓冲区和 AOF 重写缓冲区。当子进程完成 AOF 重写工作之后,它会向父进程发送一个信号,父进程在接到该信号后,将 AOF 重写缓冲区的命令写到临时 AOF 文件中,之后将临时 AOF 文件原子的覆盖现有的 AOF 文件,该过程是阻塞的进行的。

 不同于 RDB 文件的载入,由于需要执行 AOF 文件的命令,在使用 AOF 重建数据库时,Redis 服务器会创建一个不带网络连接的伪客户端,使用伪客户端循环的执行文件中的每一个写命令直到 AOF 文件读取结束。

个人公众号:啊驼

正文完
 0

Redis持久化

12次阅读

共计 1085 个字符,预计需要花费 3 分钟才能阅读完成。

RDB 持久化
redis 默认开启了 rdb 存储,保存在 redis 目录下的 dump.rdb,策略如下

save 900 1
save 300 10
save 60 10000
如果满足 900 秒内有 1 个键值被改动,则自动保存一次数据集
如果满足 300 秒内有 10 个键值被改动,则自动保存一次数据集
如果满足 60 秒内有 10000 个键值被改动,则自动保存一次数据集

AOF 持久化
默认不开启,需要在 redis.conf 中开启

appendonly yes

appendfilename “appendonly.aof”

appendfsync always

appendfsync everysec

appendfsync no

auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
appendonly 默认是 no,改为 yes 就开启了 AOF 持久化,默认文件名称为 appendonly.aof

修改 appendfilename 可以修改默认文件名称

追加同步操作 appendfsync 有三个选项
always:每当有新命令追加到 AOF 文件都会执行一次 fsync,非常慢也非常安全
everysec:每隔一秒执行一次 fsync,足够快,即使数据丢失也只是一秒的数据
no:从不进行 fsync,将数据交给操作系统处理,更快却更不安全

aof 文件相当于一个命令日志,每当有一条命令执行,都会被追加到文件末尾,例如我们循环执行 100 次 set 操作,就会有 100 条记录,虽然 99 条记录都是多余的,此时我们就需要缩减 aof 文件

方法一:
cd redis 根目录 /src/redis-cli
127.0.0.1:6379>bgrewriteaof
1
2
通过命令行来手工执行 rewrite 操作,此时我们在看 aof 文件,确实比原来少了很多。

方法二:
通过配置文件 auto-aof-rewrite-percentage 和 auto-aof-rewrite-min-size 和参数,当 aof 文件满足条件的时候自动触发 rewrite 操作。
auto-aof-rewrite-percentage:aof 重写百分比
auto-aof-rewrite-min-size:aof 重写最小值
两个条件相辅相成,只有同时满足才会触发 rewrite 操作。
例如你原来的 aof 文件为 2MB,即使现在已经达到 4MB,满足了 auto-aof-rewrite-percentage 的 100% 的条件,但是由于 auto-aof-rewrite-min-size 最小值为 64MB,不满足,所以仍然不会触发 rewrite 操作。

更多技术资讯可关注:gzitcast

正文完
 0

Redis-持久化

12次阅读

共计 3085 个字符,预计需要花费 8 分钟才能阅读完成。

Redis 有两种持久化的方式: 快照 (RDB 文件) 和追加式文件 (AOF 文件):

  • RDB 持久化方式会在一个特定的间隔保存那个时间点的一个数据快照.
  • AOF 持久化方式则会记录每一个服务器收到的写操作. 在服务启动时, 这些记录的操作会逐条执行从而重建出原来的数据. 写操作命令记录的格式跟 Redis 协议一致, 以追加的方式进行保存.
  • Redis 的持久化是可以禁用的, 就是说你可以让数据的生命周期只存在于服务器的运行时间里.
  • 两种方式的持久化是可以同时存在的, 但是当 Redis 重启时, AOF 文件会被优先用于重建数据.

RDB

工作原理

  • Redis 调用 fork(), 产生一个子进程.
  • 子进程把数据写到一个临时的 RDB 文件.
  • 当子进程写完新的 RDB 文件后, 把旧的 RDB 文件替换掉.

文件路径和名称

默认 Redis 会把快照文件存储为当前目录下一个名为 dump.rdb 的文件. 要修改文件的存储路径和名称, 可以通过修改配置文件 redis.conf 实现:

# RDB 文件名,默认为 dump.rdb。dbfilename dump.rdb

# 文件存放的目录,AOF 文件同样存放在此目录下。默认为当前工作目录。dir ./

保存点 (RDB 的启用和禁用)

你可以配置保存点, 使 Redis 如果在每 N 秒后数据发生了 M 次改变就保存快照文件. 例如下面这个保存点配置表示每 60 秒, 如果数据发生了 1000 次以上的变动, Redis 就会自动保存快照文件:

save 60 1000

保存点可以设置多个, Redis 的配置文件就默认设置了 3 个保存点:

# 格式为:save <seconds> <changes>
# 可以设置多个。save 900 1 #900 秒后至少 1 个 key 有变动
save 300 10 #300 秒后至少 10 个 key 有变动
save 60 10000 #60 秒后至少 10000 个 key 有变动 

如果想禁用快照保存的功能, 可以通过注释掉所有 “save” 配置达到,或者在最后一条 “save” 配置后添加如下的配置:

save ""

错误处理

默认情况下, 如果 Redis 在后台生成快照的时候失败, 那么就会停止接收数据, 目的是让用户能知道数据没有持久化成功.

但是如果你有其他的方式可以监控到 Redis 及其持久化的状态, 那么可以把这个功能禁止掉.

stop-writes-on-bgsave-error yes

数据压缩

默认 Redis 会采用 LZF 对数据进行压缩.

如果你想节省点 CPU 的性能, 你可以把压缩功能禁用掉, 但是数据集就会比没压缩的时候要大.

rdbcompression yes

数据校验

从版本 5 的 RDB 的开始, 一个 CRC64 的校验码会放在文件的末尾. 这样更能保证文件的完整性, 但是在保存或者加载文件时会损失一定的性能 (大概 10%).

如果想追求更高的性能, 可以把它禁用掉, 这样文件在写入校验码时会用 0 替代, 加载的时候看到 0 就会直接跳过校验.

rdbchecksum yes

手动生成快照

Redis 提供了两个命令用于手动生成快照.

BGSAVE

BGSAVE 命令使用后台的方式保存 RDB 文件, 调用此命令后, 会立刻返回 OK.

Redis 会产生一个子进程进行快照写入硬盘. 父进程继续处理命令请求.

SAVE

SAVE 命令会使用同步的方式生成 RDB 快照文件, 这意味着在这个过程中会阻塞所有其他客户端的请求.

因此不建议在生产环境使用这个命令.

重点

  1. 如果用户设置了 save 60 1000, 那么从 Redis 最近一次创建快照之后开始算起 . 当条件被满足时, 就会自动出发 BGSAVE 命令. 如果有多个 save 配置, 那么当任意一个被满足时, 都会出发一次 BGSAVE 命令.
  2. 当 Redis 通过 SHUTDOWN 命令, 来关闭服务时, 或者接收到标准 TERM 信号时, 会执行一次 SAVE 命令, 阻塞所有客户端, 并且执行完毕后会关闭 Redis 服务.

这里注意的是 fork 操作会阻塞, 导致 Redis 读写性能下降. 我们可以控制单个 Redis 实例的最大内存, 来尽可能降低 Redis 在 fork 时的事件消耗. 以及上面提到的自动触发的频率减少 fork 次数, 或者使用手动触发, 根据自己的机制来完成持久化.

AOF

快照并不是很可靠. 如果你的电脑突然宕机了, 或者电源断了, 又或者不小心杀掉了进程, 那么最新的数据就会丢失.

而 AOF 文件则提供了一种更为可靠的持久化方式. 每当 Redis 接受到会修改数据集的命令时, 就会把命令追加到 AOF 文件里, 当你重启 Redis 时, AOF 里的命令会被重新执行一次, 重建数据.

启用 AOF

把配置项 appendonly 设为 yes:

appendonly yes

文件路径和名称

# 文件存放目录,与 RDB 共用。默认为当前工作目录。dir ./

# 默认文件名为 appendonly.aof
appendfilename "appendonly.aof"

可靠性

你可以配置 Redis 调用 fsync 的频率, 有三个选项:

  • 每当有新命令追加到 AOF 的时候调用 fsync. 速度最慢, 最安全.
  • 每秒 fsync 一次. 速度快 (2.4 版本跟快照方式速度差不多), 安全性不错 (最多丢失 1 秒的数据).
  • 从不 fsync, 交由系统去处理. 这个方式速度最快, 但是安全性一般.

推荐使用每秒 fsync 一次的方式 (默认的方式), 因为它速度快, 安全性也不错. 相关配置如下:

# appendfsync always
appendfsync everysec
# appendfsync no

对于增量追加到文件这一步主要的流程是: 命令写入 =》追加到 aof_buf =》同步到 aof 磁盘. 那么这里为什么要先写入 buf 在同步到磁盘呢? 如果实时写入磁盘会带来非常高的磁盘 IO, 影响整体性能.

AOF 重写是为了减少 AOF 文件的大小, 随着写操作的不断增加, AOF 文件会越来越大. 例如你递增一个计数器 100 次, 那么最终结果就是数据集里的计数器的值为最终的递增结果, 但是 AOF 文件里却会把这 100 次操作完整的记录下来.

而事实上要恢复这个记录, 只需要 1 个命令就行了, 也就是说 AOF 文件里那 100 条命令其实可以精简为 1 条. 所以 Redis 支持这样一个功能: 在不中断服务的情况下在后台重建 AOF 文件.

对于上图有四个关键点补充一下:

  • 在重写期间, 由于主进程依然在响应命令, 为了保证最终备份的完整性; 因此它依然会写入旧的 AOF file 中, 如果重写失败, 能够保证数据不丢失.
  • 为了把重写期间响应的写入信息也写入到新的文件中, 因此也会为子进程保留一个 buf, 防止新写的 file 丢失数据.
  • 重写是直接把当前内存的数据生成对应命令, 并不需要读取老的 AOF 文件进行分析、命令合并.
  • AOF 文件直接采用的文本协议, 主要是兼容性好、追加方便、可读性高可认为修改修复.

性能与实践

通过上面的分析, 我们都知道 RDB 的快照、AOF 的重写都需要 fork, 这是一个重量级操作, 会对 Redis 造成阻塞. 因此为了不影响 Redis 主进程响应, 我们需要尽可能降低阻塞.

  • 降低 fork 的频率, 比如可以手动来触发 RDB 生成快照、与 AOF 重写;
  • 控制 Redis 最大使用内存, 防止 fork 耗时过长;
  • 使用更牛逼的硬件;
  • 合理配置 Linux 的内存分配策略, 避免因为物理内存不足导致 fork 失败.

在线上我们到底该怎么做? 我提供一些自己的实践经验.

  • 如果 Redis 中的数据并不是特别敏感或者可以通过其它方式重写生成数据, 可以关闭持久化;
  • 自己制定策略定期检查 Redis 的情况, 然后可以手动触发备份、重写数据;
  • 单机如果部署多个实例, 要防止多个机器同时运行持久化、重写操作, 防止出现内存、CPU、IO 资源竞争, 让持久化变为串行;
  • 可以加入主从机器, 利用一台从机器进行备份处理, 其它机器正常响应客户端的命令;
  • RDB 持久化与 AOF 持久化可以同时存在, 配合使用.
正文完
 0