Eu geralmente implementei a geração de números de sequência usando sequências de banco de dados no passado.
por exemplo, usando o tipo SERIAL Postgres http://www.neilconway.org/docs/sequences/
Estou curioso para saber como gerar números de sequência para grandes sistemas distribuídos onde não há banco de dados. Alguém tem alguma experiência ou sugestão de uma prática recomendada para obter a geração de números de sequência de maneira segura para threads para vários clientes?
Respostas:
OK, esta é uma pergunta muito antiga, que estou vendo pela primeira vez agora.
Você precisará diferenciar entre números de sequência e IDs exclusivos que são (opcionalmente) classificáveis livremente por um critério específico (normalmente tempo de geração). Os verdadeiros números de sequência implicam no conhecimento do que todos os outros trabalhadores fizeram e, como tal, requerem um estado compartilhado. Não há maneira fácil de fazer isso de maneira distribuída e em grande escala. Você pode examinar coisas como broadcasts de rede, intervalos de janela para cada trabalhador e tabelas de hash distribuídas para IDs de trabalhador exclusivos , mas é muito trabalhoso.
IDs exclusivos são outra questão, existem várias boas maneiras de gerar IDs exclusivos de maneira descentralizada:
a) Você pode usar o serviço de rede Snowflake ID do Twitter . Snowflake é um:
b) Você poderia gerar os IDs exclusivos nos próprios clientes, usando uma abordagem derivada de como os UUIDs e os IDs do Snowflake são feitos. Existem várias opções, mas algo como:
Os 40 bits mais significativos ou mais: um carimbo de data / hora; o tempo de geração do ID. (Estamos usando os bits mais significativos para o carimbo de data / hora para tornar os IDs classificáveis por tempo de geração.)
Os próximos 14 ou mais bits: Um contador por gerador, em que cada gerador aumenta em um para cada novo ID gerado. Isso garante que os IDs gerados no mesmo momento (mesmos carimbos de data / hora) não se sobreponham.
Os últimos 10 bits ou mais: um valor exclusivo para cada gerador. Usando isso, não precisamos fazer nenhuma sincronização entre os geradores (o que é extremamente difícil), pois todos os geradores produzem IDs não sobrepostos por causa desse valor.
c) Você poderia gerar os IDs nos clientes, usando apenas um carimbo de data / hora e um valor aleatório. Isso evita a necessidade de conhecer todos os geradores e atribuir a cada gerador um valor único. Por outro lado, não é garantido que tais IDs sejam globalmente exclusivos, mas muito provavelmente serão exclusivos. (Para colidir, um ou mais geradores teriam que criar o mesmo valor aleatório ao mesmo tempo.) Algo na linha de:
d) A maneira mais fácil é usar UUIDs / GUIDs .
fonte
twitter/snowflake
não é mais mantidoAgora existem mais opções.
Embora essa pergunta seja "velha", eu cheguei aqui, então acho que pode ser útil deixar as opções que eu conheço (até agora):
Felicidades
fonte
Você poderia fazer com que cada nó tivesse um ID exclusivo (que você pode ter de qualquer maneira) e, em seguida, acrescentá-lo ao número de sequência.
Por exemplo, o nó 1 gera a sequência 001-00001 001-00002 001-00003 etc. e o nó 5 gera 005-00001 005-00002
Único :-)
Como alternativa, se você quiser algum tipo de sistema centralizado, pode considerar que seu servidor de seqüência seja distribuído em blocos. Isso reduz a sobrecarga significativamente. Por exemplo, em vez de solicitar um novo ID do servidor central para cada ID que deve ser atribuído, você solicita IDs em blocos de 10.000 do servidor central e só precisa fazer outra solicitação de rede quando acabar.
fonte
Isso pode ser feito com Redisson . Ele implementa uma versão distribuída e escalonável do
AtomicLong
. Aqui está um exemplo:fonte
Se realmente tiver que ser sequencial globalmente, e não simplesmente exclusivo, eu consideraria a criação de um serviço único e simples para dispensar esses números.
Os sistemas distribuídos dependem da interação de muitos pequenos serviços e, para esse tipo de tarefa simples, você realmente precisa ou realmente se beneficiaria de alguma outra solução distribuída complexa?
fonte
Existem algumas estratégias; mas nenhum que eu conheça pode ser realmente distribuído e dar uma sequência real.
memcached
tem um contador atômico rápido, na grande maioria dos casos é rápido o suficiente para todo o cluster.pessoalmente, gostaria de usar UUIDs ou memcached, se quiser ter um espaço quase contíguo.
fonte
Por que não usar um gerador de UUID (thread-safe)?
Eu provavelmente deveria expandir isso.
Os UUIDs têm garantia de serem globalmente exclusivos (se você evitar aqueles baseados em números aleatórios, onde a exclusividade é altamente provável).
Seu requisito "distribuído" é atendido, independentemente de quantos geradores UUID você usa, pela exclusividade global de cada UUID.
Seu requisito de "thread safe" pode ser atendido escolhendo geradores UUID "thread safe".
Presume-se que seu requisito de "número de sequência" seja atendido pela exclusividade global garantida de cada UUID.
Observe que muitas implementações de números de sequência de banco de dados (por exemplo, Oracle) não garantem o aumento monotônico ou (até mesmo) o aumento dos números de sequência (por "conexão"). Isso ocorre porque um lote consecutivo de números de sequência é alocado em blocos "armazenados em cache" por conexão. Isso garante exclusividade global e mantém a velocidade adequada. Mas os números de sequência realmente alocados (ao longo do tempo) podem ser confundidos quando estão sendo alocados por várias conexões!
fonte
A geração de ID distribuída pode ser arquivada com Redis e Lua. A implementação disponível no Github . Ele produz ids exclusivos distribuídos e classificáveis por K.
fonte
Sei que essa é uma questão antiga, mas também estávamos diante da mesma necessidade e não foi possível encontrar a solução que atendesse a nossa necessidade. Nosso requisito era obter uma sequência única (0,1,2,3 ... n) de ids e, portanto, o floco de neve não ajudou. Criamos nosso próprio sistema para gerar os ids usando o Redis. O Redis é de thread único, portanto, seu mecanismo de lista / fila sempre forneceria 1 pop por vez.
O que fazemos é, Criamos um buffer de ids. Inicialmente, a fila terá de 0 a 20 ids que estão prontos para serem despachados quando solicitados. Vários clientes podem solicitar um id e o redis exibirá 1 id por vez. Após cada pop da esquerda, inserimos BUFFER + currentId à direita, o que mantém a lista de buffers funcionando. Implementação aqui
fonte
Eu escrevi um serviço simples que pode gerar números longos de 64 bits não sequenciais semi-únicos. Ele pode ser implantado em várias máquinas para redundância e escalabilidade. Ele usa ZeroMQ para mensagens. Para mais informações sobre como funciona, veja a página do github: zUID
fonte
Usando um banco de dados, você pode alcançar mais de 1.000 incrementos por segundo com um único núcleo. É muito fácil. Você pode usar seu próprio banco de dados como back-end para gerar esse número (como deveria ser seu próprio agregado, em termos de DDD).
Eu tive o que parece ser um problema semelhante. Eu tinha várias partições e queria obter um contador de deslocamento para cada uma. Eu implementei algo assim:
Em seguida, executei a seguinte instrução:
Se seu aplicativo permitir, você pode alocar um bloco de uma vez (foi o meu caso).
Se você precisar de mais rendimento e não puder alocar compensações com antecedência, poderá implementar seu próprio serviço usando o Flink para processamento em tempo real. Consegui obter cerca de 100 mil incrementos por partição.
Espero que ajude!
fonte
O problema é semelhante a: No mundo iscsi, onde cada luns / volumes devem ser identificados de forma única pelos iniciadores executados no lado do cliente. O padrão iscsi diz que os primeiros bits devem representar as informações do provedor / fabricante do armazenamento, e o restante deve aumentar monotonicamente.
Da mesma forma, pode-se usar os bits iniciais no sistema distribuído de nós para representar o nodeID e o resto pode ser monotonicamente crescente.
fonte
Uma solução decente é usar uma geração baseada em muito tempo. Isso pode ser feito com o apoio de um banco de dados distribuído.
fonte