2012-04-25 19 views
20

Tengo un problema donde necesito cargar una gran cantidad de datos (5+ mil millones de filas) en una base de datos muy rápidamente (idealmente menos de 30 minutos pero más rápido es mejor), y recientemente me sugirieron investigar postgresql (Fallé con mysql y estaba mirando hbase/cassandra). Mi configuración es Tengo un clúster (actualmente 8 servidores) que genera una gran cantidad de datos, y estaba pensando en ejecutar las bases de datos localmente en cada máquina del clúster, escribe rápidamente localmente y luego al final (oa través de la generación de datos) los datos fusionados. Los datos no están en ningún orden, así que no me importa en qué servidor específico esté (siempre y cuando esté allí).Auto sharding postgresql?

Mis preguntas son, ¿hay buenos tutoriales o lugares para aprender sobre PostgreSQL auto sharding (encontré resultados de firmas como Sykpe haciendo auto sharding pero no tutoriales, quiero jugar con esto yo mismo)? ¿Es lo que estoy tratando de hacer posible? Debido a que los datos no están en ningún orden, iba a utilizar el número de ID de incremento automático, ¿causará un conflicto si los datos se combinan (esto ya no es un gran problema)?

Actualización: La idea de Frank a continuación eliminó el problema del autoincremento de conflicto sobre el que estaba preguntando. La pregunta es básicamente ahora, ¿cómo puedo aprender sobre auto sharding y soportaría cargas distribuidas de datos a múltiples servidores?

+1

He cargado ~ 10 millones de filas en una base de datos de postgres en <5 min, por lo que puedo decirle con confianza que este es un recurso muy importante al que apoyarse cuando carga datos en un solo fragmento: http: // www .postgresql.org/docs/8.1/static/populate.html Esto también se ve prometedor: http://pgbulkload.projects.postgresql.org/ –

+9

'Iba a utilizar el número de ID de incremento automático, ¿eso causará un conflicto si los datos se combinan? 'Simplemente incremente en 10, y comience en diferentes desplazamientos. El servidor 1 usa los identificadores 1,11,21,31; el servidor 2 usa identificadores 2,12,22,32 –

+0

@FrankFarmer Gracias por el enlace y la gran idea de: incrementar. Creo que eso quita parte de la complejidad, entonces supongo que la pregunta solo está relacionada con el autodesmenuzamiento y las cargas distribuidas. – Lostsoul

Respuesta

2

Estas son algunas cosas que pueden ayudar:

  • La base de datos en cada servidor debe tener una pequeña mesa de metadatos con características únicas de ese servidor. Tal como qué servidor es; los servidores se pueden numerar secuencialmente. Además del contenido de esa tabla, probablemente sea prudente tratar de mantener el esquema en cada servidor lo más similar posible.

  • Con miles de millones de filas, querrás ID grandes (o UUID o similares). Con Bigints, puede asignar un rango generoso para cada servidor y configurar su secuencia para usarlo. P.ej. el servidor 1 recibe 1..1000000000000000, el servidor 2 recibe 1000000000000001-2000000000000000 etc.

  • Si los datos son simples puntos de datos (como una lectura de temperatura exactamente 10 instrumentos cada segundo) que podría obtener ganancias de eficiencia mediante el almacenamiento en una tabla con columnas (time timestamp, values double precision[]) en lugar de la más correcta (time timestamp, instrument_id int, value double precision). Esta es una desnormalización explícita en ayuda de la eficiencia. (. I blogged sobre mi propia experiencia con este esquema)

1

lo siento, no tienen un tutorial que nos ocupa, pero aquí es un esbozo de una posible solución:

  • Cargar un octavo de su datos en una instancia de PG en cada uno de los servidores
  • Para obtener una velocidad de carga óptima, no utilice insertos pero el COPY método
  • Cuando se cargan los datos, no combine las ocho bases de datos en una sola. En su lugar, utilice plProxy para lanzar una sola declaración para consultar todas las bases de datos a la vez (o el más adecuado para satisfacer su consulta)

Como ya se ha señalado, las claves pueden ser un problema. Usar secuencias o uuids no superpuestas o números de secuencia con un prefijo de cadena, no debería ser demasiado difícil de resolver.

Debe comenzar con una prueba de COPIA en uno de los servidores y ver qué tan cerca de su objetivo de 30 minutos puede obtener. Si sus datos no son importantes y tiene una versión reciente de Postgresql, puede intentar usar unlogged tables, que debería ser mucho más rápido (pero no seguro).Suena como un proyecto divertido, buena suerte.

