java 后端实现网站打开_Java后端精选技术:分布式锁的多种实现方式

news/2024/5/8 12:26:25/文章来源:https://blog.csdn.net/weixin_35866180/article/details/112085832

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

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

51e90b5594cfb77199bbe74d46814f29.png

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

基于数据库实现分布式锁 基于缓存实现分布式锁 基于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.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_803100.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

html 图片灰色,网站变灰色兼容代码 包括图片 支持所有浏览器

一般在全国哀悼日,大地震的日子,清明节,我们都会让自己的网站全站灰色,以表示对逝者的悼念。那么下面分享几种方法1、直接body中加入代码即可实现这种效果很简单,只需要一句css代码:filter: grayscale(100%…

解析 PHP 中 session 的实现原理以及大网站应用应该注意的问题

一 PHP SESSION原理 session 是在服务器端保持用户会话数据的一种方法,而 cookie 是在客户端保持用户数据。HTTP 协议是一种无状态协议,服务器响应完之后就失去了与浏览器的联系。那么,服务器是如何记住众多用户的会话数据呢? 首先…

简单快速的了解网站的安全情况

站长们最关心的问题,也是危害最大的,自己网站有没有被植入木马呢?如何最简单知道呢?下面给你们分享下最简单知道网站有没有被植入木马。 第一种方法: 在浏览器打开网址 http://webscan.360.cn/(如下图,正常…

MVC与单元测试实践之健身网站(二)-管理员模块

2019独角兽企业重金招聘Python工程师标准>>> 开始动手做这个项目时,发现无法做到完全的先设计、再编码,于是决定分模块进行,从管理员模块开始设计、编码,而且接口就已经改了好几次了。 管理员模块涉及的功能有登录和后…

Yahoo团队经验:网站性能优化的34条黄金法则

2019独角兽企业重金招聘Python工程师标准>>> 1、尽量减少HTTP请求次数 终端用户响应的时间中,有80%用于下载各项内容。这部分时间包括下载页面中的图像、样式表、脚本、Flash等。通过减少页面中的元素可以减少 HTTP请求的次数。这是提高网页速度的关键步…

网路游侠:关于几个免费在线挂马检测网站

有时候我们需要知道一个网站的安全性,那么您可以像游侠这样在网站底部挂金山和瑞星的云安全检测系统,如下图所示:需要知道扫描效果的话,看看这两个网址:金山瑞星不过不知道大家看到没,瑞星只说有没有木马&a…

我觉得网站的通用部分

这个图片是我用xmind编辑的。欢迎大家来纠正或添加! 再来说说我对网站开发的理解与碰到的问题。 网站的前端有几个部分我觉得很重要: 1.优雅的文字提示 2.合理的页面设计 3.适当的脚本特效 一进入这个网站,就让人有一种非常舒适的感觉。并且在…

二、大型网站架构模式

为什么80%的码农都做不了架构师?>>> 1.分层:应用层(视图层、业务逻辑层)、服务层(数据接口层、逻辑处理层)、数据层。使逻辑结构清晰,解耦和,便于开发维护。 2.分割&…

使用apacheBench对网站进行压力测试(ab压力测试)

ApacheBench 简称ab, 是 Apache 附带的一个小工具 , 专门用测试网站服务器的运行想能,特别是针对Apache网站服务器的效能分析。专门用于 HTTP Server 的 benchmark testing , 可以同时模拟多个并发请求。 windows下在安装完apache…

SEO优化如何让提高收录量

相信在做SEO优化的网络人员来说,最高兴的时候就是看见自己辛苦打出来的文章被收录了。可是,收录量就有点。。。。今天,我就来教教大家怎么提高收录量,主要分四个方面。 1、收录网站的时间间隔网站的重点是网站页面收录之间的时间间…

如何将网站的php版本信息隐藏起来

当我们把网站上线之后,我们可以通过curl的如下命令显示指定网站的头信息,curl的安装方法参考:https://www.wj0511.com/site/detail.html?id105 curl -I https://www.wj0511.com 如: 这时候可以看到如下信息 X-Powered-By: PHP/7.0.21 这样我们可以看到我们可以…

百度商桥放在php网站哪里_教你如何做好百度竞价推广

如何做好百度推广?这是每个百度客户在加入百度推广后必然想到的一个问题,也是每个实施顾问所困惑的问题。究竟我们可以通过哪些方法达到客户的预期,使客户与百度长久稳定的合作呢?小编给大家分享一下下面是一些优化账户的方法,供大家参考:首…

mysql学习文档_「mysql学习」MySQL学习文档 - seo实验室

mysql学习基础知识1 创建表CREATE TABLE tablename (name1 CHAR(100),name2 NUMERIC,name3 INT);2 向表中按行插入数据INSERT INTO tablename(name1,name2,name3) VALUES(value1,value2,value3);插入多行INSERT INTO tablename(name1,name2,name3) VALUES(value1,value2,value3…

资源网站

文章目录shell教程》](https://www.runoob.com/linux/linux-system-boot.html)![在这里插入图片描述Arduino学习》电子书下载》 shell教程》 Arduino学习》 电子书下载》

php网站友链直显代码,友情链接代码有哪些 怎么写

友情链接版块在大多数网站的底部都会有这块信息展示,少部分博客会在右下角显示友情链接,通常用于与别人的合作或者互相连接,达到引流、引蜘蛛的目的。那么友情链接代码是怎样的呢?href"url",url对应的是网站…

网站常用小图标

转载于:https://blog.51cto.com/181796968/42304

浏览器显示“您与此网站之间建立的连接不安全”的解决方案

现在很多网站打开的时候发现浏览器地址栏多了一个小的信息提示,点开看,谷歌的Chrome浏览器会提示“您与此网站之间建立的连接不安全”,火狐的firefox浏览器会提示“您与此网站之间建立的连接不安全”。 这种一般是什么原因导致的呢&#xff1…

适用于编程开发自学的学习网站

今天为大家分享几个编程开发自学的学习网站 1.C语言网 该网站有很多C语言相关的教程、资源、博客和练手习题,同时也有很多题库和比赛,比较实用。 网址:https://www.dotcpp.com/ 2.cppreference cppreference是一个免费网站,上面…

免费电子书下载网站,不来白嫖一波

作为开发者,多多少少都会看些技术书籍,许多经典的技术书籍作者都是国外的,等到中文翻译版出来很多书籍可能已经不适用了,购买原版书籍,价格又太高,因此知道一些免费的图书下载网站是非常重要的,…

分享一波学习编程刷题网站

相信很多小伙伴在学习了基础知识后并不清楚自己到底掌握了多少知识,也不清楚自己的实力,那这时候就需要做题来检验自己了,这里我就给各位推荐3个刷题网站,供各位大佬参考,互相学习 1.牛客网 网址:https://…