Generador de IDs de Snowflake para sistemas distribuidos
Genera y analiza IDs de Snowflake de Twitter, identificadores únicos de 64 bits utilizados en sistemas distribuidos. Esta herramienta te permite crear nuevos IDs de Snowflake y analizar los existentes, proporcionando información sobre sus componentes de marca de tiempo, ID de máquina y número de secuencia.
Generador de ID de Snowflake
Generador de ID de Snowflake
Documentación
Generador de ID de Snowflake
Introducción
Un ID de Snowflake es un identificador único utilizado en sistemas distribuidos, desarrollado originalmente por Twitter. Esta herramienta permite generar y analizar IDs de Snowflake, que son enteros de 64 bits compuestos por una marca de tiempo, ID de máquina y número de secuencia.
Cómo funcionan los IDs de Snowflake
Los IDs de Snowflake son enteros de 64 bits estructurados de la siguiente manera:
- 41 bits: Marca de tiempo (milisegundos desde una época personalizada)
- 10 bits: ID de máquina (5 bits para ID de centro de datos, 5 bits para ID de trabajador)
- 12 bits: Número de secuencia
Esta estructura permite la generación de aproximadamente 4,096 IDs únicos por milisegundo por máquina.
Uso del Generador de ID de Snowflake
- (Opcional) Establecer una época personalizada (el valor predeterminado es la época de Twitter: 2010-11-04T01:42:54.657Z)
- Ingrese un ID de máquina (0-31) y un ID de centro de datos (0-31)
- Haga clic en "Generar" para crear un nuevo ID de Snowflake
- El ID generado y sus componentes se mostrarán
Para analizar un ID de Snowflake existente, ingréselo en el campo "Analizar ID" y haga clic en "Analizar".
Fórmula
El ID de Snowflake se construye utilizando operaciones a nivel de bits:
1ID = (marcaDeTiempo << 22) | (idCentroDeDatos << 17) | (idTrabajador << 12) | secuencia
2
Donde:
marcaDeTiempo
es el número de milisegundos desde la épocaidCentroDeDatos
es un entero de 5 bits (0-31)idTrabajador
es un entero de 5 bits (0-31)secuencia
es un entero de 12 bits (0-4095)
Cálculo
El generador de ID de Snowflake realiza los siguientes pasos:
- Obtener la marca de tiempo actual en milisegundos
- Asegurarse de que la marca de tiempo sea mayor que la última marca de tiempo utilizada (para la unicidad)
- Si la marca de tiempo es la misma que la anterior, incrementar el número de secuencia
- Si el número de secuencia se desborda (llega a 4096), esperar al siguiente milisegundo
- Combinar los componentes usando operaciones a nivel de bits para crear el ID final
Casos de uso
Los IDs de Snowflake son particularmente útiles en:
- Sistemas distribuidos: Generar IDs únicos en múltiples máquinas sin coordinación
- Datos de alto volumen: Crear IDs ordenables para grandes conjuntos de datos
- Microservicios: Asegurar identificadores únicos entre diferentes servicios
- Fragmentación de bases de datos: Usar el componente de marca de tiempo o ID de máquina para una fragmentación eficiente
Alternativas
Si bien los IDs de Snowflake son potentes, otros sistemas de generación de ID incluyen:
- UUID (Identificador Único Universal): Útil cuando se necesita generación distribuida sin ordenabilidad
- IDs de base de datos auto-incrementales: Simples pero limitados a instancias de base de datos únicas
- ULID (Identificador Universal Único Lexicográficamente Ordenable): Similar a Snowflake, pero con una estructura diferente
Casos extremos y limitaciones
-
Sincronización del reloj: Los IDs de Snowflake dependen del tiempo del sistema. Si el reloj retrocede debido a ajustes de NTP o cambios de horario de verano, puede causar problemas con la generación de ID.
-
Problema del año 2038: La marca de tiempo de 41 bits se desbordará en 2079 (suponiendo la época de Twitter). Los sistemas que usan IDs de Snowflake deben planificar para esta eventualidad.
-
Colisiones de ID de máquina: En sistemas distribuidos grandes, garantizar IDs de máquina únicos puede ser un desafío y puede requerir coordinación adicional.
-
Desbordamiento de secuencia: En escenarios de rendimiento extremadamente alto, es posible agotar las 4096 secuencias por milisegundo, lo que potencialmente causaría retrasos.
-
No monotonía entre máquinas: Si bien los IDs son monotonamente crecientes en una sola máquina, pueden no ser estrictamente monótonos entre múltiples máquinas.
Historia
Los IDs de Snowflake fueron introducidos por Twitter en 2010 para abordar la necesidad de identificadores únicos distribuidos y ordenables por tiempo. Desde entonces, han sido adoptados y adaptados por muchas otras empresas y proyectos.
Ejemplos
Aquí hay implementaciones de generadores de ID de Snowflake en varios lenguajes:
1class GeneradorDeSnowflake {
2 constructor(epoch = 1288834974657, bitsIdCentroDatos = 5, bitsIdTrabajador = 5, bitsSecuencia = 12) {
3 this.epoch = BigInt(epoch);
4 this.bitsIdCentroDatos = bitsIdCentroDatos;
5 this.bitsIdTrabajador = bitsIdTrabajador;
6 this.bitsSecuencia = bitsSecuencia;
7 this.maxIdCentroDatos = -1n ^ (-1n << BigInt(bitsIdCentroDatos));
8 this.maxIdTrabajador = -1n ^ (-1n << BigInt(bitsIdTrabajador));
9 this.mascaraSecuencia = -1n ^ (-1n << BigInt(bitsSecuencia));
10 this.desplazamientoIdTrabajador = BigInt(bitsSecuencia);
11 this.desplazamientoIdCentroDatos = BigInt(bitsSecuencia + bitsIdTrabajador);
12 this.desplazamientoMarcaDeTiempo = BigInt(bitsSecuencia + bitsIdTrabajador + bitsIdCentroDatos);
13 this.secuencia = 0n;
14 this.ultimaMarcaDeTiempo = -1n;
15 }
16
17 siguienteId(idCentroDatos, idTrabajador) {
18 let marcaDeTiempo = this.marcaDeTiempoActual();
19
20 if (marcaDeTiempo < this.ultimaMarcaDeTiempo) {
21 throw new Error('El reloj se ha movido hacia atrás. Rechazando generar id');
22 }
23
24 if (marcaDeTiempo === this.ultimaMarcaDeTiempo) {
25 this.secuencia = (this.secuencia + 1n) & this.mascaraSecuencia;
26 if (this.secuencia === 0n) {
27 marcaDeTiempo = this.hastaSiguienteMilisegundo(this.ultimaMarcaDeTiempo);
28 }
29 } else {
30 this.secuencia = 0n;
31 }
32
33 this.ultimaMarcaDeTiempo = marcaDeTiempo;
34
35 return ((marcaDeTiempo - this.epoch) << this.desplazamientoMarcaDeTiempo) |
36 (BigInt(idCentroDatos) << this.desplazamientoIdCentroDatos) |
37 (BigInt(idTrabajador) << this.desplazamientoIdTrabajador) |
38 this.secuencia;
39 }
40
41 hastaSiguienteMilisegundo(ultimaMarcaDeTiempo) {
42 let marcaDeTiempo = this.marcaDeTiempoActual();
43 while (marcaDeTiempo <= ultimaMarcaDeTiempo) {
44 marcaDeTiempo = this.marcaDeTiempoActual();
45 }
46 return marcaDeTiempo;
47 }
48
49 marcaDeTiempoActual() {
50 return BigInt(Date.now());
51 }
52}
53
54// Uso
55const generador = new GeneradorDeSnowflake();
56const id = generador.siguienteId(1, 1);
57console.log(`ID de Snowflake generado: ${id}`);
58
1import time
2import threading
3
4class GeneradorDeSnowflake:
5 def __init__(self, id_centro_datos, id_trabajador, secuencia=0):
6 self.id_centro_datos = id_centro_datos
7 self.id_trabajador = id_trabajador
8 self.secuencia = secuencia
9
10 self.ultima_marca_de_tiempo = -1
11 self.epoca = 1288834974657
12
13 self.bits_id_centro_datos = 5
14 self.bits_id_trabajador = 5
15 self.bits_secuencia = 12
16
17 self.max_id_centro_datos = -1 ^ (-1 << self.bits_id_centro_datos)
18 self.max_id_trabajador = -1 ^ (-1 << self.bits_id_trabajador)
19
20 self.desplazamiento_id_trabajador = self.bits_secuencia
21 self.desplazamiento_id_centro_datos = self.bits_secuencia + self.bits_id_trabajador
22 self.desplazamiento_marca_de_tiempo = self.bits_secuencia + self.bits_id_trabajador + self.bits_id_centro_datos
23 self.mascara_secuencia = -1 ^ (-1 << self.bits_secuencia)
24
25 self._lock = threading.Lock()
26
27 def _hasta_siguiente_milisegundo(self, ultima_marca_de_tiempo):
28 marca_de_tiempo = self._obtener_marca_de_tiempo()
29 while marca_de_tiempo <= ultima_marca_de_tiempo:
30 marca_de_tiempo = self._obtener_marca_de_tiempo()
31 return marca_de_tiempo
32
33 def _obtener_marca_de_tiempo(self):
34 return int(time.time() * 1000)
35
36 def siguiente_id(self):
37 with self._lock:
38 marca_de_tiempo = self._obtener_marca_de_tiempo()
39
40 if marca_de_tiempo < self.ultima_marca_de_tiempo:
41 raise ValueError("El reloj se ha movido hacia atrás. Rechazando generar id")
42
43 if marca_de_tiempo == self.ultima_marca_de_tiempo:
44 self.secuencia = (self.secuencia + 1) & self.mascara_secuencia
45 if self.secuencia == 0:
46 marca_de_tiempo = self._hasta_siguiente_milisegundo(self.ultima_marca_de_tiempo)
47 else:
48 self.secuencia = 0
49
50 self.ultima_marca_de_tiempo = marca_de_tiempo
51
52 return ((marca_de_tiempo - self.epoca) << self.desplazamiento_marca_de_tiempo) | \
53 (self.id_centro_datos << self.desplazamiento_id_centro_datos) | \
54 (self.id_trabajador << self.desplazamiento_id_trabajador) | \
55 self.secuencia
56
57## Uso
58generador = GeneradorDeSnowflake(id_centro_datos=1, id_trabajador=1)
59id_snowflake = generador.siguiente_id()
60print(f"ID de Snowflake generado: {id_snowflake}")
61
1import java.util.concurrent.locks.Lock;
2import java.util.concurrent.locks.ReentrantLock;
3
4public class GeneradorDeSnowflake {
5 private final long epoca;
6 private final long bitsIdCentroDatos;
7 private final long bitsIdTrabajador;
8 private final long bitsSecuencia;
9 private final long maxIdCentroDatos;
10 private final long maxIdTrabajador;
11 private final long desplazamientoIdTrabajador;
12 private final long desplazamientoIdCentroDatos;
13 private final long desplazamientoMarcaDeTiempo;
14 private final long mascaraSecuencia;
15
16 private long idCentroDatos;
17 private long idTrabajador;
18 private long secuencia = 0L;
19 private long ultimaMarcaDeTiempo = -1L;
20
21 private final Lock lock = new ReentrantLock();
22
23 public GeneradorDeSnowflake(long idCentroDatos, long idTrabajador) {
24 epoca = 1288834974657L;
25 bitsIdCentroDatos = 5L;
26 bitsIdTrabajador = 5L;
27 bitsSecuencia = 12L;
28
29 maxIdCentroDatos = -1L ^ (-1L << bitsIdCentroDatos);
30 maxIdTrabajador = -1L ^ (-1L << bitsIdTrabajador);
31
32 desplazamientoIdTrabajador = bitsSecuencia;
33 desplazamientoIdCentroDatos = bitsSecuencia + bitsIdTrabajador;
34 desplazamientoMarcaDeTiempo = bitsSecuencia + bitsIdTrabajador + bitsIdCentroDatos;
35 mascaraSecuencia = -1L ^ (-1L << bitsSecuencia);
36
37 if (idCentroDatos > maxIdCentroDatos || idCentroDatos < 0) {
38 throw new IllegalArgumentException("idCentroDatos no puede ser mayor que maxIdCentroDatos o menor que 0");
39 }
40 if (idTrabajador > maxIdTrabajador || idTrabajador < 0) {
41 throw new IllegalArgumentException("idTrabajador no puede ser mayor que maxIdTrabajador o menor que 0");
42 }
43 this.idCentroDatos = idCentroDatos;
44 this.idTrabajador = idTrabajador;
45 }
46
47 public long siguienteId() {
48 lock.lock();
49 try {
50 long marcaDeTiempo = tiempoGen();
51 if (marcaDeTiempo < ultimaMarcaDeTiempo) {
52 throw new RuntimeException("El reloj se ha movido hacia atrás. Rechazando generar id");
53 }
54
55 if (ultimaMarcaDeTiempo == marcaDeTiempo) {
56 secuencia = (secuencia + 1) & mascaraSecuencia;
57 if (secuencia == 0) {
58 marcaDeTiempo = hastaSiguienteMilisegundo(ultimaMarcaDeTiempo);
59 }
60 } else {
61 secuencia = 0L;
62 }
63
64 ultimaMarcaDeTiempo = marcaDeTiempo;
65
66 return ((marcaDeTiempo - epoca) << desplazamientoMarcaDeTiempo) |
67 (idCentroDatos << desplazamientoIdCentroDatos) |
68 (idTrabajador << desplazamientoIdTrabajador) |
69 secuencia;
70 } finally {
71 lock.unlock();
72 }
73 }
74
75 private long hastaSiguienteMilisegundo(long ultimaMarcaDeTiempo) {
76 long marcaDeTiempo = tiempoGen();
77 while (marcaDeTiempo <= ultimaMarcaDeTiempo) {
78 marcaDeTiempo = tiempoGen();
79 }
80 return marcaDeTiempo;
81 }
82
83 private long tiempoGen() {
84 return System.currentTimeMillis();
85 }
86
87 public static void main(String[] args) {
88 GeneradorDeSnowflake generador = new GeneradorDeSnowflake(1, 1);
89 long id = generador.siguienteId();
90 System.out.println("ID de Snowflake generado: " + id);
91 }
92}
93
1require 'time'
2
3class GeneradorDeSnowflake
4 def initialize(id_centro_datos, id_trabajador, secuencia = 0)
5 @id_centro_datos = id_centro_datos
6 @id_trabajador = id_trabajador
7 @secuencia = secuencia
8 @ultima_marca_de_tiempo = -1
9 @epoca = 1288834974657
10
11 @bits_id_centro_datos = 5
12 @bits_id_trabajador = 5
13 @bits_secuencia = 12
14
15 @max_id_centro_datos = -1 ^ (-1 << @bits_id_centro_datos)
16 @max_id_trabajador = -1 ^ (-1 << @bits_id_trabajador)
17
18 @desplazamiento_id_trabajador = @bits_secuencia
19 @desplazamiento_id_centro_datos = @bits_secuencia + @bits_id_trabajador
20 @desplazamiento_marca_de_tiempo = @bits_secuencia + @bits_id_trabajador + @bits_id_centro_datos
21 @mascara_secuencia = -1 ^ (-1 << @bits_secuencia)
22 end
23
24 def siguiente_id
25 marca_de_tiempo = (Time.now.to_f * 1000).to_i
26
27 raise 'El reloj se ha movido hacia atrás' if marca_de_tiempo < @ultima_marca_de_tiempo
28
29 if marca_de_tiempo == @ultima_marca_de_tiempo
30 @secuencia = (@secuencia + 1) & @mascara_secuencia
31 marca_de_tiempo = hasta_siguiente_milisegundo(@ultima_marca_de_tiempo) if @secuencia == 0
32 else
33 @secuencia = 0
34 end
35
36 @ultima_marca_de_tiempo = marca_de_tiempo
37
38 ((marca_de_tiempo - @epoca) << @desplazamiento_marca_de_tiempo) |
39 (@id_centro_datos << @desplazamiento_id_centro_datos) |
40 (@id_trabajador << @desplazamiento_id_trabajador) |
41 @secuencia
42 end
43
44 private
45
46 def hasta_siguiente_milisegundo(ultima_marca_de_tiempo)
47 marca_de_tiempo = (Time.now.to_f * 1000).to_i
48 marca_de_tiempo = (Time.now.to_f * 1000).to_i while marca_de_tiempo <= ultima_marca_de_tiempo
49 marca_de_tiempo
50 end
51end
52
53## Uso
54generador = GeneradorDeSnowflake.new(1, 1)
55id_snowflake = generador.siguiente_id
56puts "ID de Snowflake generado: #{id_snowflake}"
57
1<?php
2
3class GeneradorDeSnowflake {
4 private $epoca;
5 private $bitsIdCentroDatos;
6 private $bitsIdTrabajador;
7 private $bitsSecuencia;
8 private $maxIdCentroDatos;
9 private $maxIdTrabajador;
10 private $desplazamientoIdTrabajador;
11 private $desplazamientoIdCentroDatos;
12 private $desplazamientoMarcaDeTiempo;
13 private $mascaraSecuencia;
14
15 private $idCentroDatos;
16 private $idTrabajador;
17 private $secuencia = 0;
18
19 private $ultimaMarcaDeTiempo = -1;
20
21 public function __construct($idCentroDatos, $idTrabajador) {
22 $this->epoca = 1288834974657;
23 $this->bitsIdCentroDatos = 5;
24 $this->bitsIdTrabajador = 5;
25 $this->bitsSecuencia = 12;
26
27 $this->maxIdCentroDatos = -1 ^ (-1 << $this->bitsIdCentroDatos);
28 $this->maxIdTrabajador = -1 ^ (-1 << $this->bitsIdTrabajador);
29
30 $this->desplazamientoIdTrabajador = $this->bitsSecuencia;
31 $this->desplazamientoIdCentroDatos = $this->bitsSecuencia + $this->bitsIdTrabajador;
32 $this->desplazamientoMarcaDeTiempo = $this->bitsSecuencia + $this->bitsIdTrabajador + $this->bitsIdCentroDatos;
33 $this->mascaraSecuencia = -1 ^ (-1 << $this->bitsSecuencia);
34
35 if ($idCentroDatos > $this->maxIdCentroDatos || $idCentroDatos < 0) {
36 throw new Exception("idCentroDatos no puede ser mayor que maxIdCentroDatos o menor que 0");
37 }
38 if ($idTrabajador > $this->maxIdTrabajador || $idTrabajador < 0) {
39 throw new Exception("idTrabajador no puede ser mayor que maxIdTrabajador o menor que 0");
40 }
41 $this->idCentroDatos = $idCentroDatos;
42 $this->idTrabajador = $idTrabajador;
43 }
44
45 public function siguienteId() {
46 $marcaDeTiempo = $this->tiempoGen();
47
48 if ($marcaDeTiempo < $this->ultimaMarcaDeTiempo) {
49 throw new Exception("El reloj se ha movido hacia atrás. Rechazando generar id");
50 }
51
52 if ($this->ultimaMarcaDeTiempo == $marcaDeTiempo) {
53 $this->secuencia = ($this->secuencia + 1) & $this->mascaraSecuencia;
54 if ($this->secuencia == 0) {
55 $marcaDeTiempo = $this->hastaSiguienteMilisegundo($this->ultimaMarcaDeTiempo);
56 }
57 } else {
58 $this->secuencia = 0;
59 }
60
61 $this->ultimaMarcaDeTiempo = $marcaDeTiempo;
62
63 return (($marcaDeTiempo - $this->epoca) << $this->desplazamientoMarcaDeTiempo) |
64 ($this->idCentroDatos << $this->desplazamientoIdCentroDatos) |
65 ($this->idTrabajador << $this->desplazamientoIdTrabajador) |
66 $this->secuencia;
67 }
68
69 private function hastaSiguienteMilisegundo($ultimaMarcaDeTiempo) {
70 $marcaDeTiempo = $this->tiempoGen();
71 while ($marcaDeTiempo <= $ultimaMarcaDeTiempo) {
72 $marcaDeTiempo = $this->tiempoGen();
73 }
74 return $marcaDeTiempo;
75 }
76
77 private function tiempoGen() {
78 return floor(microtime(true) * 1000);
79 }
80}
81
82// Uso
83$generador = new GeneradorDeSnowflake(1, 1);
84$id = $generador->siguienteId();
85echo "ID de Snowflake generado: " . $id . "\n";
86
1using System;
2using System.Threading;
3
4public class GeneradorDeSnowflake
5{
6 private readonly long epoca;
7 private readonly int bitsIdCentroDatos;
8 private readonly int bitsIdTrabajador;
9 private readonly int bitsSecuencia;
10 private readonly long maxIdCentroDatos;
11 private readonly long maxIdTrabajador;
12 private readonly int desplazamientoIdTrabajador;
13 private readonly int desplazamientoIdCentroDatos;
14 private readonly int desplazamientoMarcaDeTiempo;
15 private readonly long mascaraSecuencia;
16
17 private readonly long idCentroDatos;
18 private readonly long idTrabajador;
19 private long secuencia = 0L;
20 private long ultimaMarcaDeTiempo = -1L;
21
22 private readonly object lockObj = new object();
23
24 public GeneradorDeSnowflake(long idCentroDatos, long idTrabajador)
25 {
26 epoca = 1288834974657L;
27 bitsIdCentroDatos = 5;
28 bitsIdTrabajador = 5;
29 bitsSecuencia = 12;
30
31 maxIdCentroDatos = -1L ^ (-1L << bitsIdCentroDatos);
32 maxIdTrabajador = -1L ^ (-1L << bitsIdTrabajador);
33
34 desplazamientoIdTrabajador = bitsSecuencia;
35 desplazamientoIdCentroDatos = bitsSecuencia + bitsIdTrabajador;
36 desplazamientoMarcaDeTiempo = bitsSecuencia + bitsIdTrabajador + bitsIdCentroDatos;
37 mascaraSecuencia = -1L ^ (-1L << bitsSecuencia);
38
39 if (idCentroDatos > maxIdCentroDatos || idCentroDatos < 0)
40 {
41 throw new ArgumentException($"idCentroDatos no puede ser mayor que {maxIdCentroDatos} o menor que 0");
42 }
43 if (idTrabajador > maxIdTrabajador || idTrabajador < 0)
44 {
45 throw new ArgumentException($"idTrabajador no puede ser mayor que {maxIdTrabajador} o menor que 0");
46 }
47 this.idCentroDatos = idCentroDatos;
48 this.idTrabajador = idTrabajador;
49 }
50
51 public long siguienteId()
52 {
53 lock (lockObj)
54 {
55 long marcaDeTiempo = tiempoGen();
56
57 if (marcaDeTiempo < ultimaMarcaDeTiempo)
58 {
59 throw new Exception("El reloj se ha movido hacia atrás. Rechazando generar id");
60 }
61
62 if (ultimaMarcaDeTiempo == marcaDeTiempo)
63 {
64 secuencia = (secuencia + 1) & mascaraSecuencia;
65 if (secuencia == 0)
66 {
67 marcaDeTiempo = hastaSiguienteMilisegundo(ultimaMarcaDeTiempo);
68 }
69 }
70 else
71 {
72 secuencia = 0L;
73 }
74
75 ultimaMarcaDeTiempo = marcaDeTiempo;
76
77 return ((marcaDeTiempo - epoca) << desplazamientoMarcaDeTiempo) |
78 (idCentroDatos << desplazamientoIdCentroDatos) |
79 (idTrabajador << desplazamientoIdTrabajador) |
80 secuencia;
81 }
82 }
83
84 private long hastaSiguienteMilisegundo(long ultimaMarcaDeTiempo)
85 {
86 long marcaDeTiempo = tiempoGen();
87 while (marcaDeTiempo <= ultimaMarcaDeTiempo)
88 {
89 marcaDeTiempo = tiempoGen();
90 }
91 return marcaDeTiempo;
92 }
93
94 private long tiempoGen()
95 {
96 return DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
97 }
98}
99
100// Uso
101class Program
102{
103 static void Main(string[] args)
104 {
105 var generador = new GeneradorDeSnowflake(1, 1);
106 var id = generador.siguienteId();
107 Console.WriteLine($"ID de Snowflake generado: {id}");
108 }
109}
110
1package main
2
3import (
4 "fmt"
5 "sync"
6 "time"
7)
8
9type GeneradorDeSnowflake struct {
10 epoca int64
11 bitsIdCentroDatos uint
12 bitsIdTrabajador uint
13 bitsSecuencia uint
14 maxIdCentroDatos int64
15 maxIdTrabajador int64
16 desplazamientoIdTrabajador uint
17 desplazamientoIdCentroDatos uint
18 desplazamientoMarcaDeTiempo uint
19 mascaraSecuencia int64
20
21 idCentroDatos int64
22 idTrabajador int64
23 secuencia int64
24 ultimaMarcaDeTiempo int64
25
26 lock sync.Mutex
27}
28
29func NuevoGeneradorDeSnowflake(idCentroDatos, idTrabajador int64) (*GeneradorDeSnowflake, error) {
30 g := &GeneradorDeSnowflake{
31 epoca: 1288834974657,
32 bitsIdCentroDatos: 5,
33 bitsIdTrabajador: 5,
34 bitsSecuencia: 12,
35 ultimaMarcaDeTiempo: -1,
36 }
37
38 g.maxIdCentroDatos = -1 ^ (-1 << g.bitsIdCentroDatos)
39 g.maxIdTrabajador = -1 ^ (-1 << g.bitsIdTrabajador)
40
41 g.desplazamientoIdTrabajador = g.bitsSecuencia
42 g.desplazamientoIdCentroDatos = g.bitsSecuencia + g.bitsIdTrabajador
43 g.desplazamientoMarcaDeTiempo = g.bitsSecuencia + g.bitsIdTrabajador + g.bitsIdCentroDatos
44 g.mascaraSecuencia = -1 ^ (-1 << g.bitsSecuencia)
45
46 if idCentroDatos > g.maxIdCentroDatos || idCentroDatos < 0 {
47 return nil, fmt.Errorf("idCentroDatos no puede ser mayor que %d o menor que 0", g.maxIdCentroDatos)
48 }
49 if idTrabajador > g.maxIdTrabajador || idTrabajador < 0 {
50 return nil, fmt.Errorf("idTrabajador no puede ser mayor que %d o menor que 0", g.maxIdTrabajador)
51 }
52 g.idCentroDatos = idCentroDatos
53 g.idTrabajador = idTrabajador
54
55 return g, nil
56}
57
58func (g *GeneradorDeSnowflake) SiguienteId() (int64, error) {
59 g.lock.Lock()
60 defer g.lock.Unlock()
61
62 marcaDeTiempo := g.tiempoGen()
63
64 if marcaDeTiempo < g.ultimaMarcaDeTiempo {
65 return 0, fmt.Errorf("el reloj se ha movido hacia atrás, rechazando generar id")
66 }
67
68 if g.ultimaMarcaDeTiempo == marcaDeTiempo {
69 g.secuencia = (g.secuencia + 1) & g.mascaraSecuencia
70 if g.secuencia == 0 {
71 marcaDeTiempo = g.hastaSiguienteMilisegundo(g.ultimaMarcaDeTiempo)
72 }
73 } else {
74 g.secuencia = 0
75 }
76
77 g.ultimaMarcaDeTiempo = marcaDeTiempo
78
79 return ((marcaDeTiempo - g.epoca) << g.desplazamientoMarcaDeTiempo) |
80 (g.idCentroDatos << g.desplazamientoIdCentroDatos) |
81 (g.idTrabajador << g.desplazamientoIdTrabajador) |
82 g.secuencia, nil
83}
84
85func (g *GeneradorDeSnowflake) hastaSiguienteMilisegundo(ultimaMarcaDeTiempo int64) int64 {
86 marcaDeTiempo := g.tiempoGen()
87 for marcaDeTiempo <= ultimaMarcaDeTiempo {
88 marcaDeTiempo = g.tiempoGen()
89 }
90 return marcaDeTiempo
91}
92
93func (g *GeneradorDeSnowflake) tiempoGen() int64 {
94 return time.Now().UnixNano() / int64(time.Millisecond)
95}
96
97func main() {
98 generador, err := NuevoGeneradorDeSnowflake(1, 1)
99 if err != nil {
100 fmt.Printf("Error al crear el generador: %v\n", err)
101 return
102 }
103
104 id, err := generador.SiguienteId()
105 if err != nil {
106 fmt.Printf("Error al generar ID: %v\n", err)
107 return
108 }
109
110 fmt.Printf("ID de Snowflake generado: %d\n", id)
111}
112
Diagrama
Aquí hay una representación visual de la estructura del ID de Snowflake:
Referencias
- "Anunciando Snowflake." Blog de Ingeniería de Twitter, https://blog.twitter.com/engineering/en_us/a/2010/announcing-snowflake
- "ID de Snowflake." Wikipedia, https://es.wikipedia.org/wiki/Snowflake_ID
- "Generación de ID distribuido en microservicios." Medium, https://medium.com/swlh/distributed-id-generation-in-microservices-b6ce9a8dd93f
Comentarios
Haz clic en el aviso de comentarios para comenzar a dar comentarios sobre esta herramienta
Herramientas Relacionadas
Descubre más herramientas que podrían ser útiles para tu flujo de trabajo