Question

Pour la mise en cache que je pense faire pour un projet à venir, je pensais à la sérialisation Java. À savoir, devrait-il être utilisé?

Maintenant, j’ai écrit précédemment la sérialisation et la désérialisation personnalisées (Externalizable) pour diverses raisons au cours des dernières années. De nos jours, l’interopérabilité est devenue un problème encore plus important et, comme je pouvais prévoir un besoin d’interaction avec les applications .Net, j’ai donc pensé à utiliser une solution indépendante de la plate-forme.

Quelqu'un a-t-il déjà utilisé des GPB à haute performance? Comment se compare-t-il en termes de rapidité et d'efficacité à la sérialisation native de Java? Existe-t-il d’autres solutions intéressantes?

Était-ce utile?

La solution

Je n'ai pas comparé les tampons de protocole avec la sérialisation native de Java en termes de vitesse, mais pour des raisons d'interopérabilité, la sérialisation native de Java est un non sérieux. En outre, l'espace ne sera pas aussi efficace que les tampons de protocole dans la plupart des cas. Bien sûr, il est un peu plus flexible en termes de capacité de stockage, de références, etc. Les tampons de protocole conviennent très bien, et quand cela répond à vos besoins, il est génial - mais il existe des restrictions évidentes liées à l'interopérabilité. (et d'autres choses).

J'ai récemment publié un cadre d'analyse comparative pour les tampons de protocole en Java et .NET. La version Java est dans le projet Google principal (dans le répertoire de benchmarks ), la version .NET est en mon projet de port C # . Si vous souhaitez comparer la vitesse PB à la vitesse de sérialisation Java, vous pouvez écrire des classes similaires et les comparer. Toutefois, si vous êtes intéressé par l’interopérabilité, je ne donnerais pas une seconde pensée à la sérialisation native Java (ou à la sérialisation binaire native .NET).

Il existe d'autres options de sérialisation interopérables que les tampons de protocole - Thrift , JSON et YAML me vient à l’esprit, et il y en a sans doute d’autres.

EDIT: D'accord, l'interopérabilité n'étant pas si importante, il est intéressant d'essayer de répertorier les différentes qualités souhaitées dans un cadre de sérialisation. Une des choses à laquelle vous devriez penser est la gestion des versions - c’est une autre chose que PB est conçu pour gérer correctement, à la fois en amont et en aval (afin que les nouveaux logiciels puissent lire les anciennes données et vice versa) - lorsque vous vous en tenez aux règles suggérées, bien sûr :)

Ayant essayé d’être prudent sur les performances Java par rapport à la sérialisation native, je ne serais vraiment pas surpris de constater que PB était plus rapide de toute façon. Si vous en avez la possibilité, utilisez le serveur vm. Mes derniers tests ont montré que la machine virtuelle serveur était deux fois plus rapide pour la sérialisation et la désérialisation des exemples de données. Je pense que le code PB convient très bien au JIT de la machine virtuelle du serveur:)

Juste comme exemple de performance, sérialisation et désérialisation de deux messages (un de 228 octets, un de 84750 octets), j'ai obtenu ces résultats sur mon ordinateur portable à l'aide de la machine virtuelle du serveur:

Benchmarking benchmarks.GoogleSize$SizeMessage1 with file google_message1.dat 
Serialize to byte string: 2581851 iterations in 30.16s; 18.613789MB/s 
Serialize to byte array: 2583547 iterations in 29.842s; 18.824497MB/s 
Serialize to memory stream: 2210320 iterations in 30.125s; 15.953759MB/s 
Deserialize from byte string: 3356517 iterations in 30.088s; 24.256632MB/s 
Deserialize from byte array: 3356517 iterations in 29.958s; 24.361889MB/s 
Deserialize from memory stream: 2618821 iterations in 29.821s; 19.094952MB/s 

