目前几乎很多大型网站及应用都是分布式部署的,分布式场景中的数据一致性问题一直是一个比较重要的话题。分布式的CAP理论告诉我们“任何一个分布式系统都无法同时满足一致性(Consistency)、可用性(Availability)和分区容错性(Partition tolerance),最多只能同时满足两项。”所以,很多系统在设计之初就要对这三者做出取舍。在互联网领域的绝大多数的场景中,都需要牺牲强一致性来换取系统的高可用性,系统往往只需要保证“最终一致性”,只要这个最终时间是在用户可以接受的范围内即可。

在很多场景中,我们为了保证数据的最终一致性,需要很多的技术方案来支持,比如分布式事务、分布式锁等。有的时候,我们需要保证一个方法在同一时间内只能被同一个线程执行。在单机环境中,Java中其实提供了很多并发处理相关的API,但是这些API在分布式场景中就无能为力了。也就是说单纯的Java Api并不能提供分布式锁的能力。所以针对分布式锁的实现目前有多种方案。

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

基于数据库实现分布式锁 基于缓存(redis,memcached,tair)实现分布式锁 基于Zookeeper实现分布式锁

在分析这几种实现方案之前我们先来想一下,我们需要的分布式锁应该是怎么样的?(这里以方法锁为例,资源锁同理)

可以保证在分布式部署的应用集群中,同一个方法在同一时间只能被一台机器上的一个线程执行。这把锁要是一把可重入锁(避免死锁)这把锁最好是一把阻塞锁(根据业务需求考虑要不要这条)有高可用的获取锁和释放锁功能获取锁和释放锁的性能要好


基于数据库实现分布式锁

基于数据库表

要实现分布式锁,最简单的方式可能就是直接创建一张锁表,然后通过操作该表中的数据来实现了。

当我们要锁住某个方法或资源时,我们就在该表中增加一条记录,想要释放锁的时候就删除这条记录。

创建这样一张数据库表:

CREATE TABLE `methodLock` (

`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',

`method_name` varchar(64) NOT NULL DEFAULT '' COMMENT '锁定的方法名',

`desc` varchar(1024) NOT NULL DEFAULT '备注信息',

`update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '保存数据时间,自动生成',

PRIMARY KEY (`id`),

UNIQUE KEY `uidx_method_name` (`method_name `) USING BTREE

) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='锁定中的方法';

当我们想要锁住某个方法时,执行以下SQL:

insert into methodLock(method_name,desc) values (‘method_name’,‘desc’)

因为我们对method_name做了唯一性约束,这里如果有多个请求同时提交到数据库的话,数据库会保证只有一个操作可以成功,那么我们就可以认为操作成功的那个线程获得了该方法的锁,可以执行方法体内容。

当方法执行完毕之后,想要释放锁的话,需要执行以下Sql:

delete from methodLock where method_name ='method_name'

上面这种简单的实现有以下几个问题:

1、这把锁强依赖数据库的可用性,数据库是一个单点,一旦数据库挂掉,会导致业务系统不可用。2、这把锁没有失效时间,一旦解锁操作失败,就会导致锁记录一直在数据库中,其他线程无法再获得到锁。3、这把锁只能是非阻塞的,因为数据的insert操作,一旦插入失败就会直接报错。没有获得锁的线程并不会进入排队队列,要想再次获得锁就要再次触发获得锁操作。4、这把锁是非重入的,同一个线程在没有释放锁之前无法再次获得该锁。因为数据中数据已经存在了。

当然,我们也可以有其他方式解决上面的问题。

  • 数据库是单点?搞两个数据库,数据之前双向同步。一旦挂掉快速切换到备库上。
  • 没有失效时间?只要做一个定时任务,每隔一定时间把数据库中的超时数据清理一遍。
  • 非阻塞的?搞一个while循环,直到insert成功再返回成功。
  • 非重入的?在数据库表中加个字段,记录当前获得锁的机器的主机信息和线程信息,那么下次再获取锁的时候先查询数据库,如果当前机器的主机信息和线程信息在数据库可以查到的话,直接把锁分配给他就可以了。

基于数据库排他锁

除了可以通过增删操作数据表中的记录以外,其实还可以借助数据中自带的锁来实现分布式的锁。

