Falando sobre a geração de identificação única em sistemas distribuídos

prefácio

Nossos atuais sistemas de servidores principais são arquiteturas distribuídas. O negócio é distribuído em diferentes nós de máquina para gerar dados, e os dados também são armazenados em diferentes nós de máquina. Para a conveniência de identificar os dados, usamos 唯一且有序o ID para identificar os dados. qual é:

  • Em todo o sistema distribuído, o ID recém-gerado nunca será duplicado com o ID gerado anteriormente;
  • Todos os IDs gerados podem ser classificados de acordo com o tempo de geração (a última geração é posterior na ordem de classificação)

Vamos dar uma olhada em vários esquemas de geração de ID convencionais no mercado.

1. Conjunto MySQL

Como a premissa de nossa discussão é um sistema de arquitetura distribuída, o Mysql aqui é a versão do cluster por padrão.
Como todos sabemos, o Mysql possui seu próprio mecanismo de ID único, ou seja, a chave primária auto-incrementável, que pode garantir que no mesmo banco de dados, cada registro gerado na tabela seja único e ordenado.

imagem.png

Mas se for colocado em um sistema distribuído, usamos a estrutura sub-banco de dados/sub-tabela para armazenar registros, o que resultará em IDs duplicados no sistema .
Conforme mostrado na figura abaixo, as tabelas 1 2 3 são tabelas diferentes que armazenam os mesmos registros (podem estar no mesmo banco de dados ou em bancos de dados diferentes), e as tabelas 1 2 3 irão gerar dados com o mesmo id.

Problema de identificação de incremento automático de subtabela.png

Para resolver este problema, o mysql suporta oficialmente a configuração do tamanho do passo ao gerar o ID do banco de dados, o que pode garantir a exclusividade do id da mesma tabela em diferentes bancos de dados.

Solução de ID de incremento automático de subtabela.png

Conforme mostrado na figura acima, cada tabela tem um ID inicial diferente e o mesmo tamanho de etapa , o que garante a exclusividade do ID do registro comercial.
Embora a solução de definir o tamanho do passo resolva a singularidade da geração de id, ela também tem grandes desvantagens

  • A ordenação de IDs e a forte correlação de tempo não podem ser garantidas. (Por ser um sistema distribuído, não há garantia de que os dados com id=4 devem ser gerados após os dados com id=3)
  • Toda vez que um novo nó é adicionado, o valor inicial e o tamanho da etapa de todos os nós devem ser redefinidos.

O segundo ponto é que o gerenciamento de banco de dados será um pouco mais problemático, mas o primeiro ponto não pode atender aos nossos requisitos ordenados.

2. Banco de dados de identificação

这里泛指一套单独维护的ID数据库,目的是为了保证业务系统内所有的ID的唯一性和有序性。
举几个例子,比如Mysql维护一条表记录,Redis 维护一个key,zookeeper 维护一个序列号。当所有业务都通过调用这些存储服务来生成+获取唯一ID的时候,就可以保证生成Id的唯一性和有序性。

缺点:

  • 需要资源单独维护一个服务
  • 如果ID数据库挂掉,整个业务就会停摆。如果ID数据库出现数据错乱,可能会影响到唯一性和有序性

总结一下就是,ID数据库可以提供唯一有序的ID,但是有一定的维护成本且系统的风险很高。

三、雪花算法

SnowFlake是Twitter公司采用的一种算法,目的是在分布式系统中产生全局唯一且整体递增的ID。

3.1 生成ID的结构

Princípio do algoritmo do floco de neve.png

  1. 1 个 bit:0,这个是无意义的。
  2. 41 个 bit:表示的是时间戳。单位毫秒
  3. 10 个 bit:在整个业务系统内,标识服务的唯一ID
  4. 12 个 bit:表示的序号,就是某个服务同一毫秒内同时生成的 id 的序号

3.2 生成原理

我们先看一下雪花ID的生成过程:

  1. 生成毫秒级别的时间戳,填充到 41bit 的位置
  2. 序列号默认为 000000000000。如果新生成的时间戳上次生成的相等,序列号就会 + 1。将序列号填充到 12bit 位置
  3. 存储当前生成的时间戳到内存中,以便下次生成时判断
  4. 获取到当前机器+进程的唯一标识,填充到 10bit 的位置

通过上述整个流程我们可以看到,雪花算法可以确保唯一性,单机内在同一毫秒生成的ID会有序列号的递增,多机环境在同一毫秒生成的ID会有机器+进程的唯一标识。

但是无法保证强有序性,比如多个机器在同一毫秒内生成的ID,就无法按照时间规则进行排序

3.3 缺点

雪花算法除了无法实现严格按照时间的有序性之外,还有一个可能存在的风险点,就是单机时钟回拨
如果一个机器之前已经生成过ID,将机器的时间改为之前的时间,那么就有一定几率会生成与之前相同的ID。

四、mongoDB 的唯一ID生成策略

mongo唯一ID生成策略——ObjectId,和雪花算法相似度极高。区别在于雪花算法要占用64个字节,而 ObjectId 只需要占用 12个字节,但是objectId只能存储秒级别时间戳。

ObjectId如果用字符串表示则有24个字符,但实际上它是由一组十六进制的字符构成,每个字节两位的十六进制数字,总共用了12字节的存储空间。

mongoObjectId.png

比如:6331500a7cac81af7136236b 这个ID

  • 前八位字符就代表十六进制的数字 6331500a,转换为十进制的数字就是 1664176138,作为秒级时间戳转换为时间就是 2022-09-26 15:08:58
  • 从时间戳字符结束的位置,向后六位字符,代表机器码
  • 从机器码字符结束的位置,向后四位字符,代表进程的pid
  • 后六位字符就代表同一秒内生成的不同id的序号

mongoDB 的 ObjectId 和雪花算法一样,无法实现严格按照时间的有序性,并且由于是秒级别的时间戳,所以不同机器生成的ID,不按照时间排序的可能性会大很多。而且如果单机时钟回拨,也会产生与之前重复的ID。

总结

特性/方案 Mysql 集群 ID数据库 雪花算法 mongoDB ObjectId
唯一性
按照生成时间的有序性
维护的难易程度 较难 易维护 易维护

在分布式系统中:

  • 以上四种方案都可以保证生成ID的唯一性
  • 如果并发量很小的系统,可以考虑 雪花算法/mongoDB ObjectId 方案来保证有序性
  • 如果并发量很大,只能用ID数据库来保证有序性,但是会比 雪花算法/mongoDB ObjectId 方案增加维护成本

おすすめ

転載: juejin.im/post/7147594145467465764