¿Cómo insertar mil millones de datos en Mysql? 10 preguntas consecutivas ¿Cuántas se te ocurren?

Esta es una pregunta de una entrevista que tuve una vez para Qunar.com. Esta pregunta no le pide que responda la hora exacta, sino que examine cómo diseñar un sistema para insertar mil millones de datos lo más rápido posible. Respondí estúpidamente durante tres horas, dudando y hablando, no dije por qué. El entrevistador vio que todavía estaba dormido y me pidió que regresara y esperara la notificación. Afortunadamente, me devolvió el currículum y lo guardé.

Intenta pensar de nuevo hoy y dale una buena bofetada.

Para importar mil millones de datos a la base de datos lo más rápido posible, primero debe aclarar con el entrevistador qué forma y dónde existen esos mil millones de datos, qué tamaño tiene cada dato, si se importan de forma ordenada. manera, si no se puede repetir y si la base de datos es MySQL?

Una vez que los supuestos quedan claros para el entrevistador, existen las siguientes limitaciones:

  1. Mil millones de datos, cada dato pesa 1 Kb

  2. El contenido de los datos son registros de acceso de usuarios no estructurados, que deben analizarse y escribirse en la base de datos.

  3. Los datos se almacenan Hdfso S3se distribuyen en un almacenamiento de archivos.

  4. Mil millones de datos no son un archivo grande, sino que se dividen aproximadamente en 100 archivos, y el sufijo marca el orden.

  5. Es necesario importarlo en orden y tratar de no repetirlo.

  6. La base de datos esMySQL

Primero considere si es factible escribir mil millones de datos en una sola tabla MySQL.

La respuesta es no, el valor recomendado para un solo medidor está por debajo de los 2000W. ¿Cómo se calcula este valor?

La estructura de datos del índice MySQL es un árbol B+ y todos los datos se almacenan en el índice de clave principal, que es el nodo hoja del índice agrupado. El rendimiento de la inserción y consulta del árbol B + está directamente relacionado con el número de niveles del árbol B +: por debajo de 2000 W, es un índice de tres niveles, mientras que por encima de 2000 w, puede ser un índice de cuatro niveles.

Mysql b+El tamaño de página de los nodos hoja del índice es 16K. Actualmente, cada dato tiene exactamente 1K, por lo que se puede entender simplemente que cada nodo hoja almacena 16 datos. El tamaño de cada nodo no hoja en el índice b + también es 16K, pero solo necesita almacenar la clave primaria y el puntero al nodo hoja. Suponemos que el tipo de clave primaria es BigInt y la longitud es de 8 bytes. Y el tamaño del puntero se establece en 6 bytes en InnoDB, lo que suma un total de 14 bytes, por lo que se puede almacenar un nodo no hoja 16 * 1024/14=1170.

Es decir, cada nodo no hoja se puede asociar con 1170 nodos hoja y cada nodo hoja almacena 16 datos. A partir de esto, podemos obtener la tabla del número de niveles de índice del árbol B+ y la cantidad de almacenamiento. El número de capas de índice por encima de 2KW es 4 y el rendimiento es aún peor.

Número de capas Tamaño máximo de datos
2 1170 * 16 = 18720
3 1170 * 1170 * 16= 21902400 = 2000w
4 1170 * 1170 * 1170 * 16 = 25625808000 = 25,6 mil millones

Para obtener más detalles, consulte el cálculo de la capa de árbol B+[1]

Para facilitar el cálculo, podemos diseñar una sola tabla con una capacidad de 1KW y un total de 100 tablas con mil millones de datos.

El rendimiento de escribir una sola entrada en la base de datos es relativamente pobre. Puede considerar escribir en la base de datos en lotes. El valor del lote se puede ajustar dinámicamente. Cada elemento es de 1K y se puede ajustar a la escritura por lotes de 100 elementos de forma predeterminada.

¿Cómo garantizar que los datos por lotes se escriban correctamente al mismo tiempo? El motor de almacenamiento MySQL Innodb garantiza que las transacciones de escritura por lotes tengan éxito o fallen al mismo tiempo.

