Redis面试题

你在项目上缓存是怎么使用的,缓存如果使用不当会出现什么后果?

项目状态采取redis缓存,为了高性能和高并发。
一个请求过来需要走业务逻辑来判断切换的页面状态,一系列的mysql操作可能需要耗时600ms,然后丢到缓存中一个key value,通过key查出value只要2ms。
下次再访问的时候只需要从缓存中读就好了。

高并发:mysql单机2000qps,高峰期肯定会炸的,而缓存单机支撑的并发一秒十几万。

缓存说白了就是三个问题:
1)数据一致性问题
2)缓存雪崩
3)缓存穿透
4)缓存的并发竞争

缓存雪崩:高峰期的时候会来5000个请求,此时redis挂了,那么1s过来的5000请求直接落在数据库上,单机mysql能抗住的qps是2000。
解决缓存雪崩通常解决思路:
1)保证redis集群高可用,并且需要持久化机制便于事后恢复
2)本地采取ehcache缓存+hystrix限流组件【限流2000】剩下的3000走降级组件
3)这样通过限流组件确保了每秒只会过去2000个请求到数据库

缓存穿透
5000个请求,万一有4000个请求都是恶意请求不存在的数据,那么变会都请求数据库
通常采取的方式:1)布隆过滤器,把所有可能存在的数据hash到一个足够大的bigmap中,不存在的数据会被bigmap拦截掉,减少对底层数据库的压力
2)如果查询为空,把这个空的结果也缓存起来,过期时间设置为5分钟

缓存击穿
对于一些时间热点的key,在某个时间会被超高并发访问,如果存在某个时间点,这些热点都集体失效,那么大量的请求就会落到数据库上。
解决思路:限流组件hystrix

redis和memcached有什么区别?redis的线程模型是啥?为啥单线程的redis比多线程的memcached效率要高?(为什么redis是单线程还能支持高并发?)
区别:
redis支持服务器端的操作:相比于memcached而言,有更多的数据结构和支持更丰富的数据操作。
在memcached,通常需要把数据拿到客户端进行类似的修改再set回去,增加了网络io的次数和数据体积。
内存使用高效率:单纯的k-v是memcached高,但是采取hash结构的话,内存利用率是redis高
性能对比:由于redis只使用单核,memcached可以使用多核,所以平均每个核上redis存储小数据比memcached高,但是100k以上的数据,memcached性能高于redis
集群模式:memcached没有原生的集群模式,需要依靠客户端来实现往集群分片中写入数据,但是redis目前是原生支持cluster模式。

redis的线程模型:
redis是基于reactor模式开发了网络事件处理器,也叫文件事件处理器。
这个文件事件处理器是单线程的,所以redis也被叫做单线程的模型。
原理是通过采取IO多路复用机制同时监听几个socket,根据socket的时间来选择对应的事件处理器。
socket有accept,read,write,close等事件
通过上面的形式实现了高性能的通信模型【想到啥了,没错就是NIO】

文件事件:
当socket变得可读时,或者有新的应答的socket出现时,socket会产生一个AE_READABLE事件
当socket变得可些时,socket会产生一个AE_WRITEABLE事件
当IO多路复用同事监听AE_READABLE和AE_WRITEABLE事件,要是一个socket同时监听到这俩种时间,那么文件事件分派器优先处理read事件然后才是write事件

文件事件处理器:
连接redis,为socket关联连接应答处理器
写redis,为socket关联命令请求处理器
读redis,为socket关联命令回复处理器

客户端和redis通信的一次流程
在redis启动初始化的时候,redis会把连接应答处理器和AE_READABLE事件关联起来,接着如果一个客户端跟redis发起连接,此时会产生一个AE_readable事件,然后由连接应答处理器来处理和客户端的连接,创建客户端对应的socket,同时把socket的ae_readable事件和命令请求处理器关联起来

当客户端向redis发起请求时候,先会在socket中产生一个readable的事件,然后由命令请求处理器来处理,然后从socket读取请求的相关数据,进行执行和处理。接着redis这边准备好给客户端的响应数据之后,会在socket上产生一个writeable事件,会由对应的命令回复处理器来处理,把准备好的响应数据写入socket,给客户端读取。

命令回复处理器写完之后,就会删除这个socket的write事件和命令回复处理器的关联关系。

