Implemente el algoritmo de copo de nieve en C++ para generar una identificación única en segundos, milisegundos y tiempo.

Insertar descripción de la imagen aquí

1. Principio del algoritmo del copo de nieve.

El algoritmo Snowflake es un algoritmo que se utiliza para generar ID únicos, generalmente utilizado en sistemas distribuidos para garantizar que los ID generados sean únicos en todo el sistema distribuido. Su nombre proviene de la forma de un copo de nieve, ya que los ID generados suelen ser números enteros de 64 bits cuya estructura binaria parece un copo de nieve.

El principio de implementación del algoritmo Snowflake es relativamente simple, principalmente dividiendo un entero de 64 bits en diferentes partes para garantizar que la ID generada sea única y esté ordenada en el sistema distribuido . Los siguientes son los principales principios de implementación del algoritmo del copo de nieve:
Insertar descripción de la imagen aquí

  • Parte de la marca de tiempo (41 bits): el algoritmo Snowflake utiliza 41 bits para representar la marca de tiempo. Estos bits se utilizan para almacenar el número de milisegundos desde la "Epoca del copo de nieve" (un punto fijo personalizado en el tiempo, generalmente cuando el sistema se inició por primera vez). Dado que se utilizan 41 bits para representar la marca de tiempo, el rango de tiempo que se puede representar es de aproximadamente 69 años.

    • La parte de marca de tiempo del algoritmo de copo de nieve es una parte muy importante del algoritmo y se utiliza para garantizar que la ID única generada tenga un cierto orden en el sistema distribuido. El siguiente es el principio de la parte de marca de tiempo del algoritmo del copo de nieve:

    • El punto de inicio de la marca de tiempo (Snowflake Epoch): la marca de tiempo en el algoritmo Snowflake se basa en un punto de tiempo de inicio personalizado. Este punto de tiempo inicial a menudo se denomina "Epoca del copo de nieve", que es un punto de tiempo fijo que sirve como valor inicial de la marca de tiempo. Normalmente, la época del copo de nieve es un valor configurable que se puede establecer según sea necesario. Por ejemplo, puede configurar la época del copo de nieve en el momento en que el sistema se inicia por primera vez o en otro momento específico.

    • Marcas de tiempo de nivel de milisegundos: el algoritmo Snowflake utiliza marcas de tiempo de nivel de milisegundos para representar el paso del tiempo desde la época de Snowflake. Esta marca de tiempo es un valor entero que normalmente ocupa 41 bits. Esto significa que, contando desde la Época del Copo de Nieve, el lapso de tiempo que se puede representar es de aproximadamente 69 años, ya que 2^41 milisegundos equivalen aproximadamente a 69 años.

    • Incremento de la marca de tiempo: el valor de la parte de la marca de tiempo se incrementa cada vez que se genera una ID única. Este es un factor clave para garantizar que los ID generados estén ordenados hasta cierto punto. Los ID generados en el mismo milisegundo tienen el mismo valor en la parte de la marca de tiempo, mientras que los ID generados en diferentes milisegundos tienen un valor creciente en la parte de la marca de tiempo.

    • Sincronización de reloj y procesamiento de devolución de llamada de reloj: para mantener la precisión de las marcas de tiempo, las máquinas en un sistema distribuido deben realizar una sincronización de reloj para garantizar que los relojes de su sistema sean consistentes. Además, el algoritmo Snowflake incluye manejo de reversión del reloj para evitar que el reloj del sistema retroceda. Si se detecta una reversión del reloj, el algoritmo espera hasta que se complete la reversión del reloj.

    • En resumen, la parte de la marca de tiempo del algoritmo Snowflake se calcula en función de un punto de tiempo de inicio personalizado (Snowflake Epoch), utilizando marcas de tiempo de nivel de milisegundos para representar el paso del tiempo. Al incrementar el valor de la parte de la marca de tiempo, se garantiza que los ID únicos generados en el sistema distribuido tengan cierto orden. La sincronización del reloj y el procesamiento de reversión del reloj también son partes importantes del algoritmo para mantener la precisión de la marca de tiempo. Este diseño hace que el algoritmo de copo de nieve sea adecuado para la necesidad de generar identificaciones únicas en sistemas distribuidos a gran escala.

  • ID del centro de datos (5 dígitos): el ID del centro de datos se utiliza para distinguir diferentes centros de datos. Esta parte se utiliza a menudo en entornos de múltiples centros de datos para garantizar que las máquinas asignadas a cada centro de datos tengan identidades diferentes. El rango de ID del centro de datos es de 0 a 31 (5 dígitos binarios).

  • ID de la máquina del trabajador (5 dígitos): la ID de la máquina del trabajador se utiliza para distinguir diferentes máquinas en el mismo centro de datos. Esto garantiza que las ID generadas por varias máquinas en el mismo centro de datos no entren en conflicto. Los ID de las máquinas de los trabajadores también varían de 0 a 31 (binario de 5 dígitos).

  • Parte del número de serie (12 bits): la parte del número de secuencia se utiliza para manejar la situación en la que se generan múltiples ID en el mismo milisegundo para evitar conflictos de ID. Al utilizar un número de secuencia de 12 bits, se pueden generar 4096 ID diferentes en el mismo milisegundo.

  • Desplazamiento y operación: al generar una ID única, desplace a la izquierda los valores de cada parte y realice una operación lógica OR (OR) para combinarlos en un entero de 64 bits.

  • Unicidad y orden: las diferentes máquinas y solicitudes se distinguen mediante el uso de diferentes ID de centro de datos, ID de máquinas de trabajo y números de serie, y el orden de las ID se garantiza a través de la parte de marca de tiempo. La parte de la marca de tiempo se incrementa a medida que se genera el ID, lo que garantiza que los ID generados más nuevos sean siempre mayores que los ID más antiguos.

  • Manejo de reversión del reloj: el algoritmo Snowflake también incluye manejo de reversión del reloj para evitar la reversión del reloj (es decir, que la hora del sistema se ajuste hacia atrás). Si se detecta una reversión del reloj, el algoritmo espera hasta que se complete la reversión del reloj.

    • En las aplicaciones prácticas del algoritmo Snowflake, los administradores o desarrolladores del sistema generalmente deben implementar y manejar la sincronización y la reversión del reloj. El algoritmo Snowflake en sí no proporciona mecanismos integrados de sincronización de reloj ni de procesamiento de devolución de llamada de reloj, sino que depende del entorno del sistema para garantizar la precisión del reloj.

    • A continuación se presentan algunas consideraciones y opciones de implementación para la sincronización del reloj y el manejo de la reversión del reloj:

      • Sincronización del reloj: en un sistema distribuido, es importante asegurarse de que los relojes del sistema de varias máquinas estén sincronizados. Una práctica común es utilizar el protocolo de tiempo de red (NTP) o un servicio de sincronización de tiempo similar para mantener los relojes de todas las máquinas consistentes con un servidor de tiempo de red. Esto se puede lograr configurando el sistema operativo.

      • Procesamiento de reversión del reloj: la reversión del reloj se refiere al ajuste repentino del reloj del sistema hacia atrás, lo que puede causar que la marca de tiempo de los ID ya generados sea anterior a la de los ID recién generados. Para manejar la reversión del reloj, se puede adoptar una de las siguientes estrategias:

      • Estrategia de espera: si se detecta una reversión del reloj, puede esperar un período de tiempo hasta que finalice la reversión del reloj antes de continuar generando ID. Esto garantiza que los ID generados sigan siendo incrementales.

      • Denegar estrategia: otra estrategia es negarse a generar identificaciones hasta que el reloj retroceda. Esto evita generar identificaciones incorrectas.

      • Estrategia de reparación de la desviación del reloj: en algunos casos, la desviación del reloj se puede solucionar detectando el retroceso del reloj y ajustando la ID generada. Esto requiere una lógica más compleja y un almacenamiento persistente.

    • La implementación específica depende de los requisitos de la aplicación y del entorno del sistema. La sincronización del reloj y el procesamiento de devolución de llamada del reloj son consideraciones importantes para garantizar el funcionamiento normal del algoritmo Snowflake y deben configurarse e implementarse de acuerdo con la situación real. En general, se recomienda utilizar un servicio de sincronización de reloj confiable para reducir la posibilidad de reversión del reloj y seleccionar una estrategia de procesamiento de reversión del reloj adecuada según los requisitos de la aplicación.

  • La reversión del tiempo significa que el reloj del sistema se ajusta hacia atrás en un momento determinado, lo que hace que el tiempo del sistema se reduzca repentinamente, lo que equivale a "retroceder" el tiempo durante un período de tiempo. Esta situación puede ocurrir en su sistema informático, generalmente debido a una de las siguientes razones:

    • Servicio de sincronización de reloj: muchos sistemas operativos y redes informáticas utilizan servicios de sincronización de reloj (como NTP, protocolo de tiempo de red) para mantener el reloj del sistema sincronizado con fuentes horarias externas. Si el servicio de sincronización del reloj detecta que el intervalo de tiempo entre el reloj del sistema y una fuente de hora externa es demasiado grande, puede intentar sincronizar el reloj del sistema con la fuente de hora externa ajustándolo. En este caso, el reloj del sistema se ajusta hacia atrás para alinearlo con la fuente de hora externa.

    • Ajuste manual del reloj: un administrador del sistema o un usuario puede ajustar manualmente el reloj del sistema, lo que hace que la hora se retrase. Esto suele ocurrir cuando es necesario corregir errores de reloj o sincronizar los relojes del sistema.

    • La reversión del tiempo puede causar problemas a los sistemas y aplicaciones, especialmente a las aplicaciones que dependen del ordenamiento temporal, como el registro, la sincronización de datos y la generación de ID únicas en sistemas distribuidos (como el algoritmo de copo de nieve). Cuando se produce una reversión de tiempo, la aplicación puede experimentar los siguientes problemas:

    • Eventos desordenados: si una aplicación se basa en el orden cronológico para procesar eventos, la reversión de tiempo puede hacer que los eventos estén desordenados.

    • Problemas de coherencia de los datos: en los sistemas distribuidos, la reversión del tiempo puede provocar inconsistencias o conflictos en los datos.

    • Conflictos de ID únicos: ciertos algoritmos de generación de ID, como el algoritmo de copo de nieve, pueden generar el mismo ID cuando se retrasa el tiempo, lo que genera conflictos de ID.

  • Para manejar la reversión del tiempo, las aplicaciones a menudo necesitan implementar estrategias como esperar, rechazar o corregir eventos para garantizar la estabilidad y coherencia del sistema. La configuración y el seguimiento de los servicios de sincronización del reloj también son medidas importantes para reducir el impacto del retroceso de hora.
    Insertar descripción de la imagen aquí

