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. python 视频转成代码视频

    # -*- coding:utf-8 -*- # coding:utf-8 import os, cv2, subprocess, shutil from cv2 import VideoWriter ...

  2. Android 使用gradle版本冲突

    gradle默认版本冲突解决策略:自动依赖最高版本jar包 修改默认解决策略,使之出现版本错误时报错 configurations.all{ resolutionStrategy{ failOnVer ...

  3. 初识中间件Kafka

    初识中间件Kafka Author:SimplelWu 什么是消息中间件? 非底层操作系统软件,非业务应用软件,不是直接给最终用户使用的,不能直接给客户带来价值的软件统称为中间件 关注于数据的发送和接 ...

  4. 总结web自动化测试页面常用字段的定位方法

    在一次编写web自动脚本时,突然想到web页面常有的字段有:输入框,按钮,富文本输入框,下拉框选项,弹窗,表格,上传文件以及时间插件,以下总结的没有编写时间插件的用例了!以后碰到再更新, 以下是蹩脚代 ...

  5. spring boot jpa 使用update 报错解决办法

    在spring boot jpa 中自定义sql,执行update操作报错解决办法: 在@Query(...)上添加 @Modifying@Transactional注解

  6. Eureka restTemplate访问超时

    错误代码 I/O error on GET request for "http://sushibase/v1/Publich/authorize": Connection time ...

  7. C. mathematican 的二进制

    题解: subtask1:爆搜,没状压dp的分 subtask2,3:统计有几个操作就好了,分治ntt优化 subtask4,5: 发现和操作顺序无关,然后我们考虑用分治ntt优化 每个的贡献是$n+ ...

  8. Scrapy 隐含 bug: 强制关闭爬虫后从 requests.queue 读取的已保存 request 数量可能有误

    问题描述和解决方案已提交至 Scrapy issues: The size of requests.queue may be wrong when resuming crawl from unclea ...

  9. tensorflow RNN循环神经网络 (分类例子)-【老鱼学tensorflow】

    之前我们学习过用CNN(卷积神经网络)来识别手写字,在CNN中是把图片看成了二维矩阵,然后在二维矩阵中堆叠高度值来进行识别. 而在RNN中增添了时间的维度,因为我们会发现有些图片或者语言或语音等会在时 ...

  10. golang项目git-subtree完美解决差异包管理

    目标: 1.把golang官方已移动过url的包跟随自己的项目git代码上传到项目源码中. 2.把或自己修改过的差异化fork包跟随自己的项目git代码上传到项目源码中. 解决方案: 方案1.第三方包 ...