Base de datos NoSQL para series temporales

B

Buenas tardes gentes de la internet. Os leo desde hace tiempo en las sombras y aquí se debaten temas muy interesantes y hay mucha variedad de opiniones, por ello os traigo a colación un asunto al que llevamos un tiempo dando vueltas dentro de mi grupo de desarrollo.

Veréis, estamos capturando gran cantidad de datos a través de una aplicación, del orden de 18.000 paquetes a la hora, son paquetes sencillos compuestos por 5 campos en formato JSON, esto lo almacenamos en mongoDB a través de un servicio en nodeJS (guardaos la bilis, es una versión pre-alfa y fue una demo montada en 3 días literalmente).

Sometimos al sistema a una prueba de estrés de gran calibre y llegamos a la conclusión de que a tomar por culo node (está bien para hacer las cosas rápidas y al estilo gitano pero la cosa se ha puesto seria y vamos a migrar a java toda la API). El tema por el que os escribo no es otro que la base de datos.

Como os digo estamos usando MongoDB para almacenar los paquetes, pero va como el puto culo a día de hoy porque tenemos unos 2 millones y medio de documentos almacenados y estamos realizando consultas con rangos de tiempo (los paquetes llevan incluidos un timestamp y lo usamos para dichas consultas), el caso es que mongo se satura cuando le pedimos los paquetes dentro de un rango, tarde más de un minuto en devolver una consulta.

Antes de que me echéis a los perros esto es así en parte porque la definición del modelo es completa basura, está almacenado todo a cascoporro (se hizo para una hackatón y tenemos que rediseñar todo el sistema), mi consulta por lo tanto es;

Queremos agilizar las consultas y que tarden un tiempo razonable, recomendáis alguna base de datos noSQL que esté especialmente pensada para realizar consultas con series temporales?

Últimamente he escuchado hablar mucho de clickhouse https://clickhouse.yandex/ pero soy un pez en esta materia y no se cómo de bueno es aproximar el problema desde ahí, una base de datos orientada a columnas y noSql con soporte para consultas SQL, un batiburrillo del que no me entero la mitad.

Otra duda que me asalta es, puede mongo soportar de buen grado consultas temporales una vez que rediseñemos el modelo? Esto lo digo porque a la hora de hacer índices la ganancia va a ser muy justa puesto que las consultas van desde los meses hasta los minutos.

RPV: recomendáis alguna base de datos NoSQL para realizar consultas por series temporales?

Un saludo y disculpad el tochopost.

1
LLoid

Qué tal https://www.elastic.co/

1 1 respuesta
Soltrac

Hay algo que no me cuadra....dices que nodejs te da problemas para escribir y lo vas a reescribir en java. Node es muy rápido en concurrencia eh? El problema está en otro sitio.

El otro problema no tiene sentido. 2 millones y medio de documentos es nada. Hasta una base de datos relacional es capaz de buscar en 2 millones y medio de registros muy rápidamente, sobre todo si indexamos por el campo a buscar. Teneis el problema en otro lado.

3 2 respuestas
B

#3 Al contrario, de hecho hemos pensado en dejar el servicio de escritura en node, el problema son las consultas.

Te explico un poco más por poner en contexto el problema, capturamos paquetes a lo largo de las 24 horas del día, consultas un día, tenemos una función que nos devuelve en un json el conteo de los paquetes por horas. Como node es más chulo que un ocho con su asincronía nos va devolviendo las horas como a él le da la gana y en el front no podemos pintar las gráficas hasta que no ha terminado de procesar el último rango. A todo esto es singlethreading y debe estar atendiendo también los paquetes que le llegan.

Si el problema es sin duda alguna como está planteado el esquema, tenemos una colección por cada cliente que nos manda información y metemos ahí todos los paquetes que nos llegan de él. He pensado en reducir las colecciones a días u horas incluso.

Se nota mucho que somos n00bs en este tema, yo de hecho estoy terminando la carrera todavía. Aprendemos a medida que andamos, por eso cualquier ayuda u opinión o tirón de orejas es bien recibido.

#2 guay, le echaré un ojo. Gracias!

1 respuesta
HeXaN

"Nosotros" usamos InfluxDB.

Maldercito

Cuantos documentos os traéis por consulta? Como dice #3 el problema está en otro lado. Cualquier base de datos podría hacer esas querys sin despeinarse si tenéis indexado por fecha. Igual el modelo de tener una colección por cliente no es el método adecuado, sería más rápido hacer una única colección indexada por cliente y fecha.

1
7 días después
Zerokkk

Node es más rápido que Java, vamos, de lejos. No he visto un sólo caso en el que se de lo contrario. Hay herramientas más rápidas para según qué situaciones, pero vamos, que como bien te dicen por ahí arriba, no vas a solucionar gran cosa pasando todo a Java. ¿Has probado a montar varias instancias de Node en cluster, para aprovechar mejor los distintos núcleos de tu sistema?

Por lo que comentas en #4, no sé yo cómo estará el código de vuestro node, suena un poco raro eso de que "os devuelva las horas cuando le da la gana". ¿Hay algún trocito de código que se pueda revisar, para ver si el problema está a nivel de programación?

Porque así a bote pronto... no sé tío, Node + MongoDB son un dúo muy, muy rápido y capaz de escalar a cantidades de información mucho más tochas de las que comentas. Ahora mismo todo suena un poco rarillo. ¿Quizá el servidor sea un poco cutre?

edit: Pero mantennos informados, que me parece una cuestión interesante.

2 respuestas
r2d2rigo

#7 "Node es más rápido que Java, vamos, de lejos.".

Maemia, lo que hay que leer.

