Using Zookeeper

  

1. Deployment and Operation

      1. System environment

         zk supports the vast majority of operating systems. However, it should be noted that the JVM of the FreeBsd system does not support JAVA's NIO very well, and it is not recommended to deploy a production environment on this system.

      2.java environment

        It is recommended to use jdk1.6 or above.

      3. Cluster or single machine

         

          3.1 Cluster mode requires at least three machines, after both jdk and zk are downloaded and configured. Modify zoo_sample.cfg under $ZK_HOME/conf

  1. tickTime=2000    
  2. initLimit = 5    
  3. syncLimit=2    
  4. dataDir = / var / lib / zk /  
  5. dataLogDir = / var / lib / zk / logs    
  6. clientPort=2181  
  7. #0 stands for server id, create a myid file under datadir, the content inside is this id
  8. server.0=192.168.1.10:8880:7770    
  9. server.1=192.168.1.11:8881:7771    
  10. server.2=192.168.1.12:8882:7772  

       Then create a myid file in the datadir directory, the content is server.id

       Then use zkServer.sh in $ZK_HOME/bin to start, sh zkServer.sh start

       Use the command echo stat | nc localhost 2181 to test whether the startup is successful (the failure may be caused by the firewall)

       3.1 Just use the stand-alone mode for normal testing

  1. tickTime=2000    
  2. initLimit = 5    
  3. syncLimit=2    
  4. dataDir = / var / lib / zk /  
  5. dataLogDir = / var / lib / zk / logs    
  6. clientPort=2181  
  7. #0 stands for server id, create a myid file under datadir, the content inside is this id
  8. server.1=127.0.0.1:8880:7770   

        

2. zk client

          Client startup command: sh zkCli -server ip:port

          创建节点:create [-s] [-e]  path  data acl s代表持久节点,e代表临时节点,acl代表权限.默认创建持久节点.例如: create /zknode 123 digest:  username:password

          列出路径下的子节点: ls [path]  .path代表路径 。 ls   /zknode

          获取节点的属性: get [path]

          更新节点属性: set [path] data [version]  

          删除节点: delete path [version]

          设置节点acl:  setAcl path acl .例如: setAcl path acl.

         

 三.zk java客户端

    1.连接客户端

     下面的代码是一个基本的zk  java客户端的代码

 

public class ZkTest implements Watcher{
    private static CountDownLatch cdl  = new CountDownLatch(1);
	public static void main(String[] args) throws IOException {
		ZooKeeper zk = new ZooKeeper("192.168.43.191:2181", 5000, new ZkTest());
		System.out.println(zk.getState());
		try {
			cdl.await();
		} catch (InterruptedException e) {
		}
		System.out.println("connect");
	}

	@Override
	public void process(WatchedEvent arg0) {
		System.out.println("事件:"+arg0+";"+arg0.getState());
		if(KeeperState.SyncConnected == arg0.getState()){
			System.out.println(arg0.getState());
			cdl.countDown ();
		}
		
	}
	
}
        The following code is the reuse of zk session

 

    

public class Zk_ID_PWD implements Watcher{
    private static CountDownLatch cdl  = new CountDownLatch(1);
	public static void main(String[] args) throws IOException, InterruptedException {
		ZooKeeper zk = new ZooKeeper("192.168.43.191:2181",
				5000, new Zk_ID_PWD());
		cdl.await ();
		long id = zk.getSessionId();
		byte[]  pwd = zk.getSessionPasswd();
		//Connection failed
		zk = new ZooKeeper("192.168.43.191:2181",
				5000, new Zk_ID_PWD(),1l,"test".getBytes());
		//connection succeeded
		zk = new ZooKeeper("192.168.43.191:2181",
				5000, new Zk_ID_PWD (), id, pwd);
		Thread.sleep(Integer.MAX_VALUE);
	}

	@Override
	public void process(WatchedEvent arg0) {
		System.out.println("事件:"+arg0+";"+arg0.getState());
		if(KeeperState.SyncConnected == arg0.getState()){
			System.out.println(arg0.getState());
			cdl.countDown();
		}
		
	}
	
}
 

 

      2.创建节点

         

public class Zk_Create implements Watcher {
	private static CountDownLatch cdl = new CountDownLatch(1);
	private static ZooKeeper zk = null;
	static {
		try {
			zk = new ZooKeeper("192.168.43.191:2181", 5000, new Zk_Create());
			System.out.println(zk.getState());
			
		} catch (IOException e1) {
			// TODO 请把关键信息(包括堆栈)记入日志,并删除下面一行。
			e1.printStackTrace();
		}

	}

	public static void main(String[] args) throws Exception {
           Zk_Create zc = new Zk_Create();
           try {
				cdl.await();
			} catch (InterruptedException e) {
			}
			System.out.println("connect");
           // zc.createTempNode();
            zc.createTempNodeAsync();
	}

