惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

U
Unit 42
博客园 - Franky
T
Tailwind CSS Blog
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
月光博客
月光博客
人人都是产品经理
人人都是产品经理
雷峰网
雷峰网
Hugging Face - Blog
Hugging Face - Blog
有赞技术团队
有赞技术团队
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
阮一峰的网络日志
阮一峰的网络日志
C
Check Point Blog
爱范儿
爱范儿
T
The Blog of Author Tim Ferriss
aimingoo的专栏
aimingoo的专栏
Stack Overflow Blog
Stack Overflow Blog
博客园 - 聂微东
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
L
LangChain Blog
云风的 BLOG
云风的 BLOG
MyScale Blog
MyScale Blog
Microsoft Security Blog
Microsoft Security Blog
The Cloudflare Blog
博客园 - 三生石上(FineUI控件)

博客园 - 网鱼

雪花算法:生成分布式全局唯一ID 数据加密共享与签名方案 Java 8中处理集合的优雅姿势——Stream 消息中间件选型分析——从Kafka与RabbitMQ的对比来看全局 从概念到底层技术,一文看懂区块链架构设计(附知识图谱) 以太坊源码分析——BlockChain 超级账本实践——基于docker从零搭建联盟链 Hyperledger Fabric V1.0– 开发者快速入门 超级账本Fabric教程(一):超级账本入门 区块链技术基础语言(三十二):Go语言网络编程(下) 区块链技术基础语言(三十一):Go语言网络编程(上) 区块链技术基础语言(三十):Go语言常用工具包(下) 区块链技术语言(二十九)—Go语言常用工具包(上) 区块链技术语言(二十八)——Go语言并发编程(下) 区块链技术语言(二十七)——Go语言并发编程(上) 区块链技术语言(二十六)——Go语言异常处理 区块链技术语言(二十五)——面向对象:接口 区块链技术语言(二十四)——Go语言面向对象:匿名组合 区块链技术语言(二十三)——Go语言面向对象:方法
Twitter的分布式自增ID雪花算法snowflake (Java版)
网鱼 · 2019-03-22 · via 博客园 - 网鱼

概述

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

有些时候我们希望能使用一种简单一些的ID,并且希望ID能够按照时间有序生成。

twitter的snowflake解决了这种需求,最初Twitter把存储系统从MySQL迁移到Cassandra,因为Cassandra没有顺序ID生成机制,所以开发了这样一套全局唯一ID生成服务。

结构

snowflake的结构如下(每部分用-分开):

0 - 0000000000 0000000000 0000000000 0000000000 0 - 00000 - 00000 - 000000000000

第一位为未使用,接下来的41位为毫秒级时间(41位的长度可以使用69年),然后是5位datacenterId和5位workerId(10位的长度最多支持部署1024个节点) ,最后12位是毫秒内的计数(12位的计数顺序号支持每个节点每毫秒产生4096个ID序号)

一共加起来刚好64位,为一个Long型。(转换成字符串长度为18)

snowflake生成的ID整体上按照时间自增排序,并且整个分布式系统内不会产生ID碰撞(由datacenter和workerId作区分),并且效率较高。据说:snowflake每秒能够产生26万个ID。

  1. private final long twepoch = 1288834974657L;

  2. private final long workerIdBits = 5L;

  3. private final long datacenterIdBits = 5L;

  4. private final long maxWorkerId = -1L ^ (-1L << workerIdBits);

  5. private final long maxDatacenterId = -1L ^ (-1L << datacenterIdBits);

  6. private final long sequenceBits = 12L;

  7. private final long workerIdShift = sequenceBits;

  8. private final long datacenterIdShift = sequenceBits + workerIdBits;

  9. private final long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;

  10. private final long sequenceMask = -1L ^ (-1L << sequenceBits);

  11. private long datacenterId;

  12. private long sequence = 0L;

  13. private long lastTimestamp = -1L;

  14. public IdWorker(long workerId, long datacenterId) {

  15. if (workerId > maxWorkerId || workerId < 0) {

  16. throw new IllegalArgumentException(String.format("worker Id can't be greater than %d or less than 0", maxWorkerId));

  17. if (datacenterId > maxDatacenterId || datacenterId < 0) {

  18. throw new IllegalArgumentException(String.format("datacenter Id can't be greater than %d or less than 0", maxDatacenterId));

  19. this.workerId = workerId;

  20. this.datacenterId = datacenterId;

  21. public synchronized long nextId() {

  22. long timestamp = timeGen();

  23. if (timestamp < lastTimestamp) {

  24. throw new RuntimeException(String.format("Clock moved backwards. Refusing to generate id for %d milliseconds", lastTimestamp - timestamp));

  25. if (lastTimestamp == timestamp) {

  26. sequence = (sequence + 1) & sequenceMask;

  27. timestamp = tilNextMillis(lastTimestamp);

  28. lastTimestamp = timestamp;

  29. return ((timestamp - twepoch) << timestampLeftShift) | (datacenterId << datacenterIdShift) | (workerId << workerIdShift) | sequence;

  30. protected long tilNextMillis(long lastTimestamp) {

  31. long timestamp = timeGen();

  32. while (timestamp <= lastTimestamp) {

  33. protected long timeGen() {

  34. return System.currentTimeMillis();

  35. public static void main(String[] args) {

  36. IdWorker idWorker = new IdWorker(0, 0);

  37. for (int i = 0; i < 1000; i++) {

  38. long id = idWorker.nextId();

posted @ 2019-03-22 14:19  网鱼  阅读(945)  评论()    收藏  举报