UUID(Universally Unique IDentifier),通用唯一标识符,也叫GUID(Globally Unique IDentifier)。UUID是使用128bits来表示,即16个字节。通常情况下,16个字节来表示UUID所占用的字节也不算多。但是,在某些场景或应用下,由于某些限制,需要UUID所占空间进一步压缩,压缩到8字节,另外,生成的UUID还需要保持有序性。
snowflake原理
轰隆隆~,2010年Twitter提出了snowflake。snowflake是Twitter开源的分布式ID生成算法,结果是一个long型的ID。但是使用scala实现。
其核心思想是:8字节,最高位符号位总是0,接着使用41bit作为毫秒数,10bit作为机器的ID,12bit作为毫秒内的序列号。那么,在c语言中,使用8字节的基本数据类型用来存储id即可。
- 1位标识,最高位符号位总是0,所以生成的ID总是正数。
- 41位时间截(毫秒级),41位的时间截,可以使用69年,(1L << 41) / (1000L * 60 * 60 * 24 * 365) = 69年
- 10位的机器ID,显然可以表示1024台不同机器。当然还可以进一步细分,可根据自身需求定义。
- 12位序列号,12位的序列号支持每个节点每毫秒(同一机器,同一时间截)产生4096个ID序号。
理论上,每毫秒可以产生4M个ID。
了解了原理,接下来就实战,干!
snowflake实现
snowflake.h
typedef struct _snowflake_s
{
uint64_t timestamp;uint16_t machine_id;uint16_t seq_id;
}snowflake_t;typedef struct _id_gen_s
{
uint64_t epoch;snowflake_t gid;
}id_gen_t;id_gen_t* gid_gen_init(uint16_t machine_id);
void gid_gen_uninit(id_gen_t* handle);
uint64_t gid_gen_get(id_gen_t* handle);
snowflake.c
id_gen_t* gid_gen_init(uint16_t machine_id)
{
id_gen_t* handle = (id_gen_t*)malloc(sizeof(id_gen_t));handle->epoch = get_time_now_ms();handle->gid.machine_id = machine_id;handle->gid.timestamp = get_time_now_ms();handle->gid.seq_id = 0;return handle;
}void gid_gen_uninit(id_gen_t* handle)
{
free(handle);
}uint64_t gid_gen_get(id_gen_t* handle)
{
uint64_t now = get_time_now_ms();uint64_t gid = 0;if (handle->gid.timestamp > now){
perror("clock moved backwards, refusing to generate id");exit(-1);}else if (handle->gid.timestamp == now){
__sync_fetch_and_add(&handle->gid.seq_id,1);if (0 == (handle->gid.seq_id & SEQ_ID_MASK))//overflownow = wait_next_ms(handle->gid.timestamp);//wait next ms}else{
handle->gid.seq_id = 0;}handle->gid.timestamp = now;gid |= (now&TIMESTAMP_MASK) << (MACHINE_ID_BITS+SEQ_ID_BITS);gid |= (handle->gid.machine_id&MACHINE_ID_MASK) << SEQ_ID_BITS;gid |= handle->gid.seq_id&SEQ_ID_MASK;return gid;
}