forked from rongchao/epmet-cloud-rizhao
				
			
				 10 changed files with 274 additions and 18 deletions
			
			
		| @ -0,0 +1,214 @@ | |||
| /* | |||
|  * Copyright (c) 2011-2021, baomidou (jobob@qq.com). | |||
|  * | |||
|  * Licensed under the Apache License, Version 2.0 (the "License"); | |||
|  * you may not use this file except in compliance with the License. | |||
|  * You may obtain a copy of the License at | |||
|  * | |||
|  *     http://www.apache.org/licenses/LICENSE-2.0
 | |||
|  * | |||
|  * Unless required by applicable law or agreed to in writing, software | |||
|  * distributed under the License is distributed on an "AS IS" BASIS, | |||
|  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
|  * See the License for the specific language governing permissions and | |||
|  * limitations under the License. | |||
|  */ | |||
| package com.epmet.util; | |||
| 
 | |||
| import com.alibaba.fastjson.JSON; | |||
| import com.baomidou.mybatisplus.core.toolkit.Assert; | |||
| import com.baomidou.mybatisplus.core.toolkit.StringPool; | |||
| import com.baomidou.mybatisplus.core.toolkit.StringUtils; | |||
| import com.baomidou.mybatisplus.core.toolkit.SystemClock; | |||
| import com.epmet.commons.tools.utils.HttpClientManager; | |||
| import lombok.extern.slf4j.Slf4j; | |||
| import org.apache.ibatis.logging.Log; | |||
| import org.apache.ibatis.logging.LogFactory; | |||
| 
 | |||
| import java.lang.management.ManagementFactory; | |||
| import java.net.InetAddress; | |||
| import java.net.NetworkInterface; | |||
| import java.util.concurrent.ThreadLocalRandom; | |||
| 
 | |||