En general, el principio de implementación del algoritmo Snowflake es fusionar información como marcas de tiempo, ID del centro de datos, ID de la máquina del trabajador y números de serie para garantizar que los ID generados sean únicos y estén ordenados en el sistema distribuido. Con una configuración y sincronización de reloj adecuadas, puede generar ID únicas de alto rendimiento en entornos distribuidos.

2. El algoritmo Snowflake se implementa utilizando la hora actual.

El siguiente es un ejemplo de un algoritmo de copo de nieve basado en C++ que utiliza la hora actual en segundos para generar una identificación única:

  • La marca de tiempo se desplaza hacia la izquierda 22 bits y se agregan 22 ceros a la izquierda. El bit de máquina de 10 bits se desplaza hacia la izquierda 12 bits y se agregan 12 ceros a la izquierda. El último número de secuencia no necesita desplazarse hacia la izquierda.
    Insertar descripción de la imagen aquí
#include <iostream>
#include <cstdint>
#include <ctime>

class Snowflake {
    
    
public:
    Snowflake(uint16_t datacenterId, uint16_t workerId)
        : datacenterId_(datacenterId), workerId_(workerId), sequence_(0), lastTimestamp_(0) {
    
    
        if (datacenterId_ > maxDatacenterId_ || workerId_ > maxWorkerId_) {
    
    
            throw std::invalid_argument("Invalid datacenter or worker ID");
        }
    }

