你的位置:免费情侣作爱视频 > 老头把我添高潮了a片 > 少妇厨房愉情理伦片视频下载 从Curator完毕散播式锁的源码再到羊群效应

少妇厨房愉情理伦片视频下载 从Curator完毕散播式锁的源码再到羊群效应

时间:2022-05-10 21:37 点击:201 次
一、引子

Curator是一款由Java编写的少妇厨房愉情理伦片视频下载,操作Zookeeper的客户端器具,在其里面封装了散播式锁、选举等高等功能。

今上帝如果分析其完毕散播式锁的主要旨趣,算计散播式锁的一些先快乐其他完毕,有兴味的同学不错翻阅以下著作:

我用了上万字,走了一遍Redis完毕散播式锁的凹凸之路,从单机到主从再到多实例,蓝本会发生这样多的问题_阳阳的博客-CSDN博客

Redisson可重入与锁续期源码分析_阳阳的博客-CSDN博客

在使用Curator获取散播式锁时,Curator会在指定的path下创建一个有序的临时节点,如果该节点是最小的,则代表获取锁告捷。

接下来,在准备使命中,咱们不错明察是否会创建出一个临时节点出来。

二、准备使命

领先咱们需要搭建一个zookeeper集群,天然你使用单机也行。

在这篇著作口试官:能给我画个Zookeeper选举的图吗?,先容了一种使用docker-compose模式快速搭建zk集群的模式。

在pom中引入依赖:少妇厨房愉情理伦片视频下载

<dependency> 少妇厨房愉情理伦片视频下载         <groupId>org.apache.curator</groupId>          <artifactId>curator-recipes</artifactId>          <version>2.12.0</version>      </dependency

 Curator客户端的竖立项:

