面试篇-Redis-3+分布式锁+集群部署


前言

你们项目中使用过Redis 作为分布式锁吗,你们是怎么实现的,锁过期怎么办,redis 脑裂怎么办,Redis 真能保证一致性吗,本文重点对面试的问题进行介绍,祝愿每位程序员都能上岸!!!。


一、你们项目中使用Redis 作为分布式锁吗

分布式锁通常被用在对公用的资源进行修改时使用,如分布式任务调度,抢单等场景;

1.1 将余券存入到Redis 中,当有人抢券进行-1操作并存回:

在这里插入图片描述
如果按照上面的代码进行,在并发场景下很有可能出现超卖的情况:
在这里插入图片描述此时就可以考虑使用分布式锁进行加锁处理超卖的问题;

1.2 分布式锁的使用

每个线程进入该方法后,都需要先获取到一把全局的排他锁,只有获取到了锁的线程才能进入优惠券余量的查询,然后扣减库存操作,最后在进行锁的释放,获取不到锁的线程则无法抢券。
在这里插入图片描述

1.3 Redis 分布式锁是怎么实现的:

Redis实现分布式锁主要利用Redis的setnx命令。setnx是SETif not exists(如果不存在,则 SET)的简写。
在这里插入图片描述

 为了防止死锁,通常在使用setnx 时,需要为key 设置一个过期时间,那么锁的过期时间又应该怎么设置;  Redisson中提供了看门狗功能,
 来进行锁的自动延期。看门狗是一个线程,默认每隔10s 去查看主线程的任务是否结束,如果没有结束就进行所得续期,
 依次来保证主线程在任务执行完成之前一直持有锁。

在这里插入图片描述
这里注意一个使用上的细节:
加锁和设置过期时间,都是通过lua 脚本保证其原子性;这里如果传入了锁的过期时间,则不会启用看门狗进行锁的续期 ;

在这里插入图片描述

1.4 Redisson 分布式锁是可重入的吗:

Redisson 实现的分布式锁 底层数据结构,保存了当前持有锁的线程,和锁的重入次数,所以它是支持锁的重入;

在这里插入图片描述

1.5 Redis 出现脑裂时如何保证数据的一致性

redis 分布式锁-数据主从一致性问题:主节点还没有将锁的key 信息同步到从节点,此时主节点宕机后,通过选举上位的主节点没有锁信息,此时线程在来获取锁就成功了,丢失了所的互斥性。针对此场景Redis 提供了红锁来支持
在这里插入图片描述

RedLock(红锁):不能只在一个redis实例上创建锁,应该是在多个redis实例上创建锁(n/2+1),避免在一个redis实例上加锁;红锁实现起来比较复杂,而且并发性能差,redis 官网也不推荐使用。
在这里插入图片描述

Redisson锁不能解决主从数据一致的问题吗
不能解决,但是可以使用redisson提供的红锁来解决,但是这样的话,性能就太低了,如果业务中非要保证数据的强一致性,建议采用zookeeper实现的分布式锁;

二、你都知道Redis 集群的哪些部署方式

2.1 主从部署

一个Master 多个Slave,Master 负责数据的写入,Slave 可以负责数据的读取;单节点Redis的并发能力是有上限的,要进一步提高Redis的并发能力,就需要搭建主从集群,实现读写分离。

2.1.2 主从架构图:

在这里插入图片描述

2.1.2 主从数据的同步是怎么做的:

1)全量同步过程:
在这里插入图片描述

  • 从节点与主节点建立连接,发送replid 和offset;
  • 如果是第一次同步,则返回给从节点 replid 和offset,从节点进行保存;
  • 然后通过bgsave 生成rdb 文件,并且发送给从节点;
  • 从节点清空本地数据 ,然后加载rdb;
  • 后续同步,则通过offset 将新产生的数据 发送给到从节点;

2)增量同步过程:

因为slave 已经保存了offset 漂移量,此时主节点只需要将offset 之后的数据给到slave 即可;
在这里插入图片描述

2.2 哨兵模式:

主从模式下,当主节点出现故障后,无法再响应写入请求,此时必须手动将其中的一个slave 置为Master 节点才能继续提供服务;这样显然太麻烦了。可以使用哨兵模式对redis 的主从节点进行监控,并且当主节点下线后也可以触发自动选举Master。