    uint64_t generateUniqueId() {
    
    
        uint64_t timestamp = currentTimestamp();

        if (timestamp < lastTimestamp_) {
    
    
            throw std::runtime_error("Clock moved backwards");
        }
		
		//时间戳原理:获取当前时间戳如果等于上次时间戳(同一毫秒内),咋序列号加一。否则序列号设置为0,从0开始
        if (timestamp == lastTimestamp_) {
    
    
            sequence_ = (sequence_ + 1) & sequenceMask_;
            if (sequence_ == 0) {
    
    
                timestamp = waitNextMillis(lastTimestamp_);
            }
        } else {
    
    
            sequence_ = 0;
        }

        lastTimestamp_ = timestamp;

        return ((timestamp - twepoch_) << timestampLeftShift_) |
               ((datacenterId_ & maxDatacenterId_) << datacenterIdShift_) |
               ((workerId_ & maxWorkerId_) << workerIdShift_) |
               (sequence_ & sequenceMask_);
    }

private:
    uint64_t currentTimestamp() const {
    
    
        return std::time(nullptr) * 1000;
    }

    uint64_t waitNextMillis(uint64_t lastTimestamp) {
    
    
        uint64_t timestamp = currentTimestamp();
        while (timestamp <= lastTimestamp) {
    
    
            timestamp = currentTimestamp();
        }
        return timestamp;
    }

