面试归纳之:缓存,消息队列典藏

目录

Redis有哪些数据结构?分别有哪些典型的应用场景?

Redis分布式锁底层是如何实现的? 

 Redis主从复制的核心原理

缓存穿透、缓存击穿、缓存雪崩分别是什么

 Redis和Mysql如何保证数据一致

 消息队列有哪些作用

 死信队列是什么?延时队列是什么?

Kafka为什么吞吐量高

Kafka的Pull和Push分别有什么优缺点

RocketMQ的事务消息是如何实现的 

 消息队列如何保证消息可靠传输


Redis有哪些数据结构?分别有哪些典型的应用场景?

Redis的数据结构有:

  1. 字符串:可以用来做最简单的数据,可以缓存某个简单的字符串,也可以缓存某个json格式的字符串,Redis分布式锁的实现就利用了这种数据结构,还包括可以实现计数器、分布式ID
  2. 哈希表:可以用来存储一些key-value对,更适合用来存储对象
  3. 列表:Redis的列表通过命令的组合,既可以当做栈,也可以当做队列来使用,可以用来缓存类似微信公众号、微博等消息流数据
  4. 集合:和列表类似,也可以存储多个元素,但是不能重复,集合可以进行交集、并集、差集操作,从而可以实现类似,我和某人共同关注的人、朋友圈点赞等功能
  5. 有序集合:集合是无序的,有序集合可以设置顺序,可以用来实现排行榜功能

Redis分布式锁底层是如何实现的? 

  1. 首先利用setnx来保证:如果key不存在才能获取到锁,如果key存在,则获取不到锁
  2. 然后还要利用lua脚本来保证多个redis操作的原子性
  3. 同时还要考虑到锁过期,所以需要额外的一个看门狗定时任务来监听锁是否需要续约
  4. 同时还要考虑到redis节点挂掉后的情况,所以需要采用红锁的方式来同时向N/2+1个节点申请锁,都申请到了才证明获取锁成功,这样就算其中某个redis节点挂掉了,锁也不能被其他客户端获取到

 Redis主从复制的核心原理

全量同步:

  1. 一般发生在从节点初始化的时候
  2. 从节点发送SYNC命令连接主节点
  3. 主节点接收到SYNC命名后,开始执行BGSAVE命令生成RDB文件,并使用缓冲区replication buffer记录在这个过程中接收到的写命令
  4. 主节点BGSAVE命令执行完后,向所有从节点发送RDB文件,并在发送缓冲区replication buffer记录的写命令
  5. 从节点收到RDB文件后丢弃所有旧数据,载入收到的RDB文件中的数据
  6. 主节点RDB文件发送完毕后,开始向从节点发送缓冲区replication buffer中的写命令
  7. 从节点完成RDB的载入后,开始接收客户端命令,并执行来自主节点缓冲区replication buffer的写命令

增量同步:

Redis主节点每执行一个写命令就会向从节点异步发送相同的写命令,从节点接收并执行收到的写命令

缓存穿透、缓存击穿、缓存雪崩分别是什么