Benchmarking benchmarks.GoogleSpeed$SpeedMessage1 with file google_message1.dat 
Serialize to byte string: 17068518 iterations in 29.978s; 123.802124MB/s 
Serialize to byte array: 17520066 iterations in 30.043s; 126.802376MB/s 
Serialize to memory stream: 7736665 iterations in 30.076s; 55.93307MB/s 
Deserialize from byte string: 16123669 iterations in 30.073s; 116.57947MB/s 
Deserialize from byte array: 16082453 iterations in 30.109s; 116.14243MB/s
Deserialize from memory stream: 7496968 iterations in 30.03s; 54.283176MB/s 

Benchmarking benchmarks.GoogleSize$SizeMessage2 with file google_message2.dat 
Serialize to byte string: 6266 iterations in 30.034s; 16.826494MB/s 
Serialize to byte array: 6246 iterations in 30.027s; 16.776697MB/s 
Serialize to memory stream: 6042 iterations in 29.916s; 16.288969MB/s 
Deserialize from byte string: 4675 iterations in 29.819s; 12.644595MB/s 
Deserialize from byte array: 4694 iterations in 30.093s; 12.580387MB/s 
Deserialize from memory stream: 4544 iterations in 29.579s; 12.389998MB/s 

Benchmarking benchmarks.GoogleSpeed$SpeedMessage2 with file google_message2.dat 
Serialize to byte string: 39562 iterations in 30.055s; 106.16416MB/s 
Serialize to byte array: 39715 iterations in 30.178s; 106.14035MB/s 
Serialize to memory stream: 34161 iterations in 30.032s; 91.74085MB/s 
Deserialize from byte string: 36934 iterations in 29.794s; 99.98019MB/s 
Deserialize from byte array: 37191 iterations in 29.915s; 100.26867MB/s 
Deserialize from memory stream: 36237 iterations in 29.846s; 97.92251MB/s 

La " vitesse " vs " taille " est si le code généré est optimisé pour la vitesse ou la taille du code. (Les données sérialisées sont les mêmes dans les deux cas. La version "taille" est fournie dans le cas où beaucoup de messages sont définis et que vous ne souhaitez pas utiliser trop de mémoire pour le code.)

Comme vous pouvez le constater, le message le plus petit peut être très rapide - plus de 500 petits messages sérialisés ou désérialisés par milliseconde . Même avec le message 87K, cela prend moins d’une milliseconde par message.

Autres conseils

Un autre point de données: ce projet:

http://code.google.com/p/thrift-protobuf-compare /

donne une idée des performances attendues pour les petits objets, y compris la sérialisation Java sur PB.

Les résultats varient beaucoup en fonction de votre plate-forme, mais certaines tendances générales se dégagent.

Vous pouvez également consulter FST , une solution de remplacement pour les applications intégrées. dans la sérialisation JDK, cela devrait être plus rapide et avoir une sortie plus petite.

estimations brutes sur l'analyse comparative que j'ai faite au cours des dernières années:

100% = approches basées sur les binaires / structures (par exemple, SBE, fst-structs)

  • gênant
  • le post-traitement (mise en place d'objectifs "réels" du côté du récepteur) peut réduire les avantages en termes de performances et n'est jamais inclus dans les tests de performance

~ 10% -35% protobuf & amp; dérivés

~ 10% à 30% de sérialiseurs rapides tels que FST et KRYO

  • Les objets désérialisés pratiques peuvent être utilisés le plus souvent directement sans code de traduction manuelle supplémentaire.
  • peut être corrigé pour améliorer les performances (annotations, enregistrement de classe)
  • conserve les liens dans le graphe d'objet (aucun objet n'est sérialisé deux fois)
  • peut gérer les structures cycliques
  • solution générique, FST est entièrement compatible avec la sérialisation JDK

~ 2% à 15% de sérialisation JDK

~ 1% à 15% rapide JSon (par exemple, Jackson)

  • ne peut gérer aucun graphe d'objet, mais seulement un petit sous-ensemble de structures de données java
  • pas de référence de restauration

Graphique complet JSon / XML compris entre 0,001 et 1% (par exemple, JSON.io)

