设为首页 加入收藏

TOP

分布式主键解决方案之--Snowflake雪花算法(一)
2019-10-09 19:58:52 】 浏览:100
Tags:分布式 解决方案 --Snowflake 雪花 算法

0--前言

  对于分布式系统环境,主键ID的设计很关键,什么自增intID那些是绝对不用的,比较早的时候,大部分系统都用UUID/GUID来作为主键优点是方便又能解决问题,缺点是插入时因为UUID/GUID的不规则导致每插入一条数据就需要重新排列一次,性能低下;也有人提出用UUID/GUID转long的方式,可以很明确的告诉你,这种方式long不能保证唯一,大并发下会有重复long出现,所以也不可取,这个主键设计问题曾经是很多公司系统设计的一个头疼点,所以大部分公司愿意牺牲一部分性能而直接采用简单粗暴的UUID/GUID来作为分布式系统的主键;

  twitter开源了一个snowflake算法,俗称雪花算法;就是为了解决分布式环境下生成不同ID的问题;该算法会生成19位的long型有序数字,MySQL中用bigint来存储(bigint长度为20位);该算法应该是目前分布式环境中主键ID最好的解决方案之一了;

1--snowflake雪花算法实现

  好,废话不多说,直接上算法实现

  1 package com.anson;
  2 
  3 import java.lang.management.ManagementFactory;
  4 import java.net.InetAddress;
  5 import java.net.NetworkInterface;
  6 
  7 //雪花算法代码实现
  8 public class IdWorker {
  9     // 时间起始标记点,作为基准,一般取系统的最近时间(一旦确定不能变动)
 10     private final static long twepoch = 1288834974657L;
 11     // 机器标识位数
 12     private final static long workerIdBits = 5L;
 13     // 数据中心标识位数
 14     private final static long datacenterIdBits = 5L;
 15     // 机器ID最大值
 16     private final static long maxWorkerId = -1L ^ (-1L << workerIdBits);
 17     // 数据中心ID最大值
 18     private final static long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);
 19     // 毫秒内自增位
 20     private final static long sequenceBits = 12L;
 21     // 机器ID偏左移12位
 22     private final static long workerIdShift = sequenceBits;
 23     // 数据中心ID左移17位
 24     private final static long datacenterIdShift = sequenceBits + workerIdBits;
 25     // 时间毫秒左移22位
 26     private final static long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;
 27 
 28     private final static long sequenceMask = -1L ^ (-1L << sequenceBits);
 29     /* 上次生产id时间戳 */
 30     private static long lastTimestamp = -1L;
 31     // 0,并发控制
 32     private long sequence = 0L;
 33 
 34     private final long workerId;
 35     // 数据标识id部分
 36     private final long datacenterId;
 37 
 38     public IdWorker(){
 39         this.datacenterId = getDatacenterId(maxDatacenterId);
 40         this.workerId = getMaxWorkerId(datacenterId, maxWorkerId);
 41     }
 42     /**
 43      * @param workerId
 44      *            工作机器ID
 45      * @param datacenterId
 46      *            序列号
 47      */
 48     public IdWorker(long workerId, long datacenterId) {
 49         if (workerId > maxWorkerId || workerId < 0) {
 50             throw new IllegalArgumentException(String.format("worker Id can't be greater than %d or less than 0", maxWorkerId));
 51         }
 52         if (datacenterId > maxDatacenterId || datacenterId < 0) {
 53             throw new IllegalArgumentException(String.format("datacenter Id can't be greater than %d or less than 0", maxDatacenterId));
 54         }
 55         this.workerId = workerId;
 56         this.datacenterId = datacenterId;
 57     }
 58     /**
 59      * 获取下一个ID
 60      *
 61      * @return
 62      */
 63     public synchronized long nextId() {
 64         long timestamp = timeGen();
 65         if (timestamp < lastTimestamp) {
 66             throw new RuntimeException(String.format("Clock moved backwards.  Refusing to generate id for %d milliseconds", lastTimestamp - timestamp));
 67         }
 68 
 69         if (lastTimestamp == timestamp) {
 70             // 当前毫秒内,则+1
 71             sequence = (sequence + 1) & sequenceMask;
 72             if (sequence == 0) {
 73                 // 当前毫秒内计数满了,则等待下一秒
 74                 timestamp = tilNextMillis(lastTimestamp);
 75             }
 76         } else {
 77             sequence = 0L;
 78         }
 79         lastTimestamp = timestamp;
 80         // ID偏移组合生成最终的ID,并返回ID
 81         long nextId = ((timestamp - twepoch) << timestampLeftShift)
 82                 | (datacenterId << datacenterIdShift)
 83                 | (workerId << workerIdShift) | sequence;
 84 
 85         return nextId;
 86     }
 87 
 88     private long ti
首页 上一页 1 2 下一页 尾页 1/2/2
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇Elasticsearch实战-磁盘IO被打满 下一篇springcloud vue.js 微服务分布式..

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目