La compresión de objetos buscados en Java generalmente no es buena ... no tan buena.
Antes que nada, debe comprender que un objeto Java tiene mucha información adicional que no es necesaria. Si tiene millones de objetos, tiene esta sobrecarga millones de veces.
Como ejemplo, nos permite una lista de doble enlace. Cada elemento tiene un puntero anterior y uno siguiente + almacena un valor largo (marca de tiempo) + byte para el tipo de interacción y dos enteros para los identificadores de usuario. Como usamos la compresión del puntero, somos 6Bytes * 2 + 8 + 4 * 2 = 28Bytes. Java agrega 8 Bytes + 12bytes para el relleno. Esto hace 48Bytes por Elemento.
Ahora creamos 10 millones de listas con 20 elementos cada una (serie temporal de eventos de clic de los usuarios durante los últimos tres años (queremos encontrar patrones)).
Así que tenemos 200Million * 48 Bytes de elementos = 10GB de memoria (bueno, no mucho).
Aceptar junto a la recolección de basura nos mata y la sobrecarga dentro de los skyrocks JDK, terminamos con 10 GB de memoria.
Ahora permitamos usar nuestro propio almacenamiento de memoria/objeto. Lo almacenamos como una tabla de datos en columnas donde cada objeto es en realidad una sola fila. Así que tenemos 200 millones de filas en una marca de tiempo, anterior, siguiente, colección de userIdA y userIdB.
Anterior y siguiente ahora son ID de fila a fila y se convierten en 4 bytes (o 5 bytes si excedemos las 4 billones de entradas (poco probable)).
Así que tenemos 8 + 4 + 4 + 4 + 4 => 24 * 200 Mio = 4.8GB + sin problema de GC.
Dado que la columna de marca de tiempo almacena las marcas de tiempo de forma mínima y nuestras marcas de tiempo están dentro de los tres años, solo necesitamos 5 bytes para almacenar cada una de las marcas de tiempo. Dado que el puntero ahora está almacenado relativo (+ y -) y debido a que las series de clic están estrechamente relacionadas oportunamente, solo necesitamos 2 bytes en promedio tanto para el anterior como para el siguiente y para los identificadores de usuario usamos un diccionario ya que la serie de clic es para aproximadamente 500k usuarios solo necesitamos tres bytes cada uno.
Así que ahora tenemos 5 + 2 + 2 + 3 + 3 => 15 * 200Mio => 3GB + Diccionario de 4 * 500k * 4 = 8MB = 3GB + 8MB. Suena diferente a 10GB ¿verdad?
Pero todavía no hemos terminado. Como ahora no tenemos más objetos que filas y datos, almacenamos cada serie como una fila de tabla y usamos columnas especiales que son colecciones de matriz que en realidad almacenan 5 valores y un puntero a los siguientes cinco valores + un puntero anterior.
Tenemos listas de 10Mio con 20 enries cada uno (ya que tenemos gastos generales), tenemos por lista 20 * (5 + 3 + 3) + 4 * 6 (vamos a agregar algunos gastos generales de elementos parcialmente llenos) => 20 * 11 + 5 * 6 => 250 * 10Mio => 2,5 GB + podemos acceder a las matrices más rápido que los elementos que caminan.
Pero bueno, no ha terminado aún ... las indicaciones de fecha y hora están ahora relativamente almacenadas y solo requieren 3 bytes por entrada + 5 en la primera entrada. -> entonces ahorramos mucho más 20 * 9 + 2 + 5 * 6 => 212 * 10Mio => 2,12 GB. Y ahora lo guardamos todo en la memoria usando gzip it y da como resultado 1GB ya que podemos almacenarlo todo lineal primero almacenando la longitud de la matriz, todas las marcas de tiempo, todos los identificadores de usuario, lo que hace muy recomendable que haya patrones en los bits para ser comprimibles . Como utilizamos un diccionario, simplemente lo clasificamos de acuerdo con la capacidad de propagación de cada ID de usuario para formar parte de una serie.
Y como todo es una tabla, puedes deserializar todo en velocidad casi de lectura, por lo que 1GB en una SSD moderna cuesta 2 segundos para cargar. Pruebe esto con la serialización/deserialización y puede escuchar llorar al usuario interno.
Por lo tanto, antes de comprimir los datos serializados, almacenarlos en tablas, verificar cada columna/propiedad si se puede comprimir lógicamente. Y finalmente diviértete con eso.
Y recuerda que 1TB (ECC) costó 10k hoy. No es nada. Y 1TB SSD 340 Euro. Así que no pierdas tu tiempo en ese tema a menos que realmente tengas que hacerlo.
java.util.Date no ocupa más que unas pocas palabras de memoria. ¿Estás seguro de que comprimirlo es beneficioso? –
Una pregunta que debe hacerse: ¿por qué comprimir estos objetos en la memoria en lugar de escribirlos en el disco (por ejemplo, un archivo de memoria asignada)? El sistema de archivos simplemente se puede ver como una extensión de la jerarquía de la memoria (es decir, caché L1, caché L2, RAM, disco) con tiempos de acceso más lentos. Podría considerar almacenar en memoria caché los objetos usados recientemente en la memoria mientras vaciando el resto en el disco. Las bibliotecas como Berkeley DB ofrecen esta funcionalidad. – Adamski
Escribirlos en el disco no es una opción, ya que estamos muy preocupados por el rendimiento (por lo tanto, mantenerlos todos en la memoria). – Kichu