| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> 大数据 -> 一文详解如何用 MySQL/Redis/ZooKeeper 实现分布式锁 -> 正文阅读 |
|
[大数据]一文详解如何用 MySQL/Redis/ZooKeeper 实现分布式锁 |
面试开始, 直入正题。 面试官: 你有没有参与过秒杀系统的设计? 我: 没有,我平时都是开发后台管理系统、OA 办公系统、内部管理系统,从来没有开发过秒杀系统。 面试官: 嗯...,小伙子很实诚。今天就先到这里吧,后面有消息会主动联系你。 我: 参与过秒杀系统,并独立负责过秒杀系统的架构设计(【狗头】是的,都是我设计的)。 面试官: 这样才对,这样我才能接着往下问。你在设计秒杀系统的时候,怎么防止商品超卖?比如活动中只有一台 iPhone,最终卖出 100 台,肯定不行,平台要亏钱。 我: 肯定要加锁,不过由于秒杀系统请求量较大,一般使用分布式集群。而 Java 自带 Synchronized、ReentrantLock 锁只能用在单机系统中,这时候就需要用到分布式锁。 面试官: 你提到分布式锁,分布式锁都有哪些作用? 我:我觉得分布式锁主要有两个作用: 保证数据的正确性:比如:秒杀的时候防止商品超卖,表单重复提交,接口幂等性。 避免数据重复处理:比如:调度任务在多台机器重复执行,缓存过期所有请求都去加载数据库。 面试官: 小伙子总结的挺全,你知道设计一个分布式锁,要具有哪些特性? 我: 我觉得分布式锁要具有以下这些特性: 互斥:同一时刻只能有一个线程获得锁。可重入:当一个线程获取锁后,还可以再次获取这个锁,避免死锁发生。高可用:当小部分节点挂掉后,仍然能够对外提供服务。高性能:要做到高并发、低延迟。支持阻塞和非阻塞:Synchronized 是阻塞的,ReentrantLock.tryLock()就是非阻塞的支持公平锁和非公平锁:Synchronized 是非公平锁,ReentrantLock(boolean fair)可以创建公平锁 面试官: 小伙子,有点东西。你是怎么设计一个分布式锁? 我: 有几种常用的工具都可以实现分布式锁。比如:关系型数据库(例如:MySQL)、分布式数据库(例如:Redis)、分布式协调服务框架(例如:zookeeper) 使用 MySQL 实现分布式锁比较简单,建一张表:
复制代码 获取锁的时候,就插入一条记录。插入成功就代表获取到锁,插入失败就代表获取锁失败。
复制代码 释放锁的时候,就删除这条记录。
复制代码 实现比较简单,不过还不能用于实际生产中,有几个问题没有解决:
就是这么麻烦,我们看一下优化之后的锁变成什么样了:
这下应该完美了吧?不行,还有个问题: 业务逻辑没处理完,锁过期了怎么办? 假如我们设置锁过期时间是 6 秒,正常情况下业务逻辑可以在 6 秒内处理完成,但是当 JVM 发生 FullGC 或者调用第三方服务出现网络延迟,业务逻辑还没处理完,锁已经过期,被删掉,然后被其他线程获取到锁,岂不是要出问题? 这就引入了另一个知识点“锁续期”: 获取锁的同时,启动一个异步任务,每当业务执行到三分之一时间,也就是 6 秒中的第 2 秒的时候,就自动延长锁过期时间,继续延长到 6 秒,这样就能保证业务逻辑处理完成之前锁不会过期。 面试官: 小伙子,分布式锁算是让你玩明白了。我还想继续问,生产中一般很少用 MySQL 做分布式锁,因为 MySQL 并发性能跟不上。刚才提到 Redis 也可以实现分布式锁,你知道该怎么实现吗?
我: 使用 Redis 实现分布式锁,跟使用 MySQL 类似,也需要解决实现过程中遇到的各种问题,不过解决方案稍有不同。 最简单的获取锁方式:
当“resource_name1”不存在时,set 成功,也就是获取锁成功。 不过还需要加上过期时间,防止没有释放锁。
又引入新问题了,两条命令不是原子的,可能获取锁之后还没来得及设置过期时间就宕机了,这该怎么办? 好办,在 Redis 2.6.12 之后,提供一条复合命令:
复制代码 还有一个问题,释放锁的时候,并没有判断锁的持有者,有可能把其他线程持有的锁给释放了,这可不行,可以这样做:
这样行不行呢?还不行,因为 get 和 del 两条命令不是原子操作,需要引入 Lua 脚本把两条命令打包成一条发给 Redis 执行:
这样总行了吧?还不行,还有个“锁续期”的问题没有解决。 更简单了,Redis 客户端 Redisson 已经帮我们实现续期的功能,叫“WatchDog”(看门狗),在我们调用 lock 自动唤醒“看门狗”。 面试官: 小伙子,你可真行啊。你再讲一下使用 zookeeper 怎么实现分布式锁? 我: zookeeper 采用树形节点,类似 Linux 目录文件结构,同一目录下的节点名称不能重复。 节点有分为四种类型: 持久节点: 一旦创建,永久存储在服务器上,除非手动删除。临时节点: 生命周期与客户端绑定,客户端断开连接,节点就被自动删除。持久顺序节点: 特性同持久节点,只是在节点名称后面追加自增有序数字。临时顺序节点: 特性同临时节点,只是在节点名称后面追加自增有序数字。 zookeeper 还有个监听-通知机制,客户端可以在资源节点上创建 watch 事件。当节点发生变化,会通知客户端,客户端可以根据变化做相应的业务处理。 我们可以利用临时顺序节点的特性创建分布式锁,分以下三步:
实现逻辑很简单,我们来分析一下 zookeeper 实现分布式锁的优点:
面试官: 小伙子,升级加薪的机会就是留给你这样的人。薪资 double,明天就来上班吧。 总结: 关于分布式锁的所有知识点,虽然很多,但都已经总结在这张图上了,欢迎点赞收藏转发评论。 |
|
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2025年4日历 | -2025/4/22 12:29:03- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |