分布式锁的多种实现方式详解

前言

对多线程有所了解的朋友一般都会熟悉一个概念:锁。

在多线程并发场景下,要保证在同一时刻只有一个线程可以操作某个业务、数据或者变量,通常需要使用加锁机制。比如synchronizedLock等。

而随着架构演进、业务发展,我们的应用往往都不是只部署在一台服务器上,而是使用分布式集群架构,同时存在多台相同的应用。

比如某电商网站在进行商品销售时,因为商品的数量是有限的,每个用户购买一件商品,需要将商品的库存减1;

但是我们想一下,在“双十一”这种火爆的活动时,可能会有大量的用户购买同一件商品,同时对该商品库存减1,如果不加锁,则极有可能会造成商品超卖情况。

要保证在这种分布式场景下,共享数据的安全性和一致性,则需要使用分布式锁。上面例子中的商品库存就是共享数据。

什么是分布式锁

顾名思义,分布式锁是指在分布式场景下,保证同一时刻对共享数据只能被一个应用的一个线程操作。用来保证共享数据的安全性和一致性。

分布式锁应该满足哪些要求

现在我们来分析一下,我们要实现一个分布式锁的话,需要满足哪些要求呢?

  • 首先最基本的,我们要保证同一时刻只能有一个应用的一个线程可以执行加锁的方法,或者说获取到锁;(一个应用线程执行
  • 然后我们这个分布式锁可能会有很多的服务器来获取,所以我们一定要能够高性能的获取和释放;(高性能
  • 不能因为某一个分布式锁获取的服务不可用,导致所有服务都拿不到或释放锁,所以要满足高可用要求;(高可用
  • 假设某个应用获取到锁之后,一直没有来释放锁,可能服务本身已经挂掉了,不能一直不释放,导致其他服务一直获取不到锁;(锁失效机制,防止死锁
  • 一个应用如果成功获取到锁之后,再次获取锁也可以成功;(可重入性
  • 在某个服务来获取锁时,假设该锁已经被另一个服务获取,我们要能直接返回失败,不能一直等待。(非阻塞特性

以上是所有分布式锁要满足的一些基本要求。

实现方式有哪些

那么我们可以采取哪种方式来实现分布式锁呢?目前常见的方式主要有以下三种:

  • 基于数据库实现
  • 基于ZooKeeper实现
  • 基于Redis实现

接下来我们看看这三种方式具体都是怎样实现分布式锁的。

基于数据库

使用数据库实现分布式锁,有两种方式。

第一种是基于数据库表实现。

比如我们有如下表来保存分布式锁记录:

CREATE TABLE `methodLock` ( 
    `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',  
    `method_name` varchar(64) NOT NULL COMMENT '锁定的方法名',
    `desc` varchar(1024) NOT NULL DEFAULT '备注信息',
    `update_time` timestamp NOT NULL DEFAULT now() ON UPDATE now() COMMENT '保存时间',  
    PRIMARY KEY (`id`),
    UNIQUE KEY `uidx_method_name` (`method_name `)
) ENGINE=InnoDB COMMENT='分布式锁定的方法';
复制代码

当我们的某个服务要执行某段需要分布式锁定的方法时,则执行插入语句,在该表中插入一条记录。

insert into methodLock(method_name,desc) values ('saleProduct','出售产品减库存');
复制代码

因为我们在定义表时,method_name添加了唯一约束,如果在我们插入记录时,有多个服务都要执行这个操作,那么数据库可以保证只能有一个服务成功,我们认为只有插入成功的那个服务获取到了锁,可以继续执行该方法。

当方法执行完毕后,需要释放锁,则执行一条删除语句,将插入表中的记录删除。

delete from methodLock where method_name = 'saleProduct';
复制代码

另一种是基于数据库排他锁。

除了上面的通过插入删除的方式外,借助排它锁实现分布式

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
分布式锁的主要目的是在分布式系统中实现多个线程之间的互斥和可见性,从而让这些线程在某些业务场景下可以串行执行。通常情况下,在单个JVM中,可以通过使用synchronized锁或Lock锁来实现线程的串行执行。但是在分布式系统中,由于服务拆分或集群的需要,单个JVM中的锁无法实现不同服务器或不同JVM中线程的互斥。因此,需要使用分布式锁实现这种互斥。 分布式锁多种实现方式,比如基于MySQL、Redis、Zookeeper等。在使用Redis作为分布式锁时,可以利用SETNX命令来实现锁的获取和释放。SETNX命令会向Redis中添加一个key,只有当该key不存在时才添加并返回1,若key已存在则不添加并返回0。因为SETNX命令是原子性的,所以多个线程同时对同一个key执行SETNX命令时,只会有一个线程成功添加锁,从而实现了互斥。释放锁只需要将锁对应的key删除即可。 为了防止死锁,可以给锁设置过期时间,以防止某个线程获取锁后未能释放锁导致其他线程无法获取锁的情况。此外,分布式锁还存在一些问题,如重入问题、不可重试问题、超时释放和主从一致性问题等。这些问题需要根据具体情况进行解决。 综上所述,使用SETNX命令来实现分布式锁可以确保多线程之间的互斥和可见性。通过设置过期时间等方法可以增加分布式锁的稳定性和安全性。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [SETNX分布锁详解](https://blog.csdn.net/qq_47288175/article/details/127441620)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值