Twitter-Snowflake,64位自增ID算法详解

Twitter-Snowflake算法产生的背景至关简单,为了知足Twitter每秒上万条消息的请求,每条消息都必须分配一条惟一的id,这些id还须要一些大体的顺序(方便客户端排序),而且在分布式系统中不一样机器产生的id必须不一样。html

Snowflake算法核心

时间戳工做机器id序列号组合在一块儿。linux

 

snowflake-64bit

 

除了最高位bit标记为不可用之外,其他三组bit占位都可浮动,看具体的业务需求而定。默认状况下41bit的时间戳能够支持该算法使用到2082年,10bit的工做机器id能够支持1023台机器,序列号支持1毫秒产生4095个自增序列id。下文会具体分析。git

 

Snowflake – 时间戳

这里时间戳的细度是毫秒级,具体代码以下,建议使用64位linux系统机器,由于有vdso,gettimeofday()在用户态就能够完成操做,减小了进入内核态的损耗。github

1算法

2sql

3服务器

4多线程

5分布式

6ui

uint64_t generateStamp()

{

    timeval tv;

    gettimeofday(&tv, 0);

    return (uint64_t)tv.tv_sec * 1000 + (uint64_t)tv.tv_usec / 1000;

}

默认状况下有41个bit能够供使用,那么一共有T(1llu << 41)毫秒供你使用分配,年份 = T / (3600 * 24 * 365 * 1000) = 69.7年。若是你只给时间戳分配39个bit使用,那么根据一样的算法最后年份 = 17.4年。

Snowflake – 工做机器id

严格意义上来讲这个bit段的使用能够是进程级,机器级的话你可使用MAC地址来惟一标示工做机器工做进程级可使用IP+Path来区分工做进程。若是工做机器比较少,可使用配置文件来设置这个id是一个不错的选择,若是机器过多配置文件的维护是一个灾难性的事情。

这里的解决方案是须要一个工做id分配的进程,可使用本身编写一个简单进程来记录分配id,或者利用Mysql auto_increment机制也能够达到效果。

snowflake - 工做id

 

工做进程与工做id分配器只是在工做进程启动的时候交互一次,而后工做进程能够自行将分配的id数据落文件,下一次启动直接读取文件里的id使用。

PS:这个工做机器id的bit段也能够进一步拆分,好比用前5个bit标记进程id,后5个bit标记线程id之类:D

Snowflake – 序列号

序列号就是一系列的自增id(多线程建议使用atomic),为了处理在同一毫秒内须要给多条消息分配id,若同一毫秒把序列号用完了,则“等待至下一毫秒”。

1

2

3

4

5

6

7

8

uint64_t waitNextMs(uint64_t lastStamp)

{

    uint64_t cur = 0;

    do {

        cur = generateStamp();

    } while (cur <= lastStamp);

    return cur;

}

 

整体来讲,是一个很高效很方便的GUID产生算法,一个int64_t字段就能够胜任,不像如今主流128bit的GUID算法,即便没法保证严格的id序列性,可是对于特定的业务,好比用作游戏服务器端的GUID产生会很方便。另外,在多线程的环境下,序列号使用atomic能够在代码实现上有效减小锁的密度。

参考资料:https://github.com/twitter/snowflake

相关文章
相关标签/搜索