Zookeeper系列(三十三)Zookeeper场景应用之分布式ID生成器
可以理解成一个分布式的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();
- }
- }
- }