    //const uint64_t twepoch_ = 1609459200000ULL;  // 2021-01-01 00:00:00 UTC
    const uint64_t unixEpoch_ = 0ULL;  // Unix时间戳起点:1970-01-01 00:00:00 UTC
    const uint64_t workerIdBits_ = 5;
    const uint64_t datacenterIdBits_ = 5;
    const uint64_t maxWorkerId_ = (1ULL << workerIdBits_) - 1;
    const uint64_t maxDatacenterId_ = (1ULL << datacenterIdBits_) - 1;
    const uint64_t sequenceBits_ = 12;
    const uint64_t workerIdShift_ = sequenceBits_;
    const uint64_t datacenterIdShift_ = sequenceBits_ + workerIdBits_;
    const uint64_t timestampLeftShift_ = sequenceBits_ + workerIdBits_ + datacenterIdBits_;
    const uint64_t sequenceMask_ = (1ULL << sequenceBits_) - 1;

    uint16_t datacenterId_;
    uint16_t workerId_;
    uint64_t sequence_;
    uint64_t lastTimestamp_;
};

int main() {
    
    
    // 在这里设置你的数据中心ID和工作机器ID
    uint16_t datacenterId = 1;
    uint16_t workerId = 1;

    Snowflake snowflake(datacenterId, workerId);

    for (int i = 0; i < 10; ++i) {
    
    
        uint64_t uniqueId = snowflake.generateUniqueId();
        std::cout << "Generated unique ID: " << uniqueId << std::endl;
    }

    return 0;
}

En este ejemplo, creamos una clase Snowflake para implementar el algoritmo de copo de nieve. Es capaz de generar identificaciones únicas que incluyen marcas de tiempo, identificaciones de centros de datos, identificaciones de máquinas de trabajadores y números de serie. En la función principal, configuramos la ID del centro de datos y la ID de la máquina del trabajador y utilizamos el método generateUniqueId para generar 10 ID únicas y luego imprimirlas en la consola.

