Domanda

Per un po 'di cache che sto pensando di fare per un prossimo progetto, ho pensato alla serializzazione Java. Vale a dire, dovrebbe essere usato?

Ora ho precedentemente scritto serializzazione e deserializzazione personalizzate (esternalizzabili) per vari motivi negli anni passati. In questi giorni l'interoperabilità è diventata ancora più un problema e posso prevedere la necessità di interagire con le applicazioni .Net, quindi ho pensato di utilizzare una soluzione indipendente dalla piattaforma.

Qualcuno ha avuto esperienza con l'uso ad alte prestazioni di GPB? Come si confronta in termini di velocità ed efficienza con la serializzazione nativa di Java? In alternativa, ci sono altri schemi che vale la pena considerare?

È stato utile?

Soluzione

Non ho confrontato i buffer di protocollo con la serializzazione nativa di Java in termini di velocità, ma per l'interoperabilità la serializzazione nativa di Java è un no-no serio. Nella maggior parte dei casi, non sarà altrettanto efficiente in termini di spazio quanto i buffer di protocollo. Naturalmente, è un po 'più flessibile in termini di ciò che può archiviare, e in termini di riferimenti, ecc. Protocol Buffers è molto bravo in quello a cui è destinato, e quando si adatta alle tue esigenze è grande - ma ci sono ovvie restrizioni dovute all'interoperabilità (e altre cose).

Di recente ho pubblicato un framework di benchmarking Protocol Buffers in Java e .NET. La versione Java è nel progetto principale di Google (nel directory benchmarks ), la versione .NET è in il mio progetto di porta C # . Se si desidera confrontare la velocità PB con la velocità di serializzazione Java, è possibile scrivere classi simili e confrontarle. Se sei interessato all'interoperabilità, non darei un secondo pensiero alla serializzazione Java nativa (o serializzazione binaria nativa .NET).

Esistono altre opzioni per la serializzazione interoperabile oltre ai buffer di protocollo - Thrift , JSON e YAML mi viene in mente, e ce ne sono senza dubbio altri.

EDIT: Ok, con l'interoperabilità non è così importante, vale la pena provare a elencare le diverse qualità che desideri da un framework di serializzazione. Una cosa a cui dovresti pensare è il controllo delle versioni - questa è un'altra cosa che PB è progettata per gestire bene, sia all'indietro che in avanti (quindi il nuovo software può leggere i vecchi dati e viceversa) - quando ti attieni alle regole suggerite, ovviamente :)

Avendo cercato di essere cauti sulle prestazioni Java rispetto alla serializzazione nativa, non sarei davvero sorpreso di scoprire che PB era comunque più veloce. Se ne hai la possibilità, usa il server VM - i miei recenti benchmark hanno mostrato che la VM del server è due volte più veloce nel serializzare e deserializzare i dati di esempio. Penso che il codice PB si adatti perfettamente al JIT della VM del server :)

Proprio come i dati prestazionali di esempio, serializzando e deserializzando due messaggi (uno 228 byte, uno 84750 byte) ho ottenuto questi risultati sul mio laptop usando la VM del server:

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 "velocità" vs "dimensione" indica se il codice generato è ottimizzato per la velocità o la dimensione del codice. (I dati serializzati sono gli stessi in entrambi i casi. La versione "size" è fornita nel caso in cui siano stati definiti molti messaggi e non si desideri occupare molta memoria per il codice.)

Come puoi vedere, per il messaggio più piccolo può essere molto veloce - oltre 500 piccoli messaggi serializzati o deserializzati per millisecondo . Anche con il messaggio 87K ci vuole meno di un millisecondo per messaggio.

Altri suggerimenti

Un altro punto dati: questo progetto:

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

dà un'idea delle prestazioni previste per piccoli oggetti, inclusa la serializzazione Java su PB.

I risultati variano molto a seconda della piattaforma, ma ci sono alcune tendenze generali.

Potresti anche dare un'occhiata a FST , un sostituto drop-in per build- nella serializzazione JDK che dovrebbe essere più veloce e avere un output più piccolo.

stime grezze sul frequente benchmarking che ho fatto negli ultimi anni:

100% = approcci basati su binari / struct (ad esempio SBE, fst-struct)

  • scomodo
  • il postprocessing (accumulo di "obbiettivi reali" sul lato ricevente) può comportare vantaggi in termini di prestazioni e non è mai incluso nei benchmark

~ 10% -35% protobuf & amp; derivati ??