Se debe admitir el reintento al escribir en la base de datos. Si la base de datos no se puede escribir, vuelva a intentar la escritura. Si aún falla después de reintentar N veces, considere escribir 100 entradas en la base de datos. Los datos fallidos se imprimirán y registrarán, y luego descartado.

Además, escribir secuencialmente en el orden de la ID de la clave principal puede lograr el rendimiento más rápido, mientras que la inserción de índices de clave no principal no es necesariamente secuencial. Los ajustes frecuentes en la estructura del índice conducirán a una disminución en el rendimiento de la inserción. Es mejor no crear índices que no sean de clave principal o crear índices después de crear la tabla para garantizar el rendimiento de inserción más rápido.

1. ¿Necesita escribir en la misma tabla al mismo tiempo?

no puedo

  1. La escritura simultánea en la misma tabla no puede garantizar que los datos se escriban en orden.

  2. Elevar el umbral para la inserción por lotes aumenta la simultaneidad de inserción hasta cierto punto. No es necesario escribir simultáneamente en una sola tabla

MyisamTiene innodbun mejor rendimiento de inserción pero pierde soporte de transacciones. No hay garantía de éxito o fracaso al mismo tiempo durante la inserción por lotes. Por lo tanto, cuando la inserción por lotes se agota o falla, si lo intenta nuevamente, inevitablemente provocará la aparición de algún problema. datos duplicados. Pero para garantizar una velocidad de importación más rápida, el motor de almacenamiento myisam puede incluirse como uno de los planes.

En esta etapa, citaré los resultados de las pruebas de rendimiento de otras personas. # Análisis comparativo de MyISAM e InnoDB [2]

De los datos se puede ver que la escritura por lotes es significativamente mejor que la escritura única. Y después de que innodb desactiva la política de actualización instantánea del disco, el rendimiento de inserción de innodb no es mucho peor que el de myisam.

innodb_flush_log_at_trx_commit: Controla la estrategia de MySQL para vaciar datos al disco.

  1. Predeterminado = 1, es decir, los datos se descargarán al disco cada vez que se envíe una transacción, con la mayor seguridad y sin pérdida de datos.

  2. Cuando se configura en 0 y 2, los datos se actualizarán en el disco cada 1 segundo y mysql crashes posible que se pierda 1 segundo de datos cuando el sistema no funcione.

Teniendo en cuenta que el rendimiento por lotes de Innodb también es bueno cuando la política de disco de actualización instantánea está desactivada, se decide tentativamente usarla primero innodb(si el clúster MySQL de la empresa no permite cambiar este valor de política, se puede usar MyIsam). Al realizar pruebas en un entorno en línea, puede concentrarse en comparar el rendimiento de inserción de los dos.

Existe un cuello de botella en el rendimiento de la escritura concurrente en una sola base de datos MySQL. Generalmente, la escritura de 5K TPS es muy alta.

Los datos actuales se almacenan mediante SSD y el rendimiento debería ser mejor. Pero si es un disco duro, aunque la lectura y escritura secuenciales tendrán un rendimiento muy alto, el disco duro no puede soportar la escritura concurrente. Por ejemplo, si hay 10 tablas en cada biblioteca, supongamos que se escriben 10 tablas al mismo tiempo, aunque cada tabla es Escrito secuencialmente, debido a las diferentes ubicaciones de almacenamiento de varias tablas, el HDD tiene solo un cabezal magnético y no admite escritura concurrente. Solo puede buscar nuevamente, lo que aumentará en gran medida el consumo de tiempo y perderá el alto rendimiento de la lectura y escritura secuencial. . Por lo tanto, para HDD, no es una buena solución que una única base de datos escriba varias tablas al mismo tiempo. Volviendo al escenario de SSD, diferentes fabricantes de SSD tienen diferentes capacidades de escritura y diferentes capacidades de escritura concurrente: algunos admiten 500 M/s, algunos admiten lectura y escritura de 1 G/s, algunos admiten 8 escrituras concurrentes y algunos admiten 4 al mismo tiempo. Antes del experimento en línea, no sabíamos cuál sería el rendimiento real.

