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. AJAX的原理

    AJAX 什么是AJAX AJAX= Asynchronous JavaScript and XML(异步的 JavaScript 和 XML): AJAX 不是新的编程语言,而是一种使用现有标准的新 ...

  2. JpaManytoMany

    package com.allqj.calculator.entity; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; i ...

  3. GO语言一行代码实现反向代理

    本文,介绍了什么是反向代理,如何用go语言实现反向代理. 至于他的标题, "GO语言一行代码实现反向代理 | Writing a Reverse Proxy in just one line ...

  4. SLAM学习--开源测试数据集合

    Tum RGB-D SLAM Dataset and Benchmark https://vision.in.tum.de/data/datasets/rgbd-dataset Kitti http: ...

  5. 【原创】navicat for sqlite 11.1.12 patch 永久试用 不报毒

    因为最近需要用这个但是网上都是注册机没有成功注册,所以就自己动手使用ollydbg开刀,    修改成了永久试用版本. 着急用所以没仔细分析,暂时先这样吧. 这个下载版本 http://dlsw.ba ...

  6. centos7系列Cobbler+kickstart全自动装机实战

    配置yum源,以及epel源 [root@crobbler-90111 ~]# cat /etc/yum.repos.d/aliyun.repo [epel] name=ailiyun baseurl ...

  7. day23.面向对象之继承

    1.什么是继承 继承是一种创建新类的方式,在python中,新建的类可以继承一个或多个父类,父类又可称为基类或超类,新建的类称为派生类或子类 python中类的继承分为:单继承和多继承 class A ...

  8. css边框动画

    <div class="button">hover me to change</div> .button{ width:200px; height:60px ...

  9. JVM调优入门之初探

    JVM:程序计数器,jvm栈,本地方法栈,堆,方法区 JVM:虚拟机内存又分有:年轻代(eden,servivor s0,servivor s1),年老代(tenured),永久代() 问题1:如何查 ...

  10. Eclipse 那些小技巧(值得收藏)

    1.菜单命令系列 Edit→content Assist→add Alt+/ 代码关联 Windows→Next Editor→add Ctrl+Tab 切换窗口 Run→Debug Toggle L ...