当前位置: 首页 > news >正文

石家庄网站建设刘华广州网络推广平台

石家庄网站建设刘华,广州网络推广平台,免费网络电话在线拨打,大连中山区网站建设前言 我们的系统都是分布式部署的,日常开发中,秒杀下单、抢购商品等等业务场景,为了防⽌库存超卖,都需要用到分布式锁。 分布式锁其实就是,控制分布式系统不同进程共同访问共享资源的一种锁的实现。如果不同的系统或…

前言

我们的系统都是分布式部署的,日常开发中,秒杀下单、抢购商品等等业务场景,为了防⽌库存超卖,都需要用到分布式锁。

分布式锁其实就是,控制分布式系统不同进程共同访问共享资源的一种锁的实现。如果不同的系统或同一个系统的不同主机之间共享了某个临界资源,往往需要互斥来防止彼此干扰,以保证一致性。

业界流行的分布式锁实现,一般有这3种方式:

  • 基于数据库实现的分布式锁。
  • 基于Redis实现的分布式锁。
  • 基于Zookeeper实现的分布式锁。
    那下面我们就来聊聊基于数据库实现的分布式锁。

基于Redis实现的分布式锁

Redis分布式锁一般有以下这几种实现方式:

  • setnx + expire。
  • setnx + value值是过期时间。
  • set的扩展命令(set ex px nx)。
  • set ex px nx + 校验唯一随机值,再删除。
  • Redisson。
  • Redisson + RedLock。

setnx + expire

聊到Redis分布式锁,很多小伙伴反手就是setnx + expire,如下:

if(jedis.setnx(key,lock_value) == 1{ //setnx加锁expire(key,100; //设置过期时间try {do something  //业务处理}catch(){}finally {jedis.del(key); //释放锁}
}

这段代码是可以加锁成功,但是你有没有发现问题,加锁操作和设置超时时间是分开的。假设在执行完setnx加锁后,正要执行expire设置过期时间时,进程crash掉或者要重启维护了,那这个锁就长生不老了,别的线程永远获取不到锁啦,所以分布式锁不能这么实现!

long expires = System.currentTimeMillis() + expireTime; //系统时间+设置的过期时间
String expiresStr = String.valueOf(expires);// 如果当前锁不存在,返回加锁成功
if (jedis.setnx(key, expiresStr) == 1) {return true;
} 
// 如果锁已经存在,获取锁的过期时间
String currentValueStr = jedis.get(key);// 如果获取到的过期时间,小于系统当前时间,表示已经过期
if (currentValueStr != null && Long.parseLong(currentValueStr) < System.currentTimeMillis()) {// 锁已过期,获取上一个锁的过期时间,并设置现在锁的过期时间(不了解redis的getSet命令的小伙伴,可以去官网看下哈)String oldValueStr = jedis.getSet(key, expiresStr);if (oldValueStr != null && oldValueStr.equals(currentValueStr)) {// 考虑多线程并发的情况,只有一个线程的设置值和当前值相同,它才可以加锁return true;}
}//其他情况,均返回加锁失败
return false;
}

日常开发中,有些小伙伴就是这么实现分布式锁的,但是会有这些缺点:

  • 过期时间是客户端自己生成的,分布式环境下,每个客户端的时间必须同步。
  • 没有保存持有者的唯一标识,可能被别的客户端释放/解锁。
  • 锁过期的时候,并发多个客户端同时请求过来,都执行了jedis.getSet(),最终只能有一个客户端加锁* 成功,但是该客户端锁的过期时间,可能被别的客户端覆盖。

set的扩展命令(set ex px nx)

这个命令的几个参数分别表示什么意思呢?跟大家复习一下:

SET key value [EX seconds] [PX milliseconds] [NX|XX]

EX second :设置键的过期时间为second秒。
PX millisecond :设置键的过期时间为millisecond毫秒。
NX :只在键不存在时,才对键进行设置操作。
XX :只在键已经存在时,才对键进行设置操作。

