分布式锁的原理解析与实现工具介绍

本文涉及的产品
云数据库 Redis 版,社区版 2GB
推荐场景:
搭建游戏排行榜
云数据库 RDS MySQL Serverless,0.5-2RCU 50GB
简介: 分布式锁的原理解析与实现工具介绍

锁与IPC

常见的锁:互斥锁、自旋锁、原子变量、读写锁、条件变量、信号量。

IPC(进程间通信的方式):pipe、FIFO、信号量、消息队列、共性内存、socket、信号。

(拓展)虚假唤醒解决:把pthread_cond_wait放在while循环体里面,循环里判断condition是否满足。由此还能解决信号劫持的问题,比如线程池里只有一个任务,但是signal唤醒了多个消费者线程,于是需要加入判断,只能有一个线程得到满足。

分布式锁

分布式锁:在分布式场景中使用的锁。操作系统并没有提供分布式锁,只能由用户自行实现。这个锁是抽象的锁,并不是真正的锁。

分布式场景:执行程序、存储等分布在多个节点(节点通常是独立的计算机或设备等)的场景。

分布式场景的特点:执行体分布在不同的节点上,一个节点至少是一个进程。

分布式场景与锁简化模型:

如图,如果s1\s2\s3\s4都想去操作DB(数据库),但是DB同一时间最多只允许一个节点操作,那么需要设置一个锁(lock)放在s1\s2\s3\s4均能取到的地方(比如数据库,有可能和要操作的数据库放在了一起,不过在不同的表里),谁能拿到锁谁就能去操作数据。

分布式锁的构成:资源+行为。

资源:是获取到锁的节点的id(比如s1的id)。

行为:加锁和解锁,分布式场景中加锁和解锁的方式都通过网络通信的方式实现。

加锁:原来没有标记,获取到锁之后打上标记。

解锁:持锁方取出标记。

特性:

锁超时:对持锁方能持有锁的最长时间有限制,如果持锁方崩坏,不至于让其他节点也获取不到资源。

可用性和容错性其实差不多,只不过容错性更侧重数据一致性,可用性更侧重共享节点崩坏的处理。

分布式锁的类型:

重入锁:允许线程多次持有锁。

公平锁:对应互斥锁。拿不到互斥锁的线程进入阻塞态,id进入阻塞队列。

非公平锁:对应自旋锁。拿不到自旋锁的线程进入阻塞态,但是忙等待。

分布式锁的实现工具

需要基于中间件来实现,资源存储在中间件当中,加锁解锁行为基于中间件的特性来实现。

以下分别以mysql和redis为例来实现分布式锁。

用mysql实现分布式锁

首先需要建立在mysql数据库里建立用于存储锁的table,加锁的时候还要记录加锁的时间,因此设置了一个字段记录锁建立的时间。锁类型唯一,说明只能被获取一次,注意:这里的锁类型不是互斥锁、自旋锁等,而是活动1的锁、活动2的锁等。

用户节点加锁。用户节点会将以下sql语句发送到mysql数据库进行加锁操作,如果有多个用户节点,那么先发送到的节点先获取到锁,后发送到的节点会获得操作失败的信息。因为lock_type唯一,因此只有一个节点能获取到锁,获取到锁的时候数据还有记录获取到了锁的owner_id。。

用户节点解锁。解锁的时候owner_id要和之前加锁的时候的记录匹配才能解锁。

其他想获取锁但是没能获取到锁的用户节点,只能每隔一段尝试向mysql去获取一次(因为mysql不会主动通知解锁操作),看看有没有解锁。因此mysql只能实现非公平锁。

Mysql还存在锁超时问题解决,即多起一个进程去检测锁从更新时间已经过了多久了,超时了就解锁。

因此我们发现mysql实现分布式锁有这些缺点:

  1. mysql分布式锁没有可用性。但mysql节点发生了故障,整个分布式系统就会失效。
  2. 消耗资源较多。要实现锁超时操作需要另开进程。
  3. 效率不高。其他用户节点需要不断轮询看看mysql是否解锁了,mysql‘节点不会主动发起通知。
  4. 功能有限。只能是新非公平锁。

用redis实现分布式锁

Redis的特性:

  1. 内存数据库。它将数据存储在内存中而不是磁盘中。
  2. 数据结构数据库。 Redis是一种键值对存储,键一般使用字符串(不绝对)类型,值可以是字符串、哈希表、列表、集合、有序集合等各种类型。