Tenga en cuenta que la parte de la marca de tiempo de este ejemplo utiliza la hora actual, pero en aplicaciones reales es posible que necesite un mecanismo de marca de tiempo más preciso para garantizar que los ID generados en el mismo milisegundo también sean únicos. Además, asegúrese de que la ID del centro de datos y la ID de la máquina del trabajador estén configuradas correctamente en un entorno distribuido para evitar conflictos de ID. Este ejemplo es una demostración sencilla para comprender cómo funciona el algoritmo del copo de nieve.
Insertar descripción de la imagen aquí
Implementación central del algoritmo Snowflake:

return ((timestamp - twepoch_) << timestampLeftShift_) |
            ((datacenterId_ & maxDatacenterId_) << datacenterIdShift_) |
            ((workerId_ & maxWorkerId_) << workerIdShift_) |
            (sequence_ & sequenceMask_)
  • Esta línea de código es la parte central del algoritmo Snowflake utilizado para generar una identificación única y combina los diversos componentes para formar un entero de 64 bits como la identificación única final generada. Permítanme explicarles qué significan las distintas partes de esta línea de código:

    • (( marca de tiempo - twepoch_ ) << marca de tiempoLeftShift_ ): esta parte calcula el valor de la marca de tiempo. Primero, resta la época del copo de nieve ( twepoch_ ) de la marca de tiempo actual para obtener el número de milisegundos desde la época del copo de nieve. Luego, desplace este número de milisegundos hacia la izquierda en timestampLeftShift_ bits, de modo que la marca de tiempo ocupe el número correspondiente de dígitos en el ID. El propósito de esta sección es garantizar que la identificación generada contenga información de marca de tiempo para mantener las identificaciones en orden.

    • (( datacenterId_ & maxDatacenterId_ ) << datacenterIdShift_ ): Esta parte calcula el valor de la ID del centro de datos. Primero, utiliza el operador AND bit a bit & para realizar una operación AND bit a bit entre la ID del centro de datos y la ID máxima del centro de datos para garantizar que el valor de la ID del centro de datos no exceda la cantidad de bits que ocupa. Luego, desplace el resultado hacia la izquierda en datacenterIdShift_ bits para que la ID del centro de datos ocupe el número correspondiente de dígitos en la ID. El propósito de esta sección es garantizar que la identificación generada contenga información de identificación del centro de datos para garantizar que las identificaciones generadas por las máquinas en diferentes centros de datos sean únicas.

    • (( trabajadorId_ & maxWorkerId_ ) << trabajadorIdShift_ ): esta parte calcula el valor de la ID de la máquina del trabajador. El principio es similar al ID del centro de datos. Primero, utilice el operador AND bit a bit & para realizar una operación AND bit a bit entre la ID de la máquina del trabajador y la ID máxima de la máquina del trabajador para garantizar que el valor de la ID de la máquina del trabajador no exceda la cantidad de bits que ocupa. Luego, cambie el resultado dejado por los bits WorkersIdShift_ para que la ID de la máquina del trabajador ocupe el número correspondiente de dígitos en la ID. El propósito de esta sección es garantizar que la identificación generada contenga información de identificación de la máquina del trabajador para garantizar que las identificaciones generadas por diferentes máquinas en el mismo centro de datos sean únicas.

    • ( secuencia_ y secuenciaMask_ ): esta parte calcula el valor del número de secuencia. Utiliza el operador AND bit a bit & para realizar una operación AND bit a bit en el número de secuencia actual y la máscara del número de secuencia secuenciaMask_ para garantizar que el valor del número de secuencia no exceda el número de bits que ocupa. El número de secuencia ocupa el número correspondiente de dígitos de la ID para garantizar que cuando se generan varias ID en el mismo milisegundo, sus números de secuencia no entren en conflicto.

  • Finalmente, los valores de estas partes se combinan mediante el operador bit a bit OR | para formar un entero de 64 bits como ID único generado. Esta ID contiene información como la marca de tiempo, la ID del centro de datos, la ID de la máquina del trabajador y el número de serie, lo que garantiza que la ID generada sea única y esté ordenada en el sistema distribuido. Esta combinación permite extraer y analizar cada parte de la información, manteniendo al mismo tiempo la singularidad y el orden de la identificación general.