Por lo tanto, el diseño debe ser más flexible y soportar las siguientes capacidades:

  1. Número de bases de datos de configuración admitidas

  2. Admite configurar la cantidad de tablas escritas simultáneamente (si MySQL es un disco HDD, solo se escribe una tabla secuencialmente y otras tareas esperan)

A través de la configuración anterior, nuestro sistema puede ajustar de manera flexible la cantidad de bases de datos en línea y la concurrencia de tablas de escritura. Ya sea HDD o SSD, nuestro sistema puede admitirlo. Independientemente del modelo de SSD del fabricante o de su rendimiento, la configuración se puede ajustar para obtener continuamente un mayor rendimiento. Esta es también la idea detrás del diseño: no hay un número de umbral fijo, pero debe poder ajustarse dinámicamente.

A continuación, hablemos de la lectura de archivos: hay mil millones de datos, cada uno de 1K y el total es 931G. Generalmente no se genera un archivo grande de casi 1T. Entonces, nuestro archivo predeterminado se ha dividido aproximadamente en 100 archivos. El número de cada archivo debe ser aproximadamente el mismo. ¿Por qué se corta en 100 pedazos? ¿No sería posible importar la base de datos más rápido dividiéndola en 1000 partes y aumentando la simultaneidad de lectura? Como se mencionó hace un momento, el rendimiento de lectura y escritura de la base de datos está limitado por el disco, pero cualquier disco tiene operaciones de lectura más rápidas que las de escritura. Especialmente al leer, solo necesita leer del archivo, pero al escribir, MySQL tiene que realizar procesos complejos como indexación, análisis de SQL, transacciones, etc. Por lo tanto, la concurrencia máxima para escribir es 100 y la concurrencia para leer archivos no necesita exceder 100.

Más importante aún, la simultaneidad de lectura de archivos es igual al número de subtablas, lo que resulta beneficioso para simplificar el diseño del modelo. Es decir, 100 tareas de lectura y 100 tareas de escritura corresponden a 100 tablas.

Dado que el archivo está dividido en 100 archivos pequeños de 10G, el sufijo del archivo + el número de línea del archivo se pueden usar como clave única del registro, al tiempo que se garantiza que el contenido del mismo archivo se escriba en la misma tabla. Por ejemplo

  1. index_90.txt se escribe en la base de datos base de datos_9, tabla_0,

  2. index_67.txt se escribe en la base de datos base de datos_6, tabla_7.

De esta forma se ordena cada mesa. El orden general se logra mediante el sufijo de la base de datos + el sufijo del nombre de la tabla.

Obviamente, un archivo 10G no se puede leer en la memoria al mismo tiempo. La lectura del archivo de escena incluye

  1. Files.readAllBytesCarga única de la memoria interna

  2. FileReader+ BufferedReader lee línea por línea

  3. Archivo+ Lector en búfer

  4. El escáner lee línea por línea

  5. Lectura del modo de búfer Java NIO FileChannel

En MAC, comparación del rendimiento de la lectura de archivos 3.4G usando estos métodos

Método de lectura
Files.readAllBytes La memoria está llena de OOM.
FileReader+ BufferedReaderLeer línea por línea 11 segundos
File+ BufferedReader 10 segundos
Scanner 57 segundos
Java NIO FileChannelLectura en modo buffer 3 segundos

Para obtener contenido de evaluación detallado, consulte: Comparación de rendimiento de lectura de archivos [3]

Se puede ver que usar este método JavaNIO FileChannneles obviamente mejor, pero FileChannelel método consiste en leer primero el búfer de tamaño fijo y no admite la lectura línea por línea. Tampoco hay garantía de que el búfer contendrá exactamente una fila entera de datos. Si el último byte del búfer queda atascado en medio de una línea de datos, se requiere cooperación adicional para leer el siguiente lote de datos. Cómo convertir el búfer en filas de datos es más difícil.

