La compression des objets sérialisés en Java n'est généralement pas très bonne...
Tout d'abord, il faut comprendre qu'un objet Java contient beaucoup d'informations supplémentaires inutiles. Si vous avez des millions d'objets, vous avez cet surcoût des millions de fois.
Par exemple, prenons une liste doublement chaînée. Chaque élément a un pointeur précédent et suivant + vous stockez une valeur longue (horodatage) + un octet pour le type d'interaction et deux entiers pour les identifiants d'utilisateur. Comme nous utilisons la compression de pointeurs, nous sommes à 6 octets * 2 + 8 + 4 * 2 = 28 octets. Java ajoute 8 octets + 12 octets pour le padding. Cela fait 48 octets par élément.
Créons maintenant 10 millions de listes avec 20 éléments chacune (séries temporelles d'événements de clic des utilisateurs des trois dernières années (nous voulons trouver des motifs)).
Nous avons donc 200 millions * 48 octets d'éléments = 10 Go de mémoire (ok ce n'est pas énorme).
Ok, en plus la collecte des ordures nous étouffe et les surcoûts à l'intérieur de la JDK s'envolent, nous finissons avec 10 Go de mémoire.
Maintenant, utilisons notre propre stockage de mémoire / d'objets. Nous le stockons sous forme de tableau de données en colonnes où chaque objet est en fait une seule ligne. Ainsi, nous avons 200 millions de lignes dans une collection d'horodatage, précédent, suivant, userIdA et userIdB.
Précédent et suivant pointent désormais vers des identifiants de ligne et deviennent 4 octets (ou 5 octets si nous dépassons 4 milliards d'entrées (peu probable)).
Nous avons donc 8 + 4 + 4 + 4 + 4 => 24 * 200 millions = 4,8 Go + aucun problème de GC.
Comme la colonne d'horodatage stocke les horodatages de manière min-max et que nos horodatages se situent tous dans les trois dernières années, nous n'avons besoin que de 5 octets pour stocker chacun des horodatages. Comme les pointeurs sont maintenant stockés de manière relative (+ et -) et que les séries de clics sont temporellement étroitement liées, nous avons besoin en moyenne de 2 octets pour le précédent et le suivant et pour les identifiants d'utilisateur, nous utilisons un dictionnaire car les séries de clics concernent environ 500 000 utilisateurs, nous avons seulement besoin de trois octets chacun.
Ainsi, nous avons maintenant 5 + 2 + 2 + 3 + 3 => 15 * 200 millions => 3 Go + Dictionnaire de 4 * 500k * 4 = 8 Mo = 3 Go + 8 Mo. Ça change de 10 Go, non ?
Mais nous n'avons pas fini. Comme nous n'avons plus d'objets mais des lignes et des données, nous stockons chaque série sous forme de ligne de tableau et utilisons des colonnes spéciales étant des collections de tableaux qui stockent en réalité 5 valeurs et un pointeur vers les cinq valeurs suivantes + un pointeur précédent.
Nous avons donc 10 millions de listes avec 20 entrées chacune (puisque nous avons un surcoût), nous avons par liste 20 * (5 + 3 + 3) + 4 * 6 (ajoutons un surcoût d'éléments partiellement remplis) => 20 * 11 + 5 * 6 => 250 * 10 millions => 2,5 Go + nous pouvons accéder plus rapidement aux tableaux qu'en parcourant les éléments.
Mais ce n'est pas fini... les horodatages sont maintenant stockés de manière relative ne nécessitant que 3 octets par entrée + 5 à la première entrée. -> nous économisons beaucoup plus 20 * 9 + 2 + 5 * 6 => 212 * 10 millions => 2,12 Go. Et maintenant, en stockant le tout en mémoire en utilisant gzip, nous obtenons 1 Go car nous pouvons stocker tout linéairement en premier en stockant la longueur du tableau, tous les horodatages, tous les identifiants d'utilisateur ce qui rend très probable qu'il y ait des motifs dans les bits à compresser. Comme nous utilisons un dictionnaire, nous le trions selon la probabilité de chaque identifiant d'utilisateur de faire partie d'une série.
Et comme tout est un tableau, vous pouvez désérialiser tout à presque vitesse de lecture donc 1 Go sur un SSD moderne coûte 2 secondes pour charger. Essayez cela avec la sérialisation / désérialisation et vous pourrez entendre l'administrateur pleurer.
Donc avant de compresser des données sérialisées, stockez-les dans des tableaux, vérifiez chaque colonne / propriété si elle peut être compressée logiquement. Et enfin, amusez-vous avec cela.
Et rappelez-vous qu'1 To (ECC) coûte 10k aujourd'hui. Ce n'est rien. Et 1 To SSD coûte 340 euros. Ne perdez donc pas votre temps sur ce problème à moins que vous n'ayez vraiment besoin de le faire.