3. La implementación del algoritmo Snowflake utiliza milisegundos.

Cuando varias solicitudes generan ID únicas en el mismo milisegundo, el algoritmo Snowflake garantiza la unicidad de la ID mediante el uso de la parte del número de secuencia. A continuación se muestra un ejemplo que demuestra cómo manejar múltiples ID únicos generados en el mismo milisegundo:

  • La marca de tiempo se desplaza hacia la izquierda 22 bits y se agregan 22 ceros a la izquierda. El bit de máquina de 10 bits se desplaza hacia la izquierda 12 bits y se agregan 12 ceros a la izquierda. El último número de secuencia no necesita desplazarse hacia la izquierda.
    Insertar descripción de la imagen aquí
#include <iostream>
#include <cstdint>
#include <ctime>
#include <mutex>

class Snowflake {
    
    
public:
    Snowflake(uint16_t datacenterId, uint16_t workerId)
        : datacenterId_(datacenterId), workerId_(workerId), sequence_(0), lastTimestamp_(0) {
    
    
        if (datacenterId_ > maxDatacenterId_ || workerId_ > maxWorkerId_) {
    
    
            throw std::invalid_argument("Invalid datacenter or worker ID");
        }
    }

    uint64_t generateUniqueId() {
    
    
        std::unique_lock<std::mutex> lock(mutex_);

        uint64_t timestamp = currentTimestamp();

        if (timestamp < lastTimestamp_) {
    
    
            throw std::runtime_error("Clock moved backwards");
        }
		
		//时间戳原理:获取当前时间戳如果等于上次时间戳(同一毫秒内),咋序列号加一。否则序列号设置为0,从0开始
        if (timestamp == lastTimestamp_) {
    
    
            sequence_ = (sequence_ + 1) & sequenceMask_;
            if (sequence_ == 0) {
    
    
                timestamp = waitNextMillis(lastTimestamp_);
            }
        } else {
    
    
            sequence_ = 0;
        }

        lastTimestamp_ = timestamp;

        return ((timestamp - twepoch_) << timestampLeftShift_) |
               ((datacenterId_ & maxDatacenterId_) << datacenterIdShift_) |
               ((workerId_ & maxWorkerId_) << workerIdShift_) |
               (sequence_ & sequenceMask_);
    }

private:
    uint64_t currentTimestamp() const {
    
    
        return std::time(nullptr) * 1000;
    }

    uint64_t waitNextMillis(uint64_t lastTimestamp) {
    
    
        uint64_t timestamp = currentTimestamp();
        while (timestamp <= lastTimestamp) {
    
    
            timestamp = currentTimestamp();
        }
        return timestamp;
    }

    //const uint64_t twepoch_ = 1609459200000ULL;  // 2021-01-01 00:00:00 UTC
    const uint64_t unixEpoch_ = 0ULL;  // Unix时间戳起点:1970-01-01 00:00:00 UTC
    const uint64_t workerIdBits_ = 5;
    const uint64_t datacenterIdBits_ = 5;
    const uint64_t maxWorkerId_ = (1ULL << workerIdBits_) - 1;
    const uint64_t maxDatacenterId_ = (1ULL << datacenterIdBits_) - 1;
    const uint64_t sequenceBits_ = 12;
    const uint64_t workerIdShift_ = sequenceBits_;
    const uint64_t datacenterIdShift_ = sequenceBits_ + workerIdBits_;
    const uint64_t timestampLeftShift_ = sequenceBits_ + workerIdBits_ + datacenterIdBits_;
    const uint64_t sequenceMask_ = (1ULL << sequenceBits_) - 1;

