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的更多相关文章

  1. 关于全局ID,雪花(snowflake)算法的说明

    上次简单的说一下:http://www.cnblogs.com/dunitian/p/6041745.html#uid C#版本的国外朋友已经封装了,大家可以去看看:https://github.co ...

  2. Snowflake 全局唯一Id 生成

    /// <summary> /// From: https://github.com/twitter/snowflake /// An object that generates IDs. ...

  3. POJ 3349 Snowflake Snow Snowflakes(简单哈希)

    Snowflake Snow Snowflakes Time Limit: 4000MS   Memory Limit: 65536K Total Submissions: 39324   Accep ...

  4. Twitter的分布式自增ID算法snowflake (Java版)

    概述 分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的. 有些时候我们希望能使用一种 ...

  5. Twitter Snowflake 的Java实现

    在关闭显示的情况下, 可以达到每毫秒3万个的生成速度 /** * An Implementation of Twitter Snowflake ID Generator */ public class ...

  6. C# 实现 Snowflake算法 ID生成

    http://blog.csdn.net/w200221626/article/details/52064976 C# 实现 Snowflake算法 /// <summary> /// 动 ...

  7. 【hiho一下第77周】递归-减而治之 (MS面试题:Koch Snowflake)

    本题是一道微软面试题,看起来复杂,解出来会发现其实是一个很简单的递归问题,但是这道题的递归思路是很值得我们反复推敲的. 原题为hihocoder第77周的题目. 描述 Koch Snowflake i ...

  8. Snowflake Snow Snowflakes(哈希表的应用)

    Snowflake Snow Snowflakes Time Limit: 4000MS   Memory Limit: 65536K Total Submissions: 27312   Accep ...

  9. poj 3349:Snowflake Snow Snowflakes(哈希查找,求和取余法+拉链法)

    Snowflake Snow Snowflakes Time Limit: 4000MS   Memory Limit: 65536K Total Submissions: 30529   Accep ...

  10. PHP使用SnowFlake算法生成唯一ID

    前言:最近需要做一套CMS系统,由于功能比较单一,而且要求灵活,所以放弃了WP这样的成熟系统,自己做一套相对简单一点的.文章的详情页URL想要做成url伪静态的格式即xxx.html 其中xxx考虑过 ...

随机推荐

  1. python字节码,java字节码,十六进制相互转换

    下面是互相转换的代码: 有想要了解更多关于python知识的请在下方评论或私信小编

  2. Grafana-监控-报警-运维文档

    Grafana运维文档 2019/09/23 Chenxin Wuweiwei 参考资料 https://grafana.com/grafana https://blog.52itstyle.vip/ ...

  3. Django系列操作

    每次用到都去百度找....找的还不行~~得自己改~~耗时耗力虽然不难~~~直接贴代码记录下方便自己用~~~~ Django之分页 定义成一个块,直接引用到对应的位置即可... <div clas ...

  4. springboot前后端分离跨域

    @Configurationpublic class CrossConfig implements WebMvcConfigurer { @Override public void addCorsMa ...

  5. linux CVE-2019-13272 本地特权漏洞

    漏洞描述 在5.1.17之前的Linux内核中,kernel / ptrace.c中的ptrace_link错误地处理了想要创建ptrace关系的进程的凭据记录,这允许本地用户通过利用父子的某些方案来 ...

  6. selenium 元素定位常用的方法

    元素定位的方法有2个 driver.findElement(By.args) 返回值是WebElement            //此方法是获取单一的页面元素 driver.findElements ...

  7. [git] github 推送以及冲突的解决,以及一些命令

    推送以及冲突的解决:(我的觉得先看完) (正常情况就是把修改的文件 git add 然后git commit 然后推送就行啦): 下面是一些命令 1.查看分支状态(查看所有:当前检出分支的前面会有星号 ...

  8. Springboot:thymeleaf模板(八)

    存放位置:resources\templates 访问方式:通过Controller请求访问,不可直接访问(相当于web项目的WEB-INF目录) 环境依赖: <!--thymeleaf模板支持 ...

  9. react: typescript import images alias

    1.webpack.config.js resolve: { extensions: ["ts", "tsx", "js", "j ...

  10. HBase可用性分析与高可用实践

    HBase作为一个分布式存储的数据库,它是如何保证可用性的呢?对于分布式系统的CAP问题,它是如何权衡的呢? 最重要的是,我们在生产实践中,又应该如何保证HBase服务的高可用呢? 下面我们来仔细分析 ...