File file = new File("/xxx.zip")
FileInputStream fileInputStream = null
long now = System.currentTimeMillis()
try {
       fileInputStream = new FileInputStream(file)
       FileChannel fileChannel = fileInputStream.getChannel()

       int capacity = 1 * 1024 * 1024
       ByteBuffer byteBuffer = ByteBuffer.allocate(capacity)
       StringBuffer buffer = new StringBuffer()
       int size = 0
       while (fileChannel.read(byteBuffer) != -1) {
          //读取后,将位置置为0,将limit置为容量, 以备下次读入到字节缓冲中,从0开始存储
          byteBuffer.clear()
          byte[] bytes = byteBuffer.array()
          size += bytes.length
       }
       System.out.println("file size:" + size)
} catch (FileNotFoundException e) {
   e.printStackTrace()
} catch (IOException e) {
   e.printStackTrace()
} finally {
   //TODO close资源.
}
System.out.println("Time:" + (System.currentTimeMillis() - now))

JavaNIOEstá basado en búfer y ByteBufferse puede convertir en una matriz de bytes, y debe convertirse en una cadena y truncarse por línea.

Sin embargo, la lectura de BufferedReader JavaIO puede admitir naturalmente el truncamiento de líneas y el rendimiento no es malo: solo se necesitan 30 segundos para leer un archivo de 10 G. Dado que el cuello de botella general de la importación es la parte de escritura, incluso si se lee en 30 segundos, El rendimiento general no se verá afectado. Entonces, la lectura de archivos utiliza BufferedReaderla lectura línea por línea. esa es la opcion 3

Esta sección es confusa, así que léala con paciencia.

¿Es posible tener 100 tareas de lectura, cada tarea leyendo un lote de datos y escribiéndolo en la base de datos inmediatamente? Como se mencionó anteriormente, debido al cuello de botella de la escritura concurrente en la base de datos, es imposible que una base de datos escriba 10 tablas en lotes grandes al mismo tiempo, por lo que escribir 100 tareas en la base de datos al mismo tiempo conducirá inevitablemente a 10 tablas en cada base de datos se escriben secuencialmente al mismo tiempo, lo que intensifica la presión de escritura simultánea en el disco. Para aumentar la velocidad tanto como sea posible y reducir la degradación del rendimiento causada por la escritura simultánea en el disco, es necesario suspender algunas tareas de escritura. Entonces, ¿es necesario que las tareas de lectura limiten la simultaneidad? innecesario.

Suponiendo que las tareas de escritura y lectura se fusionen, la simultaneidad de las tareas de lectura se verá afectada. El plan inicial es manejar las tareas de lectura y escritura por separado, para que ninguna retrase a la otra. Sin embargo, se descubrió que esta solución era más difícil durante el diseño real.

La idea original era introducir Kafka, es decir, 100 tareas de lectura entregarían datos a Kafka, y las tareas de escritura consumirían Kafka y lo escribirían en la base de datos. 100 tareas de lectura entregan mensajes a Kafka. En este momento, el orden se interrumpe. ¿Cómo garantizar una escritura ordenada en la base de datos? Pensé que podría usar el enrutamiento de partición Kafka, es decir, leer el ID de la tarea y enrutar todos los mensajes de la misma tarea a la misma partición para garantizar un consumo ordenado en cada partición.

¿Cuántos fragmentos se deben preparar? Obviamente, 100 es demasiado, si la partición es menor que 100, como 10. Entonces debe haber mensajes de múltiples tareas mezclados. Si hay varias tablas de la misma base de datos en una partición Kafka y esta base de datos solo admite la escritura por lotes de una sola tabla, no admite la escritura simultánea de varias tablas. Los mensajes de varias tablas en esta biblioteca se mezclan en un fragmento. Debido a limitaciones de concurrencia, los mensajes correspondientes a tablas que no admiten escritura solo se pueden descartar. Por tanto, esta solución es compleja y difícil de implementar.

Por lo tanto, finalmente se abandonó la solución Kafka y se abandonó temporalmente la solución de separar las tareas de lectura y escritura.

La solución final se simplifica a la tarea de lectura de leer un lote de datos y escribir un lote. Es decir, la tarea se encarga tanto de leer archivos como de insertarlos en la base de datos.

