范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文

上千star的分布式ID生产黑科技,开箱即用,附源码

  sequence介绍
  sequence是一个基于雪花算法(Snowflake)实现的64位自增ID算法,实现语言是JAVA。
  其在雪花算法的基础上,做了一些优化,解决了原生算法的一些痛点:支持用户自定义允许时间回拨的范围;解决了跨毫秒时起始值从0开始增长的问题;解决了高并发场景中获取时间戳性能的问题;
  雪花算法的介绍可以参考博主上篇文章:还在用数据库自增ID做主键?建议了解一下雪花算法生成的分布式ID性能
  从官方的性能测试数据来看,sequence每秒可以生成最多418万个有序的ID,即TPS=400w/s,已经基本满足绝大部分的业务场景。
  源代码及使用
  核心代码一共两个类,分别是Sequence.java和SystemClock.java。
  Sequence是产生分布式ID的核心,SystemClock主要解决了高并发场景下System.currentTimeMills()的性能问题。
  大家也可根据自己的需要,修改其中的部署属性值,比如自定义机器标识,起始时间戳等。
  Sequence.java :public class Sequence {      private static final Logger log = LoggerFactory.getLogger(Sequence.class);     /**      * 时间起始标记点,作为基准,一般取系统的最近时间      * 一旦确定不能变动,确定后改变此值可能造成id重复      */     private final long twepoch = 1519740777809L;     //5位的机房id     private final long datacenterIdBits = 5L;     //5位的机器id     private final long workerIdBits = 5L;     //每毫秒内产生的id数: 2的12次方个     private final long sequenceBits = 12L;     protected final long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);     protected final long maxWorkerId = -1L ^ (-1L << workerIdBits);     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);     //所属机房id     private final long datacenterId;     //所属机器id     private final long workerId;     //并发控制序列     private long sequence = 0L;     //上次生产 ID 时间戳     private long lastTimestamp = -1L;     //获取IP     private static volatile InetAddress LOCAL_ADDRESS = null;     private static final Pattern IP_PATTERN = Pattern.compile("d{1,3}(.d{1,3}){3,5}#34;);     //默认的无参构造     public Sequence() {         this.datacenterId = getDatacenterId();         this.workerId = getMaxWorkerId(datacenterId);     }      //有参构造器,我们可以自定义机器id和机房id     public Sequence(long workerId, long datacenterId) {         if (workerId > maxWorkerId || workerId < 0) {             throw new IllegalArgumentException(String.format("Worker Id can"t be greater than %d or less than 0", maxWorkerId));         }         if (datacenterId > maxDatacenterId || datacenterId < 0) {             throw new IllegalArgumentException(String.format("Datacenter Id can"t be greater than %d or less than 0", maxDatacenterId));         }          this.workerId = workerId;         this.datacenterId = datacenterId;     }      //基于网卡MAC地址计算余数作为数据中心,如果不想用网卡可以自定义     protected long getDatacenterId() {         long id = 0L;         try {             NetworkInterface network = NetworkInterface.getByInetAddress(getLocalAddress());             if (null == network) {                 id = 1L;             } 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) {             log.warn(" getDatacenterId: " + e.getMessage());         }          return id;     }      //基于 MAC + PID 的 hashcode 获取16个低位     protected long getMaxWorkerId(long datacenterId) {         StringBuilder mpId = new StringBuilder();         mpId.append(datacenterId);         String name = ManagementFactory.getRuntimeMXBean().getName();         if (name != null && name.length() > 0) {             // GET jvmPid             mpId.append(name.split("@")[0]);         }          // MAC + PID 的 hashcode 获取16个低位         return (mpId.toString().hashCode() & 0xffff) % (maxWorkerId + 1);     }      //获取下一个 ID     public synchronized long nextId() {       //获取当前时间戳,这里通过SystemClock优化获取性能         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.INSTANCE.currentTimeMillis();     }      /**      * Find first valid IP from local network card      *      * @return first valid local IP      */     public static InetAddress getLocalAddress() {         if (LOCAL_ADDRESS != null) {             return LOCAL_ADDRESS;         }          LOCAL_ADDRESS = getLocalAddress0();         return LOCAL_ADDRESS;     }      private static InetAddress getLocalAddress0() {         InetAddress localAddress = null;         try {             localAddress = InetAddress.getLocalHost();             if (isValidAddress(localAddress)) {                 return localAddress;             }         } catch (Throwable e) {             log.warn("Failed to retrieving ip address, " + e.getMessage(), e);         }          try {             Enumeration interfaces = NetworkInterface.getNetworkInterfaces();             if (interfaces != null) {                 while (interfaces.hasMoreElements()) {                     try {                         NetworkInterface network = interfaces.nextElement();                         Enumeration addresses = network.getInetAddresses();                         while (addresses.hasMoreElements()) {                             try {                                 InetAddress address = addresses.nextElement();                                 if (isValidAddress(address)) {                                     return address;                                 }                             } catch (Throwable e) {                                 log.warn("Failed to retrieving ip address, " + e.getMessage(), e);                             }                         }                     } catch (Throwable e) {                         log.warn("Failed to retrieving ip address, " + e.getMessage(), e);                     }                 }             }         } catch (Throwable e) {             log.warn("Failed to retrieving ip address, " + e.getMessage(), e);         }         log.error("Could not get local host ip address, will use 127.0.0.1 instead.");         return localAddress;     }      private static boolean isValidAddress(InetAddress address) {         if (address == null || address.isLoopbackAddress()) {             return false;         }         String name = address.getHostAddress();         return (name != null && !"0.0.0.0".equals(name) && !"127.0.0.1".equals(name) && IP_PATTERN.matcher(name).matches());     } }
  SystemClock.java://利用ScheduledExecutorService实现高并发场景下 //System.curentTimeMillis()的性能问题的优化. public enum SystemClock {      INSTANCE(1);     private final long period;     private final AtomicLong nowTime;     private boolean started = false;     private ScheduledExecutorService executorService;      SystemClock(long period) {         this.period = period;         this.nowTime = new AtomicLong(System.currentTimeMillis());     }      public void initialize() {         if (started) {             return;         }          this.executorService = new ScheduledThreadPoolExecutor(1, r -> {             Thread thread = new Thread(r, "system-clock");             thread.setDaemon(true);             return thread;         });         executorService.scheduleAtFixedRate(() -> nowTime.set(System.currentTimeMillis()),                 this.period, this.period, TimeUnit.MILLISECONDS);         Runtime.getRuntime().addShutdownHook(new Thread(this::destroy));         started = true;     }      public long currentTimeMillis() {         return started ? nowTime.get() : System.currentTimeMillis();     }      public String currentTime() {         return new Timestamp(currentTimeMillis()).toString();     }      public void destroy() {         if (executorService != null) {             executorService.shutdown();         }     }  }最后
  sequence虽然大幅提升了性能,但是在某些情况下仍然可能出现重复的情况,比如机器标识重复、起始时间戳被修改重置等,这些问题需要我们特别注意。
  总得来说,sequence被称为分布式高效ID生产黑科技并不为过,著名的ORM框架mybatis plus用的也是这个组件,大家有兴趣也可以去了解一下。
  #头条创作挑战赛#
  学习技术,分享技术,期待与大家共同进步,也感谢您的点赞与关注。

中国能源环境高峰论坛聚焦绿色生态产业发展本报讯记者白雪报道近日,第15届中国能源环境高峰论坛(以下简称峰会)暨重大项目和中国绿色生态研究基地研讨会以线下和线上结合的方式举办。本次研讨会发布了中国绿色生态研究基地行业典型案女报评论丨团结引领青年女性争做新时代好青年论学习贯彻党的二十大精神青年强,则国家强。党的二十大对全党做好青年工作作出战略性部署,要求做青年朋友的知心人青年工作的热心人青年群众的引路人,对青年提出了立志做有理想敢担当能吃苦肯奋斗的新时代好青年的重要东南形胜,三吴都会,钱塘自古繁华钱塘是一座城还是一条江?古诗词里的地理名胜之十一望海潮望海潮宋柳永东南形胜,三吴都会,钱塘自古繁华。烟柳画桥,风帘翠幕,参差十万人家。云树绕堤沙,怒涛卷霜雪,天堑无涯。市列珠玑,户盈罗绮,竞豪奢。重湖叠獻这三样菜一起炒鲜美极了,滋补去燥又低脂饱腹,一周吃5次都不腻头条创作挑战赛进入十一月中旬,天气逐渐转凉了,尤其是北方地区,很多地方都下起了雪,即使是在南方,早晚也要穿上厚厚的衣物,要不也会被冷风吹得发抖,为了避免感冒少生病,大家一定要注意添中国6G比5G还狠!央媒全球超过一半的6G专利来自中国过去的14G时代,核心通讯专利一直被高通ATT诺基亚爱立信等科技巨头所掌控,虽然我国是全球电信规模最大的国家,但在移动互联网发展的浪潮中,那些西方企业却能轻松做到躺着赚钱。但谁也没习近平抵达曼谷出席亚太经合组织第二十九次领导人非正式会议并对泰国进行访问当地时间11月17日下午,国家主席习近平乘专机抵达泰国曼谷,出席亚太经合组织第二十九次领导人非正式会议并对泰国进行访问。这是习近平和夫人彭丽媛步出专机舱门。新华社记者翟健岚摄新华社习近平抵达曼谷出席亚太经合组织第二十九次领导人非正式会议并对泰国进行访问新华社曼谷11月17日电(记者刘华林昊)当地时间11月17日下午,国家主席习近平乘专机抵达泰国曼谷,出席亚太经合组织第二十九次领导人非正式会议并对泰国进行访问。习近平和夫人彭丽媛乘李少莉调查又有新情况弟弟也是从学徒工干到局长,籍贯并非内蒙近日,李少莉事件在网上闹得沸沸扬扬的,至今20余天!李少莉估计做梦也没有想到,自己会因为一场发布会而被网友骂惨!李少莉是内蒙古呼和浩特副局长,因为在疫情防控发布会上精致的妆容,佩戴万圣街公寓全员童年照,小孩确实都可爱,不过人类除外熊孩子自古就是一大杀器,作为称号为四足吞金的上古神兽,从古代开始熊孩子就有着无与伦比的威力,比如当初将猴哥烧得屁滚尿流的红孩儿,以及差点引发水淹钱塘的哪吒!但是无论是什么生物,只要宝宝出生24周,7个表现是发育迟缓的信号,父母早知道早应对导语宝宝出生后,最开心的莫过于宝妈了。怀胎十月,直到新生儿在自己的怀里,宝妈才有了真实的幸福感。宝妈以为宝宝出生后,苦逼的日子就结束了,没想到却只是辛苦的开始。宝宝不会说话,也没有郑州4个月女婴遭救护车拒诊抢救无效身亡后续4个月大的女婴在11月14日突发剧烈呕吐和腹泻症状!随后,女婴父亲两次拨打120求救电话。救护车都没有看到孩子就以病情不严重为由拒绝诊断治疗,李先生认为救护车不诊断不治疗,导致孩子
父母在人生尚有来处,父母去人生只剩归途的意思?头条创作挑战赛意思是父母在世的时候,自己还有归处,可以回家,可以看父母父母不在了,家只能叫做故乡了,因为最牵挂的人已经不在。这句话给人们的启示是不要等到子欲养而亲不待再后悔,善待父整个孕期苦不堪言,难以忍受怀孕期间经历的痛苦和心酸,只有怀孕的妈妈才会懂得。怀孕要经历哪几个阶段?怀孕期间你觉得哪个阶段是最难熬的?孕妈怀孕期间都没比我惨的了,回忆总让人想哭。就下来我描述一下我整个孕期是如2022年出生率断崖式下跌今天带孩子去社区医院接种流感疫苗,本以为会是人挤人的现象,结果到了才发现寥寥无几。以往取号都叫到两三百,今天就五十多个号。心里还是很窃喜不用排队很久了。记得我儿子是2018年出生的怀孕妊娠期有两种物质要远离,还有三种物质要格外注意妊娠期一定要给孩子一个健康的开始。实际上,妊娠期间你吃下的喝下的以及吸人的所有物质,都会进入胎儿体内。这种母婴之间的分享早在受孕后就开始了。在妊娠期的前2个月中,胚胎是最脆弱的。因网传沈腾抛家弃子包养小三,目前已和妻子离婚!网友打死不信近日,沈腾因为自己的婚姻问题冲上了热搜,搜索沈腾出来的都是沈腾离婚的消息,更有网友露脸爆料沈腾目前已经和妻子王琦离婚,并且早在之前就在外面包养了小三。一位网友在社交平台上发布视频,沈腾老婆胖成贾玲,抱娃出街面部浮肿身型笨重,刚被曝出离婚近日,沈腾老婆王琦被拍到现身。当天,王琦抱着儿子出街,她一身休闲打扮,宽松的黑色T恤搭配休闲裤,头发随意的扎在脑后,素面朝天。第一眼看去,王琦真的胖了不少。看近照,王琦整个人胖了一夜读丨演好人生这场戏,关键在自己。作者丨郝银主播丨吉祥人的出生无法选择。伴随着哭泣,我们无奈地进入了一场人生大剧。剧本无法选择,剧情无法选择,是否出演,是主角还是配角,也要根据不同的情境,由外界来决定。演好演坏,郎平爱徒美国生活滋润!晒2万拖鞋8万包包,嫁白人老公太幸福近日马蕴雯这位中国女排球员再次在自己的社交媒体上晒出了照片,36岁的马蕴雯如今生活在美国,她的丈夫是著名的体能训练师,当时郎平从美国回到中国女排执教时,不仅带来了先进的训练技术,同全员满分,中国女排豪取三连胜!李盈莹喜笑颜开,冲击巴西争第一30,中国女排横扫日本女排!这个比分赛前应该很多人想不到,别说一局不丢了,赢球很多人都感到意外,毕竟对方阵容齐整,状态也比我们好,最近一次交手还击败我们。只能说中国女排就是中国女排陈乔恩豪门生活太滋润,43岁仍青春甜美似少女,比小9岁老公还嫩头条创作挑战赛服装是人的第二层皮肤,在人与人交往的初期,尚未深入了解一个人之前,人们往往通过她穿什么来判断这个人的喜好与性格,一般来说你以何种面貌示人就决定了你在别人眼中是怎样的人坚定不移推动高质量发展上新台阶南方日报讯(记者吴哲李凤祥通讯员符信)9月22日,省长王伟中主持召开省政府常务会议,深入学习贯彻习近平总书记关于推动高质量发展的重要论述精神和对广东系列重要讲话重要指示精神,按照省