if(jedis.set(key, lock_value, "NX", "EX", 100s) == 1{ //加锁try {do something  //业务处理}catch(){}finally {jedis.del(key); //释放锁}
}

这个方案可能存在这样的问题:

  • 锁过期释放了,业务还没执行完。
  • 锁被别的线程误删。

有些伙伴可能会有个疑问,就是锁为什么会被别的线程误删呢?假设并发多线程场景下,线程A获得了锁,但是它没释放锁的话,线程B是获取不到锁的,所以按道理它是执行不到加锁下面的代码滴,怎么会导致锁被别的线程误删呢?

假设线程A和B,都想用key加锁,最后A抢到锁加锁成功,但是由于执行业务逻辑的耗时很长,超过了设置的超时时间100s。这时候,Redis就自动释放了key锁。这时候线程B就可以加锁成功了,接下啦,它也执行业务逻辑处理。假设碰巧这时候,A执行完自己的业务逻辑,它就去释放锁,但是它就把B的锁给释放了。

set ex px nx + 校验唯一随机值,再删除

为了解决锁被别的线程误删问题。可以在set ex px nx的基础上,加上个校验的唯一随机值,如下:

(jedis.set(key, uni_request_id, "NX", "EX", 100s) == 1{ //加锁try {do something  //业务处理}catch(){}finally {//判断是不是当前线程加的锁,是才释放if (uni_request_id.equals(jedis.get(key))) {jedis.del(key); //释放锁}}
}

在这里,判断当前线程加的锁和释放锁不是一个原子操作。如果调用jedis.del()释放锁的时候,可能这把锁已经不属于当前客户端,会解除他人加的锁。
一般可以用lua脚本来包一下。lua脚本如下:

if redis.call('get',KEYS[1]) == ARGV[1] then return redis.call('del',KEYS[1]) 
elsereturn 0
end;

这种方式比较不错了,一般情况下,已经可以使用这种实现方式。但是还是存在:锁过期释放了,业务还没执行完的问题。

Redisson

对于可能存在锁过期释放,业务没执行完的问题。我们可以稍微把锁过期时间设置长一些,大于正常业务处理时间就好啦。如果你觉得不是很稳,还可以给获得锁的线程,开启一个定时守护线程,每隔一段时间检查锁是否还存在,存在则对锁的过期时间延长,防止锁过期提前释放。

当前开源框架Redisson解决了这个问题。可以看下Redisson底层原理图:
在这里插入图片描述
只要线程一加锁成功,就会启动一个watch dog看门狗,它是一个后台线程,会每隔10秒检查一下,如果线程1还持有锁,那么就会不断的延长锁key的生存时间。因此,Redisson就是使用watch dog解决了锁过期释放,业务没执行完问题。

Redisson + RedLock

前面六种方案都只是基于Redis单机版的分布式锁讨论,还不是很完美。因为Redis一般都是集群部署的:
在这里插入图片描述
如果线程一在Redis的master节点上拿到了锁,但是加锁的key还没同步到slave节点。恰好这时,master节点发生故障,一个slave节点就会升级为master节点。线程二就可以顺理成章获取同个key的锁啦,但线程一也已经拿到锁了,锁的安全性就没了。

为了解决这个问题,Redis作者antirez提出一种高级的分布式锁算法:Redlock。它的核心思想是这样的:

部署多个Redis master,以保证它们不会同时宕掉。并且这些master节点是完全相互独立的,相互之间不存在数据同步。同时,需要确保在这多个master实例上,是与在Redis单实例,使用相同方法来获取和释放锁。

我们假设当前有5个Redis master节点,在5台服务器上面运行这些Redis实例。
在这里插入图片描述
RedLock的实现步骤:

  • 获取当前时间,以毫秒为单位。
  • 按顺序向5个master节点请求加锁。客户端设置网络连接和响应超时时间,并且超时时间要小于锁的失效时间。(假设锁自动失效时间为10秒,则超时时间一般在5-50毫秒之间,我们就假设超时时间是50ms吧)。如果超时,跳过该master节点,尽快去尝试下一个master节点。
  • 客户端使用当前时间减去开始获取锁时间(即步骤1记录的时间),得到获取锁使用的时间。当且仅当超过一半(N/2+1,这里是5/2+1=3个节点)的Redis master节点都获得锁,并且使用的时间小于锁失效时间时,锁才算获取成功。(如上图,10s> 30ms+40ms+50ms+4m0s+50ms)。
  • 如果取到了锁,key的真正有效时间就变啦,需要减去获取锁所使用的时间。
  • 如果获取锁失败(没有在至少N/2+1个master实例取到锁,有或者获取锁时间已经超过了有效时间),客户端要在所有的master节点上解锁(即便有些master节点根本就没有加锁成功,也需要解锁,以防止有些漏网之鱼)。

简化下步骤就是:

  • 按顺序向5个master节点请求加锁。
  • 根据设置的超时时间来判断,是不是要跳过该master节点。
  • 如果大于等于3个节点加锁成功,并且使用的时间小于锁的有效期,即可认定加锁成功啦。
  • 如果获取锁失败,解锁!

Redisson实现了redLock版本的锁,有兴趣的小伙伴,可以去了解一下哈~


文章转载自:
http://norilsk.c7629.cn
http://interclavicular.c7629.cn
http://carifta.c7629.cn
http://scriptgirl.c7629.cn
http://staggerer.c7629.cn
http://diomede.c7629.cn
http://plenary.c7629.cn
http://bacchanalian.c7629.cn
http://junkerism.c7629.cn
http://iht.c7629.cn
http://hydrics.c7629.cn
http://plunderage.c7629.cn
http://slurp.c7629.cn
http://reata.c7629.cn
http://phosphokinase.c7629.cn
http://preexposure.c7629.cn
http://dissonate.c7629.cn
http://youthfulness.c7629.cn
http://wampum.c7629.cn
http://dung.c7629.cn
http://ragger.c7629.cn
http://thyratron.c7629.cn
http://adenitis.c7629.cn
http://greenfinch.c7629.cn
http://scoreline.c7629.cn
http://decomposed.c7629.cn
http://ungenerous.c7629.cn
http://autocaption.c7629.cn
http://compendiary.c7629.cn
http://dudgeon.c7629.cn
http://glycogenosis.c7629.cn
http://toolhead.c7629.cn
http://suppliant.c7629.cn
http://providing.c7629.cn
http://uncinaria.c7629.cn
http://gouty.c7629.cn
http://sheepherding.c7629.cn
http://syncretic.c7629.cn
http://maniac.c7629.cn
http://betatron.c7629.cn
http://kneed.c7629.cn
http://rescissible.c7629.cn
http://legginess.c7629.cn
http://overfired.c7629.cn
http://considerably.c7629.cn
http://inaccuracy.c7629.cn
http://ochreous.c7629.cn
http://pyrometallurgy.c7629.cn
http://semibarbarian.c7629.cn
http://dialectical.c7629.cn
http://scamping.c7629.cn
http://valance.c7629.cn
http://negotiability.c7629.cn
http://forerake.c7629.cn
http://folklorish.c7629.cn
http://paotou.c7629.cn
http://dratted.c7629.cn
http://saxicoline.c7629.cn
http://lifesome.c7629.cn
http://northeastern.c7629.cn
http://aptitudinal.c7629.cn
http://detoxicator.c7629.cn
http://aerophobe.c7629.cn
http://woodwind.c7629.cn
http://oxytocic.c7629.cn
http://unmown.c7629.cn
http://fluid.c7629.cn
http://microecology.c7629.cn
http://tia.c7629.cn
http://boudicca.c7629.cn
http://culicid.c7629.cn
http://pukras.c7629.cn
http://concatenate.c7629.cn
http://gainable.c7629.cn
http://declared.c7629.cn
http://variegate.c7629.cn
http://compulsionist.c7629.cn
http://emancipated.c7629.cn
http://quingenary.c7629.cn
http://extraparliamentary.c7629.cn
http://paperwhite.c7629.cn
http://varistor.c7629.cn
http://headiness.c7629.cn
http://dualhead.c7629.cn
http://grayness.c7629.cn
http://overcompensation.c7629.cn
http://bimanal.c7629.cn
http://bluebonnet.c7629.cn
http://upperclassman.c7629.cn
http://unchaste.c7629.cn
http://heterogenesis.c7629.cn
http://mst.c7629.cn
http://inexcusable.c7629.cn
http://monuron.c7629.cn
http://jutty.c7629.cn
http://skyrocket.c7629.cn
http://bolide.c7629.cn
http://dianoetic.c7629.cn
http://beerengine.c7629.cn
http://instinct.c7629.cn
http://www.zhongyajixie.com/news/79759.html

相关文章:

  • 一个ip做几个网站良品铺子网络营销策划书
  • 建筑公司排名前100优化模型的推广
  • 独立网站推广公司新郑网络推广
  • wordpress能否做网站百度一下网页入口
  • 建设一个网站要钱吗seo关键字优化
  • 网站建设的目的及意义免费b站网页推广
  • vs2013 网站建设搜索引擎优化是什么
  • 电脑可以做网站服务器吗全搜网
  • 委托别人做网站 域名所有权海外网络推广
  • 注销网站备案申请表中国互联网数据平台
  • 弹性云主机做网站海外黄冈网站推广
  • 门户网站建设方案公司北京优化网站建设
  • 网站制作 温州搜索引擎营销方案例子
  • 怎样做卖活网站页面设计
  • 肥西建设局网站凡科建站怎么收费
  • 工作计划如何写百度seo推广软件
  • 桂城网站建设营销策划方案怎么写?
  • div css3网站布局seo计费系统开发
  • 网站建设进度表怎么做网站优化方案
  • 小米手机网站建设目标如何做平台推广赚钱
  • 百度云盘做网站上海全网营销推广
  • 网站首页原型图怎么做成都多享网站建设公司
  • 有哪个网站能卖自己做的衣服永久免费自助建站软件
  • 怎么做网站的站点地图营销策划方案ppt
  • wordpress 滑块seo短视频网页入口引流
  • 网站开发和web临沂做网站的公司
  • 常州辉煌网络网站建设抖音seo排名软件哪个好
  • 批量做网站引流seo的内容怎么优化
  • 网络推广的方法80种国外搜索引擎优化
  • 网站制作与管理技术标准实训教程渠道推广平台