缓存中存放的大多都是热点数据,目的就是防止请求可以直接从缓存中获取到数据,而不用访问Mysql

  1. 缓存雪崩:如果缓存中某一时刻大批热点数据同时过期,那么就可能导致大量请求直接访问Mysql了,解决办法就是在过期时间上增加一点随机值,另外如果搭建一个高可用的Redis集群也是防止缓存雪崩的有效手段
  2. 缓存击穿:和缓存雪崩类似,缓存雪崩是大批热点数据失效,而缓存击穿是指某一个热点key突然失效,也导致了大量请求直接访问Mysql数据库,这就是缓存击穿,解决方案就是考虑这个热点key不设过期时间
  3. 缓存穿透:假如某一时刻访问redis的大量key都在redis中不存在(比如黑客故意伪造一些乱七八糟的key),那么也会给数据造成压力,这就是缓存穿透,解决方案是使用布隆过滤器,它的作用就是如果它认为一个key不存在,那么这个key就肯定不存在,所以可以在缓存之前加一层布隆过滤器来拦截不存在的key

 Redis和Mysql如何保证数据一致

  1. 先更新Mysql,再更新Redis,如果更新Redis失败,可能仍然不一致
  2. 先删除Redis缓存数据,再更新Mysql,再次查询的时候在将数据添加到缓存中,这种方案能解决1方案的问题,但是在高并发下性能较低,而且仍然会出现数据不一致的问题,比如线程1删除了Redis缓存数据,正在更新Mysql,此时另外一个查询再查询,那么就会把Mysql中老数据又查到Redis中
  3. 延时双删,步骤是:先删除Redis缓存数据,再更新Mysql,延迟几百毫秒再删除Redis缓存数据,这样就算在更新Mysql时,有其他线程读了Mysql,把老数据读到了Redis中,那么也会被删除掉,从而把数据保持一致

 消息队列有哪些作用

  1. 解耦:使用消息队列来作为两个系统之间的通讯方式,两个系统不需要相互依赖了
  2. 异步:系统A给消息队列发送完消息之后,就可以继续做其他事情了
  3. 流量削峰:如果使用消息队列的方式来调用某个系统,那么消息将在队列中排队,由消费者自己控制消费速度

 死信队列是什么?延时队列是什么?

  1. 死信队列也是一个消息队列,它是用来存放那些没有成功消费的消息的,通常可以用来作为消息重试
  2. 延时队列就是用来存放需要在指定时间被处理的元素的队列,通常可以用来处理一些具有过期性操作的业务,比如十分钟内未支付则取消订单

Kafka为什么吞吐量高

       Kafka的生产者采用的是异步发送消息机制,当发送一条消息时,消息并没有发送到Broker而是缓存起来,然后直接向业务返回成功,当缓存的消息达到一定数量时再批量发送给Broker。这种做法减少了网络io,从而提高了消息发送的吞吐量,但是如果消息生产者宕机,会导致消息丢失,业务出错,所以理论上kafka利用此机制提高了性能却降低了可靠性。

Kafka的Pull和Push分别有什么优缺点

  1. pull表示消费者主动拉取,可以批量拉取,也可以单条拉取,所以pull可以由消费者自己控制,根据自己的消息处理能力来进行控制,但是消费者不能及时知道是否有消息,可能会拉到的消息为空
  2. push表示Broker主动给消费者推送消息,所以肯定是有消息时才会推送,但是消费者不能按自己的能力来消费消息,推过来多少消息,消费者就得消费多少消息,所以可能会造成网络堵塞,消费者压力大等问题

RocketMQ的事务消息是如何实现的 

 

  1. 生产者订单系统先发送一条half消息到Broker,half消息对消费者而言是不可见的
  2. 再创建订单,根据创建订单成功与否,向Broker发送commit或rollback
  3. 并且生产者订单系统还可以提供Broker回调接口,当Broker发现一段时间half消息没有收到任何操作命令,则会主动调此接口来查询订单是否创建成功
  4. 一旦half消息commit了,消费者库存系统就会来消费,如果消费成功,则消息销毁,分布式事务成功结束
  5. 如果消费失败,则根据重试策略进行重试,最后还失败则进入死信队列,等待进一步处理

 消息队列如何保证消息可靠传输

消息可靠传输代表了两层意思,既不能多也不能少。

  1. 为了保证消息不多,也就是消息不能重复,也就是生产者不能重复生产消息,或者消费者不能重复消费消息
  2. 首先要确保消息不多发,这个不常出现,也比较难控制,因为如果出现了多发,很大的原因是生产者自己的原因,如果要避免出现问题,就需要在消费端做控制
  3. 要避免不重复消费,最保险的机制就是消费者实现幂等性,保证就算重复消费,也不会有问题,通过幂等性,也能解决生产者重复发送消息的问题
  4. 消息不能少,意思就是消息不能丢失,生产者发送的消息,消费者一定要能消费到,对于这个问题,就要考虑两个方面
  5. 生产者发送消息时,要确认broker确实收到并持久化了这条消息,比如RabbitMQ的confirm机制,Kafka的ack机制都可以保证生产者能正确的将消息发送给broker
  6. broker要等待消费者真正确认消费到了消息时才删除掉消息,这里通常就是消费端ack机制,消费者接收到一条消息后,如果确认没问题了,就可以给broker发送一个ack,broker接收到ack后才会删除消息

 

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值