简介
Redis 是完全开源免费的,是一个高性能的key-value内存数据库。
Redis 有三个主要的特点:
- Redis支持数据的持久化,可以将内存中的数据保存在磁盘中,重启的时候可以再次加载进行使用
- Redis不仅仅支持简单的key-value类型的数据,同时还提供list,set,zset,hash等数据结构的存储
- Redis支持数据的备份,即master-slave模式的数据备份。
优点:
- 性能极高 – Redis能读的速度是110000次/s,写的速度是81000次/s 。
- 支持丰富的数据类型 - Redis支持最大多数开发人员已经知道如列表,集合,可排序集合,哈希等数据类型。这使得在应用中很容易解决的各种问题,因为我们知道哪些问题处理, 使用哪种数据类型更好解决。
- 操作都是原子的 - 所有 Redis 的操作都是原子,从而确保当两个客户同时访问 Redis 服务器得到的是更新后的值(最新值)。原子性(atomicity):一个事务是一个不可分割的最小工作单位,事务中包括的诸操作要么都做,要么都不做。Redis所有单个命令的执行都是原子性的,这与它的单线程机制有关;
- 缓存
- 消息传递队列中使用(Redis原生支持发布/订阅)
- 在应用程序中,如:Web应用程序会话,网站页面点击数等任何短暂的数据;
Redis支持八种数据类型:
- String 字符串
- Hash 哈希
- List 列表
- Set 集合
- Sorted Set 有序集合
String
string是redis最基本的类型,一个key对应一个value。
string类型是二进制安全的。意思是redis的string可以包含任何数据。比如jpg图片或者序列化的对象
string类型是Redis最基本的数据类型,一个键最大能存储512MB。
redis 127.0.0.1:6379> SET name "itcast"
OK
redis 127.0.0.1:6379> GET name
"itcast"
127.0.0.1:6379> type name
string
删除键值
redis 127.0.0.1:6379> del name
删除这个 key 及对应的 value
验证键是否存在
redis 127.0.0.1:6379> exists name
(integer) 0
在上面的例子中,SET 和 GET 是 Redis STRING命令,name 和 itcast 是存储在 Redis 的键和字符串值。
Hash 哈希
Redis hash 是一个键值对集合。
Redis hash是一个string类型的field和value的映射表,hash特别适合用于存储对象。
127.0.0.1:6379> HMSET my_hash_table username itcast age 18 sex male
OK
127.0.0.1:6379> HGETALL my_hash_table
1) "username"
2) "itcast"
3) "age"
4) "18"
5) "sex"
6) "male"
在上面的例子中,哈希数据类型用于存储包含用户基本信息的用户对象。
这里 HSET,HGETALL 是 Redis HASHES命令, 同时 my_hash_table 也是一个键。
List 列表
Redis 列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边)。
redis 127.0.0.1:6379> lpush tutorial_list redis
(integer) 1
redis 127.0.0.1:6379> lpush tutorial_list mongodb
(integer) 2
redis 127.0.0.1:6379> lpush tutorial_list rabbitmq
(integer) 3
redis 127.0.0.1:6379> lrange tutorial_list 0 10
1) "rabitmq"
2) "mongodb"
3) "redis"
列表最多可存储 232 - 1 元素 (4294967295, 每个列表可存储40多亿)。
Set 集合
Redis Set是string类型的无序集合。
集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是O(1)。
在 Redis 可以添加,删除和测试成员存在的时间复杂度为 O(1)。
127.0.0.1:6379> sadd myset redis
(integer) 1
127.0.0.1:6379> sadd myset mongodb
(integer) 1
127.0.0.1:6379> sadd myset rabitmq
(integer) 1
127.0.0.1:6379> sadd myset rabitmq
(integer) 0
127.0.0.1:6379> smembers myset
1) "mongodb"
2) "redis"
3) "rabitmq"
注:在上面的例子中 rabitmq 被添加两次,但由于它是只集合具有唯一特性。
集合中最大的成员数为 \(2^{32}\)
zset(sorted set:有序集合)
Redis zset 和 set 一样也是string类型元素的集合,且不允许重复的成员。
不同的是每个元素都会关联一个double类型的分数(权重)。redis正是通过分数来为集合中的成员(权重)进行从小到大的排序。
zset的成员是唯一的,但分数(score)却可以重复。
127.0.0.1:6379> zadd mysortset 0 redis
(integer) 1
127.0.0.1:6379> zadd mysortset 2 mongodb
(integer) 1
127.0.0.1:6379> zadd mysortset 1 rabitmq
(integer) 1
127.0.0.1:6379> ZRANGEBYSCORE mysortset 0 1000
1) "redis"
2) "rabitmq"
3) "mongodb"
请求/响应协议和RTT
Redis是一种基于客户端-服务端模型以及请求/响应协议的TCP服务。
这意味着通常情况下一个请求会遵循以下步骤:
- 客户端向服务端发送一个查询请求,并监听Socket返回,通常是以阻塞模式,等待服务端响应。
- 服务端处理命令,并将结果返回给客户端。
Client: INCR X
Server: 1
Client: INCR X
Server: 2
Client: INCR X
Server: 3
Client: INCR X
Server: 4
客户端和服务器通过网络进行连接。这个连接可以很快(loopback接口)或很慢(建立了一个多次跳转的网络连接)。无论网络延如何延时,数据包总是能从客户端到达服务器,并从服务器返回数据回复客户端。
这个时间被称之为 RTT (Round Trip Time - 往返时间). 当客户端需要在一个批处理中执行多次请求时很容易看到这是如何影响性能的(例如添加许多元素到同一个list,或者用很多Keys填充数据库)。例如,如果RTT时间是250毫秒(在一个很慢的连接下),即使服务器每秒能处理100k的请求数,我们每秒最多也只能处理4个请求。
如果采用loopback接口,RTT就短得多(比如我的主机ping 127.0.0.1只需要44毫秒),但它仍然是一笔很多的开销在一次批量写入操作中。
幸运的是有一种方法可以改善这种情况。
Redis 管道(Pipelining)
一次请求/响应服务器能实现处理新的请求即使旧的请求还未被响应。这样就可以将多个命令发送到服务器,而不用等待回复,最后在一个步骤中读取该答复。
这就是管道(pipelining),是一种几十年来广泛使用的技术。例如许多POP3协议已经实现支持这个功能,大大加快了从服务器下载新邮件的过程。
Redis很早就支持管道(pipelining)技术,因此无论你运行的是什么版本,你都可以使用管道(pipelining)操作Redis。下面是一个使用的例子:
$ (printf "PING\r\nPING\r\nPING\r\n"; sleep 1) | nc localhost 6379
+PONG
+PONG
+PONG
这一次我们没有为每个命令都花费了RTT开销,而是只用了一个命令的开销时间。
非常明确的,用管道顺序操作的第一个例子如下:
Client: INCR X
Client: INCR X
Client: INCR X
Client: INCR X
Server: 1
Server: 2
Server: 3
Server: 4
重要说明:
使用管道发送命令时,服务器将被迫回复一个队列答复,占用很多内存。所以,如果你需要发送大量的命令,最好是把他们按照合理数量分批次的处理,例如10K的命令,读回复,然后再发送另一个10k的命令,等等。这样速度几乎是相同的,但是在回复这10k命令队列需要非常大量的内存用来组织返回数据内容。
内存优化
当Redis中存在无效缓存会降低数据IO性能。具体表现为数据持久化以及主从复制
内存压缩
Redis2.2版本及以后,存储集合数据的时候会采用内存压缩技术,以使用更少的内存存储更多的数据。如Hashes,Lists,Sets和Sorted Sets,当这些集合中的所有数都小于一个给定的元素,并且集合中元素数量小于某个值时,存储的数据会被以一种非常节省内存的方式进行编码,使用这种编码理论上至少会节省10倍以上内存(平均节省5倍以上内存)。并且这种编码技术对用户和redis api透明。因为使用这种编码是用CPU换内存,所以我们提供了更改阈值的方法,只需在redis.conf里面进行修改即可.
## 最大键值元素个数
hash-max-zipmap-entries 64 (2.6以上使用hash-max-ziplist-entries)
## 最大键值长度 单位字节
hash-max-zipmap-value 512 (2.6以上使用hash-max-ziplist-value)
list-max-ziplist-entries 512
list-max-ziplist-value 64
zset-max-ziplist-entries 128
zset-max-ziplist-value 64
set-max-intset-entries 512
(集合中)如果某个值超过了配置文件中设置的最大值,redis将自动把把它(集合)转换为正常的散列表。这种操作对于比较小的数值是非常快的,但是,如果你为了使用这种编码技术而把配置进行了更改,你最好做一下基准测试(和正常的不采用编码做一下对比).
内存分配
为了存储用户数据,当设置了maxmemory后Redis会分配几乎和maxmemory一样大的内存(然而也有可能还会有其他方面的一些内存分配)
- 当某些缓存被删除后Redis并不是总是立即将内存归还给操作系统。这并不是redis所特有的,而是函数malloc()的特性。例如你缓存了5G的数据,然后删除了2G数据,从操作系统看,redis可能仍然占用了5G的内存(这个内存叫RSS,后面会用到这个概念),即使redis已经明确声明只使用了3G的空间。这是因为redis使用的底层内存分配器不会这么简单的就把内存归还给操作系统,可能是因为已经删除的key和没有删除的key在同一个页面(page),这样就不能把完整的一页归还给操作系统.
- 上面的一点意味着,你应该基于你可能会用到的 最大内存 来指定redis的最大内存。如果你的程序时不时的需要10G内存,即便在大多数情况是使用5G内存,你也需要指定最大内存为10G.
- 内存分配器是智能的,可以复用用户已经释放的内存。所以当使用的内存从5G降低到3G时,你可以重新添加更多的key,而不需要再向操作系统申请内存。分配器将复用之前已经释放的2G内存.
因为这些,当redis的peak内存非常高于平时的内存使用时,碎片所占可用内存的比例就会波动很大。当前使用的内存除以实际使用的物理内存(RSS)就是fragmentation;因为RSS就是peak memory,所以当大部分key被释放的时候,此时内存的mem_used / RSS就比较高.
如果 maxmemory 没有设置,Redis就会一直向OS申请内存,直到OS的所有内存都被使用完(针对 32 位实例,Redis 就做了限制,它的最大可用内存将限制在 3 GB)。所以通常建议设置上redis的内存限制。或许你也想设置 maxmemory-policy 的值为 noeviction(在redis的某些老版本默认 并 不是这样)
设置了maxmemory后,当redis的内存达到内存限制后,再向redis发送写指令,会返回一个内存耗尽的错误。错误通常会触发一个应用程序错误,但是不会导致整台机器宕掉.
内存碎片
什么是内存碎片?
操作系统为你分配了 32 字节的连续内存空间,而你存储数据实际只需要使用 24 字节内存空间,那这多余出来的 8 字节内存空间如果后续没办法再被分配存储其他数据的话,就可以被称为内存碎片。
内存分配有静态分配和动态分配两种。
静态分配在程序编译链接时分配的大小和使用寿命就已经确定,而应用上要求操作系统可以提供给进程运行时申请和释放任意大小内存的功能,这就是内存的动态分配。
因此动态分配将不可避免会产生内存碎片的问题,那么什么是内存碎片?内存碎片即“碎片的内存”描述一个系统中所有不可用的空闲内存,这些碎片之所以不能被使用,是因为负责动态分配内存的分配算法使得这些空闲的内存无法使用,这一问题的发生,原因在于这些空闲内存以小且不连续方式出现在不同的位置。因此这个问题的或大或小取决于内存管理算法的实现上。
为什么会产生这些小且不连续的空闲内存碎片呢?
实际上这些空闲内存碎片存在的方式有两种:a.内部碎片 b.外部碎片 。
内部碎片的产生:因为所有的内存分配必须起始于可被 4、8 或 16 整除(视处理器体系结构而定)的地址或者因为MMU的分页机制的限制,决定内存分配算法仅能把预定大小的内存块分配给客户。假设当某个客户请求一个 43 字节的内存块时,因为没有适合大小的内存,所以它可能会获得 44字节、48字节等稍大一点的字节,因此由所需大小四舍五入而产生的多余空间就叫内部碎片。
外部碎片的产生: 频繁的分配与回收物理页面会导致大量的、连续且小的页面块夹杂在已分配的页面中间,就会产生外部碎片。假设有一块一共有100个单位的连续空闲内存空间,范围是099。如果你从中申请一块内存,如10个单位,那么申请出来的内存块就为09区间。这时候你继续申请一块内存,比如说5个单位大,第二块得到的内存块就应该为1014区间。如果你把第一块内存块释放,然后再申请一块大于10个单位的内存块,比如说20个单位。因为刚被释放的内存块不能满足新的请求,所以只能从15开始分配出20个单位的内存块。现在整个内存空间的状态是09空闲,1014被占用,1534被占用,2599空闲。其中09就是一个内存碎片了。如果1014一直被占用,而以后申请的空间都大于10个单位,那么09就永远用不上了,变成外部碎片。
Redis 内存碎片虽然不会影响 Redis 性能,但是会增加内存消耗。
Redis 内存碎片产生比较常见的 2 个原因:
1、Redis 存储存储数据的时候向操作系统申请的内存空间可能会大于数据实际需要的存储空间。
Redis 使用 zmalloc 方法(Redis 自己实现的内存分配方法)进行内存分配的时候,除了要分配 size 大小的内存之外,还会多分配 PREFIX_SIZE 大小的内存。
void *zmalloc(size_t size) {
// 分配指定大小的内存
void ptr = malloc(size+PREFIX_SIZE);
if (!ptr) zmalloc_oom_handler(size);
#ifdef HAVE_MALLOC_SIZE
update_zmalloc_stat_alloc(zmalloc_size(ptr));
return ptr;
#else
((size_t)ptr) = size;
update_zmalloc_stat_alloc(size+PREFIX_SIZE);
return (char)ptr+PREFIX_SIZE;
#endif
}
另外,Redis 可以使用多种内存分配器来分配内存( libc、jemalloc、tcmalloc),默认使用 jemalloc,而 jemalloc 按照一系列固定的大小(8 字节、16 字节、32 字节…)来分配内存的。jemalloc 划分的内存单元如下图所示:
当程序申请的内存最接近某个固定值时,jemalloc 会给它分配相应大小的空间,就比如说程序需要申请 17 字节的内存,jemalloc 会直接给它分配 32 字节的内存,这样会导致有 15 字节内存的浪费。不过,jemalloc 专门针对内存碎片问题做了优化,一般不会存在过度碎片化的问题。
2、频繁修改 Redis 中的数据也会产生内存碎片。
当 Redis 中的某个数据删除时,Redis 通常不会轻易释放内存给操作系统。
过期
Redis如何淘汰过期的keys
超时后只有对key执行DEL命令或者SET命令或者GETSET时才会清除。 这意味着,从概念上讲所有改变key的值的操作都会使他清除。
Redis keys过期有两种方式:被动和主动方式。
当一些客户端尝试访问它时,key会被发现并主动的过期。
当然,这样是不够的,因为有些过期的keys,永远不会访问他们。 无论如何,这些keys应该过期,所以定时随机测试设置keys的过期时间。所有这些过期的keys将会从密钥空间删除。
具体就是Redis每秒10次做的事情:
- 测试随机的20个keys进行相关过期检测。
- 删除所有已经过期的keys。
- 如果有多于25%的keys过期,重复步奏1
这是一个平凡的概率算法,基本上的假设是,我们的样本是这个密钥控件,并且我们不断重复过期检测,直到过期的keys的百分百低于25%,这意味着,在任何给定的时刻,最多会清除1/4的过期keys。
定期删除:指Redis每隔一段时间进行定期扫描(默认10秒),扫描十次,每次扫描20个key,删除其中过期的key,若过期比例超过1/4,则判定过期key较多,再次重复此操作。
惰性删除:在定期删除的情况下会存在部分过期key无法删除的情况,惰性删除在读写key时会将过期key直接删除。
内存淘汰
Maxmemory配置指令maxmemory 100mb
设置maxmemory为0代表没有内存限制。对于64位的系统这是个默认值,对于32位的系统默认内存限制为3GB。
当数据内存达到 maxmemory 时,便会触发redis的内存淘汰策略(我们一般会将该参数设置为物理内存的四分之三,过期策略是指正常情况下清除过期键,内存淘汰是指内存超过最大值时的保护策略)。
- volatile-lru,针对设置了过期时间的key,使用lru算法进行淘汰。
- allkeys-lru,针对所有key使用lru算法进行淘汰。
- volatile-lfu,针对设置了过期时间的key,使用lfu算法进行淘汰。
- allkeys-lfu,针对所有key使用lfu算法进行淘汰。
- volatile-random,从所有设置了过期时间的key中使用随机淘汰的方式进行淘汰。
- allkeys-random,针对所有的key使用随机淘汰机制进行淘汰。
- volatile-ttl,针对设置了过期时间的key,越早过期的越先被淘汰。
- noeviction,不会淘汰任何数据,当使用的内存空间超过 maxmemory 值时,再有写请求来时返回错误。
除了比较特殊的noeviction与volatile-ttl,其余6种策略都有一定的关联性。我们可以通过前缀将它们分为2类,volatile-与allkeys-,这两类策略的区别在于二者选择要清除的键时的字典不同,volatile-前缀的策略代表从设置了过期时间的key中选择键进行清除;allkeys-开头的策略代表从所有key中选择键进行清除。
事务
- Multi 开启事务
- Exec 提交
- Discard 放弃事务
me:0>set "name" "phy"
"OK"
me:0>MULTI
"OK"
me:0>get "name" "phy2"
"ERR wrong number of arguments for 'get' command"
me:0>get "name"
"QUEUED"
me:0>set "name" "phy2"
"QUEUED"
me:0>exec
"EXECABORT Transaction discarded because of previous errors."
Redis 开启事务,会把后续的指令全部存放到队列,提交后连续执行,如果在EXEC指令被提交之前,Redis-server即检测到提交的某个指令存在语法错误,那么此事务将会被提前标记为DISCARD,此后事务提交也将直接被驳回;但是如果在EXEC提交后,在实施数据变更时(Redis将不会预检测数据类型,比如你对一个“非数字”类型的key执行INCR操作),某个操作导致了ERROR,那么redis仍然不会回滚此前已经执行成功的操作,而且也不会中断ERROR之后的其他操作继续执行。对于开发者而言,你务必关注事务执行后返回的结果(结果将是一个集合,按照操作提交的顺序排列,对于执行失败的操作,结果将是一个ERROR)。
持久化
目前Redis持久化的方式有两种: RDB 和 AOF
持久化的数据有什么用,答案是: 用于重启后的数据恢复
RDB
RDB就是Snapshot快照存储,是默认的持久化方式。可理解为半持久化模式
即按照一定的策略周期性的将数据保存到磁盘。对应产生的数据文件为dump.rdb,快照的周期通过配置文件中的save参数来定义。
dbfilename dump.rdb
# save <seconds> <changes>
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重启是会通过重新执行文件中保存的写命令来在内存中重建整个数据库的内容。
在Redis重启时会逐个执行AOF文件中的命令来将硬盘中的数据载入到内存中,所以说,载入的速度相较RDB会慢一些
- 默认情况下,Redis没有开启AOF方式的持久化,可以在redis.conf中通过appendonly参数开启:
appendonly yes #启用aof持久化方式
appendfsync always #每次收到写命令就立即强制写入磁盘,最慢的,但是保证完全的持久化,不推荐使用
appendfsync everysec #每秒钟强制写入磁盘一次,在性能和持久化方面做了很好的折中,推荐
appendfsync no #完全依赖OS的写入,一般为30秒左右一次,性能最好但是持久化最没有保证,不被推荐。
AOF文件和RDB文件的保存文件夹位置相同,都是通过dir参数设置的,默认的文件名是appendonly.aof,可以通过appendfilename参数修改
appendfilename appendonly.aof
- AOF的完全持久化方式同时也带来了另一个问题,持久化文件会变得越来越大。
比如: 我们调用INCR test 命令100次,文件中就必须保存全部的100条命令,但其实99条都是多余的。
因为要恢复数据库的状态其实文件中保存一条SET test 100就够了。
为了压缩AOF的持久化文件,Redis提供了bgrewriteaof命令。收到此命令后Redis将使用与快照类似的方式将内存中的数据以命令的方式保存到临时文件中,最后替换原来的文件,以此来实现控制AOF文件的增长。
配置redis自动重写AOF文件的参数
no-appendfsync-on-rewrite yes #在AOF重写时,不进行命令追加操作,而只是将其放在缓冲区里,避免与命令的追加造成DISK IO上的冲突。
auto-aof-rewrite-percentage 100 #当前AOF文件大小是上次日志重写得到AOF文件大小的二倍时,自动启动新的日志重写过程。
auto-aof-rewrite-min-size 64mb #当前AOF文件启动新的日志重写过程的最小值,避免刚刚启动Reids时由于文件尺寸较小导致频繁的重写。
Redis混合持久和非混合持久化的AOF重写有什么区别?
Redis 的混合持久化模式和非混合持久化模式下的 AOF 重写过程是相同的,都是通过读取当前数据库中的数据以及内存中的命令缓存来重建新的 AOF 文件,并去除旧 AOF 文件中的冗余命令,从而减小 AOF 文件的大小。但是在混合持久化模式下,AOF 重写会从内存中获取更多的信息,包括了 RDB 持久化中保存的键值对,从而缩短了重写的时间,并且节省了对磁盘的 I/O 操作。另外,在混合持久化模式下,Redis 还可以继续接受命令请求,而不必等待 AOF 重写完成,这是与非混合持久化模式下最大的区别。
细说一下aof持久化下的aof重写
在AOF持久化模式下,Redis将所有的写操作追加到AOF文件的尾部,用于记录数据的修改。随着业务的不断发展,AOF文件会越来越大,导致AOF恢复时需要读取整个AOF文件,拖慢恢复速度,同时也会增加内存占用。
为了解决这个问题,Redis引入了AOF重写机制。AOF重写是通过读取Redis服务器当前内存中的数据集来实现的。Redis后台进程会将当前的数据集转换成一个新的AOF文件,这个新的AOF文件和原有的AOF文件所表示的数据库状态一样,但体积更小。
在AOF重写过程中,Redis会分析命令日志中的写命令,并将它们转换为更紧凑的格式,例如,多次对同一个键进行的写操作只保留最后一次操作。这种方式可以大大减小AOF文件的体积。
在重写期间,Redis继续处理命令请求,新的写操作会被追加到新的AOF文件的末尾。完成AOF重写后,Redis将新的AOF文件替换旧的AOF文件,从而完成AOF大小的压缩。
细说一下混合持久化下的aof重写
混合持久化模式下的AOF重写是指将AOF文件和RDB文件相结合来进行数据持久化。在这种模式下,Redis会在RDB快照和AOF日志之间进行切换,以便在发生故障时更快地恢复数据。同时,Redis还会定期生成RDB快照,以防止AOF文件过大。
在混合持久化模式下,AOF重写机制仍然有效。当触发AOF重写时,Redis会根据当前内存中的数据集生成一个新的AOF文件,并且只保留最近一次完整的RDB快照。AOF重写的流程和AOF持久化模式下相同,但是在完成AOF重写后,Redis不会删除旧的AOF文件或者RDB文件,而是将它们作为历史备份留存。
需要注意的是,在混合持久化模式下,如果Redis在AOF重写期间崩溃或停止运行,可能会出现数据损坏或丢失的情况。因此,在使用混合持久化模式时,建议采用多副本、异地备份等策略来保证数据的可靠性。
细说一下混合持久化怎么操作的
混合持久化是将AOF和RDB两种持久化方式结合起来,以实现更好的数据可靠性和灵活性。在混合持久化模式下,Redis会同时维护AOF日志和RDB快照,并且可以根据实际需求动态地调整AOF和RDB的持久化策略。
1、启用混合持久化
在Redis配置文件中,使用以下选项启用混合持久化:
appendonly yes
appendfsync always
save 900 1
save 300 10
save 60 10000
其中,appendonly yes表示开启AOF持久化,appendfsync always表示将每个写命令都同步到磁盘上,save选项则表示定期执行RDB快照。
2、调整AOF重写规则
在混合持久化模式下,AOF重写机制和AOF持久化模式下相同。可以通过修改以下选项来调整AOF重写规则:
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
其中,auto-aof-rewrite-percentage表示当AOF文件大小增长到原始大小的百分之多少时触发AOF重写,默认值为100,即当AOF文件大小达到原始大小的两倍时触发AOF重写;auto-aof-rewrite-min-size表示AOF重写后生成的新文件最小大小,如果新文件大小低于这个值不会进行AOF重写。
3、手动执行AOF重写
可以使用以下命令手动触发AOF重写:
BGREWRITEAOF
该命令会在后台异步地执行AOF重写操作,期间Redis仍然可以继续处理命令请求。完成AOF重写后,Redis会自动将新的AOF文件替换旧的AOF文件。
4、手动执行RDB快照
可以使用以下命令手动触发RDB快照操作:
BGSAVE
该命令会在后台异步地执行RDB快照操作,期间Redis仍然可以继续处理命令请求。完成RDB快照后,Redis会将快照文件保存到磁盘上。
需要注意的是,在混合持久化模式下,当同时进行AOF重写和RDB快照操作时,Redis会先执行RDB快照,再进行AOF重写。这样做可以保证AOF文件中包含最新的数据。
主从复制
集群
安全策略
场景