分布式计数器的思路是:指定一个Zookeeper数据节点作为计数器,多个应用实例在分布式锁的控制下,通过更新该数据节点的内容来实现计数功能。

Curator中封装了实现,例如 DistributedAtomicInteger 和 DistributedAtomicLong。

以下是我写的一个测试用例:

  1. package com.my.CuratorTest;
  2. import org.apache.curator.framework.CuratorFramework;
  3. import org.apache.curator.framework.CuratorFrameworkFactory;
  4. import org.apache.curator.framework.recipes.atomic.AtomicValue;
  5. import org.apache.curator.framework.recipes.atomic.DistributedAtomicLong;
  6. import org.apache.curator.retry.ExponentialBackoffRetry;
  7. import org.apache.curator.retry.RetryNTimes;
  8. import java.util.concurrent.CyclicBarrier;
  9. import java.util.concurrent.ExecutorService;
  10. import java.util.concurrent.Executors;
  11. /**
  12. * Title: 分布式计数器演示<br/>
  13. * Intention: <br/>
  14. * <p>
  15. * Class Name: com.my.CuratorTest.RecipesDisAutomicLong<br/>
  16. * Create Date: 2017/8/20 22:48 <br/>
  17. * Project Name: MyTest <br/>
  18. * Company:  All Rights Reserved. <br/>
  19. * Copyright © 2017 <br/>
  20. * </p>
  21. * <p>
  22. * author: GaoWei <br/>
  23. * 1st_examiner: <br/>
  24. * 2nd_examiner: <br/>
  25. * </p>
  26. *
  27. * @version 1.0
  28. * @since JDK 1.7
  29. */
  30. public class RecipesDisAutomicLong {
  31. static String disAutomicIntPath = "/curator_recipes_distatomicint_path3";
  32. static CuratorFramework client = CuratorFrameworkFactory.builder()
  33. .connectString("127.0.0.1:2181")
  34. .retryPolicy(new ExponentialBackoffRetry(1000, 3)).build();
  35. static  DistributedAtomicLong atomicLong =
  36. new DistributedAtomicLong(client, disAutomicIntPath, new RetryNTimes(10, 500),
  37. null);
  38. public static void main(String[] args) throws Exception{
  39. client.start();
  40. Long[] nums = {1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L, 10L};
  41. ExecutorService executor = Executors.newFixedThreadPool(nums.length);
  42. CyclicBarrier barrier = new CyclicBarrier(nums.length);
  43. atomicLong.compareAndSet(atomicLong.get().postValue(), new Long(0));
  44. for (int i=0;i<nums.length;i++) {
  45. final int k = i;
  46. executor.execute(new Runnable() {
  47. @Override
  48. public void run() {
  49. try {
  50. barrier.await();
  51. System.out.println(Thread.currentThread().getName()+" " + System.nanoTime()+ " , 开始执行");
  52. AtomicValue<Long> av = atomicLong.add(nums[k]);
  53. System.out.println("to add value=" + nums[k] + ", Result=" + av.succeeded() + " preValue=" + av.preValue()
  54. + " postValue=" + av.postValue());
  55. } catch (Exception e) {
  56. e.printStackTrace();
  57. }
  58. }
  59. });
  60. }
  61. executor.shutdown();
  62. }
  63. }

运行结果:

pool-3-thread-10 89586635189009 , 开始执行
pool-3-thread-8 89586635508120 , 开始执行
pool-3-thread-9 89586635501453 , 开始执行
pool-3-thread-7 89586635493898 , 开始执行
pool-3-thread-6 89586635480564 , 开始执行
pool-3-thread-5 89586635470342 , 开始执行
pool-3-thread-4 89586635427231 , 开始执行
pool-3-thread-3 89586635410787 , 开始执行
pool-3-thread-2 89586635360564 , 开始执行
pool-3-thread-1 89586635236564 , 开始执行
to add value=10, Result=true preValue=0 postValue=10
to add value=2, Result=true preValue=10 postValue=12
to add value=6, Result=true preValue=12 postValue=18
to add value=1, Result=true preValue=18 postValue=19
to add value=7, Result=true preValue=19 postValue=26
to add value=3, Result=true preValue=26 postValue=29
to add value=4, Result=true preValue=29 postValue=33
to add value=8, Result=true preValue=33 postValue=41
to add value=9, Result=true preValue=41 postValue=50
to add value=5, Result=true preValue=50 postValue=55

如果在DistributedAtomicLong的构造方法参数中,RetryNTimes重试次数不够,比如是3,你会发现并不一定每次加数都会成功。显然这里是用了乐观锁机制,它并不保证操作一定成功(它在重试这么多次中都没有成功获得锁,导致操作没有执行),所以我们有必要通过调用 av.succeeded() 来查看此次加数是否成功。

下面是RetryNTimes为3时的某一次运行结果:

pool-3-thread-1 89922027531135 , 开始执行
pool-3-thread-5 89922027681802 , 开始执行
pool-3-thread-8 89922027737357 , 开始执行
pool-3-thread-4 89922027673802 , 开始执行
pool-3-thread-9 89922028120024 , 开始执行
pool-3-thread-10 89922027531580 , 开始执行
pool-3-thread-2 89922027616024 , 开始执行
pool-3-thread-3 89922027606246 , 开始执行
pool-3-thread-7 89922027722691 , 开始执行
pool-3-thread-6 89922027699580 , 开始执行
to add value=9, Result=true preValue=0 postValue=9
to add value=10, Result=true preValue=9 postValue=19
to add value=4, Result=true preValue=19 postValue=23
to add value=7, Result=true preValue=23 postValue=30
to add value=3, Result=true preValue=30 postValue=33
to add value=2, Result=true preValue=33 postValue=35
to add value=5, Result=true preValue=35 postValue=40
to add value=1, Result=false preValue=35 postValue=0
to add value=6, Result=false preValue=35 postValue=0
to add value=8, Result=false preValue=35 postValue=0

