在《悟空传》的番外篇中,有一个悲伤的故事。秋天,两片叶子从树上落下,你要和它们说再见了。但是你怎么知道这片叶子,而不是另一片叶子呢?是看它的形状,还是看它的重量?当我们在分布式环境中存储一些数据时,我们不得不面对的选择之一就是ID生成器。使用唯一的字符串来标识一条完整的记录。这个时候不能用md5或者sha1来消化整条记录,因为后面我们要改这条记录。也不可以使用单机计数器,因为计数器容易重启清零,在多台机器上会出现重复值,违背了无状态服务构建的目标。舍不得选择UUID虽然UUID在大多数语言中都有相关的类库,但是我们一般不会使用它,除非它破解不了。UUID虽然不会重复,但是很长,让人望而生畏。XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX标准UUID由5部分组成:8-4-4-4-12,共32个十六进制字符。因此,一共有128位。当使用UUID作为数据库的索引时,会因为其无序导致索引的随机分布;由于数据量巨大,查询性能会下降。同时,UUID也是不可读的。如果您将其打印在纸质订单上,那可不是个好主意。UUID在信息安全方面也存在隐患。它的数据计算包括MAC地址的参与。更为著名的是它被用来寻找梅丽莎病毒创造者的位置。RetrofittingTimestamps如果你是一个独立的应用程序,使用时间戳没有错。即使不使用纳秒,毫秒也足够了。但是在分布式环境下,timestamp也不是一个好的选择。即使你在机器上安装了ntpd时间同步,由于网络和机器的不同,电脑的时钟总是不一样的,你的时间戳总是重复的。为了解决这个问题,需要添加一些其他的标识,比如机器的ID,或者更细分的信息,以减少时间碰撞。此自定义ID生成器仅适用于特定业务。当你这样做的时候,你会发现它本质上是雪花算法的一个变体。SnowflakeAlgorithmSnowflake算法生成的ID为long型,默认字符串长度为19个字符,分为4部分。保留1位。毫秒时间戳——41位(比如从现在开始,支持未来69年),这个其实挺尴尬的,因为70年后就过期了。但你不会在一家公司工作70年,所以随它去吧。Configuredmachine/node/shardID-10bits(totalsupport2^10=1024nodes)Serialnumber-12bits(机器的本地计数,所以支持的并发度已经很高)与UUID相比,Snowflake生成的IDs算法经过排序,具有更好的紧凑性。它是目前大多数企业首选的ID生成算法。值得注意的是,雪花算法在JavaScript中有一个陷阱。后端返回ID时需要使用String类型,不能使用Long类型,否则会出现意想不到的错误。这是因为。在JavaScript中,有两种数字。数字和BigInt。最常用的是数字。最大的数字称为Number.MAX_SAFE_INTEGER,其值为:2^53-1或+/-9,007,199,254,740,991。众所周知,Java中的Long是64位的。Js中这个安全的Integer根本没有达到Java中定义的长度。这就是邪恶的IEEE_754规范,当Long的长度大于17位时,它会出现精度丢失的问题。NanoIDNanoID由JavaScript库演变而来,目前有多种语言版本。看起来像这样。V1StGXR8_Z5jdHi6B-myTNanoID虽然不能替代雪花算法,但是用这个长度替代UUID绰绰有余。NanoID的大小只有108个字节,比UUID小35%,更加紧凑。此外,它速度更快,使用默认字母表每秒生成超过220万个唯一ID,使用自定义字母表每秒生成180万个唯一ID,几乎没有发生冲突的可能性。如果你的ID对序列没有什么严格的要求,比如使用kv这样非常松散的数据库,那么NanoID是你最好的选择。介绍了这么多,你会用哪个ID生成器呢?事实上,如果一个组件的使用量增加到一定程度,就会出现问题,需要进行特殊的组件设计。比如美团的叶子,在大互联网肯定有用。但是对于一般互联网,甚至是中型互联网来说,这是一张躺椅还是一个空壳,作为决策者,你要考虑清楚。作者简介:薇薇小姐姐(xjjdog),一个不允许程序员走弯路的公众号。专注于基础架构和Linux。十年架构,每天百亿流量,与你探讨高并发世界,给你不一样的滋味。
