Al desarrollar un sistema de servidor, para adaptarse a solicitudes de datos grandes y concurrentes, a menudo necesitamos almacenar los datos de forma asincrónica, especialmente cuando trabajamos en un sistema distribuido. En este momento, no podemos esperar a que la base de datos de inserción devuelva la ID automática que se recupere. En cambio, necesitamos generar una ID única global antes de insertar la base de datos, utilizando la ID única global. En el servidor de juegos, la ID única global se puede usar para futuras combinaciones de servidores y no habrá conflictos clave. En el futuro, en caso de crecimiento comercial, se pueden implementar la base de datos y la tabla Split. Por ejemplo, los elementos de un usuario deben colocarse en el mismo fragmento, y este fragmento puede determinarse en función del valor de rango de la ID de usuario, como una ID de usuario con una ID de usuario superior a 1000 y menos de 100000 en un fragmento. Actualmente, los siguientes se usan comúnmente:
1. Java's propio uuid.
Uuid.randomuuid (). ToString () se puede generar localmente a través del programa de servicio, y la generación de ID no depende de la implementación de la base de datos.
Ventajas:
Genere ID localmente y no requiere llamadas remotas.
El mundo es el único que no repite.
La capacidad de expansión horizontal es muy buena.
Desventajas:
La ID tiene 128 bits, que ocupan un espacio grande y debe almacenarse como un tipo de cadena, y la eficiencia de indexación es extremadamente baja.
La ID generada no contiene marca de tiempo, y no se puede garantizar que la tendencia aumente. Es difícil confiar al dividir las bases de datos de la base de datos.
2. Método INC basado en Redis
Redis en sí es operado de un solo subproceso, y el aumento garantiza una operación atómicamente incrementada. También admite establecer el tamaño de paso incremental.
Ventajas:
Es fácil de implementar y fácil de usar. Solo necesita llamar a una API Redis.
Múltiples servidores pueden compartir un servicio Redis para reducir el tiempo de desarrollo de los datos compartidos.
Redis se puede implementar en grupos para resolver el problema del punto de falla único.
Desventajas:
Si el sistema es demasiado grande, la solicitud de múltiples servicios para redis al mismo tiempo causará cuellos de botella de rendimiento.
3. Solución del parpadeo
Esta solución se basa en la ID de incremento automática de la base de datos, que utiliza una base de datos separada específicamente para generar ID. Puede encontrar los detalles en línea. Personalmente, creo que es bastante problemático de usar y no se recomienda usarlo.
4. Twitter Snowflake
Snowflake es un algoritmo de generación de identificación distribuido que es de código abierto en Twitter. Su idea principal es generar una ID de tipo largo, utilizando 41 bits como el número de milisegundos, 10 bits como número de máquina y 12 bits como número de serie dentro de milisegundos. Este algoritmo puede generar teóricamente hasta 1,000*(2^12) ID por segundo por máquina, que es de aproximadamente 400W, que puede satisfacer completamente las necesidades del negocio.
Según la idea del algoritmo de copo de nieve, podemos generar nuestra propia identificación única global basada en nuestros escenarios comerciales. Debido a que la longitud del tipo largo en Java es de 64bits, la identificación que diseñamos debe controlarse a 64bits.
Ventajas: alto rendimiento, baja latencia; aplicación independiente; ordenado por el tiempo.
Desventajas: se requiere desarrollo independiente e implementación.
Por ejemplo, la identificación que diseñamos contiene la siguiente información:
| 41 bits: marca de tiempo | 3 bits: área | 10 bits: número de máquina | 10 bits: número de serie |
Código Java que genera una identificación única:
/*** Generador de identificación personalizado* Reglas de generación de ID: ID hasta 64 bits ** | 41 bits: marca de tiempo (MS) | 3 bits: área (sala de computadoras) | 10 bits: número de máquina | 10 bits: número de serie |*/public class GameUuid {// Tiempo de referencia Private Long Twepoch = 1288834974657l; // jue, 04 de noviembre de 2010 01:42:54 GMT // región dígitos de bandera dígitos finales finales largos regionIdbits = 3l; // dígitos de identificación de la máquina dígitos privados estáticos finales finales long trabajadoridbits = 10l; // dígitos de número de serie dígitos finales finales longbits = 10l; // valor máximo de la región identificador de región privado final long maxregion = -1l ^ (-1l <1l <1l <1l <jits); Valor máximo de la ID de máquina PRIVADA FINAL LARGO MAXWORKERID = -1l ^ (-1l << WorkerIdBits); // Valor máximo del número de serie ID privado SECHENCETATIC SETENCEMASK LARGO = -1L ^ (-1L << SECHENCEBITS); // El ID de la máquina se desplaza 10 bits a los bits de Long Long -Long Long -Longshift de Long -Long -Long -Long -Longs. RegionIdShift = SECHENENCEBITS + WorkersIdBits; // El tiempo se desplaza de manera izquierda por 23 bits privado final de timestample de timestampleftfift = secuenceBits + WorkerIdbits + RegionIdBits; PRIVADO ESTÁTICO LARGO LASTTIMESTAMP = -1L; secuencia larga privada = 0l; Private Final Long Workersid; Región Long Final Private Final; Public GameUuid (Long WorkersID, Long RegionID) {// Si está fuera de rango, se lanza una excepción si (WorkerID> MaxWorkerId || WorkerId <0) {Throw New IlegalArgumentException ("La identificación del trabajador no puede ser mayor que %d o menos que 0");} si (regionId> maxregionID || regionId <0) {tirar nueva ilegalArgumentception ("" datacenter no es mayor que el ID de datacenter que no puede ser más importante que el porcentaje de datacenter menos que el %mayor que el porcentaje de datacenter no es menor que el porcentaje de datacenter. que 0 ");} this.WorkerId = WorkerId; this.regionId = regionId;} public GameUuid (Long WorkerID) {// Si se tira fuera de rango si (WorkerID> MaxWorkerId || WorkerId <0) {Throw New IlegalArGumentException ("La identificación del trabajador no puede ser mayor que %d o menos que 0");} this.WorkerId = WorkerID; this.Regionidid. 0);}/*** El código real generado por @param ispadding* @param busid* @return*/private sincronizado largo nextId (boolean ispadding, long busid) {long timeStem = timeGen (); Long Paddingnum = regionId; if (isPading) {Padingnum = busid;} if (timestamp) hacia atrás. La secuencia es de solo 10 bits, se combina con secuencia y elimina la secuencia de bits alto = (secuencia + 1) y secuenceMask; // juzga si se desborda, es decir, excede 1024 en cada milisegundo. Cuando es 1024, se combina con secuenceMask, y la secuencia es igual a 0if (secuencia == 0) {// Spin espera hasta que el próximo MilliseCond TimeStamp = TailNextMillis (LastTimestamp);}} else {// Si la secuencia es diferente del tiempo de última generación, reajuste la secuencia, que comienza en el siguiente Millisecond, y el recuento de secuencia comienza de 0 de nuevo. // Para garantizar que la Mantissa sea más aleatoria, establezca un número aleatorio en la última secuencia de bit = new SecureRanDom (). NextInt (10);} lasttimeStamp = timestamp; return ((timestamp - twepoch) << timestamptshift) | (Paddingnum << RegionIdshift) | (WorkerId << WorkerIdshift) | secuencia;} // Evite que el tiempo de generación sea menor que el tiempo anterior (debido a problemas como la devolución de llamada NTP), y mantenga la tendencia incremental. TimeGen () {return System.CurrentTimemillis ();}}Algunas cosas a tener en cuenta al usar métodos personalizados:
Para mantener la tendencia de crecimiento, es necesario evitar el tiempo de algunos servidores temprano y algunos servidores tarde, por lo que se debe controlar el tiempo de todos los servidores, y el momento en que el servidor de tiempo NTP vuelve a llamar al servidor; Al cruzar milisegundos, el número de serie siempre alcanza 0, lo que hará más ID con el número de serie 0, lo que resulta en ID desiguales después de la modulación, por lo que el número de serie no pertenece a 0 cada vez, sino un número aleatorio de 0 a 9.
Podemos elegir los métodos mencionados anteriormente de acuerdo con nuestras necesidades. En el desarrollo del servidor de juegos, puedes elegir de acuerdo con tu propio tipo de juego, como los juegos móviles, y puedes usar el método simple Redis, que es simple y no fácil de cometer errores. Dado que el número de nuevas ID creadas por servidores individuales en este tipo de juego no es demasiado grande, puede satisfacer completamente las necesidades. Para los grandes servidores de juegos mundiales, se distribuyen principalmente, por lo que puedes usar Snowflake. El código de copo de nieve anterior es solo un ejemplo y debe personalizarse de acuerdo con sus necesidades, por lo que hay un volumen de desarrollo adicional, y debe prestar atención a las precauciones anteriores.
Lo anterior es un resumen de los métodos de uso del código Java para implementar el servidor de juegos para generar una ID única global basada en el código Java. Espero que sea útil para todos. Si tiene alguna pregunta, déjame un mensaje y el editor responderá a todos a tiempo. ¡Muchas gracias por su apoyo al sitio web de Wulin.com!