企业网站推广技巧有哪些怎样做免费网站推广
news/
2025/9/26 18:16:07/
文章来源:
企业网站推广技巧有哪些,怎样做免费网站推广,欧美简约风格网站设计,南昌网站开发公司电话1.你说一下什么是分布式锁
分布式锁是一种在分布式系统环境下实现的锁机制#xff0c;它主要用于解决#xff0c;多个分布式节点之间对共享资源的互斥访问问题#xff0c;确保在分布式系统中#xff0c;即使存在有多个不同节点上的进程或线程#xff0c;同一时刻也只有一…1.你说一下什么是分布式锁
分布式锁是一种在分布式系统环境下实现的锁机制它主要用于解决多个分布式节点之间对共享资源的互斥访问问题确保在分布式系统中即使存在有多个不同节点上的进程或线程同一时刻也只有一个节点可以获得锁并对共享资源进行操作从而维护数据的一致性和完整性。
扩展
分布式锁的特点
当然要实现一个分布式锁还需要考虑一些东西比如Redis的健壮性它不能随便挂掉这里总结一下分布式锁的一些要素为了确保分布式锁可用我们至少要确保锁的实现同时满足以下四个条件
互斥性同一时间只能一个节点获取到锁其他节点需要等待获取到锁的节点释放了锁才可以获取到锁而这里的等待一般是通过阻塞和自旋两种方式安全性解铃还须系铃人只能释放自己的锁不能误删别人的锁死锁比如在节点宕机时最容易出现锁没被释放的问题然后出现死锁所以做锁的过期容错当Redis宕机客户端仍然可以释放锁可重入获取锁失败可以重新尝试获取锁
2.分布式锁常用的三种方案
基于数据库实现通常基于主键或者唯一索引来实现分布式锁,但是性能比较差一般不建议使用
基于Redis 可以使用setnx来加锁 但是需要设置锁的自动删除来防止死锁所以要结合expire使用.为了保证setnx和expire两个命令的原子性可以使用set命令组合。
另外释放锁在finallly中调用del删除锁而删除锁前需要判断该锁是否是当前线程加的锁以免误删除锁需要通过get获取锁然后进行判断但是需要保证get判断或和del删除锁的原子性可以使用LUA脚本实现。
基于zookeeper 使用临时顺序节点实现线程进来都去创建临时顺序节点,第一个节点的创建线程获取到锁后面的节点监听自己的上一个节点的删除事件如果第一个节点被删除释放锁第二个节点就成为第一个节点获取到锁。
在项目中可以使用curator这个是Apache封装好的基于zookeeper的分布式锁方案。
扩展
zookeeper
存储结构
Zookeeper会维护一个具有层次关系的树状的数据结构它非常类似于一个标准的文件系统,如下图所示:同一个目录下不能有相同名称的目录节点 ZooKeeper 节点是有生命周期的这取决于节点的类型在 ZooKeeper 中节点类型可以分为持久节点PERSISTENT 、临时节点EPHEMERAL以及时序节点SEQUENTIAL 具体在节点创建过程中一般是组合使用可以生成以下 4 种节点类型。
持久节点PERSISTENT所谓持久节点是指在节点创建后就一直存在直到有删除操作来主动清除这个节点——不会因为创建该节点的客户端会话失效而消失。持久顺序节点PERSISTENT_SEQUENTIAL这类节点的基本特性和上面的节点类型是一致的。额外的特性是在ZK中每个父节点会为他的第一级子节点维护一份时序会记录每个子节点创建的先后顺序。基于这个特性在创建子节点的时候可以设置这个属性那么在创建节点过程中ZK会自动为给定节点名加上一个数字后缀作为新的节点名。这个数字后缀的范围是整型的最大值。临时节点EPHEMERAL和持久节点不同的是临时节点的生命周期和客户端会话绑定。也就是说如果客户端会话失效那么这个节点就会自动被清除掉。注意这里提到的是会话失效而非连接断开。另外在临时节点下面不能创建子节点。临时顺序节点EPHEMERAL_SEQUENTIAL在临时几点的基础上增加了顺序可以用来实现分布式锁
顺序节点可以用来为所有的事件进行全局排序这样客户端可以通过序号推断事件的顺序。
zookeeper分布式锁原理
分布式锁就是基于zk的 临时顺序节点watch监听机制完成的。临时顺序节点特点是客户端断开节点释放且自己维护节点顺序值当多个线程同时创建节点我们就可以按照顺序创建N个顺序临时节点然后依次从第一个往后获取锁。只不过能拿到锁的只能是第一个节点的线程所以后面的线程需要监听自己上一个节点的节点释放。轮到谁谁就拿到锁。 3.Redis如何实现分布式锁用什么命令
可以使用setnx来加锁 但是需要设置锁的自动删除来防止死锁所以要结合expire使用.为了保证setnx和expire两个命令的原子性可以使用set命令组合。
扩展
setnx命令只会在key不存在时将将键的key设置为value。若已经存在则不做操作。
例如果三个服务同时抢锁服务A抢先一步执行setnx(lock_stock,1)加上锁那么当服务B在执行setnx(lock_stock,1)加锁的时候就会失败服务C也一样服务A抢到锁执行完业务逻辑后就会释放锁可以使用del(lock_stock)删除锁其他服务就可以执行setnx(lock_stock,1)加锁了 ifjedis.setnxlock_stock1 1{ //获取锁expirelock_stock5 //设置锁超时try {业务代码} finally {jedis.dellock_stock //释放锁}
} 4.Redis实现分布式锁可能会出现什么问题如何解决
锁超时问题加锁和释放锁的原子性问题锁的误删除问题get获取锁和删除锁的原子性问题集群模式中redis节点宕机问题添加锁和设置过期时间可以使用set命令进行组合达到原子性加锁需要用lua解决删除和判断锁的原子性否则可能会删除掉别人的锁。Redis集群环境中redis节点挂掉可能会导致加锁失败可以使用Redisson的红锁来解决。
扩展
锁超时问题
这里有一个问题如果获取到锁的服务在释放锁的时候宕机了那么Redis中lock-stock不就永远存在那锁不就释放不了么别的服务也就没办法获取到锁就造成了死锁为了解决这个问题我们需要设置锁的自动超时也就是Key的超时自动删除即使服务宕机没有调用del释放锁那么锁本身也有超时时间可以自动删除锁别的服务就可以获取锁了Redis中Key的过期时间可以使用Redis的 expirelock_stock30命令实现这里给出伪代码如下
ifjedis.setnxlock_stock1 1{ //获取锁expirelock_stock5 //设置锁超时try {业务代码} finally {jedis.dellock_stock //释放锁}
}
setnx和expire操作的原子性问题
上面的代码依然有问题就是setnx获取锁和expire不是原子性操作假设有一极端情况当线程通过setnxlock_stock1获取到锁还没来得及执行expirelock_stock30设置锁的过期时间服务就宕机了那是不是锁也永远得不到释放呢又变成了死锁这个问题可以使用set命令解决我们先来看一下这个命令的语法
SET key value [EX seconds] [PX milliseconds] [NX|XX]
EX seconds设置时间单位为秒PX milliseconds设置时间单位为毫秒NX即setnx中的nx就是key值不存在时才去执行XX 只在键已经存在时 才对键进行设置操作。
也就是说该命令可以当做setnx和expire的组合命令来使用而且是原子性的改造代码如
ifset(lock_stock,1,NX,EX,5) 1{ //获取锁并设置超时try {业务代码} finally {dellock_stock //释放锁}
}
锁的误删除问题
上面的方案依然有问题就是在del释放锁的时候可能会误删除别人加的锁例如服务A获取到锁lock_stock过期时间为 5s如果在服务A执行业务逻辑的这一段时间内锁到期自动删除且别的服务获取到了锁lock_stock那么服务A业务执行完成执行del(lock_stock)有可能会把别人的锁给删除掉 解决方案 我们可以在删除锁的时候先判断一下要删除的锁是不是自己上的锁比如可以把锁的值使用一个UUID在释放锁的时候先获取一下锁的值和当前业务中创建的UUID是不是同一个如果是才执行·del删除锁当然也可以使用线程的ID替代UUID代码如
String uuid UUID.randomUUID().toString();
ifjedis.set(lock_stock,uuid,NX,EX,5) 1{ //获取锁并设置超时try {业务代码} finally {String lockValue jedis.get(lock_stock); //获取锁的值if(lockValue.equals(uuid)){ //判断是不是自己的锁jedis.dellock_stock //释放锁}}
}lua脚本保证操作的原子性
但是上面的代码依然有问题就是判断锁的代码和删除锁的代码也不是原子性的依然可能会导致锁的误删除问题比如服务A在判断锁成功准备删除锁时锁自动过期别的服务B获取到了锁然后服务A执行DEL就可能会把服务B的锁给删除掉所以我们必须保证 获取锁 - 判断锁 - 删除锁 的操作是原子性的才可以解决方案可以使用RedisLua脚本来解决一致性问题
String script if redis.call(get, KEYS[1]) ARGV[1] then return redis.call(del, KEYS[1]) else return 0 end;redis.call(‘get’, KEYS[1]) 是调用redis的get命令key可以通过参数传入 ARGV[1] 意思是是否和 某个值相等这里的值也可以参数传入then return redis.call(‘del’, KEYS[1]) 如果相等就执行 redis.call(del, KEYS[1]) 删除操作else return 0 end 否则就返回 0
如果我们把数据带入KEYS[1]的值为“lock_stock”,ARGV[1]的值为UUID如“xoxoxo”所以大概的含义是如果调用get(“lock_stock”)获取到的值 等于 “xoxoxo” ,那就调用 del(“lock_stock”)否则就返回 0 。 说白了就是把我们上面的判断锁和删除锁的动作使用Lua脚本去执行而已现在代码可以这样写了
String uuid UUID.randomUUID().toString();
ifjedis.set(lock_stock,uuid,NX,EX,5) 1{ //获取锁并设置超时try {业务代码} finally {//lua脚本String script if redis.call(get, KEYS[1]) ARGV[1] then return redis.call(del, KEYS[1]) else return 0 end;//执行脚本jedis.eval(script, Collections.singletonList(lock_stock),Collections.singletonList(uuid));}
} 5.你项目中怎么使用分布式锁的
自己封装Redis的分布式锁是很麻烦的我们可以使用Redissoin来实现分布式锁Redissoin已经封装好了
扩展
Redisson加锁自动有过期时间30s监控锁的看门狗发现业务没执行完会自动进行锁的续期(重回30s)这样做的好处是防止在程序执行期间锁自动过期被删除问题当业务执行完成不再给锁续期即使没有手动释放锁锁的过期时间到了也会自动释放锁 Redisson执行流程
如果没有设置过期时间Redisson以 30s 作为锁的默认过期时间获取锁成功后(底层也用到了Lua脚本保证原子性)会开启一个定时任务定时进行锁过期时间续约即每次都把过期时间设置成 30s定时任务 10s执行一次(看门狗)
如果设置了过期时间直接把设定的过期时间作为锁的过期时间然后使用Lua脚本获取锁没获取到锁的线程会while自旋重入不停地尝试获取锁
这里需要注意rLock.lock(10, TimeUnit.SECONDS)指定了解锁时间Redisson就不会再自动续期那么如果在线程A业务还没执行完就自动解锁了这时候线程B获取到锁继续执行业务那么等线程A业务执行完释放锁就可能会把线程B的锁删除当然这种情况Redisson会报异常但是这种情况是没有把所有线程都锁住的所以如果要手动设定过期时间需要让过期时间比业务逻辑执行的时间长才对
红锁RedLock
Redis常用的方式有单节点、主从模式、哨兵模式、集群模式在后三种模式中可能会出现 异步数据丢失脑裂问题Redis官方提供了解决方案RedLock,RedLock是基于redis实现的分布式
锁它能够保证以下特性
容错性只要多数节点的redis实例正常运行就能够对外提供服务,加锁释放锁互斥性只能有一个客户端能获取锁即使发生了网络分区或者客户端宕机也不会发生死锁
基于Redis的Redisson红锁RedissonRedLock对象实现了Redlock介绍的加锁算法。该对象也可以用来将多个RLock对象关联为一个红锁每个RLock对象实例可以来自于不同的Redisson实例
RLock lock1 redissonInstance1.getLock(lock1);
RLock lock2 redissonInstance2.getLock(lock2);
RLock lock3 redissonInstance3.getLock(lock3);RedissonRedLock lock new RedissonRedLock(lock1, lock2, lock3);
// 同时加锁lock1 lock2 lock3
// 红锁在大部分节点上加锁成功就算成功。
lock.lock();
lock.unlock();
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/918656.shtml
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!