美文网首页
82zookeeper 分布式锁(二)避免羊群效应

82zookeeper 分布式锁(二)避免羊群效应

作者: 滔滔逐浪 | 来源:发表于2021-03-07 22:06 被阅读0次

分布式解决方案:

分布式锁常见问题:

1,Zookeeper如何实现分布式锁;

1,重试策略;
2,超时策略;
3,续命设计,续命如何避免死锁问题。
4,性能优化。
5,高可用
6,公平性。

2, 业务超时,一直不释放锁如何处理;

可以采用续命设计,如果业务超时(),续命多次(3次)如果还没有释放锁的情况下,则认为超时
就应该:
1,主动释放锁;
2,事务回滚
3,主动停止线程
4,移除key
代码思路: 记录每次获取锁的线程,锁的信息 事务信息。
业务如果超时:定义: 当前线程获取到锁之后,在规定的时间内需要释放锁,避免其他的jvm一直阻塞等待。
可以采用续命代码设计: 续命多次如果业务还是没有执行完毕的情况下,则认为该锁超时,应主动释放该锁,防止其他jvm一直阻塞等待。
续命代码设计:
1,主动释放锁
2,回滚当前业务逻辑
3,主动停止该线程
4,移除监听;
代码实现

/**
 * 续命设计
 */
/**
 * 每隔2s执行定时任务
 */
@Scheduled(cron = "0/2 * * * * *")
@Transactional
public synchronized void taskService() {
    try {
        // 拉取数据库数据 调用第三方短信接口发送短信
        // 获取锁
        zookeeperTemplateLock.getLock();
        //##记录锁的开始执行业务逻辑信息
        TransactionStatus begin = translationUtils.begin();
        String lockId = UUID.randomUUID().toString();
        lockInfoMap.put(UUID.randomUUID().toString(), new LockInfo(lockId, Thread.currentThread(), STATE_START, zookeeperTemplateLock
                , translationUtils, begin));
        log.info("[{}]正在调用阿里云发送短信", serverPort);
        userMapper.insert("mayikt" + System.currentTimeMillis(), 22);
        // 模拟业务超时
        Thread.sleep(500000);
        translationUtils.rollback(begin);
        // 释放锁
        lockInfoMap.put(UUID.randomUUID().toString(), new LockInfo(lockId, Thread.currentThread(), STATE_STOP,
                zookeeperTemplateLock, translationUtils, begin));
        zookeeperTemplateLock.unLock();

    } catch (Exception e) {
        log.error("[e:{}]", e);
        TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
    }
}



public MayiktTask() {
    scheduledExecutorService.scheduleAtFixedRate(new DetectionAlgorithm(), 0, 5, TimeUnit.SECONDS);
}

/**
 * 检测死锁的问题
 */
class DetectionAlgorithm implements Runnable {

    @Override
    public void run() {
        lockInfoMap.forEach((k, lockInfo) -> {
            if (STATE_START.equals(lockInfo.getState())) {
                // 主动释放session连接
                lockInfo.getLock().unLock();
                // 事务回滚
                TransactionStatus transactionStatus = lockInfo.getTransactionStatus();
                lockInfo.getTranslationUtils().rollback(transactionStatus);
                log.info("[serverPort:{},lockId:{}]", serverPort, lockInfo + "事务已经回滚...");
                // 主动停止线程
                lockInfo.getLockThread().interrupt();
                // 移除
                lockInfoMap.remove(k);
            }
        });
    }
}
//##创建定时任务线程池
private ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();

3,分布式锁如何避免羊群效应问题?

什么是羊群效应:
当jvm释放锁的时候,会唤醒正在等待的jvm从新进入到获取锁的状态。
如果正在阻塞的等待获取锁的jvm,如果有几十个或者几百个,上千个的情况下zkServer端唤醒所有正在等待的jvm,从新进入到获取锁的状态,唤醒的成本是非常高,有可能会造成我们的zkserver端阻塞。