我们还用刚刚创建的那张数据库表。可以通过数据库的排他锁来实现分布式锁。 基于MySql的InnoDB引擎,可以使用以下方法来实现加锁操作:

public boolean lock(){

connection.setAutoCommit(false)

while(true){

try{

result = select * from methodLock where method_name=xxx for update;

if(result==null){

return true;

}

}catch(Exception e){

}

sleep(1000);

}

return false;

}

在查询语句后面增加for update,数据库会在查询过程中给数据库表增加排他锁(这里再多提一句,InnoDB引擎在加锁的时候,只有通过索引进行检索的时候才会使用行级锁,否则会使用表级锁。这里我们希望使用行级锁,就要给method_name添加索引,值得注意的是,这个索引一定要创建成唯一索引,否则会出现多个重载方法之间无法同时被访问的问题。重载方法的话建议把参数类型也加上。)。当某条记录被加上排他锁之后,其他线程无法再在该行记录上增加排他锁。

我们可以认为获得排它锁的线程即可获得分布式锁,当获取到锁之后,可以执行方法的业务逻辑,执行完方法之后,再通过以下方法解锁:

public void unlock(){

connection.commit();

}

通过connection.commit()操作来释放锁。

这种方法可以有效的解决上面提到的无法释放锁和阻塞锁的问题。

  • 阻塞锁? for update语句会在执行成功后立即返回,在执行失败时一直处于阻塞状态,直到成功。
  • 锁定之后服务宕机,无法释放?使用这种方式,服务宕机之后数据库会自己把锁释放掉。

但是还是无法直接解决数据库单点和可重入问题。

这里还可能存在另外一个问题,虽然我们对method_name 使用了唯一索引,并且显示使用for update来使用行级锁。但是,MySql会对查询进行优化,即便在条件中使用了索引字段,但是否使用索引来检索数据是由 MySQL 通过判断不同执行计划的代价来决定的,如果 MySQL 认为全表扫效率更高,比如对一些很小的表,它就不会使用索引,这种情况下 InnoDB 将使用表锁,而不是行锁。如果发生这种情况就悲剧了。。。


还有一个问题,就是我们要使用排他锁来进行分布式锁的lock,那么一个排他锁长时间不提交,就会占用数据库连接。一旦类似的连接变得多了,就可能把数据库连接池撑爆

总结

总结一下使用数据库来实现分布式锁的方式,这两种方式都是依赖数据库的一张表,一种是通过表中的记录的存在情况确定当前是否有锁存在,另外一种是通过数据库的排他锁来实现分布式锁。

数据库实现分布式锁的优点

直接借助数据库,容易理解。

数据库实现分布式锁的缺点

会有各种各样的问题,在解决问题的过程中会使整个方案变得越来越复杂。

操作数据库需要一定的开销,性能问题需要考虑。

使用数据库的行级锁并不一定靠谱,尤其是当我们的锁表并不大的时候。


基于缓存实现分布式锁

相比较于基于数据库实现分布式锁的方案来说,基于缓存来实现在性能方面会表现的更好一点。而且很多缓存是可以集群部署的,可以解决单点问题。

目前有很多成熟的缓存产品,包括Redis,memcached以及我们公司内部的Tair。

这里以Tair为例来分析下使用缓存实现分布式锁的方案。关于Redis和memcached在网络上有很多相关的文章,并且也有一些成熟的框架及算法可以直接使用。

基于Tair的实现分布式锁其实和Redis类似,其中主要的实现方式是使用TairManager.put方法来实现。