Ces chiffres sont censés donner une impression très grossière d'ordre de grandeur. Notez que les performances dépendent BEAUCOUP des structures de données en cours de sérialisation / benchmark. Ainsi, les tests de performances de classes simples sont pour la plupart inutiles (mais populaires: ignorer unicode, pas de collections, etc.).

voir aussi

http://java-is-the-new-c.blogspot.de/2014/12/a-persistent-keyvalue-server-in-40.html

http: //java-is-the-new-c.blogspot.de/2013/10/still-using-externalizable-to-get.html

Si vous confondez PB & amp; la sérialisation java native sur la vitesse et l'efficacité, il suffit d'aller pour PB.

  • PB a été conçu pour atteindre de tels facteurs. Voir http://code.google.com/apis/protocolbuffers/docs/overview. html
  • Les données PB sont très petites, alors que la sérialisation Java a tendance à répliquer un objet entier, y compris sa signature. Pourquoi ai-je toujours mon nom de classe, mon nom de champ ... sérialisé, même si je le connais à fond au destinataire?
  • Pensez au développement du langage. Cela devient difficile si un côté utilise Java, un autre utilise C ++ ...

Certains développeurs suggèrent Thrift, mais j’utiliserais Google PB car "je crois en Google". :-) .. Quoi qu'il en soit, ça vaut le coup d'oeil: http://stuartsierra.com/2008/07/10/thrift-vs tampons de protocole

Qu'entendez-vous par haute performance? Si vous voulez une sérialisation de quelques secondes, je vous suggère d'utiliser l'approche de la sérialisation qui est la plus simple. Si vous voulez une vitesse inférieure à une milliseconde, vous aurez probablement besoin d’un format binaire. Si vous voulez beaucoup moins de 10 microsecondes, vous aurez probablement besoin d'une sérialisation personnalisée.

Je n'ai pas vu beaucoup de points de repère pour la sérialisation / désérialisation, mais peu prennent en charge moins de 200 micro-secondes pour la sérialisation / désérialisation.

Les formats indépendants de la plate-forme ont un coût (en efforts de votre part et en temps de latence). Vous devrez peut-être décider si vous souhaitez des performances ou une indépendance de la plate-forme. Cependant, il n'y a aucune raison pour que vous ne puissiez pas utiliser les deux comme option de configuration, dans laquelle vous pouvez basculer selon les besoins.

Voici la suggestion du jour qui passe au mur :-) (vous venez d'ajuster quelque chose dans ma tête que je veux maintenant essayer) ...

Si vous pouvez utiliser l'ensemble de la solution de mise en cache, cela pourrait fonctionner: Projet Darkstar . Il est conçu comme un serveur de jeu à très hautes performances, spécialement pour que les lectures soient rapides (bon pour un cache). Il possède des API Java et C, donc je pense (je pensais que cela faisait longtemps et je n'y pensais pas à ce moment-là) qu'il était possible de sauvegarder des objets avec Java et de les relire en C et inversement.

Si rien d’autre, ça vous donnera quelque chose à lire aujourd’hui: -)

Pour une sérialisation conviviale, envisagez d'utiliser l'interface Externalizable. Utilisé intelligemment, vous aurez un savoir intime pour décider comment utiliser au mieux les champs spécifiques marshall et unmarshall. Cela dit, vous devrez gérer le versioning de chaque objet correctement - facile à décomposer, mais réorganiser un objet V2 lorsque votre code prend en charge V1 peut soit casser, soit perdre des informations, soit altérer les données corrompues, de manière à ce que vos applications ne sont pas capables de traiter correctement. Si vous recherchez un chemin optimal, méfiez-vous, aucune bibliothèque ne résoudra votre problème sans compromis. Généralement, les bibliothèques conviennent à la plupart des cas d'utilisation et présentent l'avantage supplémentaire de s'adapter et de s'améliorer au fil du temps sans votre participation, si vous avez opté pour un projet open source actif. Et ils pourraient ajouter des problèmes de performances, introduire des bugs et même corriger des bugs qui ne vous ont pas encore affecté!

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top