基于zk实现分布式锁的2种实现方案
1,多个jvm同时在zk上创建一个相同的临时节点,谁能够创建成功,谁就可以拿到这把锁。
存在羊群效应的bug。
2,基于临时顺序编号节点实现,多个jvm同时创建一个临时顺序编号节点,如果当前jvm创建的临时顺序编号节点是最小的情况下,则表示获取锁成功。如果不是最小的情况下,则表示获取锁失败,就会进入到阻塞状态:当前的jvm订阅到我们的上一个节点。;
核心思想: 当我们的jvm释放锁的时候,不会通知一群正在等待获取锁的jvm,而是会通知一个jvm获取锁,效率变高,对我们的zkserver端减去事件通知的压力。
多个jvm枪锁,最终只会有一个jvm能够抢成功。
类似于: juc并发编程中 公平锁实现原理。
伪代码实现:
1,多个jvm同时在zk/localpath 创建一个临时编号节点
2,每个jvm都能够创建到自己独立的临时顺序编号节点。
3,举个例子:
jvm01/localpath01
jvm02/localpath02
jvm03 /localpath03
获取锁的流程:
jvm01--
1,获取当前jvm 创建的临时编号节点localpath01
2,查询到localpath下所有的子节点,实现排序 查找到最小的
3,最小的临时顺序编号节点:localPath01
localPath01==localpath01 如果是最小的节点情况下,则表示获取锁成功。
Jvm02--
1,查询当前jvm创建的临时节点localPath02
2,查询到localpath下所有的子节点,实现排序,查找到最小的
3,最下的临时顺序 编号节点:localPath01
4,localPath02 !=localpath01
5,如果当前自己创建的临时顺序编号节点不是最小的情况下,则会直接阻塞
6.Jvm02订阅到localPath01该临时顺序编号节点:
唤醒以后:
zk服务器端,当localpath01节点删除之后,会通知给jvm02,jvm02从组赛状态到运行状态。
1,获取当前的jvm创建的临时编号节点localpath02
2,查询到localpath下所有的子节点,实现排序,查找到最小的
3,最小的临时顺序编号节点:localpath02
4,localpath02==localpath02 属于最小节点
5,获取锁成功。

羊群效应发生的原因:
如果多个客户端同时订阅同一个节点的情况下,当该节点失效的时候,有可能会通知给所有的客户端,如果客户端有几千或者几万个的情况下,这时会导致zk阻塞效率且非常差。本身我们最终只有一个jvm能够拿到锁,也没有必要通知给所有的客户端。
基于zk实现分布式锁如何解决羊群效应问题:


image.png

1,多个jvm首先会先创建一个临时顺序节点,在通过排序的方式找到最小的节点路径
2,如果当前节点为最小的节点的情况下,则表示获取锁。
3,如果当前节点不是为最小的节点的情况下,订阅上一个节点。
串行化
效果优点类似于:公平锁:

4,如何提高分布式锁的效率问题?

避免羊群效应;

5,Redis与Zookeeper 实现分布式锁区别?

6,分布式锁框架Curator源码解读

7,分布式框架Redisson源码解读

8 如何保证分布式锁高可用性问题。

分布式锁有哪些应用场景

1,集群环境中保证定时任务执行的幂等性问题,基于zk案例;
幂等性:执行结果保证唯一不能够重复。
当我们的定时任务服务集群的情况下,有可能会同时重复执行定时任务。
解决思路: 多个jvm集群的定时任务,在触发的时候,获取分布式锁,如果能够获取分布式锁的jvm,就能够执行定时任务,没有获取到分布式锁的jvm就不能够执行定时任务。


image.png

2,用户下单库存超卖问题,防止超卖Redis解决。

相关文章

  • 82zookeeper 分布式锁(二)避免羊群效应

    分布式解决方案: 分布式锁常见问题: 1,Zookeeper如何实现分布式锁; 1,重试策略;2,超时策略;3,续...

  • Zookeeper学习-08 Zookeeper 分布式锁

    一、设计 使用临时顺序znode来表示获取锁的请求,创建最小后缀数字znode的用户成功拿到锁。 二、避免羊群效应...

  • Java知识框架 - 分布式

    Zookeeper分布式锁创建对应的节点、消耗资源ZK的Watcher机制,唤醒等待、羊群效应创建有序的节点主要角...

  • 分布式专题|如何使用zookeeper实现分布式锁

    分布式专题|如何使用zookeeper实现分布式锁 在分布式中,避免不了使用分布式锁,在前面的专题中,我们已经说过...

  • 2022年随笔系列之(12)心理学小贴士之“羊群效应”

    今天的心理学小贴士依然和动物相关,请看“羊群效应”。 一、了解羊群效应 羊群效应理论应用于心理学,也称羊群行为,别...

  • 「生活感悟」做一只特立独行的羊

    什么叫羊群效应,最简单的理解就是盲目的跟从。 羊群效应是不好意思的心理根源之一。由于不可避免的局限性,一个人不可能...

  • 羊群效应与自我羊群效应

    羊群效应这个词好多人都听说过,那么它到底是什么意思呢? 通俗来讲就是:在羊群中,总有那么一些“出类拔萃”的,对肥美...

  • Redis分布式锁解决方案

    我们知道分布式锁的特性是排他、避免死锁、高可用。分布式锁的实现可以通过数据库的乐观锁(通过版本号)或者悲观锁(通过...

  • 《羊群效应之我见》

    《羊群效应之我见》 今天我听了杨老师讲的自律概念之《羊群效应》,有以下内容和君共勉。羊群效应是指个体的从众跟风...

  • 羊群效应

    何为羊群效应: 有这么一个实验:某高校举办一次特殊的活动,请德国化学家展示他发明的某种挥发性液体。当主持人将满脸大...

网友评论

      本文标题:82zookeeper 分布式锁(二)避免羊群效应

      本文链接:https://www.haomeiwen.com/subject/xfqyqltx.html