Proyecto del Billón de Tablas - PgDay Ecuador 2013

643 views
479 views

Published on

¿Qué es una base de datos "grande"? ¿Cuántas tablas puede contener una base de datos PostgreSQL? ¿Hay un límite? ¿Es posible crear 10^9, un billón, de tablas en una base de datos?

Charla impartida en PgDay Ecuador 2013, donde se habló de bases de datos grandes, alto rendimiento, 150.000 inserciones por segundo en un único nodo y, por supuesto... si en NOSYS llegamos a crear 1.000.000.000 tablas en una base de datos y cuántos $$$$ nos costó ejecutar el experimento en Amazon AWS.

Published in: Technology
0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total views
643
On SlideShare
0
From Embeds
0
Number of Embeds
28
Actions
Shares
0
Downloads
9
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

Proyecto del Billón de Tablas - PgDay Ecuador 2013

  1. 1. El Proyecto del Billón de Tablas Álvaro Hernández Tortosa <aht@Nosys.es>
  2. 2. Acerca de mí ● ● ● ● ● Álvaro Hernández Tortosa <aht@Nosys.es> Fundador y Director Técnico en NOSYS ¿Qué hacemos en NOSYS? ✔ Formación, consultoría y desarrollo de software con PostgreSQL (y Java) ✔ Partners de EnterpriseDB ✔ Formación avanzada en Java con Javaspecialists.eu: Java Master Course y Java Concurrency Course ✔ Partners de Amazon AWS. Formación y consultoría en AWS Twitter: @ahachete LinkedIn: http://es.linkedin.com/in/alvarohernandeztortosa/
  3. 3. ¿Qué es una base de datos “grande”? Bases de datos de un sólo nodo: hasta TBs o decenas de Tbs. Miles de millones a billones de registros. ● Bases de datos multi nodo, virtualmente ilimitadas. Casos conocidos de centenares de TBs e incluso Pbs. ● ● ● Esta charla no es acerca de Big Data. Es sólo de Big Data De hecho, aquí realmente hablamos de Big MetaData (y el peor ratio metadata/data de la historia)
  4. 4. Tipos de bases de datos (por número de tablas) Base de datos # Tablas SLST Schema-Less-Like, Single-Table 1 EDNECRM Extremely De-Normalized Enterprise CRM 2 S Small 20 M Medium 80 L Large XL Extra Large 1,000 ORMGW ORMs Gone Wild 5,000 MT Multi-Tenancy MMT Massive Multi-Tenancy BTP Billion Tables Project 200 50,000 1,000,000 1,000,000,000
  5. 5. Tipos de bases de datos (II) Number of tables by database type 100 90 80 10 log_10 (# tables) 70 60 50 40 30 20 10 0 SLST ENNECRM S M L XL ORMGW MT MMT BTP
  6. 6. Límites teóricos de PostgreSQL Característica Límite # columnas / tabla 250-1600 (dependiendo del tipo de las columnas) Max tamaño / columna 1GB Max tamaño fila 1.6 TB Max # filas / tabla ilimitado Max tamaño / tabla 32 TB Max # tablas / bbdd ilimitado Max tamaño / bbdd ilimitado
  7. 7. Dónde empezó todo... ● En 2002, un mail a pgsql-admin@postgresql.org: “I'm guessing that the maximum number of tables is related to how much can be stored in the pg_ tables […]. So, based on that, the maximum number of rows is unlimited and the maximum size for a table is 64 TB. So realistically, you would need an enormous number (trillions) of tables to exceed that limit” Simon Cawley http://www.postgresql.org/message-id/53386E0C47E7D41194BB0002B325C997747F2B@NTEX60
  8. 8. Dónde empezó todo... (II) http://it.toolbox.com/blogs/database-soup/one-billion-tables-or-bust-46270 21 de Mayo de 2011
  9. 9. ¿Por qué hacer 1BT? Demostrar que PostgreSQL no? tiene límite en el # tablas ● Someter a Postgres a stress de forma no habitual ● Probar un nuevo servidor antes de producción ● Para ganar a Josh Berkus, creando tablas más rápido que él ● “Yo la tengo más grande que tú” (la bbdd) ● Porque podemos En re al id ad .. . O f ci al m en te .. . ●
  10. 10. Redefiniendo “tps” Wikipedia (http://en.wikipedia.org/wiki/Transactions_per_second): “Transactions Per Second refers to the number of atomic actions performed by certain entity per second” En lo sucesivo, en esta presentación, querrá decir: “tablas por segundo”
  11. 11. Primeros intentos (2011) ● Josh Berkus (http://it.toolbox.com/blogs/database-soup/one-billion-tables-or-bust-46270 ): 3M tablas, 83 tps. PostgreSQL murió (sin disco). Serial + text ● Jan Urbanski (http://it.toolbox.com/blogs/database-soup/one-billion-tables-part-2-46349 ): 4.6M tablas, 1K tps. PostgreSQL murió (inodes). Int + text ● $SELF (http://it.toolbox.com/blogs/database-soup/one-billion-tables-part-2-46349 ): 10M tablas, 2K2 tps. Finalziación correcta. 1 columna int 100M tablas, 1K5 tps. Finalziación correcta. 1 columna int
  12. 12. 100M tablas. ¿Cómo lograrlo? Necesitamos RAM: Out of memory: kill process 4143 (postgres) score 235387 or a child Killed process 4146 (postgres) ● Un sistema de ficheros que pueda manejar muchos ficheros: reiserfs ● ● Estrategia de creación de tablas: ➔ No usar un fichero CSV o .sql pre-generado ➔ No usar un driver a través de TCP/IP ➔ Solución: enviar comandos SQL vía la entrada estándar, con psql sobre sockets UNIX
  13. 13. 100M tables. How to get there? (II) Configurar postgresql.conf: fsync = of synchronous_commit = of full_page_writes = of wal_bufers = 256MB autovacuum = of max_locks_per_transaction = 10000 shared_bufers = 16384MB checkpoint_segments = 128
  14. 14. 100M tables. How to get there? (III) Primer servidor probado: ● ● ● ● ● ● Intel Core 2 CPU 4GB RAM 3X 1TB SATA 7K2 rpm, RAID 0 Reiserfs Ubuntu 10.04 PostgreSQL 9.0
  15. 15. 100M tablas. El código
  16. 16. 100M tablas. Los resultados 100M tables Intel Core 2, 4GB RAM, 3TB reiser 3000 2500 2000 time (min) speed (tps) 1500 1000 500 0 10 5 20 15 30 25 40 35 50 45 M tables Uso de disco: 257GB 60 55 70 65 80 75 90 85 100 95
  17. 17. El camino a 1B tablas. Los peores enemigos Autovacuum (¿pero no estaba autovacuum = of ?) ● autovacuum_freeze_max_age = 2000000000 # maximum XID age before forced vacuum updatedb (¿quién activa esto por defecto en las distros??????) ●
  18. 18. El camino a 1B tablas. El almacenamiento ● Separar el directorio base del directorio de tablas Crear un tablespace (o más) en una partición reiserfs (llamada /data) ● El mejor rendimiento se obtuvo con base en XFS (/bigdata). El patrón es añadir, como una bbdd “normal” ● Los registros de WAL van a RAM (tmpfs con swap para evitar desbordamientos, montado en /xlog) ●
  19. 19. El camino a 1B tablas. El almacenamiento (II)
  20. 20. El camino a 1B tablas. Tablespaces Excepto reiserfs, otros sistemas de ficheros degradan rápidamente con el número de ficheros ● ● Incluso reiser pierde rendimiento con varios millones Solución: crear tantos tablespaces como sea necesario (incluso dentro del mismo sistema de ficheros) ● Para la prueba de 1B, usamos 1000 tablespaces para máximo rendimiento ●
  21. 21. El camino a 1B tablas. Una pizza más grande ● ● ● ● 2X Intel(R) Xeon(R) CPU E5-2650 @ 2.00GHz (16 cores, 32 threads) 48GB RAM Versión moderna de SO y Postgres: ➔ Debian wheezy (kernel 3.2.41) ➔ PostgreSQL 9.2.4 Apenas unos segundos para hacer “make -j16” postgresql
  22. 22. El camino a 1B tablas.. Concurrencia La creación de tablas no limita por disco. El rendimiento medio fue de < 5MB/s en la prueba de 100M tablas ● ● Hay dos límites principales: ➔ La velocidad de la CPU (los backends alcanzan el 100% si se ejecutan aisladamente) ➔ La contención (locking) Para mejorar el rendimiento, lanzamos varios procesos en segundo plano ● ● 16 procesos fue la mejor combinación
  23. 23. El camino a 1B tablas. Concurrencia (II) Con múltiples procesos, no podemos permitir que cada proceso loguee sus propios datos (por la dificultad de agregar los datos) ● ● Ejecutamos otro proceso sólo para loguear los datos: ➔ El logger tiene el PID de cada trabajador ➔ Cuando el logger quiere loguear, envía una señal SIGUSR1 a los trabajadores ➔ El logger espera la información en un fifo identificado por el PID del trabajador ➔ El trabajador escribe el número de tablas que ha generado hasta la fecha
  24. 24. El camino a 1B tablas. El código El trabajador es un script en python: ➔ Divide en interaciones el número de tablas asignado ➔ En cada iteración, crea un proceso psql al que le manda el comando CREATE TABLE … TABLESPACE … a través de la entrada estándar ➔ Cuando recibe la señal USR1, escribe el número de tablas actual al fifo ➔ Sale cuando recibe (del logger) la señal TERM ➔ Las iteraciones (I/O) se ejecutan en un thread ● El logger es un shell script que loguea cuando recibe USR1 ● Main es también un shell script. Lanza todos los procesos y manda al logger que loguee cada 10s (le manda USR1) ●
  25. 25. El camino a 1B tablas. El código (II)
  26. 26. btp-main.sh
  27. 27. btp-process.py
  28. 28. btp-logger.sh
  29. 29. 1B tablas. ¿Funcionó? $ time ./btp-main.sh 1000000000 16 50000 1000 real 2022m19.961s user 240m7.044s sys 165m25.336s (esto es: 33h 42m 20s) ● Media: 8242tps btp=# SELECT txid_current(); txid_current -------------1000001685
  30. 30. 1B tablas. ¿Funcionó? (II) $ echo -e 'timing onnSELECT count(*) FROM pg_class' |psql btp count -----------1000000288 Time: 9221642.102 ms $ df -h /data /bigdata /var/tmp Filesystem Size Used Avail Use% Mounted on /dev/mapper/vgMain-data 500G 97G 404G 20% /data /dev/etherd/e15.0 5.5T 2.6T 3.0T 46% /bigdata tmpfs 90G 4.1G 86G 5% /var/tmp
  31. 31. 1B tablas. ¿Funcionó? (III) btp=# SELECT relname, heap_blks_read, heap_blks_hit, idx_blks_read, idx_blks_hit FROM pg_statio_all_tables WHERE relname IN ('pg_tablespace', 'pg_database', 'pg_shdepend'); relname | heap_blks_read | heap_blks_hit | idx_blks_read | idx_blks_hit ---------------+----------------+---------------+---------------+-------------pg_tablespace | 35 | 6226009368 | pg_database | 3| 63015 | pg_shdepend | 1| 1000001001 | 13 | 12 | 6794 105017 5 | 1001537778 btp=# INSERT INTO _3ade68b1 VALUES (2), (3); Time: 20.673 ms btp=# SELECT * FROM _3ade68b1 LIMIT 1; [...] Time: 0.207 ms
  32. 32. 1B tablas. ¿Cuánto tiempo requiere un “dt”? $ time ./postgresql-9.2.4/bin/psql btp -c "dt" > tables ∞ ERROR: canceling statement due to user request real 2993m51.710s user 0m0.000s sys 0m0.000s Terminado vía pg_cancel_backend()
  33. 33. 1B tablas. Rendimiento 1B tables. Performance Tables per second 12000 10000 8000 tps 6000 4000 2000 0 80 20 260 200 320 380 300 340 460 440 M tables Pico: 10Ktps 540 600 640 620 680 860 1000
  34. 34. 1B tablas. Rendimiento (II) 1B tables Memory usage 45000 40000 35000 30000 25000 20000 15000 10000 5000 0 mem free (MB) buffers (MB) Cached (MB) 80 20 260 200 320 380 300 340 460 440 540 600 640 620 680 M tables Carga media de los backends: 57% Carga media del sistema: 11.7 860 1000
  35. 35. Restaurando la durabilidad de la bbdd ● Detener el servidor y llevar pg_xlog a disco de nuevo ● Configurar postgresql.conf: fsync = on synchronous_commit = on full_page_writes = on autovacuum = of ● Reiniciar el servidor. Y disfrutar :)
  36. 36. El camino a... 2B de tablas ● Una pizza aún mayor  2x Xeon quad-core de última generación a 3.3 Ghz ➔ Más rápido que 16-core 2.0Ghz (8K5tps @100Mt): ✔ Con 16 procesos: 11K9 tps @100Mt ✔ Con 8 procesos: 12K3 tps @100Mt $ time ./btp-main.sh 1000000000 8 50000 1000 real 1400m6.680s user 165m32.565s sys 119m46.493s (esto es: 23h 20m 07s) Media: 11903tps
  37. 37. El camino a... 2B de tablas (II) ● ● Necesidades de almacenamiento: ➔ Base: ~6TB ➔ Tablespaces: ~ 300GB El problema de autovacuum (otra vez): ➔ autovacuum_freeze_max_age como máximo es 2E9 ➔ Autovacuum se lanzará. Si los matamos, postgres los relanza ➔ Antes hacíamos una tabla por transacción ➔ Si agrupamos varias tablas creadas por transacción, el rendimiento baja (curioso)
  38. 38. ¿Qué tablas de catálogo escribe CREATE TABLE? ● ➔ Para una tabla de 1 columna, sin índices: ➔ 1 entrada en pg_class ➔ 2 entradas en pg_type (el tipo de la tabla y el tipo del array de tabla) ➔ 3 entradas en pg_depend (2 para los tipos, 1 para el schema al que pertenece la tabla) ➔ 7 entradas en pg_attribute (xmin, xmax, cmin, cmax, ctid, tableoid y la propia columna) Así que crear 11K9 tablas realmente quiere decir: ➔ Hacer 154K inserciones por segundo ➔ Más 11K9 fcheros creados por segundo (1MB/s de metainformación)
  39. 39. Entonces, ¿hay algún límite en el número de tablas? ● Tanto pg_class como pg_type tienen columnas oid ● Los oids son enteros de 32 bits sin signo ● Para cada tabla creada, se insertan 2 registros en pg_type ● Hay 330 tipos por defecto en 9.2 ● Por lo tanto, hay un límite en el número máximo de tablas: (2^32 – 330) / 2 = 2_147_483_483 (2_147_483_481 en 9.3)
  40. 40. Validando empíricamente la teoría ● Objetivo: intentar crear 2_147_483_481 tablas en pg9.3 ● Llegados allí, intentar crear una tabla más :) Hemos usado Amazon AWS para ello. Una instancia cr1.8xlarge (16 cores, 244GB RAM, 2x120GB SSD) ● ● Los tablespaces estaban en un RAID0 de los 2 SSDs Tablas de catálogo: RAID0 de 6x volúmenes de 1TB IOPSs no garantizados ●
  41. 41. Validando empíricamente la teoría: los costes $1,877.23 Amazon aportó créditos para la realización de estas pruebas. ¡Muchas gracias, Amazon!
  42. 42. Validando empíricamente la teoría: las tablas
  43. 43. Validando empíricamente la teoría: las tablas (II)
  44. 44. Validando empíricamente la teoría: el resultado 2,147,475,456 tablas (a 8025 del límite teórico)
  45. 45. Agradecimientos A Josh Berkus (y Selena Deckelmann, Jan Urbanski y Álvaro Herrara) que son los locos inventores de esta idea ● ● Grandes agradecimientos a José Luis Tallón: ➔ Por proveer del hardware inicial y tunearlo Por co-crear, co-programar, co-organizar y co-disfrutar este proyecto conmigo ➔ A ASLE, patrocinadores del evento, PostgreSQL Global y especialmente a Jaime Casanova por el esfuerzo en trarme acá :) ●
  46. 46. El Proyecto del Billón de Tablas Álvaro Hernández Tortosa <aht@Nosys.es>

×