Java分布式ID生成解决方案
程序员文章站
2022-03-25 22:18:09
分布式ID生成器 我们采用的是开源的twitter( 非官方中文惯称:推特.是国外的一个网站,是一个社交网络及微博客服务) 的snowflake算法(推特雪花算法)。 封装为工具类,源码如下: ......
分布式id生成器
我们采用的是开源的twitter( 非官方中文惯称:推特.是国外的一个网站,是一个社交网络及微博客服务) 的snowflake算法(推特雪花算法)。
封装为工具类,源码如下:
package util; import java.lang.management.managementfactory; import java.net.inetaddress; import java.net.networkinterface; /** * <p>名称:idworker.java</p> * <p>描述:分布式自增长id</p> * <pre> * twitter的 snowflake java实现方案 * </pre> * 核心代码为其idworker这个类实现,其原理结构如下,我分别用一个0表示一位,用—分割开部分的作用: * 1||0---0000000000 0000000000 0000000000 0000000000 0 --- 00000 ---00000 ---000000000000 * 在上面的字符串中,第一位为未使用(实际上也可作为long的符号位),接下来的41位为毫秒级时间, * 然后5位datacenter标识位,5位机器id(并不算标识符,实际是为线程标识), * 然后12位该毫秒内的当前毫秒内的计数,加起来刚好64位,为一个long型。 * 这样的好处是,整体上按照时间自增排序,并且整个分布式系统内不会产生id碰撞(由datacenter和机器id作区分), * 并且效率较高,经测试,snowflake每秒能够产生26万id左右,完全满足需要。 * <p> * 64位id (42(毫秒)+5(机器id)+5(业务编码)+12(重复累加)) * * @author polim */ public class idworker { // 时间起始标记点,作为基准,一般取系统的最近时间(一旦确定不能变动) private final static long twepoch = 1288834974657l; // 机器标识位数 private final static long workeridbits = 5l; // 数据中心标识位数 private final static long datacenteridbits = 5l; // 机器id最大值 private final static long maxworkerid = -1l ^ (-1l << workeridbits); // 数据中心id最大值 private final static long maxdatacenterid = -1l ^ (-1l << datacenteridbits); // 毫秒内自增位 private final static long sequencebits = 12l; // 机器id偏左移12位 private final static long workeridshift = sequencebits; // 数据中心id左移17位 private final static long datacenteridshift = sequencebits + workeridbits; // 时间毫秒左移22位 private final static long timestampleftshift = sequencebits + workeridbits + datacenteridbits; private final static long sequencemask = -1l ^ (-1l << sequencebits); /* 上次生产id时间戳 */ private static long lasttimestamp = -1l; // 0,并发控制 private long sequence = 0l; private final long workerid; // 数据标识id部分 private final long datacenterid; public idworker(){ this.datacenterid = getdatacenterid(maxdatacenterid); this.workerid = getmaxworkerid(datacenterid, maxworkerid); } /** * @param workerid * 工作机器id * @param datacenterid * 序列号 */ public idworker(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; } /** * 获取下一个id * * @return */ public synchronized long nextid() { long timestamp = timegen(); if (timestamp < lasttimestamp) { throw new runtimeexception(string.format("clock moved backwards. refusing to generate id for %d milliseconds", lasttimestamp - timestamp)); } if (lasttimestamp == timestamp) { // 当前毫秒内,则+1 sequence = (sequence + 1) & sequencemask; if (sequence == 0) { // 当前毫秒内计数满了,则等待下一秒 timestamp = tilnextmillis(lasttimestamp); } } else { sequence = 0l; } lasttimestamp = timestamp; // id偏移组合生成最终的id,并返回id long nextid = ((timestamp - twepoch) << timestampleftshift) | (datacenterid << datacenteridshift) | (workerid << workeridshift) | sequence; return nextid; } private long tilnextmillis(final long lasttimestamp) { long timestamp = this.timegen(); while (timestamp <= lasttimestamp) { timestamp = this.timegen(); } return timestamp; } private long timegen() { return system.currenttimemillis(); } /** * <p> * 获取 maxworkerid * </p> */ protected static long getmaxworkerid(long datacenterid, long maxworkerid) { stringbuffer mpid = new stringbuffer(); mpid.append(datacenterid); string name = managementfactory.getruntimemxbean().getname(); if (!name.isempty()) { /* * get jvmpid */ mpid.append(name.split("@")[0]); } /* * mac + pid 的 hashcode 获取16个低位 */ return (mpid.tostring().hashcode() & 0xffff) % (maxworkerid + 1); } /** * <p> * 数据标识id部分 * </p> */ protected static long getdatacenterid(long maxdatacenterid) { long id = 0l; try { inetaddress ip = inetaddress.getlocalhost(); networkinterface network = networkinterface.getbyinetaddress(ip); if (network == null) { id = 1l; } else { byte[] mac = network.gethardwareaddress(); id = ((0x000000ff & (long) mac[mac.length - 1]) | (0x0000ff00 & (((long) mac[mac.length - 2]) << 8))) >> 6; id = id % (maxdatacenterid + 1); } } catch (exception e) { system.out.println(" getdatacenterid: " + e.getmessage()); } return id; } /** * 测试 */ public static void main(string[] args) { idworker idworker=new idworker(0,0); for(int i=0; i<100;i++) { long nextid = idworker.nextid(); system.out.println(nextid); } } }