本篇主要内容如下:

一、本地锁的问题

首先我们来回顾下本地锁的问题:

目前题目微服务被拆分成了四个微服务。前端请求进来时,会被转发到不同的微服务。假如前端接收了 10 W 个请求,每个微服务接收 2.5 W 个请求,假如缓存失效了,每个微服务在访问数据库时加锁,通过锁(synchronziedlock)来锁住自己的线程资源,从而防止缓存击穿

这是一种本地加锁的方式,在分布式情况下会带来数据不一致的问题:比如服务 A 获取数据后,更新缓存 key =100,服务 B 不受服务 A 的锁限制,并发去更新缓存 key = 99,最后的结果可能是 99 或 100,但这是一种未知的状态,与期望结果不一致。流程图如下所示:

二、什么是分布式锁

基于上面本地锁的问题,我们需要一种支持分布式集群环境下的锁:查询 DB 时,只有一个线程能访问,其他线程都需要等待第一个线程释放锁资源后,才能继续执行。

生活中的案例:可以把锁看成房门外的一把,所有并发线程比作,他们都想进入房间,房间内只能有一个人进入。当有人进入后,将门反锁,其他人必须等待,直到进去的人出来。

我们来看下分布式锁的基本原理,如下图所示:

我们来分析下上图的分布式锁:

  • 1.前端将 10W 的高并发请求转发给四个题目微服务。

  • 2.每个微服务处理 2.5 W 个请求。

  • 3.每个处理请求的线程在执行业务之前,需要先抢占锁。可以理解为“占坑”。

  • 4.获取到锁的线程在执行完业务后,释放锁。可以理解为“释放坑位”。

  • 5.未获取到的线程需要等待锁释放。

  • 6.释放锁后,其他线程抢占锁。

  • 7.重复执行步骤 4、5、6。

大白话解释:所有请求的线程都去同一个地方“占坑”,如果有坑位,就执行业务逻辑,没有坑位,就需要其他线程释放“坑位”。这个坑位是所有线程可见的,可以把这个坑位放到 Redis 缓存或者数据库,这篇讲的就是如何用 Redis 做“分布式坑位”

三、Redis 的 SETNX

Redis 作为一个公共可访问的地方,正好可以作为“占坑”的地方。

用 Redis 实现分布式锁的几种方案,我们都是用 SETNX 命令(设置 key 等于某 value)。只是高阶方案传的参数个数不一样,以及考虑了异常情况。

我们来看下这个命令,SETNXset If not exist的简写。意思就是当 key 不存在时,设置 key 的值,存在时,什么都不做。

在 Redis 命令行中是这样执行的:

set <key> <value> NX

我们可以进到 redis 容器中来试下 SETNX 命令。

先进入容器:

docker exec -it <容器 id> redis-cli

然后执行 SETNX 命令:将 wukong 这个 key 对应的 value 设置成 1111

set wukong 1111 NX

返回 OK,表示设置成功。重复执行该命令,返回 nil表示设置失败。

四、青铜方案

我们先用 Redis 的 SETNX 命令来实现最简单的分布式锁。

3.1 青铜原理

我们来看下流程图:

  • 多个并发线程都去 Redis 中申请锁,也就是执行 setnx 命令,假设线程 A 执行成功,说明当前线程 A 获得了。

  • 其他线程执行 setnx 命令都会是失败的,所以需要等待线程 A 释放锁。

  • 线程 A 执行完自己的业务后,删除锁。

  • 其他线程继续抢占锁,也就是执行 setnx 命令。因为线程 A 已经删除了锁,所以又有其他线程可以抢占到锁了。

代码示例如下,Java 中 setnx 命令对应的代码为 setIfAbsent

setIfAbsent 方法的第一个参数代表 key,第二个参数代表值。

// 1.先抢占锁
Boolean lock = redisTemplate.opsForValue().setIfAbsent("lock", "123");
if(lock) {// 2.抢占成功,执行业务List<TypeEntity> typeEntityListFromDb = getDataFromDB();// 3.解锁redisTemplate.delete("lock");return typeEntityListFromDb;
} else {// 4.休眠一段时间sleep(100);// 5.抢占失败,等待锁释放return getTypeEntityListByRedisDistributedLock();
}

一个小问题:那为什么需要休眠一段时间?

因为该程序存在递归调用,可能会导致栈空间溢出。

3.2 青铜方案的缺陷

青铜之所以叫青铜,是因为它是最初级的,肯定会带来很多问题。

