工程搭建:搭建子工程之分布式id生成器
分布式ID生成器
目前微服务架构盛行,在分布式系统中的操作中都会有一些全局性ID的需求,所以我们不能使用数据库本身的自增
功能来产生主键值,只能由程序来生成唯一的主键值。我们采用的是开源的twitter( 非官方中文惯称:推特.是国外
的一个网站,是一个社交网络及微博客服务) 的snowflake (雪花)算法。
各个段解析:
分段 | 作用 | 说明 |
1bit | 保留(不用) | --- |
41bit | 时间戳,精确到毫秒 | 最多可以支持69年的跨度 |
5bit | 机器id | 最多支持2的5次方(32)个节点 |
5bit | 业务编码 | 最多支持2的5次方(32)个节点 |
12bit | 毫秒内的计数器 | 每个节点每毫秒最多产生2的12次方(4096)个id |
默认情况下41bit的时间戳可以支持该算法使用到2082年,10bit的工作机器id可以支持1024台机器,序列号
支持1毫秒产生4096个自增序列id . SnowFlake的优点是,整体上按照时间自增排序,并且整个分布式系统内
不会产生ID碰撞(由数据中心ID和机器ID作区分),并且效率较高,经测试,SnowFlake每秒能够产生26万ID
左右
package com.hrm.common.utils;import java.lang.management.ManagementFactory;
import java.net.InetAddress;
import java.net.NetworkInterface;//雪花算法代码实现
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) {// 当前毫秒内,则+1sequence = (sequence + 1) & sequenceMask;if (sequence == 0) {// 当前毫秒内计数满了,则等待下一秒timestamp = tilNextMillis(lastTimestamp);}} else {sequence = 0L;}lastTimestamp = timestamp;// ID偏移组合生成最终的ID,并返回IDlong 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;}
}
工程搭建:搭建子工程之分布式id生成器相关推荐
- Qt把已有工程添加到其他工程中作为子工程或新创建子工程
Qt创建子工程 新建一个空工程 添加子工程 在当前工程下添加一个子工程 一个已有的qt工程,想添加到其他工程作为一个子工程,或是在当前工程中添加一个子工程,可以使用以下方法. 假设已有的工程为test ...
- 融云发送图片消息_IM消息ID技术专题(五):开源分布式ID生成器UidGenerator的技术实现...
1.引言 很多人一想到IM应用开发,第一印象就是"长连接"."socket"."保活"."协议"这些关键词,没错,这些确 ...
- IM消息ID技术专题(五):开源分布式ID生成器UidGenerator的技术实现
1.引言 很多人一想到IM应用开发,第一印象就是"长连接"."socket"."保活"."协议"这些关键词,没错,这些确 ...
- 来吧,自己动手撸一个分布式ID生成器组件
在经过了众多轮的面试之后,小林终于进入到了一家互联网公司的基础架构组,小林目前在公司有使用到架构组研究到分布式id生成器,前一阵子大概看了下其内部的实现,发现还是存在一些架构设计不合理之处.但是又由于 ...
- 美团(Leaf)分布式ID生成器,好用的一批!
不了解分布式ID的同学,先行去看<一口气说出 9种 分布式ID生成方式,面试官有点懵了>温习一下基础知识,这里就不再赘述了 美团(Leaf) Leaf是美团推出的一个分布式ID生成服务,名 ...
- c#分布式ID生成器
c#分布式ID生成器 简介 这个是根据twitter的snowflake来写的.这里有中文的介绍. 如上图所示,一个64位ID,除了最左边的符号位不用(固定为0,以保证生成的ID都是正数),还剩余63 ...
- 分布式ID生成器的解决方案总结
转载自 分布式ID生成器的解决方案总结 在互联网的业务系统中,涉及到各种各样的ID,如在支付系统中就会有支付ID.退款ID等.那一般生成ID都有哪些解决方案呢?特别是在复杂的分布式系统业务场景中,我们 ...
- java redis id生成器_基于redis的分布式ID生成器
项目地址 基于redis的分布式ID生成器. 准备 首先,要知道redis的EVAL,EVALSHA命令: 原理 利用redis的lua脚本执行功能,在每个节点上通过lua脚本生成唯一ID. 生成的I ...
- 分布式id生成器:彻底解决雪花算法时间回拨问题
Butterfly 简介 雪花算法是twitter提出的分布式id生成器方案,但是有三个问题,其中前两个问题在业内很常见: 时间回拨问题 机器id的分配和回收问题 机器id的上限问题 Butterfl ...
最新文章
- eeglab教程系列(10)-绘制ERP图像
- Mybatis主要内容
- Linux设备管理(三):sysfs文件系统的功能及其应用
- assert()理解
- svn汉化依然失败无解
- 淘宝,京东,苏宁易购技术架构(路线)分析和比较
- 第三章 高频谐振功率放大器(关键点:功率、效率)
- 8.用C/C++实现一个科学计算器———(超级详细完整,包含C/C++版本和Qt版本)
- 靠写iPhone程序发财的三个故事
- C#操作开机自启动(写进注册表)
- Java图形用户界面设计音乐播放器
- WordPress 衍生产品 BuddyPress 年底发布
- 关于xamarin汉字转换成拼音
- 论文导读:A Diversity-Promoting Objective Function for Neural Conversation Models
- 条码打印软件之如何在条码内容插入字符而不被扫描
- 2019华为软件精英挑战赛赛后总结
- win8 激活历程 真激活与假激活
- WIN10 3个手指拖动_老树谷歌地图数据采集大师下载-谷歌地图数据采集 v1.3.0.3 官方版...
- 【2019CVPR学习】翻译-Graph Attention Convolution for Point Cloud Semantic Segmentation
- 教女朋友学Python