    uint16_t datacenterId_;
    uint16_t workerId_;
    uint64_t sequence_;
    uint64_t lastTimestamp_;
    std::mutex mutex_;
};

int main() {
    
    
    // 在这里设置你的数据中心ID和工作机器ID
    uint16_t datacenterId = 1;
    uint16_t workerId = 1;

    Snowflake snowflake(datacenterId, workerId);

    for (int i = 0; i < 10; ++i) {
    
    
        uint64_t uniqueId = snowflake.generateUniqueId();
        std::cout << "Generated unique ID: " << uniqueId << std::endl;
    }

    return 0;
}

Insertar descripción de la imagen aquí

En este ejemplo, agregamos un mutex (std::mutex) para garantizar que solo un subproceso pueda acceder al método generateUniqueId cuando se generan múltiples ID únicos en el mismo milisegundo. Esto puede evitar conflictos al generar ID simultáneamente.

Implementación central del algoritmo Snowflake:

return ((timestamp - twepoch_) << timestampLeftShift_) |
            ((datacenterId_ & maxDatacenterId_) << datacenterIdShift_) |
            ((workerId_ & maxWorkerId_) << workerIdShift_) |
            (sequence_ & sequenceMask_)
  • Esta línea de código es la parte central del algoritmo Snowflake utilizado para generar una identificación única y combina los diversos componentes para formar un entero de 64 bits como la identificación única final generada. Permítanme explicarles qué significan las distintas partes de esta línea de código:

    • (( marca de tiempo - twepoch_ ) << marca de tiempoLeftShift_ ): esta parte calcula el valor de la marca de tiempo. Primero, resta la época del copo de nieve ( twepoch_ ) de la marca de tiempo actual para obtener el número de milisegundos desde la época del copo de nieve. Luego, desplace este número de milisegundos hacia la izquierda en timestampLeftShift_ bits, de modo que la marca de tiempo ocupe el número correspondiente de dígitos en el ID. El propósito de esta sección es garantizar que la identificación generada contenga información de marca de tiempo para mantener las identificaciones en orden.

    • (( datacenterId_ & maxDatacenterId_ ) << datacenterIdShift_ ): Esta parte calcula el valor de la ID del centro de datos. Primero, utiliza el operador AND bit a bit & para realizar una operación AND bit a bit entre la ID del centro de datos y la ID máxima del centro de datos para garantizar que el valor de la ID del centro de datos no exceda la cantidad de bits que ocupa. Luego, desplace el resultado hacia la izquierda en datacenterIdShift_ bits para que la ID del centro de datos ocupe el número correspondiente de dígitos en la ID. El propósito de esta sección es garantizar que la identificación generada contenga información de identificación del centro de datos para garantizar que las identificaciones generadas por las máquinas en diferentes centros de datos sean únicas.

    • (( trabajadorId_ & maxWorkerId_ ) << trabajadorIdShift_ ): esta parte calcula el valor de la ID de la máquina del trabajador. El principio es similar al ID del centro de datos. Primero, utilice el operador AND bit a bit & para realizar una operación AND bit a bit entre la ID de la máquina del trabajador y la ID máxima de la máquina del trabajador para garantizar que el valor de la ID de la máquina del trabajador no exceda la cantidad de bits que ocupa. Luego, cambie el resultado dejado por los bits WorkersIdShift_ para que la ID de la máquina del trabajador ocupe el número correspondiente de dígitos en la ID. El propósito de esta sección es garantizar que la identificación generada contenga información de identificación de la máquina del trabajador para garantizar que las identificaciones generadas por diferentes máquinas en el mismo centro de datos sean únicas.

    • ( secuencia_ y secuenciaMask_ ): esta parte calcula el valor del número de secuencia. Utiliza el operador AND bit a bit & para realizar una operación AND bit a bit en el número de secuencia actual y la máscara del número de secuencia secuenciaMask_ para garantizar que el valor del número de secuencia no exceda el número de bits que ocupa. El número de secuencia ocupa el número correspondiente de dígitos de la ID para garantizar que cuando se generan varias ID en el mismo milisegundo, sus números de secuencia no entren en conflicto.

  • Finalmente, los valores de estas partes se combinan mediante el operador bit a bit OR | para formar un entero de 64 bits como ID único generado. Esta ID contiene información como la marca de tiempo, la ID del centro de datos, la ID de la máquina del trabajador y el número de serie, lo que garantiza que la ID generada sea única y esté ordenada en el sistema distribuido. Esta combinación permite extraer y analizar cada parte de la información, manteniendo al mismo tiempo la singularidad y el orden de la identificación general.