参考:

1、从PAXOS到ZOOKEEPER分布式一致性原理与实践

zookeeper 分布式计数器的更多相关文章

  1. zookeeper之分布式锁以及分布式计数器(通过curator框架实现)

    有人可能会问zookeeper我知道,但是curator是什么呢? 其实curator是apachede针对zookeeper开发的一个api框架是apache的顶级项目 他与zookeeper原生a ...

  2. ZooKeeper 分布式锁

    在Redis分布式锁一文中, 作者介绍了如何使用Redis开发分布式锁. Redis分布式锁具有轻量高吞吐量的特点,但是一致性保证较弱.我们可以使用Zookeeper开发分布式锁,来满足对高一致性的要 ...

  3. Zookeeper分布式过程协同技术 - 群首选举

    Zookeeper分布式过程协同技术 - 群首选举 群首概念 群首为集群中服务器选择出来的一个服务器,并被集群认可.设置群首目的在与对客户端所发起的状态变更请求进行排序,包括:create.setDa ...

  4. Zookeeper 分布式锁 (图解+秒懂+史上最全)

    文章很长,而且持续更新,建议收藏起来,慢慢读! 高并发 发烧友社群:疯狂创客圈(总入口) 奉上以下珍贵的学习资源: 疯狂创客圈 经典图书 : 极致经典 + 社群大片好评 < Java 高并发 三 ...

  5. Curator Zookeeper分布式锁

    Curator Zookeeper分布式锁 pom.xml中添加如下配置 <!-- https://mvnrepository.com/artifact/org.apache.curator/c ...

  6. Zookeeper分布式集群搭建

    实验条件:3台安装linux的机子,配置好Java环境. 步骤1:下载并分别解包到每台机子的/home/iHge2k目录下,附上下载地址:http://mirrors.cnnic.cn/apache/ ...

  7. ZooKeeper 分布式锁实现

    1 场景描述 在分布式应用, 往往存在多个进程提供同一服务. 这些进程有可能在相同的机器上, 也有可能分布在不同的机器上. 如果这些进程共享了一些资源, 可能就需要分布式锁来锁定对这些资源的访问. 2 ...

  8. ZooKeeper分布式锁浅谈(一)

    一.概述 清明节的时候写了一篇分布式锁概述,里面介绍了分布式锁实现的几种方式,其实那时候我一直沉迷于使用redis的悲观锁和乐观锁来实现分布式锁,直到一个血案的引发才让我重新认识了redis分布式锁的 ...

  9. [转载] zookeeper 分布式锁服务

    转载自http://www.cnblogs.com/shanyou/archive/2012/09/22/2697818.html 分布式锁服务在大家的项目中或许用的不多,因为大家都把排他放在数据库那 ...

随机推荐

  1. 【Matplotlib】线设置,坐标显示范围

    改变线的颜色和线宽 参考文章: controlling line properties Line API 线有很多属性你可以设置:线宽,线型,抗锯齿等等:具体请参考matplotlib.lines.L ...

  2. 049——VUE中使用animation与transform实现vue的动画效果

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  3. android中LayoutInflater.from(context).inflate的分析

    在应用中自定义一个view,需要获取这个view的布局,需要用到 (LinearLayout) LayoutInflater.from(context).inflate(R.layout.conten ...

  4. java基础第10天

    Java异常 Exception 异常指的的在运行期出现的错误,在编译阶段出现的语法错误等,不能称之为异常. 编译类异常 必须处理之后才能正常编译(类找不到,IO异常,在API文档中明确写明throw ...

  5. New Concept English Two 32 88

    $课文86  失控 940. As the man tried to swing the speedboat round, the steering wheel came away in his ha ...

  6. Cause: org.postgresql.util.PSQLException: ERROR: cached plan must not change result type的前因后果

    首先说明一下遇到的问题: PG数据库,对其中的某张表增加一列后,应用报错,信息如下: 应用使用相关框架如下:SpringBoot.MyBatis. ### Cause: org.postgresql. ...

  7. C#中系统时间和UNIX时间戳互相转换

    在项目开发过程中,有时会遇到不同程序之间相互调用数据,数据中不免会包含时间,比如ASP.NET调用PHP,牵扯到时间就要做一下处理,PHP程序中一般存取的都是UNIX时间,不像ASP.NET存储的是年 ...

  8. 7-8 List Leaves(25 分)

    Given a tree, you are supposed to list all the leaves in the order of top down, and left to right. I ...

  9. streamsets mongodb destinations 使用

    测试集成了directory(excel) 以及redis && field splitter 组件 pipeline flow docker-compose 配置 redis 服务& ...

  10. streamsets excel 数据处理

    streamsets 有一个directory的origin 可以方便的进行文件的处理,支持的格式也比较多,使用简单 pipeline flow 配置 excel 数据copy 因为使用的是容器,会有 ...