redis单线程效率高的问题:
1)纯内存操作
2)核心的nio的io多路复用
3)单线程反而避免了多线程的频繁上下文切换

redis都有哪些数据类型啊?分别在什么场景下使用比较好啊?

string :这是最基本的类型, set 和get 做简单的k-v的缓存
hash:这是类似map的结构,就是可以结构化的数据,比如一个对象。
key=001
value={
“id”:001,
“name”:“joe”
“age”:20
}
主要是缓存一些对象,这样后续我们可以操作的话只修改对象中某个字段。
list:有序列表
就以微博为例,某个大V的粉丝就可以以list的格式来放在redis缓存中
可以通过list来存储列表型的数据结构比如粉丝列表啊,评论列表之类的,可以通过lrange命令来从某个元素开始到某个元素,实现分页。或者可以利用他的有序性做简单的消息队列。
set:无序集合,自动去重
可以用它做分布式情况下的全局去重。
比如说俩个明星的粉丝我们可以利用set来整一个交集,看下他们俩的共同好友是谁?
sorted set:有序集合 自动去重
也可以排序,根据时间或者分数等等排序。

redis的过期策略都有哪些?内存淘汰机制都有哪些?手写一下LRU算法?
redis是可以设置过期时间的 ,在set的时候都可以给一个expiretime,过期时间。
定期删除和惰性删除。
redis默认每隔100ms就随机抽取一些设置了过期时间的key,检查是否过期,过期则删除。
定期删除是随机抽取一部分并不是全部,所以可能会导致很多过期key到了时间没有被删除掉。
所以这边会有一个机制,当你去get一个key的时候,redis会检查一下这个key是否过期了,如果
过期了,那么就删除,这就是惰性删除。

如果说上面俩种情况下还有大量的过期key堆积在内存里,导致redis内存块耗尽,那么redis就会走内存淘汰机制。
redis有六种淘汰机制:
1)noeviction:当内存不足以容纳新数据,新写入数据报错【这种一般没有人用】
2)allkeys-lru:当内存不足以容纳新的数据,移除最近最少使用的key【最常用】
3)allkeys-random:内存不足。随机溢出某个key
4)volatile-lru:当内存不足,在设置了过期时间的key中移除,最近最少使用的key
5)volatile-random:内存不足,在设置了过期时间的key中随机移除一个key
6) volatile-ttl:内存不足,在设置过期时间的key中,有更早过期时间的key被移除

手写lru
package com.allen.test;

import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.Map;

public class LRULinkedHashMap<K, V> {

// 最大缓存大小
private int cacheSize;

private LinkedHashMap<K, V> cacheMap;

public LRULinkedHashMap(int cacheSize) {
	this.cacheSize = cacheSize;
	cacheMap = new LinkedHashMap<K, V>(16, 0.75F, true) {
		protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
			if (cacheSize + 1 == cacheMap.size()) {
				return true;
			} else {
				return false;
			}
		}
	};
}

public void put(K key,V value){
	cacheMap.put(key, value);
}

public V get(K key){
	return cacheMap.get(key);
}

public Collection<Map.Entry<K, V>> getAll(){
	return new ArrayList<Map.Entry<K, V>>(cacheMap.entrySet());
}

}

如何保证redis的高并发和高可用?redis的主从复制管理介绍下?redis的哨兵原理能介绍下?

redis的高并发的实现:【本质就是读写分离】
首先先理解一个常识,单机的redis能够承载的qps是上万到几万不等,如果qps在10万+,那单机的redis肯定是会崩的。
所以处理处理高并发说白了就是分流,redis采取主从的模式,对于落到redis上的操作我们区分为读和写。正常情况下,读操作的数量都是大于写的,所以我们把所有的读操作落在slave上,所有的写操作落在master上,然后master把数据同步到所有的slave上。

redis replication–》主从架构–》读写分离–》水平扩容支撑读写高并发
replication的核心机制:
1)redis采用异步方式复制数据到slave节点,不过redis 2.8开始,slave node会周期性地确认自己每次复制的数据量
(2)一个master node是可以配置多个slave node的
(3)slave node也可以连接其他的slave node
(4)slave node做复制的时候,是不会block master node的正常工作的
(5)slave node在做复制的时候,也不会block对自己的查询操作,它会用旧的数据集来提供服务; 但是复制完成的时候,需要删除旧数据集,加载新数据集,这个时候就会暂停对外服务了
(6)slave node主要用来进行横向扩容,做读写分离,扩容的slave node可以提高读的吞吐量

