Antecedentes :
he creado una aplicación web que me gustaría poder escalar razonablemente bien. Sé que no soy Google ni Twitter, pero mi aplicación utiliza una cantidad bastante grande de datos para cada usuario y, por lo tanto, tiene requisitos de datos bastante altos. Quiero estar listo para escalar razonablemente bien sin tener que rediseñar todo más tarde.
Me considero un desarrollador de software, no un experto en bases de datos. Es por eso que estoy publicando aquí. Espero que alguien con mucha más experiencia en bases de datos pueda darme consejos.
Con un número relativamente grande de usuarios, pero nada parecido a los números de Facebook, espero tener un DB que se vea así:
Una "mesa grande":
- 250 millones de registros
- 20 columnas
- Aproximadamente 100 GB de datos
- Tiene una clave foránea indexada bigint (20)
- Tiene una columna varchar (500) string_id indexada
- Tiene una columna de "valor" int (11)
4 otras mesas:
- 10 millones de registros cada uno
- Aproximadamente 2 - 4 GB de datos cada uno
- cada una de estas tablas tiene 4 - 8 columnas
- una columna es datetime date_created
- una columna es la columna varchar (500) string_id
- se seleccionarán una o dos columnas de cada una de estas tablas en una unión
Una de estas tablas se usa para almacenar promedios: su esquema es bigint (20) id, varchar (20) string_id, datetime date_created, float average_value
Lo que quiero hacer : dos consultas relativamente caras:
Calcular nuevos valores promedio:
- Con una clave externa, seleccione hasta varios millones de registros separados de la tabla grande.
- Calcule un nuevo promedio, agrupando por string_id.
- Insertar resultados en la tabla de promedios.
- Tal como se construye actualmente, esta consulta usa dos combinaciones.
Cree registros de solo lectura no normalizados para servir a los usuarios:
- Use una clave externa para seleccionar entre 1,000 y 40,000 registros de la tabla grande.
- Únase a cada una de las otras cuatro tablas en el registro más nuevo con la columna de id. De cadena.
- Inserte los resultados en una tabla desnormalizada.
- Estos registros son para uso del front-end para mostrar información a los usuarios.
- Tal como se construye actualmente, esta consulta usa cuatro combinaciones.
Planeo ejecutar cada una de estas costosas consultas en una base de datos de fondo de lote que empujará sus resultados a un servidor de base de datos front-end en tiempo real que maneja las solicitudes de los usuarios. Estas consultas se ejecutarán a intervalos regulares. No he decidido con qué frecuencia. La consulta promedio podría hacerse quizás una vez al día. La consulta de normalización deberá ser más frecuente, tal vez cada pocos minutos.
Cada una de estas consultas se ejecuta actualmente en unos pocos segundos en MySQL en una máquina de muy bajo nivel con un conjunto de datos con 100K registros en la "tabla grande". Me preocupan tanto mi capacidad de escalar como los costos de escalar.
Preguntas :
- ¿Este enfoque parece sólido? ¿Hay algo obviamente malo desde una perspectiva general?
- ¿Es un RDBMS la herramienta adecuada, o debería mirar otras soluciones de "big data" como algo de la familia Hadoop? Mi inclinación es usar un RDBMS porque los datos están estructurados y encajan perfectamente en el modelo relacional. Sin embargo, en cierto momento, entiendo que es posible que ya no pueda usar un RDBMS. ¿Es eso cierto? ¿Cuándo sería necesario este cambio?
- ¿Funcionará? ¿Se pueden ejecutar estas consultas en un tiempo razonable? Puedo esperar quizás horas para la consulta n. ° 1, pero la consulta n. ° 2 debería finalizar en minutos.
- ¿Qué debo considerar desde una perspectiva de hardware? ¿Cuáles son mis cuellos de botella de RAM y CPU? Asumo que mantener índices en RAM es importante. ¿Hay algo más que deba considerar?
- En algún momento, probablemente tendré que particionar mis datos y usar múltiples servidores. ¿Parece que mi caso de uso ya está en esa categoría, o podré escalar una sola máquina verticalmente por un tiempo? ¿Funcionará esto con 10 veces los datos? 100x?
Respuestas:
¿Has intentado acumular más datos y compararlos? 100K filas son intrascendentes. Pruebe 250M o 500M como espera que necesite manejar y ver dónde están los cuellos de botella.
Un RDBMS puede hacer muchas cosas si presta mucha atención a las limitaciones e intenta trabajar con las fortalezas del sistema. Son excepcionalmente buenos en algunas cosas y terribles en otras, por lo que tendrá que experimentar para asegurarse de que encajan bien.
Para algunos trabajos de procesamiento por lotes, realmente no puede vencer a los archivos planos, cargar los datos en la RAM, destruirlos usando una serie de bucles y variables temporales, y descartar los resultados. MySQL nunca podrá igualar ese tipo de velocidad, pero si se ajusta correctamente y se usa correctamente, puede entrar en un orden de magnitud.
Lo que querrá hacer es investigar cómo se pueden particionar sus datos. ¿Tiene un gran conjunto de datos con demasiados enlaces cruzados para poder dividirlo, o hay lugares naturales para dividirlo? Si puede dividirlo, no tendrá una tabla con un montón de filas, sino potencialmente muchas más pequeñas. Las tablas más pequeñas, con índices mucho más pequeños, tienden a funcionar mejor.
Desde una perspectiva de hardware, deberá probar para ver cómo funciona su plataforma. A veces la memoria es esencial. Otras veces es E / S de disco. Realmente depende de lo que esté haciendo con los datos. Deberá prestar mucha atención al uso de su CPU y buscar altos niveles de E / S. Espere para saber dónde radica el problema.
Siempre que sea posible, divida sus datos en múltiples sistemas. Puede usar MySQL Cluster si se siente valiente, o simplemente activar muchas instancias independientes de MySQL donde cada una almacena una porción arbitraria del conjunto de datos completo utilizando algún esquema de partición que tenga sentido.
fuente
Tablas de resumen.
Todos los días, calcule información agregada para los datos del día. Ponga eso en la (s) tabla (s) de "resumen". Haz tus consultas contra ellos. Fácilmente 10 veces más rápido.
Para mayor discusión, por favor proporcione
Algunas cosas obvias ...
"Más pequeño -> más almacenable en caché -> más rápido
fuente
Para servir sus datos de front-end, a menos que haya montones y montones de insertos todo el tiempo, realmente no puede superar el uso de disparadores para insertar en vistas materializadas que se mantienen sincronizadas con el back-end pero optimizadas para servir los datos. Por supuesto, debe mantener las uniones, etc., etc., al mínimo en estos desencadenantes. Una estrategia que he usado es poner estos insertos / actualizaciones en una tabla intermedia y luego enviarlos más tarde cada minuto más o menos. Es mucho más fácil enviar un registro que 4 GB de registros. La transmisión de 4 GB de datos tarda mucho tiempo, incluso si puede encontrar rápidamente los registros que está buscando.
Estoy de acuerdo con tadman. Lo mejor es perfilarlo con el tipo de datos que espera del tipo de sistema que desea.
fuente