/**  * @author qcy  * @create 2022/01/01 22:59:34  */ @Configuration public class CuratorFrameworkConfig {      //zk各节点地址     private static final String CONNECT_STRING = "localhost:2181,localhost:2182,localhost:2183";     //承接超往往代(单元:毫秒)     private static final int CONNECTION_TIME_OUT_MS = 10 * 1000;     //会话超往往代(单元:毫秒)     private static final int SESSION_TIME_OUT_MS = 30 * 1000;     //重试的开动恭候时期(单元:毫秒)     private static final int BASE_SLEEP_TIME_MS = 2 * 1000;     //最大重试次数     private static final int MAX_RETRIES = 3;      @Bean     public CuratorFramework getCuratorFramework() {         CuratorFramework curatorFramework = CuratorFrameworkFactory.builder()                 .connectString(CONNECT_STRING)                 .connectionTimeoutMs(CONNECTION_TIME_OUT_MS)                 .sessionTimeoutMs(SESSION_TIME_OUT_MS)                 .retryPolicy(new ExponentialBackoffRetry(BASE_SLEEP_TIME_MS, MAX_RETRIES))                 .build();         curatorFramework.start();         return curatorFramework;     }      } 

 SESSION_TIME_OUT_MS参数则会保证,在某个客户端获取到锁之后倏得宕机,zk能在该时期内删除现时客户端创建的临时有序节点。

测试代码如下:

//临时节点旅途,qcy是博主名字缩写哈    private static final String LOCK_PATH = "/lockqcy";     @Resource    CuratorFramework curatorFramework;     public void testCurator() throws Exception {        InterProcessMutex interProcessMutex = new InterProcessMutex(curatorFramework, LOCK_PATH);        interProcessMutex.acquire();         try {            //模拟业务耗时            Thread.sleep(30 * 1000);        } catch (Exception e) {            e.printStackTrace();        } finally {            interProcessMutex.release();        }    } 

 当使用接口调用该设施时,在Thread.sleep处打上断点,干与到zk容器中明察创建出来的节点。

使用 docker exec -it zk容器名 /bin/bash 以交互模式干与容器少妇厨房愉情理伦片视频下载,接着使用 ./bin/zkCli.sh 承接到zk的server端。

然后使用 ls path 检察节点

这三个节点都是耐久节点,不错使用 get path 检察节点的数据结构信息

若一个节点的ephemeralOwner值为0,即该节点的临时领有者的会话id为0,则代表该节点为耐久节点。

当走到断点Thread.sleep时,确乎发目下lockqcy下创建出来一个临时节点

​到这里吗少妇厨房愉情理伦片视频下载,准备使命仍是做已矣,接下来分析interProcessMutex.acquire与release的历程

三、源码分析

Curator复旧多种类型的锁,举例

InterProcessMutex,可重入锁排它锁 InterProcessReadWriteLock,读写锁 InterProcessSemaphoreMutex,不成重入排它锁

今上帝如果分析InterProcessMutex的加解锁过程,先看加锁过程

加锁
public void acquire() throws Exception {       if (!internalLock(-1, null)) {           throw new IOException("Lost connection while trying to acquire lock: " + basePath);       }   } 

 这里是防碍式获取锁,获取不到锁,就一直进行防碍。是以对于internalLock设施,超往往代诞生为-1,时期单元诞生成null。

private boolean internalLock(long time, TimeUnit unit) throws Exception {        Thread currentThread = Thread.currentThread();        //通过能否在map中取到该线程的LockData信息,来判断该线程是否仍是持有锁        LockData lockData = threadData.get(currentThread);        if (lockData != null) {            //进行可重入,平直复返加锁告捷            lockData.lockCount.incrementAndGet();            return true;        }        //进行加锁        String lockPath = internals.attemptLock(time, unit, getLockNodeBytes());        if (lockPath != null) {            //加锁告捷,保存到map中            LockData newLockData = new LockData(currentThread, lockPath);            threadData.put(currentThread, newLockData);            return true;        }         return false;    } 

其中threadData是一个map,key线程对象,value为该线程绑定的锁数据。

7-bit address :2 的 7 次方,能挂 128 个设备。

按照当前的这种发展趋势,我国也做出了明确的发展计划,那就是在今后不仅需要始终保持领先之位,同时到2035年时,其境内的5G基站数量需要达到了360万座,由此也可以看出我国对于5G的发展还是充满信心的。

统商人和售卖方式亦在不断“升级”,面对更好的购物体验,越来越多的人选择进行网上交易,这对传统的面面交易无疑是一个巨大的冲击。尤其是近几年,网购人数的激增,致使线上成交额逐年飙升,至今依旧是呈加速度式增长,5G网的运行又为电商的发展按下了加速键!

这并非是电信运营商第一次将矛头指向互联网巨头,但是13家运营商联合“揭竿而起”并不多见。类似的问题在很多国家都出现过少妇厨房愉情理伦片视频下载,这对国内运营商的启示是什么?

LockData中保存了加锁线程owningThread,重入计数lockCount与加锁旅途lockPath,举例

/lockqcy/_c_c46513c3-ace0-405f-aa1e-a531ce28fb47-lock-0000000005 
private final ConcurrentMap<Thread, LockData> threadData = Maps.newConcurrentMap();      private static class LockData {         final Thread owningThread;         final String lockPath;         final AtomicInteger lockCount = new AtomicInteger(1);          private LockData(Thread owningThread, String lockPath) {             this.owningThread = owningThread;             this.lockPath = lockPath;         }     } 

 干与到internals.attemptLock设施中

String attemptLock(long time, TimeUnit unit, byte[] lockNodeBytes) throws Exception {       //发轫时期       final long startMillis = System.currentTimeMillis();       //将超往往代长入行化为毫秒单元       final Long millisToWait = (unit != null) ? unit.toMillis(time) : null;       //节点数据,这里为null       final byte[] localLockNodeBytes = (revocable.get() != null) ? new byte[0] : lockNodeBytes;       //重试次数       int retryCount = 0;       //锁旅途       String ourPath = null;       //是否获取到锁       boolean hasTheLock = false;       //是否完成       boolean isDone = false;        while (!isDone) {           isDone = true;            try {               //创建一个临时有序节点,并复返节点旅途               //里面调用client.create().creatingParentContainersIfNeeded().withProtection().withMode(CreateMode.EPHEMERAL_SEQUENTIAL).forPath(path);               ourPath = driver.createsTheLock(client, path, localLockNodeBytes);               //依据复返的节点旅途,判断是否抢到了锁               hasTheLock = internalLockLoop(startMillis, millisToWait, ourPath);           } catch (KeeperException.NoNodeException e) {               //在会话过时时,可能导致driver找不到临时有序节点,从而抛出NoNodeException               //这里就进行重试               if (client.getZookeeperClient().getRetryPolicy().allowRetry(retryCount++, System.currentTimeMillis() - startMillis, RetryLoop.getDefaultRetrySleeper())) {                   isDone = false;               } else {                   throw e;               }           }       }       //获取到锁,则复返节点旅途,供调用方记载到map中       if (hasTheLock) {           return ourPath;       }        return null;   } 

 接下来,将会在internalLockLoop中诈欺刚才创建出来的临时有序节点,判断是否获取到了锁。

private boolean internalLockLoop(long startMillis, Long millisToWait, String ourPath) throws Exception {        //是否获取到锁        boolean haveTheLock = false;        boolean doDelete = false;        try {            if (revocable.get() != null) {                //现时不会干与这里                client.getData().usingWatcher(revocableWatcher).forPath(ourPath);            }            //一直尝试获取锁            while ((client.getState() == CuratorFrameworkState.STARTED) && !haveTheLock) {                //复返basePath(这里是lockqcy)下所有的临时有序节点,况且按照后缀从小到大胪列                List<String> children = getSortedChildren();                //取出现时哨程创建出来的临时有序节点的称呼,这里即是/_c_c46513c3-ace0-405f-aa1e-a531ce28fb47-lock-0000000005                String sequenceNodeName = ourPath.substring(basePath.length() + 1);                //判断现时节点是否处于排序后的首位,如果处于首位,则代表获取到了锁                PredicateResults predicateResults = driver.getsTheLock(client, children, sequenceNodeName,老头把我添高潮了a片 maxLeases);                if (predicateResults.getsTheLock()) {                    //获取到锁之后,则拒绝轮回                    haveTheLock = true;                } else {                    //这里代表莫得获取到锁                    //获取比现时节点索引小的前一个节点                    String previousSequencePath = basePath + "/" + predicateResults.getPathToWatch();                     synchronized (this) {                        try {                            //如果前一个节点不存在,则平直抛出NoNodeException,catch中不进行处理,不才一轮中陆续获取锁                            //如果前一个节点存在,则给它诞生一个监听器,监听它的开释事件                            client.getData().usingWatcher(watcher).forPath(previousSequencePath);                            if (millisToWait != null) {                                millisToWait -= (System.currentTimeMillis() - startMillis);                                startMillis = System.currentTimeMillis();                                //判断是否超时                                if (millisToWait <= 0) {                                    //获取锁超时,删除刚才创建的临时有序节点                                    doDelete = true;                                    break;                                }                                //没超时的话,在millisToWait内进行恭候                                wait(millisToWait);                            } else {                                //无尽期防碍恭候,监听到前一个节点被删除时,才会触发叫醒操作                                wait();                            }                        } catch (KeeperException.NoNodeException e) {                            //如果前一个节点不存在,则平直抛出NoNodeException,catch中不进行处理,不才一轮中陆续获取锁                        }                    }                }            }        } catch (Exception e) {            ThreadUtils.checkInterrupted(e);            doDelete = true;            throw e;        } finally {            if (doDelete) {                //删除刚才创建出来的临时有序节点                deleteOurPath(ourPath);            }        }        return haveTheLock;    } 

 判断是否获取到锁的中枢逻辑位于getsTheLock中

public PredicateResults getsTheLock(CuratorFramework client, List<String> children, String sequenceNodeName, int maxLeases) throws Exception {      //获取现时节点在所有子节点排序后的索引位置      int ourIndex = children.indexOf(sequenceNodeName);      //判断现时节点是否处于子节点中      validateOurIndex(sequenceNodeName, ourIndex);      //InterProcessMutex的构造设施,会将maxLeases开动化为1      //ourIndex必须为0,才气使得getsTheLock为true,也即是说,现时节点必须是basePath下的最末节点,才气代表获取到了锁      boolean getsTheLock = ourIndex < maxLeases;      //如果获取不到锁,则复返上一个节点的称呼,用作对其诞生监听      String pathToWatch = getsTheLock ? null : children.get(ourIndex - maxLeases);       return new PredicateResults(pathToWatch, getsTheLock);  }   static void validateOurIndex(String sequenceNodeName, int ourIndex) throws KeeperException {      if (ourIndex < 0) {          //可能会由于承接丢失导致临时节点被删除,因此这里属于保障步伐          throw new KeeperException.NoNodeException("Sequential path not found: " + sequenceNodeName);      }  } 

 那什么时候,在internalLockLoop处于wait的线程能被叫醒呢?

在internalLockLoop设施中,仍是使用

client.getData().usingWatcher(watcher).forPath(previousSequencePath); 

给前一个节点诞生了监听器,当该节点被删除时,将会触发watcher中的回调

private final Watcher watcher = new Watcher() {         //回调设施         @Override         public void process(WatchedEvent event) {             notifyFromWatcher();         }     };      private synchronized void notifyFromWatcher() {         //叫醒是以在LockInternals实例上恭候的线程         notifyAll();     } 

 到这里,基本上仍是分析完加锁的过程了少妇厨房愉情理伦片视频下载,在这里追忆下:

领先创建一个临时有序节点

如果该节点是basePath下最末节点,则代表获取到了锁,存入map中,下次平直进行重入。

如果该节点不是最末节点,则对前一个节点诞生监听,接着进行wait恭候。现时一个节点被删除时,将会见知notify该线程。

解锁

解锁的逻辑,就相比浅易了,平直干与release设施中

public void release() throws Exception {       Thread currentThread = Thread.currentThread();       LockData lockData = threadData.get(currentThread);       if (lockData == null) {           throw new IllegalMonitorStateException("You do not own the lock: " + basePath);       }        int newLockCount = lockData.lockCount.decrementAndGet();       //平直减少一次重入次数       if (newLockCount > 0) {           return;       }       if (newLockCount < 0) {           throw new IllegalMonitorStateException("Lock count has gone negative for lock: " + basePath);       }        //到这里代表重入次数为0       try {           //开释锁           internals.releaseLock(lockData.lockPath);       } finally {           //从map中移除           threadData.remove(currentThread);       }   }    void releaseLock(String lockPath) throws Exception {       revocable.set(null);       //里面使用guaranteed,会在后台络续尝试删除节点       deleteOurPath(lockPath);   } 

 重入次数大于0,就减少重入次数。当减为0时,调用zk去删除节点,这小数和Redisson可重入锁开释时一致。

四、羊群效应

在这里谈谈使用Zookeeper完毕散播式锁场景中的羊群效应

什么是羊群效应

领先,羊群是一种很狼藉的组织,漫无所在,厚爱不停,一般需要牧羊犬来匡助主人甩手羊群。

某个时候,当其中一只羊发现前边有愈加可口的草而动起来少妇厨房愉情理伦片视频下载,就会导致其余的羊一哄而起,根柢无论周围的情况。

是以羊群效应,指的是一个人在进行感性的活动后,导致其余人平直遵从,产生非感性的从众活动。

而Zookeeper中的羊群效应,则是指一个znode被篡改后,触发了大批本不错被幸免的watch见知,形成集群资源的虚耗。

获取不到锁时的恭候演化 sleep一段时期

如果某个线程在获取锁失败后,饱和不错sleep一段时期,再尝试获取锁。

但这样的模式,成果极低。

sleep时期短的话,会凡俗地进行轮询,虚耗资源。

sleep时期长的话,会出现锁被开释但仍然获取不到锁的窘态情况。

是以,这里的优化点,在于怎么变主动轮询为异步见知。

watch被锁住的节点

所有的客户端要获取锁时,只去创建一个同名的node。

当znode存在时,这些客户端对其诞生监听。当znode被删除后,见知所有恭候锁的客户端,接着这些客户端再次尝试获取锁。

天然这里使用watch机制来异步见知,但是当客户端的数目相等多时,会存在性能低点。

当znode被删除后,在这刹那间,需要给大批的客户端发送见知。在此时期,其余提交给zk的宽泛请求可能会被延长大概防碍。

这就产生了羊群效应,一个点的变化(znode被删除),形成了全面的影响(见知大批的客户端)。

是以,这里的优化点,在于怎么减少对一个znode的监听数目,最佳的情况是唯有一个。

watch前一个有序节点

如果先指定一个basePath,想要获取锁的客户端,平直在该旅途下创建临时有序节点。

当创建的节点是最末节点时,代表获取到了锁。如果不是最小的节点,则只对前一个节点诞生监听器,只监听前一个节点的删除活动。

这样前一个节点被删除时,只会给下一个节点代表的客户端发送见知,不会给所有客户端发送见知,从而幸免了羊群效应。

​在幸免羊群效应的同期,使顺应前锁成为平正锁。即按照肯求锁的先后规矩取得锁,幸免存在饥饿过度的线程。

五、后语

本文从源码角度莳植了使用Curator获取散播式锁的历程,接着从恭候锁的演化过程角度起程,分析了Zookeeper在散播式锁场景下幸免羊群效应的处治有筹画。

这是Zookeeper系列的第二篇,对于其watch旨趣分析、zab合同等著作也在安排的路上了。

 

服务热线
官方网站:www.365jz.com
工作时间:周一至周六(09:00-18:00)
联系我们
QQ:2852320325
邮箱:w365jzcom@qq.com
地址:武汉东湖新技术开发区光谷大道国际企业中心
关注公众号

Powered by 免费情侣作爱视频 RSS地图 HTML地图


免费情侣作爱视频-少妇厨房愉情理伦片视频下载 从Curator完毕散播式锁的源码再到羊群效应