关于分布式环境下的id生成
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生成的更多相关文章
- 分布式环境下的id生成方法
分布式环境下的id生成方法 前几天研究数据库分表分库的问题,其中有一个关键的地方就是生成唯一键的问题,假如数据表有1亿条数据,而且还在不断的增加,这里我们就需要考虑到分表分库,假设我们采用Hash ...
- 分布式环境下Unique ID生成方法
ID即标示符,在某个搜索域内能唯一标示其中某个对象.在关系型数据库中每个表都需要定义一个主键来唯一标示一条记录.为了方便一般都会使用一个auto_increment属性的整形数做为ID.因为数据库本身 ...
- 【融云分析】如何实现分布式场景下唯一 ID 生成?
◀背景▶ 对于一套分布式部署的 IM 系统,要求每条消息的 ID 要保证在集群中全局唯一且按生成时间有序排列.如何快速高效的生成消息数据的唯一 ID ,是影响系统吞吐量的关键因素.那么,融云是如何做到 ...
- MySQL分库分表环境下全局ID生成方案 转
在大型互联网应用中,随着用户数的增加,为了提高应用的性能,我们经常需要对数据库进行分库分表操作.在单表时代,我们可以完全依赖于数据库的自增ID来唯一标识一个用户或数据对象.但是当我们对数据库进行了分库 ...
- MySQL分库分表环境下全局ID生成方案
在大型互联网应用中,随着用户数的增加,为了提高应用的性能,我们经常需要对数据库进行分库分表操作.在单表时代,我们可以完全依赖于数据库的自增ID来唯一标识一个用户或数据对象.但是当我们对数据库进行了分库 ...
- 【转】MySQL分库分表环境下全局ID生成方案
转载一篇博客,里面有很多的知识和思想值得我们去思考. —————————————————————————————————————————————————————————————————————— 在大 ...
- 高并发环境下全局id生成策略
解决方案: 基于Redis的全局id生成策略:(推荐此方法) 基于雪花算法的全局id生成: https://www.cnblogs.com/kobe-qi/p/8761690.html 基于zooke ...
- Shiro权限管理框架(二):Shiro结合Redis实现分布式环境下的Session共享
首发地址:https://www.guitu18.com/post/2019/07/28/44.html 本篇是Shiro系列第二篇,使用Shiro基于Redis实现分布式环境下的Session共享. ...
- 分布式全局不重复ID生成算法
分布式全局不重复ID生成算法 算法全局id唯一id 在分布式系统中经常会使用到生成全局唯一不重复ID的情况.本篇博客介绍生成的一些方法. 常见的一些方式: 1.通过DB做全局自增操作 优点:简单.高 ...
随机推荐
- cocos2dx-lua调用C++
文参考:https://www.cnblogs.com/xiaonanxia/p/4987856.html 上面的文章是IOS版教程,用4部分说明原理,1部分说操作步骤. 这里用window VS20 ...
- 2019年Python、Golang、Java、C++如何选择?
前言 作为开发者我们都知道,开发后台语言可选择的方向会很多,比如,Java,go,Python,C/C++,PHP,NodeJs….等很多,这么多语言都有什么样的优势?如果让你学习一门后端语言,又该如 ...
- css背景图片充满DIV
最近接手前端页面,让给调样式.哥纯粹一个代码程序猿,表示那些个样式应该让前端人员或者美工小妹妹来实现. 书归正传,碰到了问题,页面要在手机上展现,众所周知,手机在中国的牌子很多,很难做到统一. 页面上 ...
- Django By Example 总结
从3月1号到3月23号总共24天完成了三个项目,时间很赶,学的很充实,但是憋的有点难受了,从下周开始就有上机实验了,抽不出来很多时间学课外的东西了.任务进度拖延了一个星期的进度,主要是因为我懒.... ...
- TCP和UDP的区别以及使用python服务端客户端简单编程
一.TCP.UDP区别总结 1.TCP面向连接(如打电话要先拨号建立连接):UDP是无连接的,即发送数据之前不需要建立连接 2.TCP提供可靠的服务,也就是说,通过TCP连接传送的数据,无差错,不丢失 ...
- unity一个按钮实现开和关
using System.Collections; using System.Collections.Generic; using UnityEngine; public class ButtonCl ...
- OO Unit 2 电梯调度
目录 OO Unit2 博客作业 基于度量来分析⾃己的程序结构 复杂度分析 架构分析 改进和重构 发现过的BUG 简化问题 多线程初探 OO Unit2 博客作业 基于度量来分析⾃己的程序结构 自认为 ...
- Shell脚本学习 - 基本内容以及数据格式
为了捞取日志,自己用python写了一些东西,大致套路就是读取写入文件的操作,放到linux上跑.实际使用时发现要操作的文件有时比较大,直接打开文件找需要的东西可能会有一些效率问题.所以学习一下she ...
- RSP小组——团队冲刺博客六
RSP小组--团队冲刺博客六 冲刺日期:2018年12月18日 前言 各成员今日(12.18)完成的任务 李闻洲,赵乾宸代码合并 马瑞蕃图形后续支持,编写博客,燃尽图 蒋子行会议记录 各个成员的任务安 ...
- Linux 查询服务数据
1. htop 可以时时查看 2. free -m 查看缓存