PostgreSQL分布式id-雪花算法snowflake

观看视频

基础知识在这里插入图片描述

基本原理:由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
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

kmblack1

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值