• Zookeeper分布式唯一主键id生成


    一、导入依赖包

    使用Curator客户端连接ZK

    <!-- curator ZK 客户端 -->
                <dependency>
                    <groupId>org.apache.curator</groupId>
                    <artifactId>curator-framework</artifactId>
                    <version>4.2.0</version>
                </dependency>
                <dependency>
                    <groupId>org.apache.curator</groupId>
                    <artifactId>curator-recipes</artifactId>
                    <version>4.2.0</version>
                </dependency>
    

    二、配置文件

    在resources目录下薪资zookeeper.properties 文件

    # zk host地址
    zk.host=192.168.xxx.xxx:2181
    # zk自增存储node
    zk.sequence-path=/carpxt/sequence/
    

    三、枚举封装

    /**
     * <p>用于定义通过Zk生成自增ID的枚举,</p>
     * 
     * @date: 2021/6/10 13:55
     */
    public enum ZkSequenceEnum {
               T_USER,T_ORG,T_APP,T_FALLOW,T_ATTENTION
    }
    

    四、序列封装

    /**
     *  <p>用于封装在程序运行时每个表对应的自增器,主要采用分布式原子自增类 `DistributedAtomicLong`</p>
     *                 <p>每500ms重试3次之后还是生成失败 就返回null</p>
     * @date  2021/6/10 13:55
     * @version:   1.0
     */
    public class ZkSequence {
    
        //每500ms重试3次
        RetryPolicy retryPolicy = new ExponentialBackoffRetry(500, 3);
    
        DistributedAtomicLong distAtomicLong;
        public ZkSequence(String sequenceName, CuratorFramework client){
            distAtomicLong = new DistributedAtomicLong(client,sequenceName,retryPolicy);
        }
    
        /**
         * 生成序列
         * @return: 
         * @throws Exception
         */
        public Long sequence() throws Exception{
            AtomicValue<Long> sequence = this.distAtomicLong.increment();
            if(sequence.succeeded()){
                return sequence.postValue();
            }else{
                return null;
            }
        }
    }
    

    五、Client封装

    @Data
    @Slf4j
    public class ZookeeperClient {
        private String host;
        private String sequencePath;
        // 重试休眠时间
        private final int SLEEP_TIME_MS = 1000;
        // 最大重试1000次
        private final int MAX_RETRIES = 1000;
        //会话超时时间
        private final int SESSION_TIMEOUT = 30 * 1000;
        //连接超时时间
        private final int CONNECTION_TIMEOUT = 3 * 1000;
        //创建连接实例
        private CuratorFramework client = null;
        // 序列化集合
        private Map<String, ZkSequence> zkSequenceMap = Maps.newConcurrentMap();
        public ZookeeperClient(String host,String sequencePath){
            this.host = host;
            this.sequencePath = sequencePath;
        }
        // 通过PostConstruct注解在内构器之后调用init方法初始化客户端连接
        @PostConstruct
        public void init() throws Exception{
            this.client = CuratorFrameworkFactory.builder()
                    .connectString(this.getHost())
                    .connectionTimeoutMs(CONNECTION_TIMEOUT)
                    .sessionTimeoutMs(SESSION_TIMEOUT)
                    .retryPolicy(new ExponentialBackoffRetry(SLEEP_TIME_MS,
                            MAX_RETRIES)).build();
            this.client.start();
            //初始化 自定义的 ZkSequence
            this.initZkSequence();
        }
        public void initZkSequence(){
            ZkSequenceEnum[] list = ZkSequenceEnum.values();
            for (int i = 0; i < list.length; i++) {
                String name = list[i].name();
                String path = this.sequencePath+name;
                ZkSequence seq = new ZkSequence(path,this.client);
                zkSequenceMap.put(name,seq);
            }
        }
        /**
         * 生成SEQ
         * @param name
         * @return
         * @throws Exception
         */
        public Long sequence(ZkSequenceEnum name){
            try {
                ZkSequence seq = zkSequenceMap.get(name.name());
    
                if (seq != null) {
                    return seq.sequence();
                }
            }catch (Exception e){
                log.error("获取[{}]Sequence错误:{}",name,e);
            }
            return null;
        }
    }
    

    六、配置封装

    @Getter
    @Setter
    @Configuration
    @ConfigurationProperties(prefix = "zk")
    @PropertySource("classpath:zookeeper.properties")
    public class ZkConfig {
        String host;
        String sequencePath;
    
    
        @Bean
        public ZookeeperClient zookeeperClient(){
            return new ZookeeperClient(this.host,this.sequencePath);
        }
    
    }
    

    七、调用Sequences封装

    /**
     * <p>统一暴露生成自增主键的功能</p>
     * @author tianjie
     * @date: 2021/6/10 14:30
     */
    @Component
    public class Sequences {
        @Autowired
        private ZookeeperClient client;
    
        public Long sequenceUser() {
            return this.client.sequence(ZkSequenceEnum.T_USER);
        }
     
        public Long sequenceOrg() {
            return this.client.sequence(ZkSequenceEnum.T_ORG);
        }
    
        public Long sequenceAPP() {
            return this.client.sequence(ZkSequenceEnum.T_APP);
        }
    
        public Long sequenceFallow() {
            return this.client.sequence(ZkSequenceEnum.T_FALLOW);
        }
    
        public Long sequenceAttention() {
            return this.client.sequence(ZkSequenceEnum.T_ATTENTION);
        }
    }
    

    八、使用

    1、包扫描配置类
    @Configuration
    @ComponentScan("com.carpxt.common.zookeeper")
    public class ZookeeperConfig {
    }
    
    2、注入Sequences
    @Autowired
    private Sequences sequences;
    
    3、方法中调用
    xxx.setId(sequences.sequenceUser());
    

    如后期需要新增ZkSequence自增表,可参考以下操作步骤,快速实现: 在ZkSequenceEnum中定义对应的枚举项,规范要求枚举项与物理表名一致且大写 在Sequences中定义对应的调用方法,规范要求方法由sequence前缀+驼峰表名组成

  • 相关阅读:
    设计高效SQL: 一种视觉的方法
    由于学校要两张2寸的照片,蓝底,所以下午课就去后面照相打印店去了
    如果一个事情总在同一个地点停留,就是没有执行效率
    我也是不得不说我的学习能力下降了,这两天都没有完成一个模块
    我也是不得不说我的学习能力下降了,这两天都没有完成一个模块
    就好像是回到了高中时候。没有什么感受
    今天中午还收到了,一条诈骗短信,说是中奖了
    今天晚上的主要事项是,完成上午考试所有不清楚的地方
    今天中午的时候,可能是自己太忙过头了,所以出现了拿错卡去充值
    项目并没有采用一端服务器做法,我也没有弄清楚原因
  • 原文地址:https://www.cnblogs.com/kt-ting/p/14871587.html
Copyright © 2020-2023  润新知