+0

Gracias, veré plProxy ... parece muy interesante.Lo probaré y tablas sin registrar. – Lostsoul

14

Primero: ¿Realmente necesita insertar los datos generados de su clúster directamente en una base de datos relacional? No te importa fusionarlo al final de todos modos, ¿por qué molestarse en insertarlo en una base de datos? En su posición, los nodos de su clúster escribirían archivos planos, probablemente gzip'd datos CSV. Luego, granel importar y combinar esos datos utilizando una herramienta como pg_bulkload.

Si necesita insertar directamente en una base de datos relacional: Eso es (parte de) lo que PgPool-II y (especeially) PgBouncer son para. Configure PgBouncer para balancear la carga entre diferentes nodos y debería estar bastante ordenado.

Tenga en cuenta que PostgreSQL es una base de datos transaccional con sólidas garantías de durabilidad de los datos. Eso también significa que si lo usa de manera simplista, hacer muchas pequeñas escrituras puede ser lento. Debe considerar qué compensaciones está dispuesto a hacer entre la durabilidad, la velocidad y el costo del hardware.

En un extremo, cada INSERT puede ser su propia transacción que se sincroniza con el disco antes de devolver el éxito. Esto limita el número de transacciones por segundo al número de fsync() que su subsistema de disco puede hacer, que a menudo solo está en decenas o cientos por segundo (sin controlador RAID de respaldo de batería). Este es el valor predeterminado si no hace nada especial y si no ajusta su INSERT en un BEGIN y COMMIT.

En el otro extremo, se dice "Realmente no importa si pierdo todo estos datos" y el uso de unlogged tables para sus inserciones. Esto básicamente le da permiso a la base de datos para descartar sus datos si no puede garantizar que está bien, por ejemplo, después de un bloqueo del sistema operativo, bloqueo de la base de datos, pérdida de energía, etc.

El terreno medio es donde probablemente querrá estar . Esto implica una combinación de asynchronous commit, group commits (commit_delay y commit_siblings), insertos en grupos de dosificación envuelto en BEGIN explícita y END, etc. En lugar de INSERT de procesamiento por lotes que podría hacer COPY cargas de unos pocos miles de registros a la vez. Todas estas cosas intercambian la durabilidad de los datos contra la velocidad.

Para inserciones masivas rápidas, también debería considerar insertar en tablas sin ningún índice, excepto una clave principal. Quizás ni siquiera eso. Crea los índices una vez que termines tus inserciones en bloque. Esto será muchísimo más rápido.

+0

Guau ... gracias por la gran respuesta. Su derecho. No necesito una base de datos, pero estoy tratando de usarla para compartir los datos finales con otros nodos de trabajadores. Por lo tanto, mi primer proceso genera una gran cantidad de datos, pero el segundo proceso usa un clúster para analizar los datos con un conjunto de datos anterior (generados de la misma manera en un día diferente). No estoy seguro si necesito el terreno intermedio o las tablas más extremas no registradas porque si solo uso datos si el db muere, entonces sabré cuándo muere y puedo reiniciar nuevamente mi procesamiento, pero si no muero y va lento entonces perderé mi fecha límite. – Lostsoul

+0

¿Crees que en mi caso tiene más sentido guardar los datos como un archivo y simplemente subirlos? Pensé que como lo iba a tener en una base de datos para analizar, al final también podría crear hilos en mi programa que lo envíen mientras estoy procesando, pero si es más rápido solo para escribir localmente y luego subirlo a granel, podría simplemente hacer eso ... Además, no tengo ningún índice en la tabla (mi columna es un diccionario de cadena/int que estoy cargando como una cadena y la otra es una columna de ID que creo que será un int largo ...) Todas las otras consideraciones de decisión son solo por velocidad. – Lostsoul

+0

La cuestión de insertar los datos en una base de datos fragmentada es que solo es útil si puede consultarla en su forma fragmentada. Existen herramientas para eso (ver, por ejemplo, PL/Proxy) pero son más complejas y difíciles de usar que una sola instancia de DB. OTOH, pueden ser mucho más rápidos. Si no va a consultar los fragmentos, sino que desea fusionar los datos antes de analizarlos, también puede escribirlos como archivos planos e insertarlos en el DB final. –

-1

Puede usar mySQL, que admite auto-sharding en un clúster.

+2

Creo que estás pensando en MySQL Cluster, que es un producto pago separado de MySQL. – Peeja

1

Use citus para PostgreSQL auto sharding. También this link es útil.