Si la tarea de lectura está a la mitad, ¿cómo lidiar con el tiempo de inactividad o la liberación del servicio? O si hay una falla en la base de datos, la escritura continúa fallando y la tarea finaliza temporalmente, ¿cómo garantizar que cuando la tarea se reinicie, el procesamiento continúe en el punto de interrupción sin repetir la escritura?

Hace un momento mencionamos que podemos establecer una ID de clave principal para cada registro, es decir, el índice del sufijo del archivo + el número de línea del archivo. La idempotencia de la escritura se puede garantizar mediante la identificación de la clave primaria.

El valor máximo del número de línea donde se encuentra el archivo es aproximadamente 10G/1k = 10M, que es 10000000. Empalme el sufijo más grande 99. La identificación más grande es 990000000.

Por lo tanto, no es necesario que la base de datos incremente automáticamente el ID de la clave principal. El ID de la clave principal se puede especificar durante la inserción por lotes.

¿Qué pasa si otra tarea también necesita importar la base de datos? Cómo lograr el aislamiento de la ID de la clave principal, de modo que aún sea necesario empalmar la ID de la clave principal taskId. Por ejemplo, {taskId}{fileIndex}{fileRowNumber}convierta al tipo largo. Si el taskId es grande y el valor empalmado es demasiado grande, puede ocurrir un error al convertir al tipo Long.

Lo más importante es que si algunas tareas escriben 1kw y otras tareas escriben 100W, la longitud de cada marcador de posición no se puede conocer usando el tipo Largo y existe la posibilidad de conflicto. Sin embargo, si se empalman cadenas {taskId}_{fileIndex}_{fileRowNumber}y se agrega un índice único, el rendimiento de la inserción será aún peor, por lo que no podrá satisfacer la demanda de la importación de datos más rápida. Entonces necesitamos pensar en otro plan.

Puede considerar usar Redis para registrar el progreso de la tarea actual. Por ejemplo, Redis registra el progreso de las tareas y lo actualiza después de una escritura por lotes exitosa en la base de datos.

INCRBY KEY_NAME INCR_AMOUNT

Especifica que el progreso actual aumenta en 100, por ejemplo incrby task_offset_{taskId}100. Si falla la inserción por lotes, vuelva a intentar la inserción. Si ocurren múltiples fallas, se realizará una única inserción y una única actualización a redis. Para asegurarse de que la actualización de Redis se realice correctamente, también puede agregar un reintento durante la actualización de Redis.

Si no está seguro de la coherencia del progreso de Redis y las actualizaciones de la base de datos, puede considerar consumir el binlog de la base de datos. Cada vez que se agrega un registro, se agregará redis +1.

Si la tarea se interrumpe, primero se consulta el desplazamiento de la tarea. Luego lea el archivo hasta el desplazamiento especificado y continúe procesando.

Como se mencionó anteriormente, para evitar una concurrencia excesiva de una sola base de datos, inserte una tabla que afecte el rendimiento de la base de datos. Considere limitar la simultaneidad. ¿Cómo hacerlo?

Dado que las tareas de lectura y escritura se fusionan. Entonces es necesario limitar las tareas de lectura al mismo tiempo. Es decir, cada vez solo se selecciona para su ejecución un lote de tareas de lectura y escritura.

Antes de hacer esto, es necesario diseñar el modelo de almacenamiento de la tabla de tareas.

Tarea

-int identificación,

int parentTaskId,

ruta del archivo de cadena,

tu eres mi mano,

int base de datosIndex,//sufijo de base de datos

int tableIndex, //sufijo del nombre de la tabla

int status,//init、proceso、fail、hecho、cancelar

int offset,//También puedes poner el desplazamiento del progreso actual en la base de datos

int startTime,//Tiempo de ejecución de inicio de la tarea

tiempo int,

tiempo int,

  1. bizId es un campo predeterminado para admitir otras líneas de productos en el futuro. El valor predeterminado es 1, que representa la línea de negocio actual.

  2. datbaseIndex representa el sufijo de base de datos asignado

  3. tableIndex representa el sufijo del nombre de la tabla asignada

  4. parentTaskId, es decir, la identificación total de la tarea

  5. El desplazamiento se puede utilizar para registrar el progreso de la tarea actual.

  6. Se importan mil millones de datos a la base de datos y se dividen en 100 tareas. Se agregarán 100 ID de tarea para procesar una parte de los datos respectivamente, que es un archivo 10G.

  7. El estado de estado se utiliza para distinguir si la tarea actual se está ejecutando y la ejecución está completa.