所以master节点必须要做持久化操作

redis主从复制的原理:

1 主从架构的核心原理

当启动一个slave node的时候,它会发送一个PSYNC命令给master node

如果这是slave node重新连接master node,那么master node仅仅会复制给slave部分缺少的数据; 否则如果是slave node第一次连接master node,那么会触发一次full resynchronization

开始full resynchronization的时候,master会启动一个后台线程,开始生成一份RDB快照文件,同时还会将从客户端收到的所有写命令缓存在内存中。RDB文件生成完毕之后,master会将这个RDB发送给slave,slave会先写入本地磁盘,然后再从本地磁盘加载到内存中。然后master会将内存中缓存的写命令发送给slave,slave也会同步这些数据。

slave node如果跟master node有网络故障,断开了连接,会自动重连。master如果发现有多个slave node都来重新连接,仅仅会启动一个rdb save操作,用一份数据服务所有slave node

2 主从复制的断点续传
从redis 2.8开始,就支持主从复制的断点续传,如果主从复制过程中,网络连接断掉了,那么可以接着上次复制的地方,继续复制下去,而不是从头开始复制一份
master node会在内存中常见一个backlog,master和slave都会保存一个replica offset还有一个master id,offset就是保存在backlog中的。如果master和slave网络连接断掉了,slave会让master从上次的replica offset开始继续复制
但是如果没有找到对应的offset,那么就会执行一次resynchronization

3、无磁盘化复制
master在内存中直接创建rdb,然后发送给slave,不会在自己本地落地磁盘了
repl-diskless-sync
repl-diskless-sync-delay,等待一定时长再开始复制,因为要等更多slave重新连接过来

4、过期key处理
slave不会过期key,只会等待master过期key。如果master过期了一个key,或者通过LRU淘汰了一个key,那么会模拟一条del命令发送给slave。

1、复制的完整流程

(1)slave node启动,仅仅保存master node的信息,包括master node的host和ip,但是复制流程没开始

master host和ip是从哪儿来的,redis.conf里面的slaveof配置的

(2)slave node内部有个定时任务,每秒检查是否有新的master node要连接和复制,如果发现,就跟master node建立socket网络连接
(3)slave node发送ping命令给master node
(4)口令认证,如果master设置了requirepass,那么salve node必须发送masterauth的口令过去进行认证
(5)master node第一次执行全量复制,将所有数据发给slave node
(6)master node后续持续将写命令,异步复制给slave node

2、数据同步相关的核心机制

指的就是第一次slave连接msater的时候,执行的全量复制,那个过程里面你的一些细节的机制

(1)master和slave都会维护一个offset

master会在自身不断累加offset,slave也会在自身不断累加offset
slave每秒都会上报自己的offset给master,同时master也会保存每个slave的offset

这个倒不是说特定就用在全量复制的,主要是master和slave都要知道各自的数据的offset,才能知道互相之间的数据不一致的情况

(2)backlog

master node有一个backlog,默认是1MB大小
master node给slave node复制数据时,也会将数据在backlog中同步写一份
backlog主要是用来做全量复制中断候的增量复制的

(3)master run id

info server,可以看到master run id
如果根据host+ip定位master node,是不靠谱的,如果master node重启或者数据出现了变化,那么slave node应该根据不同的run id区分,run id不同就做全量复制
如果需要不更改run id重启redis,可以使用redis-cli debug reload命令

(4)psync

从节点使用psync从master node进行复制,psync runid offset
master node会根据自身的情况返回响应信息,可能是FULLRESYNC runid offset触发全量复制,可能是CONTINUE触发增量复制

3、全量复制

(1)master执行bgsave,在本地生成一份rdb快照文件
(2)master node将rdb快照文件发送给salve node,如果rdb复制时间超过60秒(repl-timeout),那么slave node就会认为复制失败,可以适当调节大这个参数
(3)对于千兆网卡的机器,一般每秒传输100MB,6G文件,很可能超过60s
(4)master node在生成rdb时,会将所有新的写命令缓存在内存中,在salve node保存了rdb之后,再将新的写命令复制给salve node
(5)client-output-buffer-limit slave 256MB 64MB 60,如果在复制期间,内存缓冲区持续消耗超过64MB,或者一次性超过256MB,那么停止复制,复制失败
(6)slave node接收到rdb之后,清空自己的旧数据,然后重新加载rdb到自己的内存中,同时基于旧的数据版本对外提供服务
(7)如果slave node开启了AOF,那么会立即执行BGREWRITEAOF,重写AOF

