zookeeper分布式计数器

一、背景

在分布式环境中,常规的计数器是不能使用的,在此介绍基本zookeeper实现的分布式计数器(注意说计数器,每次值的修改是可自定义的)。

包括SharedCount计数器,DistributedAtomicLong计数器(如int等其它类型计数器类似)。

二、添加maven依赖


    org.apache.zookeeper
    zookeeper
    3.4.6


    org.apache.curator
    curator-framework
    4.0.0


    org.apache.curator
    curator-client
    4.0.0


    org.apache.curator
    curator-recipes
    4.0.0
三、SharedCount计数器

SharedCount计数器在操作失败时,需要自己去重试,代码如下:

import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.recipes.shared.SharedCount;
import org.apache.curator.framework.recipes.shared.SharedCountListener;
import org.apache.curator.framework.recipes.shared.SharedCountReader;
import org.apache.curator.framework.recipes.shared.VersionedValue;
import org.apache.curator.framework.state.ConnectionState;
import org.apache.curator.retry.ExponentialBackoffRetry;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;
import java.util.function.Consumer;

public class ZookeeperSharedCountMain {
    public static void main(String[] args) throws Exception {
        //创建zookeeper客户端
        CuratorFramework client = CuratorFrameworkFactory.newClient("127.0.0.1:2181", new ExponentialBackoffRetry(1000, 3));
        client.start();

        //指定锁路径
        String lockPath = "/zkLockRoot/lock_2";
        //创建分布式计数器,初始为0
        SharedCount sharedCount = new SharedCount(client, lockPath, 0);
        //定义监听器
        SharedCountListener sharedCountListener = new SharedCountListener() {
            @Override
            public void countHasChanged(SharedCountReader sharedCountReader, int i) throws Exception {
                System.out.println("new cnt : " + i);
            }

            @Override
            public void stateChanged(CuratorFramework curatorFramework, ConnectionState connectionState) {
                System.out.println("stated change : " + connectionState);
            }
        };
        //添加监听器
        sharedCount.addListener(sharedCountListener);
        sharedCount.start();

        //生成线程池
        ExecutorService executor = Executors.newCachedThreadPool();
        Consumer consumer = (SharedCount count) -> {
            try {
                List> callList = new ArrayList<>();
                Callable call = () -> {
                    boolean result = false;
                    try {
                        //数据更新,若失败,则重试10次,每次间隔30毫秒
                        for(int i=0; i<10;i++){
                            //获取当前版本数据
                            VersionedValue oldVersion = sharedCount.getVersionedValue();
                            int newCnt = oldVersion.getValue() + 1;
                            result = sharedCount.trySetCount(oldVersion, newCnt);
                            if(result){
                                System.out.println(Thread.currentThread().getName()
                                        + "  oldVersion:"+oldVersion.getVersion()
                                        +"  oldCnt:"+oldVersion.getValue()
                                        +"  newCnt:"+sharedCount.getCount()
                                        +"  result:"+result);
                                break;
                            }
                            TimeUnit.MILLISECONDS.sleep(30);
                        }
                    } catch (Exception e) {
                    } finally {
                    }
                    return result;
                };
                //5个线程
                for (int i = 0; i < 5; i++) {
                    callList.add(call);
                }
                List> futures = executor.invokeAll(callList);
            } catch (Exception e) {

            }
        };

        //测试分布式int类型的计数器
        consumer.accept(sharedCount);
        System.out.println("final cnt : " + sharedCount.getCount());
        sharedCount.close();

        executor.shutdown();
    }
}
输出:

stated change : CONNECTED
pool-3-thread-5  oldVersion:0  oldCnt:0  newCnt:1  result:true
new cnt : 1
pool-3-thread-3  oldVersion:1  oldCnt:1  newCnt:2  result:true
new cnt : 2
pool-3-thread-1  oldVersion:2  oldCnt:2  newCnt:3  result:true
new cnt : 3
pool-3-thread-2  oldVersion:3  oldCnt:3  newCnt:4  result:true
new cnt : 4
pool-3-thread-4  oldVersion:4  oldCnt:4  newCnt:5  result:true
final cnt : 5

四、DistributedAtomicLong计数器(其它类型如Int操作类似)

DistributedAtomicLong计数器可以自己设置重试的次数与间隔,代码如下:

import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.framework.recipes.atomic.AtomicValue;
import org.apache.curator.framework.recipes.atomic.DistributedAtomicLong;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.apache.curator.retry.RetryNTimes;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.function.Consumer;

public class ZookeeperDistributedAtomicLongMain {
    public static void main(String[] args) throws Exception {
        //创建zookeeper客户端
        CuratorFramework client = CuratorFrameworkFactory.newClient("127.0.0.1:2181", new ExponentialBackoffRetry(1000, 3));
        client.start();

        //指定锁路径
        String lockPath = "/zkLockRoot/lock_3";
        //分布式计数器,失败时重试10,每次间隔30毫秒
        DistributedAtomicLong distributedAtomicLong = new DistributedAtomicLong(client, lockPath, new RetryNTimes(10, 30));

        //生成线程池
        ExecutorService executor = Executors.newCachedThreadPool();
        Consumer consumer = (DistributedAtomicLong count) -> {
            try {
                List> callList = new ArrayList<>();
                Callable call = () -> {
                    boolean result = false;
                    try {
                        AtomicValue val = count.increment();
                        System.out.println("old cnt: "+val.preValue()+"   new cnt : "+ val.postValue()+"  result:"+val.succeeded());
                        result = val.succeeded();
                    } catch (Exception e) {
                    } finally {
                    }
                    return result;
                };
                //5个线程
                for (int i = 0; i < 5; i++) {
                    callList.add(call);
                }
                List> futures = executor.invokeAll(callList);
            } catch (Exception e) {

            }
        };

        //测试计数器
        consumer.accept(distributedAtomicLong);
        System.out.println("final cnt : " + distributedAtomicLong.get().postValue());

        executor.shutdown();
    }
}

输出:

old cnt: 0   new cnt : 1  result:true
old cnt: 1   new cnt : 2  result:true
old cnt: 2   new cnt : 3  result:true
old cnt: 3   new cnt : 4  result:true
old cnt: 4   new cnt : 5  result:true
final cnt : 5



你可能感兴趣的:(分布式处理)