我正在阅读: https://instagram-engineering.com/sharding-ids-at-instagram-1cf5a71e5a5c
在上一节“解决方案”中,他们将根据数据库的自动增量功能+历元以来的毫秒数+分片ID生成全局唯一的ID。
我们为什么需要在其中添加分片ID?
具体说来
接下来,我们获取此特定数据的分片ID 试图插入。假设我们要通过用户ID分片, 2000个逻辑分片;如果我们的用户ID为31341,则分片ID为 31341%2000->1341。我们用该值填充接下来的13位
这没有任何意义:如果您已经通过分片数量(31341%2000)来修改用户ID,则意味着1)您已经具有用户ID! 2)您已经知道mod功能所属的分片了!
我在这里误会什么?
答案 0 :(得分:4)
也许我可以为您更好地分解它,但这不是 ,因为user-id不适合。
他们正在使用Twitter Snowflake ID。它旨在并行生成多个服务器,多个数据中心之间的唯一ID。例如,在相同的确切瞬间,两个“位置”中的两个“项目”需要一个相距不到一毫秒(甚至在同一纳秒内)的东西的有保证的唯一ID。此唯一ID具有以下要求:需要以极快的速度生产,高效,以可以有效解析的逻辑方式构建,可以容纳64位以内,并且如果ID在许多人的生命周期内,生成它的方法需要能够处理大量的数据。这意味着他们无法进行数据库查找以获得尚未使用的唯一ID,无法确定生成的ID在确定后是否为唯一,并且他们无法使用可能会生成重复项的现有方法很少像UUID。因此,他们设计了一种方法。
他们设置了一个自定义通用纪元,例如今天以长整数为基点。因此,有了它们,它有一个42位长的整数,从那个时期开始,在0+时间开始。
然后,如果一台计算机上的单个进程必须在同一毫秒内生成2个或更多ID,则他们还添加了一个12位长的整数序列。现在它们有42 + 12 = 54位在使用,当您考虑到多台机器上的多个进程(通常每个数据中心只有一台机器提供ID,但是可能更多,并且通常每台机器只有一个工作者/进程)时,您会意识到您不仅需要42 + 12。.
因此,他们还必须编码数据中心ID和“工人”(流程)ID。这将覆盖多个数据中心,每个数据中心中都有多个工作人员。这两个ID均为5位长的整数。所有这些整数都是无符号的,因此这5位整数可以增加到31,这使这些部分ID中的每一个都有32种可能性,包括0。因此,有32个数据中心,每个数据中心最多有32个工作线程。 42 + 12 + 5 + 5 = 64位,最多32x32 = 1024个工人分发这些ID。
所以..能够适应42位部分的使用寿命长达139年...节点ID(或数据中心+工人ID)的10位... 12位序列(4096每位员工每毫秒的ID)...您想出了64种最大保证的唯一ID系统/公式,在139年中,它的扩展性非常好,它不以任何方式依赖数据库,但可以高效地生成并存储在数据库中。数据库。
因此,此ID系统的计算结果为42 + 12 + 10,您可以将这10位除以或除以10位,但是您喜欢并且不希望超出在任何地方存储64位无符号长整数的范围。非常灵活,效果很好。
同样,它被称为雪花ID,Twitter提出了它。这10位可以称为分片ID,节点ID或数据中心ID和工作人员ID的组合,这实际上取决于您的需求。但是,通过不将分片/节点ID绑定到用户,而是将其绑定到多个进程,并能够在多个“事物”之间使用该ID,您将不必担心很多事情,并且可以跨多个包含很多事物的数据库和and and ..
一件重要的事情是,分片/节点ID只能容纳1024个不同的值,并且用户ID或他们可以使用的任何唯一ID不会从0分配到1023,因为它们没有分配它自己去做。
因此,您看到,这10位必须是东西,它们是静态的,可分配的,并且易于解析,无论它们如何。
这是一个简单的python函数,它将生成雪花ID:
def genSnowflakeId(worker_id, data_center_id, ids_generated):
"Returns a snowflake ID - This function will generate a unique ID that fits in a 64 bit unsigned number that scales for multiple workers running in mutiple datacenters. You must manage a timestamp and sequence sanity with ids_generated (i.e. increment if time apart < 1 millisecond or always increment and roll over to 0 if > 4095). Ultimately this will allow you to efficiently generate unique IDs across multiple locations for 139 years that fits in a bigint(20) database field and can be parsed for the created timestamp, worker ID, and datacenter ID. See https://github.com/twitter-archive/snowflake/tree/snowflake-2010"
import sys
import time
# Mon Jul 8 05:07:56 EDT 2019
twepoch = 1562576876131L
sequence = 0L
worker_id_bits = 5L
data_center_id_bits = 5L
sequence_bits = 12L
timestamp_bits = 42L
#total bits 64
max_worker_id = -1L ^ (-1L << worker_id_bits)
max_data_center_id = -1L ^ (-1L << data_center_id_bits)
max_ids_generated = -1L ^ (-1L << sequence_bits)
worker_id_shift = sequence_bits
data_center_id_shift = sequence_bits + worker_id_bits
timestamp_left_shift = sequence_bits + worker_id_bits + data_center_id_bits
sequence_mask = -1L ^ (-1L << sequence_bits)
# Sanity checks for input
if worker_id > max_worker_id or worker_id < 0:
raise ValueError("worker_id", "worker id can't be greater than %i or less than 0" % max_worker_id)
if data_center_id > max_data_center_id or data_center_id < 0:
raise ValueError("data_center_id", "data center id can't be greater than %i or less than 0" % max_data_center_id)
if ids_generated > max_ids_generated or ids_generated < 0:
raise ValueError("ids_generated", "ids generated can't be greater than %i or less than 0" % max_ids_generated)
timestamp = long(int(time.time() * 1000))
new_id = ((timestamp - twepoch) << timestamp_left_shift) | (data_center_id << data_center_id_shift) | (worker_id << worker_id_shift) | sequence
return new_id
希望这个答案满足您:)
答案 1 :(得分:0)
他们需要一个长度为64位的图片ID。
从纪元以来的41毫秒(毫秒)+ shard-id的13位+递增值的10位。
他们之所以使用shard-id而不是user-id,是因为仅shard-id可以容纳13位,而user-id将需要更多位。