rdb生成、rdb通过网络拷贝、slave旧数据的清理、slave aof rewrite,很耗费时间

如果复制的数据量在4G~6G之间,那么很可能全量复制时间消耗到1分半到2分钟

4、增量复制

(1)如果全量复制过程中,master-slave网络连接断掉,那么salve重新连接master时,会触发增量复制
(2)master直接从自己的backlog中获取部分丢失的数据,发送给slave node,默认backlog就是1MB
(3)msater就是根据slave发送的psync中的offset来从backlog中获取数据的

5、heartbeat

主从节点互相都会发送heartbeat信息

master默认每隔10秒发送一次heartbeat,salve node每隔1秒发送一个heartbeat

6、异步复制

master每次接收到写命令之后,现在内部写入数据,然后异步发送给slave node

1、哨兵的介绍

sentinal,中文名是哨兵

哨兵是redis集群架构中非常重要的一个组件,主要功能如下

(1)集群监控,负责监控redis master和slave进程是否正常工作
(2)消息通知,如果某个redis实例有故障,那么哨兵负责发送消息作为报警通知给管理员
(3)故障转移,如果master node挂掉了,会自动转移到slave node上
(4)配置中心,如果故障转移发生了,通知client客户端新的master地址

哨兵本身也是分布式的,作为一个哨兵集群去运行,互相协同工作

(1)故障转移时,判断一个master node是宕机了,需要大部分的哨兵都同意才行,涉及到了分布式选举的问题
(2)即使部分哨兵节点挂掉了,哨兵集群还是能正常工作的,因为如果一个作为高可用机制重要组成部分的故障转移系统本身是单点的,那就很坑爹了

目前采用的是sentinal 2版本,sentinal 2相对于sentinal 1来说,重写了很多代码,主要是让故障转移的机制和算法变得更加健壮和简单

2、哨兵的核心知识

(1)哨兵至少需要3个实例,来保证自己的健壮性
(2)哨兵 + redis主从的部署架构,是不会保证数据零丢失的,只能保证redis集群的高可用性
(3)对于哨兵 + redis主从这种复杂的部署架构,尽量在测试环境和生产环境,都进行充足的测试和演练

3、为什么redis哨兵集群只有2个节点无法正常工作?

哨兵集群必须部署2个以上节点

如果哨兵集群仅仅部署了个2个哨兵实例,quorum=1

±—+ ±—+
| M1 |---------| R1 |
| S1 | | S2 |
±—+ ±—+

Configuration: quorum = 1

master宕机,s1和s2中只要有1个哨兵认为master宕机就可以还行切换,同时s1和s2中会选举出一个哨兵来执行故障转移

同时这个时候,需要majority,也就是大多数哨兵都是运行的,2个哨兵的majority就是2(2的majority=2,3的majority=2,5的majority=3,4的majority=2),2个哨兵都运行着,就可以允许执行故障转移

但是如果整个M1和S1运行的机器宕机了,那么哨兵只有1个了,此时就没有majority来允许执行故障转移,虽然另外一台机器还有一个R1,但是故障转移不会执行

4、经典的3节点哨兵集群

   +----+
   | M1 |
   | S1 |
   +----+
      |

±—+ | ±—+
| R2 |----±—| R3 |
| S2 | | S3 |
±—+ ±—+

Configuration: quorum = 2,majority

如果M1所在机器宕机了,那么三个哨兵还剩下2个,S2和S3可以一致认为master宕机,然后选举出一个来执行故障转移

同时3个哨兵的majority是2,所以还剩下的2个哨兵运行着,就可以允许执行故障转移

课程大纲

1、两种数据丢失的情况
2、解决异步复制和脑裂导致的数据丢失


1、两种数据丢失的情况

主备切换的过程,可能会导致数据丢失

(1)异步复制导致的数据丢失

因为master -> slave的复制是异步的,所以可能有部分数据还没复制到slave,master就宕机了,此时这些部分数据就丢失了

