基于数据库实现的分布式锁

概述

在单机时代,虽然不需要分布式锁,但也面临过类似的问题,只不过在单机的情况下,如果有多个线程要同时访问某个共享资源的时候,我们可以采用线程间加锁的机制,即当某个线程获取到这个资源后,就立即对这个资源进行加锁,当使用完资源之后,再解锁,其它线程就可以接着使用了。例如,在JAVA中,甚至专门提供了一些处理锁机制的一些API(synchronize/Lock等)。

但是到了分布式系统的时代,这种线程之间的锁机制,就没作用了,系统可能会有多份并且部署在不同的机器上,这些资源已经不是在线程之间共享了,而是属于进程之间共享的资源。

因此,为了解决这个问题,我们就必须引入分布式锁。分布式锁是指在分布式的部署环境下,通过锁机制来让多客户端互斥的对共享资源进行访问。

目前比较常见的分布式锁实现方案有以下几种:

  1. 基于数据库,如MySQL
  2. 基于缓存,如Redis
  3. 基于Zookeeper、etcd等

我们在讨论使用分布式锁的时候往往首先排除掉基于数据库的方案,本能的会觉得这个方案不够“高级”。从性能的角度考虑,基于数据库的方案性能确实不够优异,整体性能对比:缓存 > Zookeeper、etcd > 数据库。也有人提出基于数据库的方案问题很多,不太可靠。笔者认为采用哪种方案是要基于使用场景来看的,选择哪种方案,合适最重要。

我这里引用一下之前文章中的一个应用场景——分配任务场景。在这个场景中,由于是公司的业务后台系统,主要是用于审核人员的审核工作,并发量并不是很高,而且任务的分配规则设计成了通过审核人员每次主动的请求拉取,然后服务端从任务池中随机的选取任务进行分配。这个场景看到这里你会觉得比较单一,但是实际的分配过程中,由于涉及到了按用户聚类的问题,所以要比我描述的复杂,但是这里为了说明问题,大家可以把问题简单化理解。那么在使用过程中,主要是为了避免同一个任务同时被两个审核人员获取到的问题。在这个场景下使用基于数据库的方案就比较合理。

再补充一下,比如某一个服务它下游依赖数据库来做一些数据的读写操作,模型如下图所示:

一般服务也是多实例部署,如果多个实例需要操作同一份数据的时候(比如前面所说的同一个任务同时被两个审核人员获取到的问题),自然而然的引入了分布式锁。不过此时,我们并没有采用数据库的方案,而是引入了Redis,模型如下图所示:

引入Redis之后,正向的收益我就不赘述了,反向的收益是增加了系统的复杂度,对于整个服务而言,还需要多考虑1和2失效的情况。1失效是指服务模块与Redis的交互出现了异常,这种异常不单是指无法通信的异常,也有可能是服务模块发送请求只Redis的过程中或者Redis响应服务模块的过程中出现的异常,整体服务需要考虑这种情况:是重试、丢弃还是采取其他措施;2失效是指Redis本身出现了异常。数据链路一旦变长,系统复杂度一旦变大,在出现问题的时候会阻碍故障排查以及服务恢复,从而使得服务的整体可用性下调。

反观,如果采用数据库的方案,那么就可以省去了这部分的复杂度,如果数据库的方案能满足当下场景以及可视范围内的未来扩展,为什么还要平白地增加系统复杂度呢?大家要根据具体业务场景选择合适的技术方案,而不是随便找一个足够复杂、足够新潮的技术方案来解决业务问题。

下面我们来了解一下基于数据库(MySQL)的方案,一般分为3类:基于表记录、乐观锁和悲观锁。

基于表记录
要实现分布式锁,最简单的方式可能就是直接创建一张锁表,然后通过操作该表中的数据来实现了。当我们想要获得锁的时候,就可以在该表中增加一条记录,想要释放锁的时候就删除这条记录。

为了更好的演示,我们先创建一张数据库表,参考如下:

CREATE TABLE `database_lock` (
	`id` BIGINT NOT NULL AUTO_INCREMENT,
	`resource` int NOT NULL COMMENT '锁定的资源',
	`description` varchar(1024) NOT NULL DEFAULT "" COMMENT '描述',
	PRIMARY KEY (`id`),
	UNIQUE KEY `uiq_idx_resource` (`resource`) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='数据库分布式锁表';
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值