go实现SnowFlake
package main import (
"errors"
"fmt"
"strconv"
"sync"
"time"
) /*
* 算法解释
* SnowFlake的结构如下(每部分用-分开):<br>
* 0 - 0000000000 0000000000 0000000000 0000000000 0 - 00000 - 00000 - 000000000000 <br>
* 1位标识,由于long基本类型在Java中是带符号的,最高位是符号位,正数是0,负数是1,所以id一般是正数,最高位是0<br>
* 41位时间截(毫秒级),注意,41位时间截不是存储当前时间的时间截,而是存储时间截的差值(当前时间截 - 开始时间截)
* 得到的值),这里的的开始时间截,一般是我们的id生成器开始使用的时间,由我们程序来指定的(如下的epoch属性)。
* 41位的时间截,可以使用69年,年T = (1L << 41) / (1000L * 60 * 60 * 24 * 365) = 69<br>
* 10位的数据机器位,可以部署在1024个节点,包括5位datacenterId和5位workerId<br>
* 12位序列,毫秒内的计数,12位的计数顺序号支持每个节点每毫秒(同一机器,同一时间截)产生4096个ID序号<br>
* 加起来刚好64位,为一个Long型。<br>
* SnowFlake的优点是,整体上按照时间自增排序,并且整个分布式系统内不会产生ID碰撞(由数据中心ID和机器ID作区分),并且效率较高,经测试,SnowFlake每秒能够产生26万ID左右。
*/
const (
//t := time.Date(2015, 1, 1, 00, 00, 00, 00, time.Local).UnixNano() / 1e6;//获取时间戳 毫秒
//开始时间戳 2015-1-1
epoch int64 = 1420041600000
// 机器id所占的位数
workerIdBits int64 = 5
// 数据标识id所占的位数
datacenterIdBits int64 = 5
//支持的最大机器id,结果是31 (这个移位算法可以很快的计算出几位二进制数所能表示的最大十进制数)
maxWorkerId int64 = -1 ^ (-1 << workerIdBits)
// 支持的最大数据标识id,结果是31
maxDatacenterId int64 = -1 ^ (-1 << datacenterIdBits)
//序列在id中占的位数
sequenceBits int64 = 12
// 机器ID向左移12位
workerIdShift int64 = sequenceBits;
// 数据标识id向左移17位(12+5)
datacenterIdShift int64 = sequenceBits + workerIdBits;
// 时间截向左移22位(5+5+12)
timestampLeftShift int64 = sequenceBits + workerIdBits + datacenterIdBits
// 生成序列的掩码,这里为4095 (0b111111111111=0xfff=4095)
sequenceMask int64 = -1 ^ (-1 << sequenceBits)
) /*
* 构造
*/
type SnowflakeIdWorker struct {
mutex sync.Mutex // 添加互斥锁 确保并发安全
lastTimestamp int64 // 上次生成ID的时间截
workerId int64 // 工作机器ID(0~31)
datacenterId int64 //数据中心ID(0~31)
sequence int64 // 毫秒内序列(0~4095)
} /*
* 创建SnowflakeIdWorker
* workerId 工作ID (0~31)
* datacenterId 数据中心ID (0~31)
*/
func createWorker(wId int64,dId int64)(*SnowflakeIdWorker,error){
if wId < 0 || wId > maxWorkerId {
return nil, errors.New("Worker ID excess of quantity")
}
if dId < 0 || dId > maxDatacenterId {
return nil, errors.New("Datacenter ID excess of quantity")
}
// 生成一个新节点
return &SnowflakeIdWorker{
lastTimestamp: 0,
workerId: wId,
datacenterId: dId,
sequence: 0,
}, nil
} /*
* 获取ID
*/
func (w *SnowflakeIdWorker) nextId() int64 {
// 保障线程安全 加锁
w.mutex.Lock()
// 生成完成后 解锁
defer w.mutex.Unlock()
// 获取生成时的时间戳 毫秒
now := time.Now().UnixNano() / 1e6
//如果当前时间小于上一次ID生成的时间戳,说明系统时钟回退过这个时候应当抛出异常
if now < w.lastTimestamp {
errors.New("Clock moved backwards")
//根据需要自定义错误码
return 3001
}
if w.lastTimestamp == now {
w.sequence = (w.sequence + 1) & sequenceMask
if w.sequence == 0 {
// 阻塞到下一个毫秒,直到获得新的时间戳
for now <= w.lastTimestamp {
now = time.Now().UnixNano() / 1e6
}
}
}else {
// 当前时间与工作节点上一次生成ID的时间不一致 则需要重置工作节点生成ID的序号
w.sequence = 0
}
// 将机器上一次生成ID的时间更新为当前时间
w.lastTimestamp = now
ID := int64((now - epoch) << timestampLeftShift | w.datacenterId << datacenterIdShift | (w.workerId << workerIdShift) | w.sequence)
return ID
} /*
* 将十进制数字转化为二进制字符串
*/
func convertToBin(num int64) string {
s := ""
if num == 0 {
return "0"
}
// num /= 2 每次循环的时候 都将num除以2 再把结果赋值给 num
for ;num > 0 ; num /= 2 {
lsb := num % 2
// 将数字强制性转化为字符串
s = strconv.FormatInt(lsb,10) + s
}
return s
} func main() {
worker,err := createWorker(0,0)
if err != nil {
fmt.Println(err)
return
}
ch := make(chan int64)
count := 100
// 并发 goroutine ID生成
for i := 0; i < count; i++ {
go func() {
id := worker.nextId()
ch <- id
}()
}
defer close(ch)
m := make(map[int64]int)
for i := 0; i < count; i++ {
id := <- ch
// map中存在为id的key,说明生成的 ID有重复
_, ok := m[id]
if ok {
fmt.Println("ID is not unique!")
}
// id作为key存入map
m[id] = i
fmt.Println(id)
fmt.Println(convertToBin(id))
}
}
go实现SnowFlake的更多相关文章
- 关于全局ID,雪花(snowflake)算法的说明
上次简单的说一下:http://www.cnblogs.com/dunitian/p/6041745.html#uid C#版本的国外朋友已经封装了,大家可以去看看:https://github.co ...
- Snowflake 全局唯一Id 生成
/// <summary> /// From: https://github.com/twitter/snowflake /// An object that generates IDs. ...
- POJ 3349 Snowflake Snow Snowflakes(简单哈希)
Snowflake Snow Snowflakes Time Limit: 4000MS Memory Limit: 65536K Total Submissions: 39324 Accep ...
- Twitter的分布式自增ID算法snowflake (Java版)
概述 分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的. 有些时候我们希望能使用一种 ...
- Twitter Snowflake 的Java实现
在关闭显示的情况下, 可以达到每毫秒3万个的生成速度 /** * An Implementation of Twitter Snowflake ID Generator */ public class ...
- C# 实现 Snowflake算法 ID生成
http://blog.csdn.net/w200221626/article/details/52064976 C# 实现 Snowflake算法 /// <summary> /// 动 ...
- 【hiho一下第77周】递归-减而治之 (MS面试题:Koch Snowflake)
本题是一道微软面试题,看起来复杂,解出来会发现其实是一个很简单的递归问题,但是这道题的递归思路是很值得我们反复推敲的. 原题为hihocoder第77周的题目. 描述 Koch Snowflake i ...
- Snowflake Snow Snowflakes(哈希表的应用)
Snowflake Snow Snowflakes Time Limit: 4000MS Memory Limit: 65536K Total Submissions: 27312 Accep ...
- poj 3349:Snowflake Snow Snowflakes(哈希查找,求和取余法+拉链法)
Snowflake Snow Snowflakes Time Limit: 4000MS Memory Limit: 65536K Total Submissions: 30529 Accep ...
- PHP使用SnowFlake算法生成唯一ID
前言:最近需要做一套CMS系统,由于功能比较单一,而且要求灵活,所以放弃了WP这样的成熟系统,自己做一套相对简单一点的.文章的详情页URL想要做成url伪静态的格式即xxx.html 其中xxx考虑过 ...
随机推荐
- 在数组添加元素时报错:IndexError: list index out of range
今天第一次发随笔还有许多不足之处,欢迎评论!!! 最近在写一个成语接龙的小游戏,结果在数组添加元素时报错:IndexError: list index out of range 源码: import ...
- 归并排序(归并排序求逆序对数)--16--归并排序--Leetcode面试题51.数组中的逆序对
面试题51. 数组中的逆序对 在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对.输入一个数组,求出这个数组中的逆序对的总数. 示例 1: 输入: [7,5,6,4] 输出 ...
- async 和 await 例子
/// <summary> /// C# 5.0 /// .net framework4.5 /// CLR4.0 /// 引入了async 和 await.这两个关键字可以让你更方便的写 ...
- Java中集合的嵌套
集合的嵌套遍历 获取10个1-20之间的随机数,要求不能重复 键盘录入多个数据,以0结束,要求在控制台输出这多个数据的最大值. public static void main(String[] arg ...
- linux--配置开发环境 --Nginx篇
安装: 安装好了话,我们的nginx的目录在: /etc/nginx 启动: sudo service nginx start 然后访问我们的页面就可以看到了我们的界面 然后我们配置我们的域名: 我 ...
- js事件冒泡于事件捕获
事件冒泡 事件捕获指的是从document到触发事件的那个节点,即自上而下的去触发事件. 事件冒泡是自下而上(从最深节点开始,向上传播事件)的触发事件 //例子 <div id="pa ...
- [C语言] 获得 pwd 的几种函数
_getcwd() GetCurrentDirectory GetModuleFileName main函数参数 argv[0] // crt_getcwd.c // This program pla ...
- Window+Protobuf使用说明
Window+Protobuf使用说明 C++WindowCmakeProtocbuf 介绍 起因 由于项目中要用到二进制存储数据,之前使用的方式是按照字节数依次将数据写入字节流中, 但是这样做起来做 ...
- 【集群实战】NFS网络文件共享服务
1. NFS介绍 1.1 什么是NFS? NFS是Network File System的缩写,中文意思是网络文件系统. 它的主要功能是通过网络(一般是局域网)让不同的主机系统之间可以共享文件或目录. ...
- Echarts设置点击事件
简单明了. echarts初始化完成之后,给实例对象通过on绑定事件. 这里的事件包括: 'click','dblclick','mousedown','mouseup','mouseover','m ...