(2)脑裂导致的数据丢失

脑裂,也就是说,某个master所在机器突然脱离了正常的网络,跟其他slave机器不能连接,但是实际上master还运行着

此时哨兵可能就会认为master宕机了,然后开启选举,将其他slave切换成了master

这个时候,集群里就会有两个master,也就是所谓的脑裂

此时虽然某个slave被切换成了master,但是可能client还没来得及切换到新的master,还继续写向旧master的数据可能也丢失了

因此旧master再次恢复的时候,会被作为一个slave挂到新的master上去,自己的数据会清空,重新从新的master复制数据


2、解决异步复制和脑裂导致的数据丢失

min-slaves-to-write 1
min-slaves-max-lag 10

要求至少有1个slave,数据复制和同步的延迟不能超过10秒

如果说一旦所有的slave,数据复制和同步的延迟都超过了10秒钟,那么这个时候,master就不会再接收任何请求了

上面两个配置可以减少异步复制和脑裂导致的数据丢失

(1)减少异步复制的数据丢失

有了min-slaves-max-lag这个配置,就可以确保说,一旦slave复制数据和ack延时太长,就认为可能master宕机后损失的数据太多了,那么就拒绝写请求,这样可以把master宕机时由于部分数据未同步到slave导致的数据丢失降低的可控范围内

(2)减少脑裂的数据丢失

如果一个master出现了脑裂,跟其他slave丢了连接,那么上面两个配置可以确保说,如果不能继续给指定数量的slave发送数据,而且slave超过10秒没有给自己ack消息,那么就直接拒绝客户端的写请求

这样脑裂后的旧master就不会接受client的新数据,也就避免了数据丢失

上面的配置就确保了,如果跟任何一个slave丢了连接,在10秒后发现没有slave给自己ack,那么就拒绝新的写请求

因此在脑裂场景下,最多就丢失10秒的数据

1、sdown和odown转换机制

sdown和odown两种失败状态

sdown是主观宕机,就一个哨兵如果自己觉得一个master宕机了,那么就是主观宕机

odown是客观宕机,如果quorum数量的哨兵都觉得一个master宕机了,那么就是客观宕机

sdown达成的条件很简单,如果一个哨兵ping一个master,超过了is-master-down-after-milliseconds指定的毫秒数之后,就主观认为master宕机

sdown到odown转换的条件很简单,如果一个哨兵在指定时间内,收到了quorum指定数量的其他哨兵也认为那个master是sdown了,那么就认为是odown了,客观认为master宕机

2、哨兵集群的自动发现机制

哨兵互相之间的发现,是通过redis的pub/sub系统实现的,每个哨兵都会往__sentinel__:hello这个channel里发送一个消息,这时候所有其他哨兵都可以消费到这个消息,并感知到其他的哨兵的存在

每隔两秒钟,每个哨兵都会往自己监控的某个master+slaves对应的__sentinel__:hello channel里发送一个消息,内容是自己的host、ip和runid还有对这个master的监控配置

每个哨兵也会去监听自己监控的每个master+slaves对应的__sentinel__:hello channel,然后去感知到同样在监听这个master+slaves的其他哨兵的存在

每个哨兵还会跟其他哨兵交换对master的监控配置,互相进行监控配置的同步

3、slave配置的自动纠正

哨兵会负责自动纠正slave的一些配置,比如slave如果要成为潜在的master候选人,哨兵会确保slave在复制现有master的数据; 如果slave连接到了一个错误的master上,比如故障转移之后,那么哨兵会确保它们连接到正确的master上

4、slave->master选举算法

如果一个master被认为odown了,而且majority哨兵都允许了主备切换,那么某个哨兵就会执行主备切换操作,此时首先要选举一个slave来

会考虑slave的一些信息

(1)跟master断开连接的时长
(2)slave优先级
(3)复制offset
(4)run id

如果一个slave跟master断开连接已经超过了down-after-milliseconds的10倍,外加master宕机的时长,那么slave就被认为不适合选举为master

(down-after-milliseconds * 10) + milliseconds_since_master_is_in_SDOWN_state

接下来会对slave进行排序

(1)按照slave优先级进行排序,slave priority越低,优先级就越高
(2)如果slave priority相同,那么看replica offset,哪个slave复制了越多的数据,offset越靠后,优先级就越高
(3)如果上面两个条件都相同,那么选择一个run id比较小的那个slave