设想一种家庭场景:晚上小空一个人开锁进入了房间,打开了电灯

Redis 分布式锁|从青铜到钻石的五种演进方案相关推荐

  1. Redis分布式锁加时效和不加时效两种方案的最全代码实现

    锁住3秒: @Autowired private RedisTemplate redisTemplate;String withdrawals_apply_key = WITHDRAWALS_REDI ...

  2. 从青铜到王者,带你完成Redis分布式锁的实现和优化

    0.分布式锁的常见面试题 Redis除了拿来做缓存,你还见过基于Redis的什么用法? Redis做分布式锁的时候有需要注意的问题? 如果是Redis是单点部署的,会带来什么问题? 那你准备怎么解决单 ...

  3. Redis分布式锁详解

    Redis分布式锁详解 1. 分布式所概述 1.1 分布式锁 2. 缓存数据库Redis 2.1 redis简介 2.2 Springboot整合Redis两种方式 3. 实现验证 3.1 环境准备 ...

  4. redis分布式锁 在集群模式下如何实现_收藏慢慢看系列:简洁实用的Redis分布式锁用法...

    在微服务中很多情况下需要使用到分布式锁功能,而目前比较常见的方案是通过Redis来实现分布式锁,网上关于分布式锁的实现方式有很多,早期主要是基于Redisson等客户端,但在Spring Boot2. ...

  5. 快来学习Redis 分布式锁的背后原理

    以前在学校做小项目的时候,用到Redis,基本也只是用来当作缓存.可阿粉在工作中发现,Redis在生产中并不只是当作缓存这么简单.在阿粉接触到的项目中,Redis起到了一个分布式锁的作用,具体情况是这 ...

  6. Redis分布式锁使用不当,酿成一个重大事故,超卖了100瓶飞天茅台!!!

    点击关注公众号,Java干货及时送达 来源:juejin.cn/post/6854573212831842311 基于Redis使用分布式锁在当今已经不是什么新鲜事了. 本篇文章主要是基于我们实际项目 ...

  7. Redis 分布式锁使用不当,酿成一个重大事故,超卖了100瓶飞天茅台!!!

    点击上方蓝色"方志朋",选择"设为星标" 回复"666"获取独家整理的学习资料! 基于Redis使用分布式锁在当今已经不是什么新鲜事了. 本 ...

  8. 秒杀商品超卖事故:Redis分布式锁请慎用!

    点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试文章 作者:浪漫先生 来源:juejin.im/post/6854573 ...

  9. 记一次由Redis分布式锁造成的重大事故,避免以后踩坑!

    点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试文章 作者:浪漫先生 juejin.im/post/5f159cd8f2 ...

最新文章

  1. VMware14安装CentOS7的详细教程
  2. 归一化变换 Normalizing transformations
  3. 基于AI的便携式神经假肢让截肢14年患者操作自如,高精度、低延迟
  4. JAVA并发编程: CAS和AQS
  5. Spring 基于设值函数的依赖注入
  6. SAP CRM HANA report filter的工作原理
  7. Python help 函数 - Python零基础入门教程
  8. 引入静态变量_Common Lisp变量的一些事情
  9. ANDROID笔记:Activity之间的传值
  10. Linux命令之grep
  11. 概率论——几何随机变量
  12. 51计数器(理论+实践【代码】)
  13. Mocking Void Methods with Mockito
  14. 硬件安全技术-5G时代IOT环境下芯片安全风险与挑战
  15. c语言捉迷藏,捉迷藏
  16. EPICS记录参考2--EPICS过程数据库概念
  17. 斗图表情包爬虫(基于多线程)
  18. 干货:压敏电阻选型和注意事项,必知
  19. 向Linux增加一个系统调用或内核模块
  20. 从UAP-Studio中导出项目并且部署到服务器上

热门文章

  1. 2018年总结与2019年目标与计划
  2. 2018年第四阶段组队训练赛第七场
  3. php怎样随机设置颜色,php简单生成随机颜色的方法
  4. 【sql: 联系题 23 24】查询同名学生名单,并统计同名人数 找到同名的名字并统计个数,查询 1990 年出生的学生名单...
  5. CocosCreator之节点悬浮效果组件
  6. 去年卖出4000万台后,荣耀发布了搭载麒麟650的畅玩5C
  7. 安装CentOS 7并部署jdk和mysql
  8. 众至科技:网络安全保险如何定价?
  9. Eclipse注释详解
  10. SQL:group by中属性为什么一定要出现在select语句中?