4. Principio de implementación del algoritmo del copo de nieve.

SnowFlake significa copo de nieve en chino, por eso se le llama algoritmo de copo de nieve. Twitter fue la primera empresa en generar identificaciones únicas internamente en un entorno distribuido. La versión en lenguaje Scala fue de código abierto en 2014. No existen dos copos de nieve idénticos en el mundo. De ahí el nombre de algoritmo de copo de nieve para identificar diferentes uuid.
Insertar descripción de la imagen aquí
El principio del algoritmo de copo de nieve es generar una identificación única de tipo largo de 64 bits.

  • El bit más alto tiene un valor fijo de 0, porque la identificación generada es un número entero positivo y si es 1, es un número negativo.
  • Los siguientes 41 bits almacenan la marca de tiempo a nivel de milisegundos, 2^41/(1000 60 60 24 365)=69, que se puede utilizar durante aproximadamente 69 años.
  • Los siguientes 10 bits almacenan el código de máquina, incluido el ID del centro de datos de 5 bits y el ID del trabajador de 5 bits. Se puede implementar un máximo de 2^10=1024 máquinas.
  • Los últimos 12 bits almacenan el número de serie. La misma marca de tiempo de milisegundos se distingue por este número de secuencia incremental. Es decir, para la misma máquina, con la misma marca de tiempo de milisegundos, se pueden generar 2 ^ 12 = 4096 ID únicos.

El algoritmo Snowflake se puede implementar como un servicio independiente y luego, para los sistemas que requieren una ID única a nivel mundial, simplemente solicite el servicio del algoritmo Snowflake para obtener la ID.

Para cada servicio del algoritmo Snowflake, primero debe especificar un código de máquina de 10 dígitos, que puede configurar según su propio negocio. Por ejemplo, número de sala de ordenadores + número de máquina, número de máquina + número de servicio u otros valores enteros de 10 bits que se puedan distinguir.

5. Ventajas y desventajas del algoritmo de copo de nieve

  • El algoritmo del copo de nieve tiene las siguientes ventajas:

    • Genere identificaciones únicas en un entorno distribuido de alta concurrencia y puede generar millones de identificaciones únicas por segundo.
    • Según la marca de tiempo y el incremento automático del número de secuencia bajo la misma marca de tiempo, básicamente se garantiza que la identificación aumentará de manera ordenada.
    • No depende de bibliotecas ni middleware de terceros.
    • El algoritmo es simple, se realiza en memoria y altamente eficiente.
  • El algoritmo del copo de nieve tiene las siguientes deficiencias:

    • Dependiendo de la hora del servidor, es posible que se generen identificaciones duplicadas cuando se retrasa el reloj del servidor. El algoritmo se puede resolver registrando la marca de tiempo cuando se generó la última ID. Antes de cada generación de ID, compare si el reloj actual del servidor se ha retrocedido para evitar generar ID duplicadas.

Supongo que te gusta

Origin blog.csdn.net/qq_44918090/article/details/133356010
Recomendado
Clasificación