	// 创建临时节点
	public void createTempNode() throws KeeperException, InterruptedException {
		String path = zk.create("/zcf", "zcf".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);
		System.out.println("成功创建节点:" + path);
		String path1 = zk.create("/zcf", "zcf".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
		System.out.println("成功创建节点:" + path1);
    }
    
	public void createTempNodeAsync() throws Exception{
		zk.create("/zcf", "zcf".getBytes(), 
				Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL
				,new IStringBack(),"async");
		Thread.sleep(Integer.MAX_VALUE);
    }
	
	public class IStringBack implements AsyncCallback.StringCallback{

		@Override
		public void processResult(int arg0, String arg1, Object arg2, String arg3) {

			System.out.println("create path result:"+ arg0+","+arg1+","+arg2+","+arg3);
			
		}
		
	}
	
	@Override
	public void process(WatchedEvent arg0) {
		System.out.println("事件:" + arg0 + ";" + arg0.getState());
		if (KeeperState.SyncConnected == arg0.getState()) {
			System.out.println(arg0.getState());
			cdl.countDown ();
		}

	}
}
     3. Permission settings and authorization

 

  

public class Zk_Auth implements Watcher{
    final static String path = "/zcf_auth";
    final static String path1 = path + "/child";
    private static CountDownLatch cdl = new CountDownLatch(3);
    public static void main(String[] args) throws Exception {
		Zk_Auth za = new Zk_Auth();
		//za.testAuth();
		za.testDelete ();
	}
    //The setting of delete permission does not affect the deletion of nodes without child nodes
    public void testAuth() throws Exception{
    	ZooKeeper zk = ZKUtil.getInstance(null, new Zk_Auth());
    	ZooKeeper zk1 = ZKUtil.getInstance(null, new Zk_Auth());
    	ZooKeeper zk2 = ZKUtil.getInstance(null, new Zk_Auth());
    	cdl.await();
    	System.out.println("connect");
    	//第二个参数类似username:pwd
    	zk.addAuthInfo("digest", "zcf:true".getBytes());
    	zk.create(path, "zcf".getBytes(),
    			Ids.CREATOR_ALL_ACL, CreateMode.PERSISTENT);
    	zk.create(path, "zcf".getBytes(),
    			Ids.CREATOR_ALL_ACL, CreateMode.PERSISTENT);
    	
    	zk1.addAuthInfo("digest", "zcf:true".getBytes());
    	System.out.println(zk1.getData(path, false, null));
    	
    	zk2.addAuthInfo("digest", "zcf:false".getBytes());
    	//会爆没权限错误
    	System.out.println(zk2.getData(path, false, null));
    }
    public void testDelete() throws IOException, Exception{
    	ZooKeeper zk = ZKUtil.getInstance(null, new Zk_Auth());
    	ZooKeeper zk1 = ZKUtil.getInstance(null, new Zk_Auth());
    	ZooKeeper zk2 = ZKUtil.getInstance(null, new Zk_Auth());
    	cdl.await();
    	System.out.println("connect");
    	//第二个参数类似username:pwd
    	zk.addAuthInfo("digest", "zcf:true".getBytes());
    	zk.create(path, "zcf".getBytes(),
    			Ids.CREATOR_ALL_ACL, CreateMode.PERSISTENT);
    	zk.create(path1, "zcf".getBytes(),
    			Ids.CREATOR_ALL_ACL, CreateMode.PERSISTENT);
    	try {
    		zk1.delete(path1, -1);
		} catch (Exception e) {
			e.printStackTrace();
		}
    	zk2.addAuthInfo("digest", "zcf:true".getBytes());
    	//会爆没权限错误
    	zk2.delete(path1, -1);
    	System.out.println("成功删除节点:"+path1);
    	zk1.delete(path, -1);
    	System.out.println("成功删除节点:"+path);
    	
    }
    @Override
	public void process(WatchedEvent arg0) {
		System.out.println("事件:" + arg0 + ";" + arg0.getState());
		if (KeeperState.SyncConnected == arg0.getState()) {
			System.out.println(arg0.getState());
			cdl.countDown();
		}

	}
}
 

 

二.curator

    1.master选举

      应用场景:定时任务只需要在一台机器上执行,通过master选择功能,选择其中一台执行.

      原理:每个zk客户端会在指定path下生产一个类似这样的path.节点序号递增,每次节点最小的成为leader.然后每次执行完任务之后,抢到资源的节点会自己删除,然后重新生产一个节点,继续和其他节点竞争.

 

    [_c_54dd51db-0e4a-4fdf-9251-f39e88102a87-lock-0000000121, 
    _c_af3197ec-da19-4812-b20d-bb3a010be549-lock-0000000118,
    _c_9a0edc16-5489-4d95-b24b-e1610c133bbe-lock-0000000120]
 

 

      反思:

        我们都知道,通过Leader选举可以选举出一台机器来执行定时任务.每次到执行Job的时候重新进行一次竞选,成为Leader者进行执行。

