可以理解成一个分布式的ID生成器

1.命名服务

命名服务可以理解为提供名字的服务

Zookeeper的命名服务,有两个应用方向:

   1.提供类似JNDI的功能:

             利用zookeeper中的树形分层结构,可以把系统中的各种服务的名称,地址以及目录信息存放在zookeeper中,需要的时候去zookeeper中去读取

   2.

            利用zookeeper中的顺序节点的特性,制作分布式的序列号生成器(ID生成器)

(在往数据库中插入数据,通常是要有一个ID号,在单机环境下,可以利用数据库的主键自动生成id号,但是这种在分布式环境下就无法使用了,可以使用UUID,但是UUID有一个缺点,就是没有什么规律很难理解。使用zookeeper的命名服务可以生成有顺序的容易理解的,支持分布式的编号)

2.架构图


3.算法流程



生成ID的方法

package com.jike.nameservice;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

import org.I0Itec.zkclient.ZkClient;
import org.I0Itec.zkclient.exception.ZkNodeExistsException;
import org.I0Itec.zkclient.serialize.BytesPushThroughSerializer;

public class IdMaker {
	
	
	private ZkClient client = null;
	private final String server;//记录服务器的地址
	private final String root;//记录父节点的路径
	private final String nodeName;//节点的名称
	private volatile boolean running = false;
	private ExecutorService cleanExector = null;
	
	//删除节点的级别
	public enum RemoveMethod{
		NONE,IMMEDIATELY,DELAY
		
	}
	
	public IdMaker(String zkServer,String root,String nodeName){
		
		this.root = root;
		this.server = zkServer;
		this.nodeName = nodeName;
		
	}
	
	public void start() throws Exception {
		
		if (running)
			throw new Exception("server has stated...");
		running = true;
		
		init();
		
	}
	
	
	public void stop() throws Exception {
		
		if (!running)
			throw new Exception("server has stopped...");
		running = false;
		
		freeResource();
		
	}
	
	/**
	 * 初始化服务资源
	 */
	private void init(){
		
		client = new ZkClient(server,5000,5000,new BytesPushThroughSerializer());
		cleanExector = Executors.newFixedThreadPool(10);
		try{
			client.createPersistent(root,true);
		}catch (ZkNodeExistsException e){
			//ignore;
		}
		
	}
	
	/**
	 * 释放服务资源
	 */
	private void freeResource(){
	
		cleanExector.shutdown();
		try{
			cleanExector.awaitTermination(2, TimeUnit.SECONDS);
			
		}catch(InterruptedException e){
			e.printStackTrace();
		}finally{
			cleanExector = null;
		}
	
		if (client!=null){
			client.close();
			client=null;
			
		}
	}
	
	/**
	 * 检测服务是否正在运行
	 * @throws Exception
	 */
	private void checkRunning() throws Exception {
		if (!running)
			throw new Exception("请先调用start");
		
	}
	
	private String ExtractId(String str){
		int index = str.lastIndexOf(nodeName);
		if (index >= 0){
			index+=nodeName.length();
			return index <= str.length()?str.substring(index):"";
		}
		return str;
		
	}
	
	/**
	 * 产生ID
	 * 核心函数
	 * @param removeMethod 删除的方法
	 * @return
	 * @throws Exception
	 */
	public String generateId(RemoveMethod removeMethod) throws Exception{
		checkRunning();
		final String fullNodePath = root.concat("/").concat(nodeName);
		//返回创建的节点的名称
		final String ourPath = client.createPersistentSequential(fullNodePath, null);
		
		
		/**
		 * 在创建完节点后为了不
		 */
		if (removeMethod.equals(RemoveMethod.IMMEDIATELY)){
			client.delete(ourPath);
		}else if (removeMethod.equals(RemoveMethod.DELAY)){
			cleanExector.execute(new Runnable() {
				
				public void run() {
					// TODO Auto-generated method stub
					client.delete(ourPath);
				}
			});
			
		}
		//node-0000000000, node-0000000001,ExtractId提取ID
		return ExtractId(ourPath);
	}

}

测试节点ID生成

package com.jike.nameservice;

import com.jike.nameservice.IdMaker.RemoveMethod;

public class TestIdMaker {

	public static void main(String[] args) throws Exception {
		
		IdMaker idMaker = new IdMaker("192.168.1.105:2181",
				"/NameService/IdGen", "ID");
		idMaker.start();

		try {
			for (int i = 0; i < 10; i++) {
				String id = idMaker.generateId(RemoveMethod.DELAY);
				System.out.println(id);

			}
		} finally {
			idMaker.stop();

		}
	}

}








Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