5、quorum和majority

每次一个哨兵要做主备切换,首先需要quorum数量的哨兵认为odown,然后选举出一个哨兵来做切换,这个哨兵还得得到majority哨兵的授权,才能正式执行切换

如果quorum < majority,比如5个哨兵,majority就是3,quorum设置为2,那么就3个哨兵授权就可以执行切换

但是如果quorum >= majority,那么必须quorum数量的哨兵都授权,比如5个哨兵,quorum是5,那么必须5个哨兵都同意授权,才能执行切换

6、configuration epoch

哨兵会对一套redis master+slave进行监控,有相应的监控的配置

执行切换的那个哨兵,会从要切换到的新master(salve->master)那里得到一个configuration epoch,这就是一个version号,每次切换的version号都必须是唯一的

如果第一个选举出的哨兵切换失败了,那么其他哨兵,会等待failover-timeout时间,然后接替继续执行切换,此时会重新获取一个新的configuration epoch,作为新的version号

7、configuraiton传播

哨兵完成切换之后,会在自己本地更新生成最新的master配置,然后同步给其他的哨兵,就是通过之前说的pub/sub消息机制

这里之前的version号就很重要了,因为各种消息都是通过一个channel去发布和监听的,所以一个哨兵完成一次新的切换之后,新的master配置是跟着新的version号的

其他的哨兵都是根据版本号的大小来更新自己的master配置的

redis的持久化方式有哪些?不同的持久化机制都有什么优点?持久化机制的底层原理是如何实现的?
课程大纲

1、RDB和AOF两种持久化机制的介绍
2、RDB持久化机制的优点
3、RDB持久化机制的缺点
4、AOF持久化机制的优点
5、AOF持久化机制的缺点
6、RDB和AOF到底该如何选择

我们已经知道对于一个企业级的redis架构来说,持久化是不可减少的

企业级redis集群架构:海量数据、高并发、高可用

持久化主要是做灾难恢复,数据恢复,也可以归类到高可用的一个环节里面去

比如你redis整个挂了,然后redis就不可用了,你要做的事情是让redis变得可用,尽快变得可用

重启redis,尽快让它对外提供服务,但是就像上一讲说,如果你没做数据备份,这个时候redis启动了,也不可用啊,数据都没了

很可能说,大量的请求过来,缓存全部无法命中,在redis里根本找不到数据,这个时候就死定了,缓存雪崩问题,所有请求,没有在redis命中,就会去mysql数据库这种数据源头中去找,一下子mysql承接高并发,然后就挂了

mysql挂掉,你都没法去找数据恢复到redis里面去,redis的数据从哪儿来?从mysql来。。。

具体的完整的缓存雪崩的场景,还有企业级的解决方案,到后面讲

如果你把redis的持久化做好,备份和恢复方案做到企业级的程度,那么即使你的redis故障了,也可以通过备份数据,快速恢复,一旦恢复立即对外提供服务

redis的持久化,跟高可用,是有关系的,企业级redis架构中去讲解

redis持久化:RDB,AOF


1、RDB和AOF两种持久化机制的介绍

RDB持久化机制,对redis中的数据执行周期性的持久化

AOF机制对每条写入命令作为日志,以append-only的模式写入一个日志文件中,在redis重启的时候,可以通过回放AOF日志中的写入指令来重新构建整个数据集

如果我们想要redis仅仅作为纯内存的缓存来用,那么可以禁止RDB和AOF所有的持久化机制

通过RDB或AOF,都可以将redis内存中的数据给持久化到磁盘上面来,然后可以将这些数据备份到别的地方去,比如说阿里云,云服务

如果redis挂了,服务器上的内存和磁盘上的数据都丢了,可以从云服务上拷贝回来之前的数据,放到指定的目录中,然后重新启动redis,redis就会自动根据持久化数据文件中的数据,去恢复内存中的数据,继续对外提供服务

如果同时使用RDB和AOF两种持久化机制,那么在redis重启的时候,会使用AOF来重新构建数据,因为AOF中的数据更加完整


2、RDB持久化机制的优点

(1)RDB会生成多个数据文件,每个数据文件都代表了某一个时刻中redis的数据,这种多个数据文件的方式,非常适合做冷备,可以将这种完整的数据文件发送到一些远程的安全存储上去,比如说Amazon的S3云服务上去,在国内可以是阿里云的ODPS分布式存储上,以预定好的备份策略来定期备份redis中的数据