La forma de asignar tareas a cada nodo se puede considerar mediante el método de preferencia. Cada nodo de tarea necesita adelantarse a las tareas, y cada nodo solo puede adelantarse a una tarea al mismo tiempo. ¿Cómo implementarlo específicamente? Puede considerar iniciar una tarea programada en cada nodo, escanear la tabla con regularidad, buscar subtareas para ejecutar e intentar ejecutar la tarea.

¿Cómo controlar la concurrencia? Puede utilizar el semáforo de redissión. la clave es la identificación de la base de datos,

  RedissonClient redissonClient = Redisson.create(config)
  RSemaphore rSemaphore = redissonClient.getSemaphore("semaphore")
    // 设置1个并发度
  rSemaphore.trySetPermits(1)
  rSemaphore.tryAcquire()

La misión es responsable del entrenamiento de rotación regular y, después de conseguir un lugar, comienza la misión. Establezca el estado de la tarea en Procesar y suelte el semáforo después de que la tarea se complete o falle.

Redisalt de la tabla de tareas de TaskTassk [Competencia exitosa por el semáforo] [No se pudo competir por el semáforo] La tarea de entrenamiento de rotación programada comienza a consultar las tareas a ejecutar. La competencia de bucle por el semáforo modifica el estado de la tarea. Establezca la hora y la hora de inicio para consultar el progreso actual Leer el archivo desde El progreso actual es leer el archivo, se completa el progreso de actualización de la base de datos de importación por lotes y se libera el semáforo para solicitar el semáforo de la siguiente tarea TaskTassk tabla de tareas Redis

Pero existe un problema con el uso de semáforos para limitar la corriente: si la tarea se olvida de liberar el semáforo o el proceso falla y no puede liberar el semáforo, ¿cómo solucionarlo? Considere agregar un tiempo de espera al semáforo. Entonces, ¿qué pasa si la ejecución de la tarea tarda demasiado, lo que provoca que el semáforo se publique antes de tiempo y otro cliente compite por el semáforo, lo que provoca que dos clientes escriban una tarea al mismo tiempo?

Obviamente, al importar mil millones de datos a la base de datos, ¿cómo se convirtió en un problema similar de tiempo de espera de bloqueo distribuido?

De hecho Redisson, no existe una buena manera de resolver el problema del tiempo de espera del semáforo con semáforos. Pensamiento normal: si la ejecución de la tarea es demasiado larga, lo que provoca que se libere el semáforo, solo necesita renovar el contrato para resolver este problema. se está ejecutando, siempre que se encuentre Cuando el semáforo esté a punto de caducar, renuévelo por un período de tiempo para evitar que el semáforo caduque. Pero Redission no ofrece la posibilidad de renovar el semáforo, ¿qué debo hacer?

Pensémoslo de otra manera: hemos estado tratando de permitir que múltiples nodos compitan por el semáforo, limitando así la concurrencia. Puede intentar seleccionar un nodo maestro y rotar la lista de tareas a través del nodo maestro. Hay tres situaciones:

Caso 1 El número de ejecuciones actuales es menor que la concurrencia.

  1. Luego seleccione la tarea que se ejecutará con la ID más pequeña, establezca el estado en en curso y notifique el mensaje de liberación.

  2. El proceso que consume el mensaje solicita un bloqueo distribuido y comienza a procesar la tarea. Libere el bloqueo cuando se complete el procesamiento. Con la ayuda de la renovación del bloqueo distribuido de Redission, se garantiza que el bloqueo no expirará antes de que se complete la tarea.

Caso 2 El número que se está ejecutando actualmente es igual a la concurrencia.

  1. El nodo maestro intenta averiguar si la tarea en curso tiene un bloqueo.

  2. Si no hay ningún bloqueo, significa que la ejecución de una tarea falló y la tarea debe volver a emitirse en este momento. Si hay un bloqueo, significa que se está ejecutando una tarea.

