PostgreSQL分布式id-雪花算法snowflake

观看视频

基础知识PostgreSQL分布式id-雪花算法snowflake_第1张图片

基本原理:由4部份组成一个64字节的整数(bigint).

  • 字节计算读取顺序从左至右,下标计数从0开始.
  • 第0位为符号位:正数是0,负数是1.但是有些语言没有无符号整数(java\PostgreSQL),为保证可移植性因此固定为0。
  • 第1-41位为时间戳:单位为毫秒,时间戳只有41位,所以值范围为0-2199023255551毫秒,最多可以存储69年的数据.因为值范围较小,不能直接使用UNIX时间戳,应该使用时间戳的差值(当前时间-你指定的开始时间).你指定的开始时间可以是任意时间,比如系统于2020年开始开发,这个时间可以指定为2020-1-1.
select (2199023255551::bigint) / (24::bigint * 60 * 60 * 1000) / 365
  • 第42-51位为机器id:可以自己组合这10bit数据.例如:如果主机都在C类IP段之内(0-255),可以取IP地址的最后一位做为机器id.此时只需要8字节即可,多出来的2字节可以分配给时间戳,此时时间戳占用43字节,值范围为0-8796093022207,存储范围可以扩大至278年.
select (((1::bigint)<<43) - 1) / (24::bigint * 60 * 60 * 1000) / 365
  • 第52-63位顺序号:值范围为0-4095,为同一时间戳同一个机器可以生成的ID个数,也就是同一毫秒同一个机器最多可以生成4095个ID.
select (((1::bigint)<<12) - 1)

位运算技巧

要设置bit位的任一1位为0时,将该位设置为0,其它位设置为1,然后执行&运算.例如将第7位设置为0

select (32767::bit(16)) &  x'FF7F'
-- 32767二进制表示为 01111111 11111111
-- FF7F二进制表示为  11111111 01111111
-- 结果             01111111 01111111

要设置bit位的任一1位为1时,将该位设置为1,其它位设置为0,然后执行|运算.例如将第7位设置为1

select (0::bit(16)) &  x'0080'
-- 0二进制表示为     00000000 00000000
-- 0080二进制表示为  00000000 10000000
-- 结果             00000000 10000000

用SQL实现雪花算法snowflake

select 
	id>>22,
	((id<<41)&9223372036854775807)>>53,
	((id<<51)&9223372036854775807)>>51
from (select (((2199023255551::bigint)<<22) | (1023<<12) | 4095 ) as id) as tmp
  • 2199023255551:为时间戳的最大值
  • 1023:为机器id的最大值
  • 4095:为顺序号的最大值
  • 注意:如果输入值超过最大值将无法还原数据,因此在生成时必须先范围范围是否在有效范围内.
  • 9223372036854775807是确保符号位设置0,因为算法规定符号位必须0.
--9223372036854775807的二进制
0111111111111111111111111111111111111111111111111111111111111111
  • 在机器id和顺序号左移位时必须保持符号位,因此机器id左移41位,顺序号左移51位.左移位完成后,符号位不一定为0,因此在左移位后必须保证符号位为0.

变种

在使用分布式程序时,此时同一毫秒内同一台机器只会产生很少量的序列号,因此可以将工作机器id扩充至12位、14位、16位,序列号使用10位、8位、6位.具体如何选择请结合需求.

  • 工作机器id12位值范围:1-4095
  • 工作机器id14位值范围:1-16383
  • 工作机器id16位值范围:1-65535
  • 序列号10位值范围:1-1023
  • 序列号8位值范围:1-255
  • 序列号6位值范围:1-63

工作机器id12位,序列号10位

select 
	id>>22,
	((id<<41)&9223372036854775807)>>51,
	((id<<53)&9223372036854775807)>>53
from (select (((2199023255551::bigint)<<22) | (4095<<10) | 1023 ) as id) as tmp

工作机器id14位,序列号8位

select 
	id>>22,
	((id<<41)&9223372036854775807)>>49,
	((id<<55)&9223372036854775807)>>55
from (select (((2199023255551::bigint)<<22) | (16383<<8) | 2 ) as id) as tmp

工作机器id16位,序列号6位

select 
	id>>22,
	((id<<41)&9223372036854775807)>>47,
	((id<<57)&9223372036854775807)>>57
from (select (((2199023255551::bigint)<<22) | (65535<<6) | 63 ) as id) as tmp

你可能感兴趣的:(PostgreSQL二次开发,snowflake,雪花算法)