(2)RDB对redis对外提供的读写服务,影响非常小,可以让redis保持高性能,因为redis主进程只需要fork一个子进程,让子进程执行磁盘IO操作来进行RDB持久化即可

(3)相对于AOF持久化机制来说,直接基于RDB数据文件来重启和恢复redis进程,更加快速


3、RDB持久化机制的缺点

(1)如果想要在redis故障时,尽可能少的丢失数据,那么RDB没有AOF好。一般来说,RDB数据快照文件,都是每隔5分钟,或者更长时间生成一次,这个时候就得接受一旦redis进程宕机,那么会丢失最近5分钟的数据

(2)RDB每次在fork子进程来执行RDB快照数据文件生成的时候,如果数据文件特别大,可能会导致对客户端提供的服务暂停数毫秒,或者甚至数秒


4、AOF持久化机制的优点

(1)AOF可以更好的保护数据不丢失,一般AOF会每隔1秒,通过一个后台线程执行一次fsync操作,最多丢失1秒钟的数据

(2)AOF日志文件以append-only模式写入,所以没有任何磁盘寻址的开销,写入性能非常高,而且文件不容易破损,即使文件尾部破损,也很容易修复

(3)AOF日志文件即使过大的时候,出现后台重写操作,也不会影响客户端的读写。因为在rewrite log的时候,会对其中的指导进行压缩,创建出一份需要恢复数据的最小日志出来。再创建新日志文件的时候,老的日志文件还是照常写入。当新的merge后的日志文件ready的时候,再交换新老日志文件即可。

(4)AOF日志文件的命令通过非常可读的方式进行记录,这个特性非常适合做灾难性的误删除的紧急恢复。比如某人不小心用flushall命令清空了所有数据,只要这个时候后台rewrite还没有发生,那么就可以立即拷贝AOF文件,将最后一条flushall命令给删了,然后再将该AOF文件放回去,就可以通过恢复机制,自动恢复所有数据


5、AOF持久化机制的缺点

(1)对于同一份数据来说,AOF日志文件通常比RDB数据快照文件更大

(2)AOF开启后,支持的写QPS会比RDB支持的写QPS低,因为AOF一般会配置成每秒fsync一次日志文件,当然,每秒一次fsync,性能也还是很高的

(3)以前AOF发生过bug,就是通过AOF记录的日志,进行数据恢复的时候,没有恢复一模一样的数据出来。所以说,类似AOF这种较为复杂的基于命令日志/merge/回放的方式,比基于RDB每次持久化一份完整的数据快照文件的方式,更加脆弱一些,容易有bug。不过AOF就是为了避免rewrite过程导致的bug,因此每次rewrite并不是基于旧的指令日志进行merge的,而是基于当时内存中的数据进行指令的重新构建,这样健壮性会好很多。


6、RDB和AOF到底该如何选择

(1)不要仅仅使用RDB,因为那样会导致你丢失很多数据

(2)也不要仅仅使用AOF,因为那样有两个问题,第一,你通过AOF做冷备,没有RDB做冷备,来的恢复速度更快; 第二,RDB每次简单粗暴生成数据快照,更加健壮,可以避免AOF这种复杂的备份和恢复机制的bug

(3)综合使用AOF和RDB两种持久化机制,用AOF来保证数据不丢失,作为数据恢复的第一选择; 用RDB来做不同程度的冷备,在AOF文件都丢失或损坏不可用的时候,还可以使用RDB来进行快速的数据恢复

缓存和数据库数据一致性问题?
一般我们有三种策略:
1)先删缓存,再更新数据库,可能会出现脏读
2)先更新数据库,更新成功之后再让缓存失效,减少了脏读的可能性
3)更新数据,只更新缓存,不更新数据库,然后通过异步调度来批量更新数据库,这样是性能比较好,但是无法保证强一致性。

redis的并发竞争问题该怎么解决?
分布式锁来处理,我们可以借助zk的有序节点来保证多节点赋值的顺序性。

生产环境中的redis是怎么部署的?
生产环境的redis采取的是主从模式,一主二从,俩个从节点用来读,一个主节点用来写。
机器是32g内存+8核cpu+ 1T磁盘

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值