public boolean trylock(String key) {

ResultCode code = ldbTairManager.put(NAMESPACE, key, "This is a Lock.

分布式锁的三种实现方式_分布式锁的几种实现方式~相关推荐

  1. 分布式锁的三种实现方式_分布式锁的多种实现方式

    目前几乎很多大型网站及应用都是分布式部署的,分布式场景中的数据一致性问题一直是一个比较重要的话题.分布式的CAP理论告诉我们"任何一个分布式系统都无法同时满足一致性(Consistency) ...

  2. 依赖注入的三种方式_一起学Spring之三种注入方式及集合类型注入

    本文主要讲解Spring开发中三种不同的注入方式,以及集合数据类型的注入,仅供学习分享使用,如有不足之处,还请指正. 概述 Spring的注入方式一共有三种,如下所示: 通过set属性进行注入,即通过 ...

  3. 查询方式中断方式_【每日“一”题】中断方式

    ↑ 点击上方"计算机考研说"关注我们 1. 某磁盘的转速为10 000转/分,平均寻道时间是6  ms,磁盘传输速率是20  MB/s,磁盘控制器延迟为0.2 ms,读取一个4 K ...

  4. g2是一种编程语言吗_我写了一种编程语言。 这也是您可以的方式。

    g2是一种编程语言吗 by William W Wold 威廉·沃尔德(William W Wold) 我写了一种编程语言. 这也是您可以的方式. (I wrote a programming lan ...

  5. 创建线程的方式_创建线程有几种不同的方式?

    方式可以用来创建线程 1)继承Thread类 2)实现Runnable接口 3)应用程序可以适用Executor框架来创建线程池 实现了Runnable接口这种方式更受欢迎,因为这不需要继承Threa ...

  6. 墙面有几种装修方法_墙面装修有几种方式

    展开全部 墙面装修其实e68a84e8a2ad62616964757a686964616f31333366303833是室内装修中比较基础的一个步骤,一般来说室内装修大致上可以分为两个部分,一个部分就 ...

  7. sa结构组网方式_关于 SA/NSA 两种组网模式,你了解多少?-通信/网络-与非网

    之前关于一则 5G 的消息在引起了大家的关注,中移动董事长表示,明年 1 月 1 日起非独立组网5G 手机将不能入网. 这样的新闻在很多自媒体的报道和发酵之下,不知怎么就变成了 NSA 是" ...

  8. 负载均衡的几种方式_负载均衡的几种方式

    负载均衡其实就是任务的分发,使得任务能按照你的预想分配到各个计算单元上,它能提高服务对外的性能,避免单点失效场景.这里要注意的一点是虽说叫负载均衡,但是有时候我们的分配算法就是不是均衡的. 比如配个n ...

  9. 四种依恋类型_依恋类型的四种模式影响着我们的亲密关系

    如果你想拥有一段健康快乐的关系,你首先需要更好地了解自己和自己的需求.了解自己的依恋类型不仅能帮助你更好地理解自己的需求,还能更好地向别人表达这些需求,并找到一个能够满足这些需求的伴侣. 一项针对10 ...

最新文章

  1. 实现Date函数属性中的format方法
  2. 关于SQL漏洞注入(Ado.Net)
  3. 配置浮动路由,实现链路冗余
  4. BEA Workshop Studio有什么用?
  5. hive 和 impala 时间参数错误的问题 yyyy-MM-dd
  6. 贝壳集团IPO背后,风投协议之外还要面临何时盈利的问题
  7. hiveSql常见错误记录
  8. boost::gil::pixel_bit_size用法的测试程序
  9. 【Python反射】通过函数名称获取函数
  10. MGW——美团点评高性能四层负载均衡
  11. html点击图片放大_vue 插件之picture-markert图片标注
  12. 东八区转为0时区_格林尼治时间转换为北京时间
  13. 计算机网络系统由什么系统组成,从资源构成上看计算机网络系统由什么构成
  14. 使用cmd命令创建vue(ivieiw)项目
  15. Linux桌面鼠标取词自动翻译
  16. 汇编语言与接口技术——期末设计
  17. 永不停歇(obama在亚利桑那州治大学毕业典礼上的演讲)
  18. bootstrap 图片上传框架
  19. Python黑马头条推荐系统第五天 头条排序模型进阶-神经网络
  20. 华硕fx60vm拆机图解_技术编辑处置华硕fx60vm【处理手段】

热门文章

  1. 使用SAP Analytics Cloud显示全球新冠肺炎确诊人数和发展趋势的预测
  2. 如何将bing搜索页面以HTML Mashup的方式嵌入到SAP C4C页面
  3. SAP UI5 Web Component的图标实现
  4. SAP SD数据库表一览
  5. SAP UI5 why failed to load 'sap/cus/crm/lib/reuse/library.js' from resources/sap/cus/crm
  6. CRM order lock will trigger product read API
  7. when is oData transaction data request sent for an xml view binding case
  8. Jerry带您了解Restful ABAP Programming模型系列之二:Action和Validation的实现
  9. UI5 xml view里control id的生成逻辑
  10. 另一种launch SAP CRM AET的方式