         这里就需要考虑一下问题:

        1 .  第二种方案如果服务器的时间不一致如何处理?如果每台机器Job执行的时间不一致如何处理?
        2.  定时任务的幂等性保证.(token)

 

public class Zk_Curator_Master {

    public static void main(String[] args) throws InterruptedException {

    for(int i = 0;i< 6;i++){

    CuratorFramework  cf = CuratorFrameworkFactory.newClient("192.168.43.191:2181",

        new ExponentialBackoffRetry(1000, 3));

        cf.start();

        String name ="client #"+i;

        LeaderSelector s = new LeaderSelector(cf,

        "/zcf/master_test", new LeaderSelectorListener() {

    @Override

    public void stateChanged(CuratorFramework client, ConnectionState newState) {

    

    if(newState == ConnectionState.SUSPENDED||ConnectionState.LOST == newState){

    throw new CancellationException();

    }
    }

    @Override

    public void takeLeadership(CuratorFramework arg0) throws Exception {

    System.out.println(name+"become the master role");

     Thread.sleep(3000);

    System.out.println(name+"Complete master task");

    

    }

    });

        s.autoRequeue();

        s.start();

Thread.sleep(Integer.MAX_VALUE);

    }

}

 

  2. Distributed locks and distributed counters

   

public class ZK_Distributed_Lock {
	
	private static ReentrantLock lock = new ReentrantLock();
    public static void main(String[] args) {
		 normalLockTest();
    	DistributedLock();
	}
    
    public static void DistributedLock(){
    	CuratorFramework  cf = 	CuratorFrameworkFactory.newClient("192.168.43.191:2181",
    			new ExponentialBackoffRetry(1000, 3));
    	cf.start();
    	final InterProcessMutex lock = new InterProcessMutex(
    			cf, "/zcf/distributeLock");
    	CountDownLatch cdl = new CountDownLatch(1);
    	for(int i = 0 ;i< 30 ;i++){
    		new Thread(new Runnable() {
				
				@Override
				public void run() {
					try {
						cdl.await();
						lock.acquire();
						SimpleDateFormat  sdf = new SimpleDateFormat("HH:mm:ss/SSS");
						System.out.println(sdf.format(new Date()));
					} catch (InterruptedException e) {
						// TODO 请把关键信息(包括堆栈)记入日志,并删除下面一行。
						e.printStackTrace();
					} catch (Exception e) {
						// TODO 请把关键信息(包括堆栈)记入日志,并删除下面一行。
						e.printStackTrace();
					}finally{
						try {
							lock.release();
						} catch (Exception e) {
							// TODO 请把关键信息(包括堆栈)记入日志,并删除下面一行。
							e.printStackTrace();
						}
					}
					
				}
			}).start();
    	}
    	cdl.countDown();
    }
    
    public static void normalLockTest(){
    	 CountDownLatch cdl = new CountDownLatch(1);
    	for(int i = 0 ;i< 10;i++){
			new Thread(new Runnable() {
				
				@Override
				public void run() {
					try {
						cdl.await();
						lock.lock();
						SimpleDateFormat  sdf = new SimpleDateFormat("HH:mm:ss/SSS");
						System.out.println(sdf.format(new Date()));
					} catch (InterruptedException e) {
						// TODO 请把关键信息(包括堆栈)记入日志,并删除下面一行。
						e.printStackTrace();
					}finally {
						lock.unlock();
					}
					
				}
			}).start();
		}
		cdl.countDown();
    }
}

 

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.locks.ReentrantLock;

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.DistributedAtomicInteger;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.apache.curator.retry.RetryNTimes;

public class ZK_Distributed_Count {
	
    public static void main(String[] args) {
    	DistributedCount();
	}
    
    public static void DistributedCount(){
    	CuratorFramework  cf = 	CuratorFrameworkFactory.newClient("192.168.43.191:2181",
    			new ExponentialBackoffRetry(1000, 3));
    	cf.start();
    	   	CountDownLatch cdl = new CountDownLatch(1);
    	for(int i = 0 ;i< 30 ;i++){
    		final DistributedAtomicInteger d = new DistributedAtomicInteger(
        			cf, "/zcf/distributeCount",new RetryNTimes(3, 1000));
     
    		new Thread(new Runnable() {
				
				@Override
				public void run() {
					try {
						cdl.await();
						AtomicValue<Integer> value = d.add(1);
						while(!value.succeeded()){
							value = d.add(1);
						}
						System.out.println(value.postValue());
					} catch (InterruptedException e) {
						// TODO 请把关键信息(包括堆栈)记入日志,并删除下面一行。
						e.printStackTrace();
					} catch (Exception e) {
						// TODO 请把关键信息(包括堆栈)记入日志,并删除下面一行。
						e.printStackTrace();
					}
					
				}
			}).start();
    	}
    	cdl.countDown();
    }
    
   
}
  

 

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326137228&siteId=291194637