Redis学习总结(1)——数据持久化
以前研究Redis的时候,很多东西都不太明白,理解得也不太深,现在有时间重新拾起来看看,将一些心得记录下来,希望和大家一起探讨。
一、简介
Redis是一个单线程高可用的Key-Value存储系统,和Memcached类似,但是实际使用上最大的区别有两方面:
- Redis支持多种数据结构类型的value,比如string(字符串)、list(链表)、set(集合)、zset(sorted set --有序集合)和hash(哈希类型);
- Memcached在出现系统瘫痪的情况下,无法实现系统恢复,而Redis支持两种数据持久化的方式(RDB和AOF),并且在此基础上实现了master-slave同步,从而体现了其自身高可用的特点;
二、Redis的持久化方式介绍(注:为了省事,相关配置直接贴的是网上的)
1. RDB(默认):即snapshot(快照),从字面意思上理解,就像将其进行的一些命令操作以照片方式记录下来,那么,有人肯定会存在以下几个疑问:
- Redis在持续写入的过程,通过来进行快照的?答:Redis借助了fork命令的copy on write机制(私有内存非共享内存)。在生成快照时,将当前进程fork出一个子进程(主进程继续接受客户端的请求操作),然后在子进程中循环所有的数据,将数据写成为RDB文件。(注:由于os的写时复制机制父子进程会共享相同的物理页面(内存区),当父进程处理写请求时os会为父进程要修改的页面创建副本,而不是写共享的页面。所以子进程的地址空间内的数据是fork时刻整个数据库的一个快照。)
- 如何配置策略写入RDB?:答:在redis.conf文件中,可以配置 save M N ,意思是在M秒内,进行N次操作,比如:save 300 10 即当300秒内有10条Keys数据被改变时,则进行快照,生成RDB;(注:如果不配置任何的save规则,即默认不开启快照功能)
################################ SNAPSHOTTING ################################# # Save the DB on disk: # 设置sedis进行数据库镜像的频率。 # 900秒(15分钟)内至少1个key值改变(则进行数据库保存--持久化)。 # 300秒(5分钟)内至少10个key值改变(则进行数据库保存--持久化)。 # 60秒(1分钟)内至少10000个key值改变(则进行数据库保存--持久化)。 save 900 1 save 300 10 save 60 10000 stop-writes-on-bgsave-error yes # 在进行镜像备份时,是否进行压缩。yes:压缩,但是需要一些cpu的消耗。no:不压缩,需要更多的磁盘空间。 rdbcompression yes # 一个CRC64的校验就被放在了文件末尾,当存储或者加载rbd文件的时候会有一个10%左右的性能下降,为了达到性能的最大化,你可以关掉这个配置项。 rdbchecksum yes # 快照的文件名 dbfilename dump.rdb # 存放快照的目录 dir /var/lib/redis
- Redis快照持久化写入哪些数据?:答:每次快照持久化都是将内存数据完整写入到磁盘一次(达到save条件的时,保存该时间点的内存数据),并不是增量的只同步RDB文件中不存在的数据。在数据量大并且写操作较多的情况下,会引起大量的磁盘io操作,可能会严重影响性能。
- Redis的RDB文件不会坏掉?答:因为其写操作是在一个新进程中进行的。当生成一个新的RDB文件时,Redis生成的子进程会先将数据写到一个临时文件中,然后通过原子性rename系统调用将临时文件重命名为RDB文件。这样在任何时候出现故障,Redis的RDB文件都总是可用的。
- Redis的RDB持久化方式有什么不足?答:如果主机down机的话,那么有可能造成数据丢失,比如上次快照到down机这段时间内的数据可能丢失,因为还没有到达那个触发快照的条件(配置的save机制),为了解决这个问题,请看第二种持久化方式。
2. AOF:即Append Only File,该种持久化解决了上面提到的数据丢失问题,但是同样,可能有人会存在以下几个疑问:
- AOF是如何来进行的呢?答:和快照一样,也是fork出一个子进程,将内存中的数据写入到AOF文件中;
- 有哪几种模式?答:在redis.conf文件,如下面配置中,appendfsync的值即为写入AOF文件的模式;
############################## APPEND ONLY MODE ############################### # 是否开启AOF,默认关闭(no) appendonly yes # 指定 AOF 文件名 appendfilename appendonly.aof # Redis支持三种不同的刷写模式: # appendfsync always #每次收到写命令就立即强制写入磁盘,是最有保证的完全的持久化,但速度也是最慢的,一般不推荐使用。 appendfsync everysec #每秒钟强制写入磁盘一次,在性能和持久化方面做了很好的折中,是受推荐的方式。 # appendfsync no #完全依赖OS的写入,一般为30秒左右一次,性能最好但是持久化最没有保证,不被推荐。 #在日志重写时,不进行命令追加操作,而只是将其放在缓冲区里,避免与命令的追加造成DISK IO上的冲突。 #设置为yes表示rewrite期间对新写操作不fsync,暂时存在内存中,等rewrite完成后再写入,默认为no,建议yes no-appendfsync-on-rewrite yes #当前AOF文件大小是上次日志重写得到AOF文件大小的二倍时,自动启动新的日志重写过程。 auto-aof-rewrite-percentage 100 #当前AOF文件启动新的日志重写过程的最小值,避免刚刚启动Reids时由于文件尺寸较小导致频繁的重写。 auto-aof-rewrite-min-size 64mb
- AOF存在什么问题呢?答:1⃣由于写入AOF文件的频率远大于快照,那么势必会出现一种问题,就是在高并发操作下,内存很快就会爆满,那怎么办?AOF提供一种重写(Rewrite,使用bgrewriteaof命令)的机制。创建一个新的AOF文件来替代已有文件,新文件中不存在一些冗余的命令,比如连续的set a 1,set a 2,其实这个压缩后只会保留set a 2。2⃣数据一致性问题(见下一个);
- 数据一致性问题?答:子进程在重写期间,如果有新的命令对现有的数据做出更改的操作,那么会出现所谓的内存中数据和AOF不一致问题。Redis提供了一个AOF重写缓冲区,该缓冲区是在fork出子进程的时候创建,当父进程进行一些操作时,在子进程重写新文件的过程中,父的所有的写操作日志还是会写到原来老的AOF文件中(为了防止写入AOF时发生故障系统也没有影响),同时还会将这些命令发送到缓冲区中。子进程写入AOF结束后,会像父进程发送一个信号,父进程会进行两个操作:1⃣将缓冲区的内容写入AOF文件末尾;2⃣rename方法对AOF文件改名,覆盖现有的AOF文件。
- 纯粹的日志追加,如果包含了未写入完整的命令怎么办?答:可能某些原因而包含了未写入完整的命令(比如写入时磁盘已满,写入中途主机崩溃等等), 可以使用redis-check-aof 工具修复这种问;
三、总结
今天主要介绍Redis的两种持久化机制,在现实系统中应用时该如何选择,那么不能一定说哪个好!比如,如果系统能够容忍数据部分丢失的情况下,则使用RDB,如果不能则使用AOF;但是AOF频繁写入文件,也会带来一定的性能损耗。有些时候也会混合使用,在这种情况下,Redis crash后,通过加载AOF文件来恢复数据。
以后会再列出Redis的高可用(master-slave)部分!