Caso 3 El número que se está ejecutando actualmente es mayor que el grado de concurrencia

  1. Informar situaciones anormales, llamar a la policía e intervenir manualmente

El uso de la tarea de capacitación de rotación del nodo maestro puede reducir la competencia de tareas, publicar mensajes a través de Kafka y el proceso que recibe el mensaje maneja la tarea. Para garantizar que más nodos participen en el consumo, puede considerar aumentar la cantidad de fragmentos de Kafka. Aunque cada nodo puede manejar múltiples tareas al mismo tiempo, esto no afectará el rendimiento porque el cuello de botella del rendimiento está en la base de datos.

Entonces, ¿cómo se debe seleccionar el nodo maestro? Puede Zookeeper+curatorseleccionar el nodo maestro a través de . La confiabilidad es relativamente alta.

Hay muchos factores que afectan el tiempo que lleva insertar mil millones de datos en la base de datos. Incluyendo el tipo de disco y el rendimiento de la base de datos. Si el número de subbases de datos se puede dividir en 1000 bases de datos, el rendimiento sin duda será más rápido. El número de subbases de datos y subtablas debe determinarse en función de la situación real en línea, lo que determina en gran medida la velocidad de escritura. Finalmente, el umbral de inserción por lotes de la base de datos no es estático y debe probarse y ajustarse continuamente para obtener el mejor rendimiento. Puede probar continuamente el umbral óptimo para la inserción por lotes según 100, 1000, 10000, etc.

Finalmente, resumamos algunos puntos importantes.

  1. Primero se deben confirmar las restricciones antes de poder diseñar el plan. Determine la dirección principal que el entrevistador quiere preguntar, como cómo cortar un archivo 1T en archivos pequeños. Aunque es difícil, puede que no sea una pregunta que el entrevistador quiera investigar.

  2. Desde la perspectiva de la escala de datos, es necesario crear subbases de datos y subtablas, y determinar aproximadamente la escala de las subtablas.

  3. A partir del análisis del cuello de botella de escritura de una única base de datos, se determina que se necesitan bases de datos separadas.

  4. Teniendo en cuenta que los discos tienen diferente soporte para la escritura simultánea, es necesario limitar la escritura simultánea en varias tablas de la misma biblioteca. También admite el ajuste dinámico, lo que facilita la depuración del valor óptimo en un entorno en línea.

  5. MySQL innodb、myisamLos motores de almacenamiento tienen diferente soporte para el rendimiento de escritura, que también debe compararse y verificarse en línea.

  6. El umbral óptimo para la inserción por lotes de bases de datos requiere pruebas repetidas.

  7. Debido a las limitaciones de concurrencia, es difícil separar las tareas de lectura y las tareas de escritura basadas en Kafka. Así que combine las tareas de lectura y escritura.

  8. Se requiere Redis para registrar el progreso de la ejecución de la tarea. Después de que falla una tarea, el progreso se registra al volver a importar para evitar problemas de duplicación de datos.

  9. La coordinación de tareas distribuidas es difícil y el uso de semáforos de Redission no puede resolver el problema de la renovación del tiempo de espera. Las tareas pueden ser asignadas por el nodo maestro + bloqueos distribuidos para garantizar la escritura exclusiva de las tareas. El nodo maestro utiliza Zookeeper+Curatorla selección.

Referencias

[1]

https://baijiahao.baidu.com/s?id=1709205029044038742&wfr=spider&for=pc: https://link.juejin.cn/?target=https%3A%2F%2Fbaijiahao.baidu.com%2Fs%3Fid%3D1709205029044038742 %26wfr%3Dspider%26for%3Dpc

[2]

http://t.csdn.cn/eFm9z: https://link.juejin.cn/?target=http%3A%2F%2Ft.csdn.cn%2FeFm9z

[3]

https://zhuanlan.zhihu.com/p/142029812: https://link.juejin.cn/?target=https%3A%2F%2Fzhuanlan.zhihu.com%2Fp%2F142029812

Supongo que te gusta

Origin blog.csdn.net/weixin_54542328/article/details/133180772
Recomendado
Clasificación