| /** | |||
|  * 分布式高效有序 ID 生产黑科技(sequence) | |||
|  * | |||
|  * <p>优化开源项目:https://gitee.com/yu120/sequence</p>
 | |||
|  * | |||
|  * @author hubin | |||
|  * @since 2016-08-18 | |||
|  */ | |||
| @Slf4j | |||
| public class MySequence { | |||
| 
 | |||
|     private static final Log logger = LogFactory.getLog(MySequence.class); | |||
|     /** | |||
|      * 时间起始标记点,作为基准,一般取系统的最近时间(一旦确定不能变动) | |||
|      */ | |||
|     private final long twepoch = 1288834974657L; | |||
|     /** | |||
|      * 机器标识位数 | |||
|      */ | |||
|     private final long workerIdBits = 5L; | |||
|     private final long datacenterIdBits = 5L; | |||
|     private final long maxWorkerId = -1L ^ (-1L << workerIdBits); | |||
|     private final long maxDatacenterId = -1L ^ (-1L << datacenterIdBits); | |||
|     /** | |||
|      * 毫秒内自增位 | |||
|      */ | |||
|     private final long sequenceBits = 12L; | |||
|     private final long workerIdShift = sequenceBits; | |||
|     private final long datacenterIdShift = sequenceBits + workerIdBits; | |||
|     /** | |||
|      * 时间戳左移动位 | |||
|      */ | |||
|     private final long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits; | |||
|     private final long sequenceMask = -1L ^ (-1L << sequenceBits); | |||
| 
 | |||
|     private final long workerId; | |||
| 
 | |||
|     /** | |||
|      * 数据标识 ID 部分 | |||
|      */ | |||
|     private final long datacenterId; | |||
|     /** | |||
|      * 并发控制 | |||
|      */ | |||
|     private long sequence = 0L; | |||
|     /** | |||
|      * 上次生产 ID 时间戳 | |||
|      */ | |||
|     private long lastTimestamp = -1L; | |||
| 
 | |||
|     public MySequence() { | |||
|         this.datacenterId = getDatacenterId(maxDatacenterId); | |||
|         this.workerId = getMaxWorkerId(datacenterId, maxWorkerId); | |||
|         String msg = "MySequence datacenterId:" + this.datacenterId + ";workerId:" + this.workerId; | |||
|         log.info(msg); | |||
|         HttpClientManager.getInstance().sendAlarmMsg(msg); | |||
|     } | |||
| 
 | |||
|     /** | |||
|      * 有参构造器 | |||
|      * | |||
|      * @param workerId     工作机器 ID | |||
|      * @param datacenterId 序列号 | |||
|      */ | |||
|     public MySequence(long workerId, long datacenterId) { | |||
|         Assert.isFalse(workerId > maxWorkerId || workerId < 0, | |||
|                 String.format("MySequence worker Id can't be greater than %d or less than 0", maxWorkerId)); | |||
|         Assert.isFalse(datacenterId > maxDatacenterId || datacenterId < 0, | |||
|                 String.format("MySequence datacenter Id can't be greater than %d or less than 0", maxDatacenterId)); | |||
|         this.workerId = workerId; | |||
|         this.datacenterId = datacenterId; | |||
|     } | |||
| 
 | |||
|     /** | |||
|      * 获取 maxWorkerId | |||
|      */ | |||
|     protected static long getMaxWorkerId(long datacenterId, long maxWorkerId) { | |||
|         StringBuilder mpid = new StringBuilder(); | |||
|         mpid.append(datacenterId); | |||
|         String name = ManagementFactory.getRuntimeMXBean().getName(); | |||
|         String msg = "MySequence getMaxWorkerId name:" + name; | |||
|         log.info(msg); | |||
|         HttpClientManager.getInstance().sendAlarmMsg(msg); | |||
|         if (StringUtils.isNotBlank(name)) { | |||
|             /* | |||
|              * GET jvmPid | |||
|              */ | |||
|             mpid.append(name.split(StringPool.AT)[0]); | |||
|         } | |||
|         /* | |||
|          * MAC + PID 的 hashcode 获取16个低位 | |||
|          */ | |||
|         return (mpid.toString().hashCode() & 0xffff) % (maxWorkerId + 1); | |||
|     } | |||
| 
 | |||
|     /** | |||
|      * 数据标识id部分 | |||
|      */ | |||
|     protected static long getDatacenterId(long maxDatacenterId) { | |||
|         long id = 0L; | |||
|         try { | |||
|             InetAddress ip = InetAddress.getLocalHost(); | |||
|             NetworkInterface network = NetworkInterface.getByInetAddress(ip); | |||
|             String msg = "MySequence ip:" + JSON.toJSONString(ip) + ";network: " + JSON.toJSONString(network); | |||
|             log.info(msg); | |||
|             HttpClientManager.getInstance().sendAlarmMsg(msg); | |||
|             if (network == null) { | |||
|                 id = 1L; | |||
|                 log.info("MySequen cenetwork ==null "); | |||
|             } else { | |||
|                 byte[] mac = network.getHardwareAddress(); | |||
|                 if (null != mac) { | |||
|                     id = ((0x000000FF & (long) mac[mac.length - 2]) | (0x0000FF00 & (((long) mac[mac.length - 1]) << 8))) >> 6; | |||
|                     id = id % (maxDatacenterId + 1); | |||
|                 } | |||
|             } | |||
|         } catch (Exception e) { | |||
|             logger.warn(" getDatacenterId: " + e.getMessage()); | |||
|         } | |||
|         return id; | |||
|     } | |||
| 
 | |||
|     /** | |||
|      * 获取下一个 ID | |||
|      * | |||
|      * @return 下一个 ID | |||
|      */ | |||
|     public synchronized long nextId() { | |||
|         long timestamp = timeGen(); | |||
|         //闰秒
 | |||
|         if (timestamp < lastTimestamp) { | |||
|             long offset = lastTimestamp - timestamp; | |||
|             if (offset <= 5) { | |||
|                 try { | |||
|                     wait(offset << 1); | |||
|                     timestamp = timeGen(); | |||
|                     if (timestamp < lastTimestamp) { | |||
|                         throw new RuntimeException(String.format("Clock moved backwards.  Refusing to generate id for %d milliseconds", offset)); | |||
|                     } | |||
|                 } catch (Exception e) { | |||
|                     throw new RuntimeException(e); | |||
|                 } | |||
|             } else { | |||
|                 throw new RuntimeException(String.format("Clock moved backwards.  Refusing to generate id for %d milliseconds", offset)); | |||
|             } | |||
|         } | |||
| 
 | |||
|         if (lastTimestamp == timestamp) { | |||
|             // 相同毫秒内,序列号自增
 | |||
|             sequence = (sequence + 1) & sequenceMask; | |||
|             if (sequence == 0) { | |||
|                 // 同一毫秒的序列数已经达到最大
 | |||
|                 timestamp = tilNextMillis(lastTimestamp); | |||
|             } | |||
|         } else { | |||
|             // 不同毫秒内,序列号置为 1 - 3 随机数
 | |||
|             sequence = ThreadLocalRandom.current().nextLong(1, 3); | |||
|         } | |||
| 
 | |||
|         lastTimestamp = timestamp; | |||
| 
 | |||
|         // 时间戳部分 | 数据中心部分 | 机器标识部分 | 序列号部分
 | |||
|         return ((timestamp - twepoch) << timestampLeftShift) | |||
|                 | (datacenterId << datacenterIdShift) | |||
|                 | (workerId << workerIdShift) | |||
|                 | sequence; | |||
|     } | |||
| 
 | |||
|     protected long tilNextMillis(long lastTimestamp) { | |||
|         long timestamp = timeGen(); | |||
|         while (timestamp <= lastTimestamp) { | |||
|             timestamp = timeGen(); | |||
|         } | |||
|         return timestamp; | |||
|     } | |||
| 
 | |||
|     protected long timeGen() { | |||
|         return SystemClock.now(); | |||
|     } | |||
| 
 | |||
| } | |||
| 
 | |||
					Loading…
					
					
				
		Reference in new issue