~ 10% -30% serializzatori veloci come FST e KRYO

  • oggetti convenienti e deserializzati possono essere usati il ??più delle volte direttamente senza un codice di traduzione manuale aggiuntivo.
  • può essere sfruttato per l'esecuzione (annotazioni, registrazione di classe)
  • conserva i collegamenti nel grafico degli oggetti (nessun oggetto serializzato due volte)
  • può gestire strutture cicliche
  • soluzione generica, FST è pienamente compatibile con la serializzazione JDK

~ 2% -15% serializzazione JDK

~ 1% -15% JSon veloce (ad esempio Jackson)

  • non è in grado di gestire alcun oggetto grafico ma solo un piccolo sottoinsieme di strutture di dati Java
  • nessun ripristino ref

0,001-1% grafico completo JSon / XML (ad esempio JSON.io)

Questi numeri hanno lo scopo di dare un'impressione di ordine di grandezza molto approssimativa. Si noti che le prestazioni dipendono MOLTO dalle strutture dati serializzate / confrontate. Quindi i benchmark di singole classi semplici sono per lo più inutili (ma popolari: ad esempio ignorando unicode, nessuna raccolta, ..).

vedi anche

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

Se stai confondendo tra PB e amp; serializzazione java nativa su velocità ed efficienza, scegli PB.

  • PB è stato progettato per raggiungere tali fattori. Vedi http://code.google.com/apis/protocolbuffers/docs/overview. html
  • I dati PB sono molto piccoli mentre la serializzazione Java tende a replicare un intero oggetto, inclusa la sua firma. Perché ricevo sempre il nome della mia classe, il nome del campo ... serializzato, anche se lo conosco perfettamente al ricevitore?
  • Pensa allo sviluppo del linguaggio. Sta diventando difficile se una parte usa Java, una parte usa C ++ ...

Alcuni sviluppatori suggeriscono Thrift, ma vorrei utilizzare Google PB perché " Credo in google " :-) .. Ad ogni modo, vale la pena dare un'occhiata: http://stuartsierra.com/2008/07/10/thrift-vs -Protocollo-buffer

Cosa intendi per alte prestazioni? Se si desidera la serializzazione di milli-secondo, suggerisco di utilizzare l'approccio di serializzazione che è più semplice. Se si desidera sub milli-secondi, è probabile che sia necessario un formato binario. Se desideri molto meno di 10 micro-secondi, probabilmente avrai bisogno di una serializzazione personalizzata.

Non ho visto molti parametri di riferimento per la serializzazione / deserializzazione, ma pochi supportano meno di 200 micro-secondi per la serializzazione / deserializzazione.

I formati indipendenti dalla piattaforma hanno un costo (nello sforzo da parte tua e nella latenza) potresti dover decidere se vuoi prestazioni o indipendenza della piattaforma. Tuttavia, non vi è alcun motivo per cui non è possibile avere entrambi come opzione di configurazione tra cui passare come richiesto.

Ecco il suggerimento off the wall del giorno :-) (hai appena modificato qualcosa nella mia testa che ora voglio provare) ...

Se puoi cercare l'intera soluzione di memorizzazione nella cache tramite questa, potrebbe funzionare: Project Darkstar . È progettato come un server di gioco ad altissime prestazioni, in particolare in modo che le letture siano veloci (quindi buono per una cache). Ha API Java e C, quindi credo (ho pensato che fosse da tanto tempo che non lo guardavo, e non ci pensavo allora) che potresti salvare oggetti con Java e rileggerli in C e viceversa.

Se non altro ti darà qualcosa da leggere oggi :-)

Per una serializzazione intuitiva, è consigliabile utilizzare l'interfaccia Externalizable. Utilizzato in modo intelligente, avrai una conoscenza intima per decidere come eseguire il marshalling e lo smascheramento di campi specifici in modo ottimale. Detto questo, dovrai gestire correttamente il controllo delle versioni di ogni oggetto: facile da smontare, ma il re-marshalling di un oggetto V2 quando il tuo codice supporta V1 interromperà, perderà informazioni o peggiorerà i dati corrotti in un modo che le tue app non sono in grado di elaborare correttamente. Se stai cercando un percorso ottimale, attenzione che nessuna libreria risolverà il tuo problema senza alcuni compromessi. Generalmente le biblioteche si adatteranno alla maggior parte dei casi d'uso e avranno il vantaggio aggiuntivo che si adatteranno e miglioreranno nel tempo senza il tuo contributo, se hai optato per un progetto open source attivo. E potrebbero aggiungere problemi di prestazioni, introdurre bug e persino correggere bug che non ti hanno ancora influenzato!

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top