"¿Quizá el servidor sea un poco cutre?"

Quiza es que esta usando Mongo para lo que NO se debe usar? Una relacional con los indices bien montados se refollaria a todo lo que tiene montado.

1 respuesta
Zerokkk

#8 No conozco muchos casos de uso donde Java sea más rápido que Node, y mira que Java es mi área y lo que me da de comer, pero las cosas son como son. Es un lenguaje súper robusto y muy capaz, creo que nadie lo niega, pero J2EE NO tiene como objetivo crear servidores rápidos, sino estables, escalables y fácilmente mantenibles.

Hay otras muchas herramientas que corren sobre la JVM que mismamente se follan a Java en velocidad y que también son mejores que Node para según qué función, pero un servidor Node a pelo es considerablemente más rápido en la misma máquina, que un Java a pelo.

Y si no me crees, prueba a demostrar lo contrario. Verás lo que pasa.

#8r2d2rigo:

"¿Quizá el servidor sea un poco cutre?"

Quiza es que esta usando Mongo para lo que NO se debe usar? Una relacional con los indices bien montados se refollaria a todo lo que tiene montado.

Esto supongo que depende de qué datos está guardando y cómo los está indexando, pero vamos que cualquier bbdd No-SQL moderna, suele ser bastante más rápida devolviendo datos que las relacionales, para casi cualquier caso. Otra cosa es que sea más fácil, sencillo, escalable, mantenible e incluso rápido para gestionar consultas complejas, usar una relacional. Eso no te lo voy a negar, hay muchos casos en los que así es. Pero la realidad es que para casi cualquier caso práctico, NoSQL > SQL en cuanto a velocidad, incluso cuando se les meten interpretadores SQL, fíjate tú xD.

El amor que le tenéis algunos a las tecnologías viejas no deja de sorprenderme, cuando cada vez más empresas tochas que manejan miles de veces más datos que nosotros, se van pasando poco a poco a Node y Go, y cambian sus bbdd relaciones por No-SQL... en fin, yo sigo esperando razones reales y datos de verdad.

1 respuesta
B

#7 Ahí está el quid del problema.

Repito hasta la saciedad que el código es puta porquería, más que nada para que no me eché a los perros.

Está disponible en https://github.com/CompadreHackTeam/Hermes

Y el fragmento de código responsable de la lentitud de la respuesta es una llamada recursiva que devuelve el numero de paquetes por franjas horarias

function iteratorSearch(i, plusHourDate, nextDate, arrayJsonObject, clientCollection,callback) {
    var jsonObject = {};

if (i == 0) {
    callback(null,arrayJsonObject);
} else {
    //Hacer la primera consulta tal y como viene, luego se añade una hora en la siguiente iteracion
    clientCollection.distinct("mac",
        {
            "date": {
                '$gte': plusHourDate,
                '$lt': nextDate
            }
        }, function (err, obj) {
            if (err != null)
                callback(err,null);
            else {
                //concatenar al json magico
                jsonObject.fhour = getWellTime(plusHourDate);
                jsonObject.clients = obj.length;

                arrayJsonObject.push(jsonObject);
                console.log(jsonObject);

                plusHourDate.setHours(plusHourDate.getHours() + 1);
                nextDate.setHours(nextDate.getHours() + 1);

                iteratorSearch(i - 1, plusHourDate, nextDate, arrayJsonObject, clientCollection,callback);
            }
        });
}
}

https://github.com/CompadreHackTeam/Hermes/blob/master/repository/PacketRepository.js

Esa es la madre del cordero, pero esa función se escribió después de 16 horas de curro a las 3 de la mañana.

A parte, al final el objetivo es reducir el numero de documentos que traemos de mongo por consulta

1 respuesta
Zerokkk

#10 WTF, no uséis llamadas recursivas en JS!

Nunca, nunca, nunca uses llamadas recursivas en JS. Es una de sus debilidades, pues no tiene Tail Recursion Optimization. Además de que es mejor (y más limpio) que useis promises que andarse con callbacks. Con las últimas versiones de Node incluso os podéis permitir usar el async/await, búscalo que es facilito de usar y queda muy legible.

1
HeXaN
#9Zerokkk:

yo sigo esperando razones reales y datos de verdad.

El problema es que tú en lo único que piensas es en webs normales y corrientes, aquí quiere trabajar con series temporales y hay mejores opciones que Node, Mongo y las cosas que siempre dices.

1 respuesta
Zerokkk

#12 Y seguramente tengas razón, ciertamente yo desconozco qué soluciones serán mejores para este caso concreto, pero vamos que como ya se ha visto, aquí el problema es una mala implementación más que una pobre decisión de tecnologías a utilizar.

Por curiosidad, ¿qué bbdd usarías para un caso como este, y por qué? ¿InfluxDB, por qué?

1 respuesta
HeXaN
#13Zerokkk:

¿InfluxDB, por qué?

Porque está creada específicamente para series temporales. Escala a millones de escrituras por segundo, te facilita la compresión y borrado de los datos antiguos, consultas en tiempo real de los datos que insertas, soporta OpenTSDB, está escrita en un lenguaje de verdad (Go) y varios detalles más que te facilitan el trabajo con series temporales.

1 1 respuesta
Starshow

Nosotros en un proyecto que estuvimos trabajando necesitabamos usar especificamente series temporales. Tras malgastar casi 10-12 días haciendo el ganso en Node y Mongo, un compañero nos recomendó InfluxDB ( tal como aconseja #14 ) y es CREMA, está implementado por y para series temporales , y es un jodida delicia, así que darle un try que no es dificil y os va a solucionar la papeleta sobremanera.

Usuarios habituales