原文转自:http://www.tanjp.com (即时修正和更新)
目录
32位唯一ID(一年(388天)内的每秒内有128个唯一值)
32位唯一ID(一个月(48天)内的每秒内有1024个唯一值)
32位唯一ID(一周(12天)内的每秒内有4096个唯一值)
64位全局唯一标识
snowflake是用64位整型来表示一个序列号的,看上去和我们的时间戳很像,但是它的起始元年不是1970年,而是自定义的。然后时间戳里面只是记录下当前毫秒与自定义的元年时间差,这样起始就用不到64位的bit来记录整个时间戳,多出来的几位就可以做其他的事情,来看下面的结构:
00000.......000 00000 00000 000000000000
|___________| |___| |___| |__________|
| | | |
42bit 5bit 5bit 12bit
参考snowflake算法改造:
00000.......000 0000000000 000000000000
|___________| |________| |__________|
| | |
42bit 10bit 12bit
64位的全局唯一ID,保证在138年内的每1毫秒内有4095个唯一值。
第一部分 长度为42位,精确到毫秒级的自定义时间戳。当前时间戳减去指定时间开始的时间戳,最大可记录138年。
第二部分 长度为10位,根据不同业务ID做区分,取值范围[0,1023]。
第三部分 长度为12位,自增ID,取值范围[0,4095]。
C++代码实现:
class Uid64
{
public:
explicit Uid64(uint32 pn_1st_from_year = 2000, uint32 pn_2nd_business_id = 0);
uint64 generate(uint32 pn_2nd_business_id);
private:
uint32 mn_1st_from_year; //毫秒级时间
uint32 mn_2nd_business_id; //业务ID
uint32 mn_3rd_index; //自增
};
Uid64::Uid64(uint32 pn_1st_from_year, uint32 pn_2nd_business_id)
: mn_1st_from_year(pn_1st_from_year)
, mn_2nd_business_id(pn_2nd_business_id)
, mn_3rd_index(0)
{
namespace pt = boost::posix_time;
if ( (mn_1st_from_year > pt::microsec_clock::universal_time().date().year())
|| (mn_1st_from_year < 1970) )
{
mn_1st_from_year = 1970;
}
if (pn_2nd_business_id > 1023)
{
pn_2nd_business_id = 0;
}
}
uint64 Uid64::generate(uint32 pn_2nd_business_id)
{
namespace pt = boost::posix_time;
mn_2nd_business_id = pn_2nd_business_id;
if (mn_2nd_business_id > 1023)
{
mn_2nd_business_id = 0;
}
++mn_3rd_index;
if (mn_3rd_index > 4095)
{
mn_3rd_index = 0;
}
pt::ptime now = pt::microsec_clock::universal_time();
pt::ptime from_time(boost::gregorian::date(mn_1st_from_year, 1, 1));
pt::time_duration time_span = now - from_time;
uint64 zn_1st = time_span.total_milliseconds();
uint64 zn_2nd = mn_2nd_business_id;
uint64 zn_3rd = mn_3rd_index;
uint64 zn_result = (zn_1st << 22) | (zn_2nd << 12) | zn_3rd;
return zn_result;
}
测试例子:
void main()
{
const uint32 kLen = 100000;
Uid64 zo_u64(2019, 1);
uint64 zc_vec[kLen];
for (u