public class IdWorker
{
//基准时间
public const long Twepoch = 1288834974657L; //机器标识位数
private const int WorkerIdBits = ; //数据标志位数
private const int DatacenterIdBits = ; //序列号识位数
private const int SequenceBits = ; //机器ID最大值
private const long MaxWorkerId = -1L ^ (-1L << WorkerIdBits); //数据标志ID最大值
private const long MaxDatacenterId = -1L ^ (-1L << DatacenterIdBits); //序列号ID最大值
private const long SequenceMask = -1L ^ (-1L << SequenceBits); //机器ID偏左移10位
private const int WorkerIdShift = SequenceBits; //数据ID偏左移15位
private const int DatacenterIdShift = SequenceBits + WorkerIdBits; //时间毫秒左移20位
public const int TimestampLeftShift = SequenceBits + WorkerIdBits + DatacenterIdBits; private static readonly DateTime Jan1St1970 = new DateTime
(, , , , , , DateTimeKind.Utc); private readonly object _lock = new object();
private long _lastTimestamp = -1L; public IdWorker(long workerId, long datacenterId, long sequence = 0L)
{
// 如果超出范围就抛出异常
if (workerId > MaxWorkerId || workerId < )
throw new ArgumentException(string.Format("worker Id 必须大于0,且不能大于MaxWorkerId: {0}", MaxWorkerId)); if (datacenterId > MaxDatacenterId || datacenterId < )
throw new ArgumentException(string.Format("datacenterId Id 必须大于0,且不能大于MaxWorkerId: {0}",
MaxDatacenterId)); //先检验再赋值
WorkerId = workerId;
DatacenterId = datacenterId;
Sequence = sequence;
} public long WorkerId { get; protected set; }
public long DatacenterId { get; protected set; } public long Sequence { get; internal set; } public virtual long NextId(long dataNode=)
{
lock (_lock)
{
if (dataNode > MaxDatacenterId || dataNode < )
throw new ArgumentException($"dataNode 必须大于0,且不能大于MaxWorkerId: {MaxDatacenterId}");
if (dataNode == )
dataNode = DatacenterId;
var timestamp = TimeGen();
if (timestamp < _lastTimestamp)
throw new Exception($"时间戳必须大于上一次生成ID的时间戳. 拒绝为{_lastTimestamp - timestamp}毫秒生成id"); //如果上次生成时间和当前时间相同,在同一毫秒内
if (_lastTimestamp == timestamp)
{
//sequence自增,和sequenceMask相与一下,去掉高位
Sequence = (Sequence + ) & SequenceMask;
//判断是否溢出,也就是每毫秒内超过1024,当为1024时,与sequenceMask相与,sequence就等于0
if (Sequence == )
timestamp = TilNextMillis(_lastTimestamp);
}
else
{
//如果和上次生成时间不同,重置sequence,就是下一毫秒开始,sequence计数重新从0开始累加,
//为了保证尾数随机性更大一些,最后一位可以设置一个随机数
Sequence = ; //new Random().Next(10);
} _lastTimestamp = timestamp;
return ((timestamp - Twepoch) << TimestampLeftShift) | (dataNode << DatacenterIdShift) |
(WorkerId << WorkerIdShift) | Sequence;
}
} /// <summary>
/// 防止产生的时间比之前的时间还要小(由于NTP回拨等问题),保持增量的趋势.
/// </summary>
/// <param name="lastTimestamp"></param>
/// <returns></returns>
protected virtual long TilNextMillis(long lastTimestamp)
{
var timestamp = TimeGen();
while (timestamp <= lastTimestamp)
timestamp = TimeGen();
return timestamp;
} /// <summary>
/// 获取当前的时间戳
/// </summary>
/// <returns></returns>
protected virtual long TimeGen()
{
return (long) (DateTime.UtcNow - Jan1St1970).TotalMilliseconds;
}
}
 public void GetId()
{
new IdWorker(, ).NextId();
}