因为redis是一句数据库,启动了之后,会进入redis服务器的运行态,在这上面可以数据redis的操作命令,redis有自己的原语操作命令。

Redis收到以下命令,说明在完成相应的锁操作:

Setnx lock1 user1:用户1尝试抢锁并进行加锁(setnx:set no lock)。

Get lock1:某个用户在尝试看看是谁持有lock1。

Del lock1:如果用户发现锁的持有者是自己,那么可以进行解锁。

注意:get lock1和del lock1需要实现原子性,可以用redis的lua脚本实现。

Set lock user1 nx ex 20:Setnx lock1 user1的拓展版,多了20s之后会自动删除记录的功能,实现锁超时功能。

Ttl lock1:看看lock1还有多久被删除。

Redis分布式锁的lua脚本

用户节点向redis发送命令,redis去执行lua脚本。脚本的具体实现不用被用户知道,但此处进行一下redis的lua脚本的大致解析。

加锁:

先判断锁是否存在。如果不存在则设置锁与超时时间,如果存在则进入监听状态,监听未来释放锁的广播。

解锁:

解锁成功的时候要进行广播,告知给正在监听的用户。

注意防范锁不存在、锁与用户不匹配等问题。如果出现了这些情况那么直接return。

Red-lock算法

目录
相关文章
|
5天前
|
Java
并发编程之线程池的底层原理的详细解析
并发编程之线程池的底层原理的详细解析
15 0
|
5天前
|
SQL 存储 关系型数据库
数据库开发之图形化工具以及表操作的详细解析
数据库开发之图形化工具以及表操作的详细解析
21 0
|
15天前
|
SQL 分布式计算 监控
Sqoop数据迁移工具使用与优化技巧:面试经验与必备知识点解析
【4月更文挑战第9天】本文深入解析Sqoop的使用、优化及面试策略。内容涵盖Sqoop基础,包括安装配置、命令行操作、与Hadoop生态集成和连接器配置。讨论数据迁移优化技巧,如数据切分、压缩编码、转换过滤及性能监控。此外,还涉及面试中对Sqoop与其他ETL工具的对比、实际项目挑战及未来发展趋势的讨论。通过代码示例展示了从MySQL到HDFS的数据迁移。本文旨在帮助读者在面试中展现Sqoop技术实力。
27 2
|
15天前
|
监控 负载均衡 Cloud Native
ZooKeeper分布式协调服务详解:面试经验与必备知识点解析
【4月更文挑战第9天】本文深入剖析ZooKeeper分布式协调服务原理,涵盖核心概念如Server、Client、ZNode、ACL、Watcher,以及ZAB协议在一致性、会话管理、Leader选举中的作用。讨论ZooKeeper数据模型、操作、会话管理、集群部署与管理、性能调优和监控。同时,文章探讨了ZooKeeper在分布式锁、队列、服务注册与发现等场景的应用,并在面试方面分析了与其它服务的区别、实战挑战及解决方案。附带Java客户端实现分布式锁的代码示例,助力提升面试表现。
30 2
|
2天前
|
安全 索引
【集合】03 Linkedlist原理深入解析
【集合】03 Linkedlist原理深入解析
6 0
|
2天前
|
Java Spring 容器
SpringBoot自动装配原理之@Import注解解析
SpringBoot自动装配原理之@Import注解解析
|
4天前
|
存储 NoSQL 分布式数据库
【Flink】Flink分布式快照的原理是什么?
【4月更文挑战第21天】【Flink】Flink分布式快照的原理是什么?
|
4天前
|
缓存 JavaScript 前端开发
|
5天前
|
SQL 分布式计算 资源调度
一文解析 ODPS SQL 任务优化方法原理
本文重点尝试从ODPS SQL的逻辑执行计划和Logview中的执行计划出发,分析日常数据研发过程中各种优化方法背后的原理,覆盖了部分调优方法的分析,从知道怎么优化,到为什么这样优化,以及还能怎样优化。
|
5天前
|
JSON Java Maven
Javaweb之SpringBootWeb案例之 SpringBoot原理的详细解析
Javaweb之SpringBootWeb案例之 SpringBoot原理的详细解析
8 0
Javaweb之SpringBootWeb案例之 SpringBoot原理的详细解析

推荐镜像

更多