Em resposta às questões de desempenho que frequentemente surgem durante o uso, apresento os três conjuntos de práticas recomendadas a seguir:
❄ Se o requisito de geração de ID não exceder 5W/s, não há necessidade de modificar nenhum parâmetro de configuração.
❄ Se exceder 5W peças/s e for inferior a 50W peças/s, recomenda-se modificar: SeqBitLength=10
❄ Se exceder 50W bits/s e estiver próximo de 500W bits/s, recomenda-se modificar: SeqBitLength=12
Em resumo, aumentar o SeqBitLength resultará em melhor desempenho, mas os IDs gerados serão mais longos.
❄ Este é um algoritmo de floco de neve otimizado (desvio de floco de neve), que gera IDs mais curtos e rápidos.
❄ Suporta expansão automática de ambientes de contêiner, como k8s (registro automático de WorkerId), e pode gerar um ID digital exclusivo em um ambiente independente ou distribuído.
❄ Suporta nativamente C#/Java/Go/C/Rust/Python/Node.js/PHP (extensão C)/SQL/ e outras linguagens, e fornece chamada de biblioteca dinâmica segura (FFI) multithread.
❄ Compatível com todos os algoritmos de floco de neve (modo de segmento numérico ou modo clássico, fabricantes grandes ou pequenos), você pode fazer qualquer atualização ou troca no futuro.
❄ Esta é a ferramenta de geração de ID do Snowflake mais abrangente da história do computador. 【Em agosto de 2022】
? Como arquiteto, você deseja resolver o problema de chaves primárias exclusivas em um banco de dados, especialmente em um sistema distribuído com vários bancos de dados.
Você deseja que a chave primária da tabela de dados use menos espaço de armazenamento, indexe mais rapidamente e selecione, insira e atualize mais rapidamente.
? Você deve considerar que ao dividir bancos de dados e tabelas (mesclando bancos de dados e tabelas), o valor da chave primária pode ser usado diretamente e pode refletir o momento do negócio.
? Se esse valor de chave primária for muito longo e exceder o valor máximo do tipo js Number do front-end, o tipo Long deverá ser convertido para o tipo String e você se sentirá um pouco frustrado.
? Embora o Guid possa incrementar automaticamente, ele ocupa muito espaço e a velocidade de indexação é lenta. Você não deseja usá-lo.
? Pode haver mais de 50 instâncias de aplicação e cada solicitação simultânea pode atingir 10W/s.
? Para implantar aplicativos em um ambiente de contêiner, suporte à replicação horizontal e à expansão automática.
?Você não deseja confiar na operação de incremento automático do redis para obter IDs de chave primária contínua, porque IDs contínuos representam riscos à segurança dos dados de negócios.
?Você quer que o sistema opere por mais de 100 anos.
O ID gerado é muito longo.
A quantidade de simultaneidade instantânea não é suficiente.
O problema de discagem de tempo não pode ser resolvido.
A geração pós-suplementar de ID de encomenda não é suportada.
Pode contar com sistemas de armazenamento externos.
✔ Números inteiros, aumentando monotonicamente ao longo do tempo (não necessariamente contínuos), mais curtos em comprimento e não excederão o valor máximo do tipo js Number em 50 anos. (configuração padrão)
✔ Mais rápido, 2 a 5 vezes mais rápido que o algoritmo tradicional de floco de neve, 500.000 podem ser gerados em 0,1 segundos (com base no i7 de baixa tensão de 8ª geração).
✔ Suporte ao processamento de retorno de chamada em tempo. Por exemplo, se o horário do servidor for atrasado em 1 segundo, esse algoritmo poderá se adaptar automaticamente para gerar um ID exclusivo para o horário crítico.
✔Suporta inserção manual de novos IDs. Quando o negócio precisa gerar novos IDs em tempo histórico, os bits reservados desse algoritmo podem gerar 5.000 IDs por segundo.
✔ Não depende de nenhum cache ou banco de dados externo. (A biblioteca dinâmica que registra automaticamente WorkerId no ambiente k8s depende do redis)
✔ Funções básicas, prontas para uso, sem necessidade de arquivos de configuração, conexões de banco de dados, etc.
(Parâmetros: sequência de aumento automático de 10 bits, valores máximos de desvio de 1000)
Solicitações contínuas | 5K | 5W | 50W |
---|---|---|---|
Algoritmo tradicional de floco de neve | 0,0045s | 0,053s | 0,556s |
Algoritmo de deriva de neve | 0,0015s | 0,012s | 0,113s |
?Desempenho final: 500W/s~3000W/s. (Todos os dados de teste são calculados com base na baixa tensão i7 de 8ª geração)
? Quando ocorre o dialback de horário do sistema, o algoritmo usa o número de sequência reservado da série temporal anterior para gerar um novo ID.
? O número de ID gerado pelo retorno de chamada é colocado primeiro por padrão e também pode ser ajustado para ser posterior.
? Permitir que o tempo seja redefinido para a base predefinida deste algoritmo (os parâmetros são ajustáveis).
? O ID gerado por este algoritmo é um número inteiro (ocupa até 8 bytes de espaço).
129053495681099 (运行1年,长度:15)
387750301904971 (运行3年,长度:15)
646093214093387 (运行5年,长度:15)
1292658282840139 (运行10年,长度:16)
9007199254740992 (运行70年,达到 js Number 最大值,长度:16)
165399880288699493 (运行1000年,等同普通雪花算法运行1年,长度:18)
?O valor de ID gerado por este algoritmo é de 1% a 10% do valor máximo do número js, que é um milésimo do valor do algoritmo de floco de neve comum, mas a velocidade de geração é mais rápida do que o algoritmo de floco de neve comum.
? O valor máximo do tipo js Number: 9007199254740992. Este algoritmo pode levar 70 anos para atingir o valor js Number Max, mantendo o desempenho de simultaneidade (5W+/0,01s) e um máximo de 64 WorkerIds (6 bits).
? 每增加 1位 WorkerIdBitLength 或 SeqBitLength,生成的ID数字值将会乘以2(基础长度可参考前一节“ID示例”),反之则除以2。
A explicação de quanto tempo pode ser usado refere-se a quando o número de ID gerado pode crescer e exceder o valor máximo de comprimento (64 bits assinados, 8 bytes).
• Na configuração padrão, estão disponíveis 71.000 IDs exclusivos.
? Ao suportar 1.024 nós de trabalho, os IDs ficam disponíveis por 4.480 anos sem duplicação.
? Ao suportar 4.096 nós de trabalho, os IDs ficam disponíveis por 1.120 anos sem duplicação.
❄ WorkerIdBitLength , o comprimento do bit do código de máquina, determina o valor máximo de WorkerId, o valor padrão é 6 e o intervalo de valores é [1, 19]. Na verdade, algumas linguagens usam o tipo ushort (uint16) não assinado para receber. este parâmetro, portanto o valor máximo é 16. Se If Designed Short (int16) for usado, o valor máximo será 15.
❄ WorkerId , código de máquina, o parâmetro mais importante , sem valor padrão, deve ser globalmente exclusivo (ou exclusivo dentro do mesmo DataCenterId), deve ser definido programaticamente , a condição padrão (WorkerIdBitLength assume o valor padrão), o valor máximo é 63, o valor máximo teórico é 2^WorkerIdBitLength -1 (diferentes linguagens de implementação podem ser limitadas a 65535 ou 32767, o princípio é o mesmo da regra WorkerIdBitLength). Não pode ser o mesmo em máquinas diferentes ou em instâncias de aplicativos diferentes. Você pode configurar esse valor por meio do aplicativo ou obter o valor chamando um serviço externo. Em resposta à necessidade de registro automático de WorkerId, este algoritmo fornece uma implementação padrão: registrar automaticamente a biblioteca dinâmica de WorkerId por meio de redis, consulte "FerramentasAutoRegisterWorkerId" para obter detalhes.
Observação especial : se um servidor implantar vários serviços independentes, será necessário especificar um WorkerId diferente para cada serviço.
❄ SeqBitLength , comprimento de bits de sequência, valor padrão 6 , intervalo de valores [3, 21] (recomendado não menos que 4), determina o número de IDs gerados por milissegundo. Caso o número de solicitações por segundo não ultrapasse 5W, basta manter o valor padrão de 6; caso ultrapasse 5W e não ultrapasse 50W, recomenda-se atribuir um valor igual ou superior a 10, e assim por diante. Requisito da regra: WorkerIdBitLength + SeqBitLength não excede 22.
❄ MinSeqNumber , número de sequência mínimo, valor padrão 5, intervalo de valores [5, MaxSeqNumber], os primeiros 5 números de sequência por milissegundo correspondem aos números 0-4 são bits reservados, dos quais 1-4 são bits reservados correspondentes ao dialback de tempo, 0 é um bit reservado para novos valores manuais.
❄ MaxSeqNumber , o número de sequência máximo, o intervalo de configuração é [MinSeqNumber, 2 ^ SeqBitLength-1], o valor padrão é 0, o número de sequência máximo real é o valor máximo (2 ^ SeqBitLength-1), se não for 0 , é o número de sequência máximo real e geralmente não precisa ser definido, a menos que várias máquinas compartilhem o WorkerId para gerar IDs em segmentos (neste caso, o número de sequência mínimo deve ser definido corretamente).
❄ BaseTime , tempo base (também conhecido como: tempo do ponto base, tempo de origem, tempo de época), tem um valor padrão (2020), é um carimbo de data e hora em milissegundos (um número inteiro, .NET é um tipo DatetTime), sua função é: usar ao gerar o ID A diferença (em milissegundos) entre a hora do sistema e a hora base é usada como carimbo de data/hora para gerar o ID. Geralmente não há necessidade de definir o tempo base. Se achar que o valor padrão é muito antigo, você pode redefini-lo. No entanto, observe que é melhor não alterar esse valor no futuro.
A segunda versão planeja adicionar parâmetros:
❄ DataCenterId , ID do data center (ID da sala de computadores, padrão 0), certifique-se de que seja globalmente exclusivo.
❄ DataCenterIdBitLength , comprimento do ID do data center (padrão 0).
❄ TimestampType , tipo de carimbo de data/hora (0 milissegundos, 1 segundo), padrão 0.
1️⃣ Ligue no modo singleton. Este algoritmo usa um único thread para gerar IDs e as chamadas de várias partes serão mutuamente exclusivas. Dentro da mesma instância do aplicativo, o chamador usa multithreading (ou paralelo) para chamar esse algoritmo, o que não aumentará a velocidade de saída do ID.
2️⃣ Especifique um WorkerId exclusivo. O sistema externo deve garantir a exclusividade global do WorkerId e atribuí-lo ao parâmetro de entrada deste algoritmo.
3️⃣ Use WorkerIds diferentes ao implantar várias instâncias em uma única máquina. Nem todas as implementações suportam exclusividade simultânea entre processos. Para garantir a segurança, ao implantar várias instâncias de aplicativo no mesmo host, certifique-se de que cada WorkerId seja exclusivo.
4️⃣ Tratamento de exceções. O algoritmo lançará todas as exceções, e o sistema externo deverá capturar as exceções e tratá-las bem para evitar causar uma falha maior no sistema.
5️⃣ Entenda cuidadosamente a definição de IdGeneratorOptions, que será útil para integrar e usar este algoritmo.
6️⃣ Use o algoritmo de deriva de neve. Embora o código contenha a definição do algoritmo de floco de neve tradicional e você possa especificar (Método = 2) no ponto de entrada para ativar o algoritmo tradicional, ainda é recomendado usar o algoritmo de desvio de floco de neve (Método = 1, o padrão) afinal, possui melhor elasticidade e maior desempenho.
7️⃣ Não modifique o algoritmo principal. Este algoritmo possui muitos parâmetros internos e lógica complexa. Quando você não domina a lógica central, não modifique o código principal e use-o em um ambiente de produção, a menos que tenha sido verificado por meio de um grande número de testes meticulosos e científicos.
8️⃣ As políticas de configuração dentro do domínio do aplicativo são as mesmas. Quando o sistema estiver em execução por um período de tempo e o projeto precisar mudar da especificação programática do WorkerId para o registro automático do WorkerId, certifique-se de que todas as instâncias em uso no mesmo domínio do aplicativo adotem uma estratégia de configuração consistente. , mas também inclui outros parâmetros de configuração.
9️⃣ Gerencie bem o tempo do servidor. O algoritmo Snowflake depende da hora do sistema. Não ajuste muito a hora do sistema operacional. Se você precisar fazer ajustes, lembre-se de certificar-se de que a hora do sistema quando o serviço for reiniciado seja maior que a hora em que ele foi desligado pela última vez. (Observação: pequenas alterações no horário do sistema causadas por sincronização de horário de classe mundial ou em nível de rede ou retorno de chamada não têm impacto neste algoritmo)
As alterações de configuração referem-se ao ajuste dos parâmetros operacionais (propriedades do objeto IdGeneratorOptions) após o sistema estar em execução por um período de tempo.
? 1. O primeiro princípio é: BaseTime só pode ser mais antigo (mais distante do presente), de modo que o valor do ID gerado seja maior que o valor máximo histórico, garantindo que não haja sobreposição de tempo e que nenhum ID duplicado seja gerado. [ Não é recomendado ajustar o BaseTime após o sistema estar em execução]
? 2. Aumentar WorkerIdBitLength ou SeqBitLength a qualquer momento é permitido, mas a operação "diminuir" deve ser usada com cautela, pois isso pode fazer com que o ID gerado no futuro seja igual à configuração antiga. [Permitir que qualquer valor xxxBitLength seja aumentado após o sistema estar em execução]
? 3. Se um dos WorkerIdBitLength ou SeqBitLength precisar ser reduzido, a condição deverá ser atendida: a soma dos dois novos xxxBitLength deverá ser maior que a soma dos valores antigos. [Restringir qualquer valor BitLength após a execução não é recomendado ]
? 4. As três regras acima não são controladas logicamente neste algoritmo. Os usuários devem fazer alterações na configuração após confirmarem que a nova configuração atende aos requisitos.
? O gerador de ID exclusivo depende do WorkerId Quando os serviços empresariais exigem replicação horizontal e indiscriminada (expansão automática), isso requer a capacidade de registrar automaticamente um WorkerId globalmente exclusivo antes de gerar um ID exclusivo.
? Este algoritmo fornece uma biblioteca dinâmica de código aberto (implementada na linguagem Go), que pode registrar automaticamente WorkerId por meio de redis em ambientes de contêiner como k8s.
? Registrar WorkerId por meio do redis não é a única maneira. Também é possível desenvolver um serviço de configuração centralizado. Quando cada serviço de terminal é iniciado, o WorkerId exclusivo é obtido por meio do serviço central.
?Claro, se o seu serviço não precisa ser expandido automaticamente, você não precisa registrar WorkerId automaticamente, mas definir valores globalmente exclusivos para eles.
? Existem muitos métodos, como o desenvolvimento de um serviço centralizado de geração de ID que gera IDs utilizáveis para cada serviço de terminal (único ou em lote).
Link da imagem: https://github.com/yitter/IdGenerator/blob/master/Tools/AutoRegisterWorkerId/regprocess.jpg
Caminho do código-fonte:/Go/source/regworkerid/reghelper.go
Link para download: https://github.com/yitter/IdGenerator/releases/download/v1.3.3/workeridgo_lib_v1.3.3.zip
// 注册一个 WorkerId,会先注销所有本机已注册的记录
// address: Redis连接地址,单机模式示例:127.0.0.1:6379,哨兵/集群模式示例:127.0.0.1:26380,127.0.0.1:26381,127.0.0.1:26382
// password: Redis连接密码
// db: Redis指定存储库,示例:1
// sentinelMasterName: Redis 哨兵模式下的服务名称,示例:mymaster,非哨兵模式传入空字符串即可
// minWorkerId: WorkerId 最小值,示例:30
// maxWorkerId: WorkerId 最大值,示例:63
// lifeTimeSeconds: WorkerId缓存时长(秒,3的倍数),推荐值15
extern GoInt32 RegisterOne(char* server, char* password, GoInt32 db, char* sentinelMasterName, GoInt32 minWorkerId, GoInt32 maxWorkerId, GoInt32 lifeTimeSeconds);
// 注销本机已注册的 WorkerId
extern void UnRegister();
linguagem | GitHub |
---|---|
?C# | Ver exemplo |
? | Ver exemplo |
? Ir | Ver exemplo |
? Ferrugem | Ver exemplo |
?Python | Ver exemplo |
?C | Ver exemplo |
?C (extensão PHP) | Ver exemplo |
?Delphi (Pascal) | Ver exemplo |
?JavaScript | Ver exemplo |
?TypeScript | Ver exemplo |
?V | Ver exemplo |
?D | Ver exemplo |
Endereço de código aberto: https://github.com/yitter/IdGenerator
Grupo QQ: 646049993