关于分布式环境下的id生成的更多相关文章

  1. 分布式环境下的id生成方法

    分布式环境下的id生成方法   前几天研究数据库分表分库的问题,其中有一个关键的地方就是生成唯一键的问题,假如数据表有1亿条数据,而且还在不断的增加,这里我们就需要考虑到分表分库,假设我们采用Hash ...

  2. 分布式环境下Unique ID生成方法

    ID即标示符,在某个搜索域内能唯一标示其中某个对象.在关系型数据库中每个表都需要定义一个主键来唯一标示一条记录.为了方便一般都会使用一个auto_increment属性的整形数做为ID.因为数据库本身 ...

  3. 【融云分析】如何实现分布式场景下唯一 ID 生成?

    ◀背景▶ 对于一套分布式部署的 IM 系统,要求每条消息的 ID 要保证在集群中全局唯一且按生成时间有序排列.如何快速高效的生成消息数据的唯一 ID ,是影响系统吞吐量的关键因素.那么,融云是如何做到 ...

  4. MySQL分库分表环境下全局ID生成方案 转

    在大型互联网应用中,随着用户数的增加,为了提高应用的性能,我们经常需要对数据库进行分库分表操作.在单表时代,我们可以完全依赖于数据库的自增ID来唯一标识一个用户或数据对象.但是当我们对数据库进行了分库 ...

  5. MySQL分库分表环境下全局ID生成方案

    在大型互联网应用中,随着用户数的增加,为了提高应用的性能,我们经常需要对数据库进行分库分表操作.在单表时代,我们可以完全依赖于数据库的自增ID来唯一标识一个用户或数据对象.但是当我们对数据库进行了分库 ...

  6. 【转】MySQL分库分表环境下全局ID生成方案

    转载一篇博客,里面有很多的知识和思想值得我们去思考. —————————————————————————————————————————————————————————————————————— 在大 ...

  7. 高并发环境下全局id生成策略

    解决方案: 基于Redis的全局id生成策略:(推荐此方法) 基于雪花算法的全局id生成: https://www.cnblogs.com/kobe-qi/p/8761690.html 基于zooke ...

  8. Shiro权限管理框架(二):Shiro结合Redis实现分布式环境下的Session共享

    首发地址:https://www.guitu18.com/post/2019/07/28/44.html 本篇是Shiro系列第二篇,使用Shiro基于Redis实现分布式环境下的Session共享. ...

  9. 分布式全局不重复ID生成算法

    分布式全局不重复ID生成算法 算法全局id唯一id  在分布式系统中经常会使用到生成全局唯一不重复ID的情况.本篇博客介绍生成的一些方法. 常见的一些方式: 1.通过DB做全局自增操作 优点:简单.高 ...

随机推荐

  1. phpredis扩展实现LBS距离计算和范围筛选

    来源 public function geo(){ $redis = new \redis(); $redis -> connect('127.0.0.1',6379); //位置增加 $res ...

  2. MUI底部导航切换子页面

    1.登陆页面进入之后,进入到main页面,main页面只有一个底部导航,然后引入子页面进行渲染. <nav class="mui-bar mui-bar-tab" id=&q ...

  3. Java - day002 - 运算符,位运算,流程控制

    1 运算符 +-*/               (+)   既是数学运算 ,也是 字符串链接 %                  求余  /  求模  (进口大麻袋) ==             ...

  4. SQL语句原理解析(原创)

    基本的sql语句很好理解这里不做分析,这里只考虑复杂的sql语法和关键词用法的实验分析: 一,join关联的作用: 作用: 1,为了生成信息信息更加全面的中间表:2,为了where可以使用含有单表外字 ...

  5. 关于解决微信支付sdk中NoClassDefFoundError: Failed resolution of: org.apache.http.conn.ssl.DefaultHostnameVerifier;

    导入依赖<dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>ht ...

  6. Qt之excel 操作使用说明

    学习背景: 适合熟悉些qt开发,但是不是深入了解的开发者学习.具体实现(qt 5.1版本),office2007 Excel做验证,Win 7(64位),如有讲解有误,欢迎斧正! 一.简单介绍 QAx ...

  7. Javascript执行上下文和执行栈

    什么是执行上下文? 执行上下文就是当前JavaScript代码被解析和执行时所在环境的抽象概念,JavaScript中运行任何的代码都是在执行上下文. 什么是执行栈? 执行栈,在其他编程语言中也被叫做 ...

  8. 【玩转开源】BananaPi R2 —— 第二篇 Openwrt 网口配置分析

    上次和大家分享了如何烧录和安装Openwrt到BananaPi R2,运行Openwrt的R2目前就具备路由器的功能了,这次我们来看看R2运行Openwrt的性能如何,同时也会讲解一些常用的网络知识. ...

  9. UOJ#335. 【清华集训2017】生成树计数 多项式,FFT,下降幂,分治

    原文链接www.cnblogs.com/zhouzhendong/p/UOJ335.html 前言 CLY大爷随手切这种题. 日常被CLY吊打系列. 题解 首先从 pruffer 编码的角度考虑这个问 ...

  10. CF 552 Neko does Maths

    给出两个数a,b 求k     使得 a+k b+k有最小公倍数 a,b同时加上一个非负整数k,使得,a+k,b+k的最小公倍数最小 因为最小公公倍数=x*y / gcd(x,y),所以肯定离不开最大 ...