2.2.1 哨兵模式架构:

代码如下(示例):
Redis提供了哨兵(Sentinel)机制来实现主从集群的自动故障恢复。哨兵的结构和作用如下:

  • 监控:Sentinel会不断检查您的master和slave是否按预期工作;
  • 自动故障恢复:如果master故障,Sentinel会将一个slave提升为master。当故障实例恢复后也以新的master为主;
  • 通知:Sentinel充当Redis客户端的服务发现来源,当集群发生故障转移时,会将最新信息推送给Redis的客户端;

2.2.2 Sentinel的选举:

Sentinel 会检查集群内的所有节点,如果Master 下线则会触发选举;

服务状态监控如下:

  • Sentinel基于心跳机制监测服务状态,每隔1秒向集群的每个实例发送ping命令:
  • 主观下线:如果某sentinel节点发现某实例未在规定时间响应,则认为该实例主观下线。
  • 客观下线:若超过指定数量(quorum)的sentinel都认为该实例主观下线,则该实例客观下线。quorum值最好超过Sentinel实例数量的一半。
    在这里插入图片描述

哨兵选主规则:

  • 首先判断主与从节点断开时间长短,如超过指定值就排除该从节点;
  • 然后判断从节点的slave-priority值,越小优先级越高
  • 如果slave-prority一样,则判断slave节点的offset值,越大优先级越高
  • 最后是判断slave节点的运行id大小,越小优先级越高。

2.2.3 哨兵模式下的脑裂问题:

出现网络问题,触发了集群的选举,然后后续网络恢复后,集群出现两个主节点,新晋升的主节点将老的主节点强制降级为从节点,如果出现网络问题时,redis 客户端还是连接了老的主节点进行了数据的写入,此时老的主节点被降级为从节点后,则会造成数据丢失;我们可以修改redis的配置,可以设置最少的从节点数量以及缩短主从数据同步的延迟时间,达不到要求就拒绝请求就可以避免大量的数据丢失。
在这里插入图片描述

2.3 分片模式:

主从和哨兵可以解决高可用、高并发读的问题。但是依然有两个问题没有解决:

  • 海量数据存储问题;
  • 高并发写的问题;

2.3.1 分片架构:

在这里插入图片描述

使用分片集群可以解决上述问题,分片集群特征:

  • 集群中有多个master,每个master保存不同数据
  • 每个master都可以有多个slave节点
  • master之间通过ping监测彼此健康状态
  • 客户端请求可以访问集群任意节点,最终都会被转发到正确节点;

2.3.2 分片是怎么实现的:

Redis 分片集群引入了哈希槽的概念,Redis 集群有 16384 个哈希槽,每个 key通过 CRC16 校验后对 16384 取模来决定放置哪个槽,集群的每个节点负责一部分 hash 槽。

在这里插入图片描述

三、Redis 单线程为什么还能保证高吞吐

Redis是纯内存操作,执行速度非常快,它的性能瓶颈是网络延迟而不是执行速度;

3.1 Redis 高性能的三个原因:

  • Redis是纯内存操作,执行速度非常快
  • 采用单线程,避免不必要的上下文切换可竞争条件,多线程还要考虑线程安全问题
  • 使用I/O多路复用模型,非阻塞IO

3.2 Redis的线程网络模型:

3.2.1 单线程模型:

在这里插入图片描述

3.2.2 多线程模型:

redis 最新的版本 在命令解析和结果返回时都使用多线程模型,在命令执行时,是单线程串行执行
在这里插入图片描述

3.3 Redis 的IO多路复用:

IO多路复用:是利用单个线程来同时监听多个Socket ,并在某个Socket可读、可写时得到通知,从而避免无效的等待,充分利用CPU资源。
在这里插入图片描述

此外:select 模型底层是使用数组来存储socket 的所以连接socket的数量有一定限制;poll模型底层使用链表来存储socket 所以socket 的连接是没有限制的,但是poll 和select 一样都需要不断地进行轮训来获取到哪个socket 就绪;而epoll 提供了事件监听机制,可以在有socket 连接或者可读写的时候 进行通知;


总结

本文对Redis 的主从,哨兵,分片三种集群部署进行介绍,并对Redis 分布式锁的使用问题进行概括。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值