Quali sono le principali differenze tra Apache Thrift, Google Protocol Buffers, MessagePack, ASN.1 e Apache Avro?


124

Tutti questi forniscono serializzazione binaria, framework RPC e IDL. Sono interessato alle differenze chiave tra loro e alle caratteristiche (prestazioni, facilità d'uso, supporto dei linguaggi di programmazione).

Se conosci altre tecnologie simili, menzionalo in una risposta.



@Zenikoder: questo collegamento non contiene informazioni per 2 dei 5 formati interrogati.
SOLO LA MIA OPINIONE corretta


2
per coloro che non conoscono RPC - Remote Prodecure Call, IDL - Interface Definition language
garg10may

Risposte:


97

ASN.1 è uno standard ISO / ISE. Ha un linguaggio sorgente molto leggibile e una varietà di back-end, sia binari che leggibili dall'uomo. Essendo uno standard internazionale (e anche vecchio!) La lingua di partenza è un po 'affondata da cucina (più o meno allo stesso modo in cui l'Oceano Atlantico è un po' umido) ma è estremamente ben specificato e ha una discreta quantità di supporto . (Probabilmente puoi trovare una libreria ASN.1 per qualsiasi lingua tu chiami se scavi abbastanza a fondo, e in caso contrario ci sono buone librerie di linguaggio C disponibili che puoi usare in FFIs.) Essendo un linguaggio standardizzato, è ossessivamente documentato e ha anche alcuni buoni tutorial disponibili.

La parsimonia non è uno standard. È originariamente di Facebook ed è stato successivamente reso open source ed è attualmente un progetto Apache di primo livello. Non è ben documentato - in particolare i livelli di tutorial - e al mio sguardo (certamente breve) non sembra aggiungere nulla che altri sforzi precedenti non fanno già (e in alcuni casi meglio). Per essere onesti, ha un numero piuttosto impressionante di lingue che supporta immediatamente, incluse alcune di quelle non tradizionali di alto profilo. L'IDL è anche vagamente simile a un C.

Protocol Buffers non è uno standard. È un prodotto Google che viene rilasciato alla comunità più ampia. È un po 'limitato in termini di linguaggi supportati immediatamente (supporta solo C ++, Python e Java) ma ha molto supporto di terze parti per altri linguaggi (di qualità altamente variabile). Google fa praticamente tutto il loro lavoro utilizzando i buffer di protocollo, quindi è un protocollo testato in battaglia e indurito in battaglia (anche se non così indurito come ASN.1. Ha una documentazione molto migliore di Thrift, ma, essendo un Prodotto Google, è molto probabile che sia instabile (nel senso di in continua evoluzione, non nel senso di inaffidabile). Anche l'IDL è simile al C.

Tutti i sistemi di cui sopra utilizzano uno schema definito in una sorta di IDL per generare codice per una lingua di destinazione che viene quindi utilizzata nella codifica e decodifica. Avro no. La tipizzazione di Avro è dinamica ei suoi dati dello schema vengono utilizzati in fase di esecuzione direttamente sia per codificare che per decodificare (il che ha alcuni ovvi costi di elaborazione, ma anche alcuni ovvi vantaggi rispetto ai linguaggi dinamici e la mancanza di una necessità per i tipi di tagging, ecc.) . Il suo schema utilizza JSON che rende il supporto di Avro in una nuova lingua un po 'più facile da gestire se esiste già una libreria JSON. Di nuovo, come con la maggior parte dei sistemi di descrizione dei protocolli che reinventano la ruota, anche Avro non è standardizzato.

Personalmente, nonostante il mio rapporto di amore / odio con esso, probabilmente userei ASN.1 per la maggior parte degli scopi di trasmissione di messaggi e RPC, sebbene non abbia davvero uno stack RPC (dovresti crearne uno, ma i CIO lo fanno abbastanza semplice).


3
Grazie per la spiegazione dettagliata. Ma per quanto riguarda il controllo delle versioni, ho sentito che protobuf è in grado di gestirlo, per quanto riguarda le altre librerie e come è utilizzabile in comune? Inoltre, sembra che Avro ora abbia IDL con sintassi simile a C oltre a quella JSON.
andreypopp

2
ASN.1 supporta il controllo manuale delle versioni tramite i ...marcatori di estensione o automatico EXTENSIBILITY IMPLIEDnell'intestazione del modulo. Protocol Buffers, IIRC, supporta il controllo manuale delle versioni. Non so se supporta qualcosa come l'estensibilità implicita (e sono troppo pigro per cercarlo). Thrift supporta anche un po 'di controllo delle versioni, ma ancora una volta mi colpisce come un processo manuale senza l'estensibilità implicita.
SOLO LA MIA OPINIONE corretta

7
Per la cronaca, i buffer di protocollo codificano sempre in modo esplicito i campi in base ai numeri e non è mai un errore a livello di libreria se sono presenti campi aggiuntivi e i campi mancanti non sono un errore se sono contrassegnati come facoltativi o espliciti. Quindi tutti i messaggi di buffer di protocollo hanno EXTENSIBILITY IMPLIED.
Kevin Cathcart

per IOC - intendi l'inversione del controllo? cosa si userebbe per lo stack RPC in PHP, qualcosa come l'estensione XML-RPC? o uno dovrebbe scrivere qualcosa da solo?
Stann

4
Avro è più flessibile perché consente di lavorare dinamicamente su schemi definiti o di generare classi boilerplate. Dalla mia esperienza, è molto potente: il suo punto di forza risiede nel suo ricco set di funzionalità, incluso il generatore RPC (questa è una caratteristica comune a Thrift).
Paolo Maresca

38

Abbiamo appena fatto uno studio interno sui serializzatori, ecco alcuni risultati (anche per mio futuro riferimento!)

Risparmio = serializzazione + stack RPC

La differenza più grande è che Thrift non è solo un protocollo di serializzazione, è uno stack RPC completo che è come uno stack SOAP moderno. Quindi, dopo la serializzazione, gli oggetti potrebbero (ma non obbligatori) essere inviati tra macchine su TCP / IP. In SOAP, si è iniziato con un documento WSDL che descrive completamente i servizi disponibili (metodi remoti) e gli argomenti / oggetti previsti. Questi oggetti sono stati inviati tramite XML. In Thrift, il file .thrift descrive completamente i metodi disponibili, gli oggetti dei parametri previsti e gli oggetti vengono serializzati tramite uno dei serializzatori disponibili (con Compact Protocolun protocollo binario efficiente, essendo il più popolare nella produzione).

ASN.1 = Nonno

ASN.1 è stato progettato da persone delle telecomunicazioni negli anni '80 ed è scomodo da usare a causa del supporto limitato delle librerie rispetto ai recenti serializzatori emersi da CompSci. Esistono due varianti, la codifica DER (binaria) e la codifica PEM (ascii). Entrambi sono veloci, ma DER è più veloce e più efficiente in termini di dimensioni dei due. In effetti ASN.1 DER può facilmente tenere il passo (e talvolta battere) i serializzatori progettati per 30 annidopo di sé, una testimonianza del suo design ben progettato. È molto compatto, più piccolo di Protocol Buffers e Thrift, battuto solo da Avro. Il problema è avere ottime librerie da supportare e in questo momento Bouncy Castle sembra essere il migliore per C # / Java. ASN.1 è il re dei sistemi di sicurezza e crittografia e non andrà via, quindi non preoccuparti della "prova futura". Basta avere una buona libreria ...

MessagePack = metà del pacchetto

Non è male ma non è né il più veloce, né il più piccolo né il meglio supportato. Nessun motivo di produzione per sceglierlo.

Comune

Oltre a ciò, sono abbastanza simili. La maggior parte sono varianti del TLV: Type-Length-Valueprincipio di base .

I buffer di protocollo (originati da Google), Avro (basato su Apache, utilizzato in Hadoop), Thrift (originato da Facebook, ora progetto Apache) e ASN.1 (originato da Telecom) implicano tutti un certo livello di generazione di codice in cui per prima cosa esprimi i tuoi dati in un serializzatore -formato specifico, quindi il "compilatore" del serializzatore genererà il codice sorgente per la tua lingua tramite la code-genfase. L'origine dell'app usa quindi queste code-genclassi per IO. Nota che alcune implementazioni (ad esempio: la libreria Avro di Microsoft o ProtoBuf.NET di Marc Gavel) ti consentono di decorare direttamente gli oggetti POCO / POJO a livello di app e quindi la libreria utilizza direttamente quelle classi decorate invece delle classi di code-gen. Abbiamo visto che questo offre un aumento delle prestazioni poiché elimina una fase di copia di oggetti (dai campi POCO / POJO a livello di applicazione ai campi di generazione del codice).

Alcuni risultati e un progetto live con cui giocare

Questo progetto ( https://github.com/sidshetye/SerializersCompare ) mette a confronto importanti serializzatori nel mondo C #. La gente di Java ha già qualcosa di simile .

1000 iterations per serializer, average times listed
Sorting result by size
Name                Bytes  Time (ms)
------------------------------------
Avro (cheating)       133     0.0142
Avro                  133     0.0568
Avro MSFT             141     0.0051
Thrift (cheating)     148     0.0069
Thrift                148     0.1470
ProtoBuf              155     0.0077
MessagePack           230     0.0296
ServiceStackJSV       258     0.0159
Json.NET BSON         286     0.0381
ServiceStackJson      290     0.0164
Json.NET              290     0.0333
XmlSerializer         571     0.1025
Binary Formatter      748     0.0344

Options: (T)est, (R)esults, s(O)rt order, (S)erializer output, (D)eserializer output (in JSON form), (E)xit

Serialized via ASN.1 DER encoding to 148 bytes in 0.0674ms (hacked experiment!)

3
ASN.1 ha anche BER (Basic Encoding Rules), PER (Packed Encoding Rules) e XER (XML Encoding Rules). DER è una variazione del BER utilizzata principalmente per la crittografia poiché garantisce una codifica univoca per ogni dato. Sia BER che PER possono essere più efficienti di DER. La maggior parte delle biblioteche processa DER. Alcuni non gestiscono correttamente tutti i costrutti BER. Per coloro che sono interessati a saperne di più: luca.ntop.org/Teaching/Appunti/asn1.html
Joe Steele

Ha anche JER - Regole di codifica della notazione degli oggetti JavaScript. Puoi anche definire le tue regole di codifica con ECN (Encoding Control Notation). Buon elenco di specifiche con link per il download: oss.com/asn1/resources/standards-define-asn1.html
Dmitry

There are two variants, DER (binary) encoding and PEM (ascii) encoding. Tieni presente che PEM è solo un dato binario codificato in base 64 all'interno dei commenti BEGIN END. Questi dati binari potrebbero essere stati generati utilizzando la codifica DER, quindi è strano confrontare PEM e DER.
RafalS

14

In aggiunta alla prospettiva delle prestazioni, Uber ha recentemente valutato molte di queste librerie sul proprio blog di ingegneria:

https://eng.uber.com/trip-data-squeeze/

Il vincitore per loro? MessagePack + zlib per la compressione

Il nostro obiettivo era trovare la combinazione di protocollo di codifica e algoritmo di compressione con il risultato più compatto alla massima velocità. Abbiamo testato il protocollo di codifica e le combinazioni di algoritmi di compressione su 2.219 viaggi anonimi pseudocasuali da Uber New York City (inseriti in un file di testo come JSON).

La lezione qui è che le tue esigenze guidano la libreria giusta per te. Per Uber non potevano utilizzare un protocollo basato su IDL a causa della natura priva di schemi del passaggio dei messaggi che hanno. Ciò ha eliminato un sacco di opzioni. Inoltre per loro non è solo il tempo di codifica / decodifica grezzo che entra in gioco, ma la dimensione dei dati a riposo.

Risultati di dimensione

Risultati di dimensione

Risultati di velocità

inserisci qui la descrizione dell'immagine


13

L'unico aspetto importante di ASN.1 è che è progettato per le specifiche e non per l' implementazione. Quindi è molto bravo a nascondere / ignorare i dettagli di implementazione in qualsiasi linguaggio di programmazione "reale".

È compito del compilatore ASN.1 applicare le regole di codifica al file asn1 e generare da entrambi il codice eseguibile. Le regole di codifica potrebbero essere fornite in EnCoding Notation (ECN) o potrebbero essere una di quelle standardizzate come BER / DER, PER, XER / EXER. Questo è ASN.1 è i tipi e le strutture, le regole di codifica definiscono la codifica in rete e, ultimo ma non meno importante, il compilatore lo trasferisce al tuo linguaggio di programmazione.

I compilatori gratuiti supportano C, C ++, C #, Java ed Erlang per quanto ne so. I compilatori commerciali (molto costosi e con brevetti / licenze) sono molto versatili, di solito assolutamente aggiornati e supportano a volte anche più lingue, ma vedi i loro siti (OSS Nokalva, Marben ecc.).

È sorprendentemente facile specificare un'interfaccia tra parti di culture di programmazione totalmente diverse (ad es. Persone "embedded" e "server farmers") utilizzando queste tecniche: un file asn.1, la regola di codifica ad es. BER e un diagramma di interazione UML ad es. . Non preoccuparti di come viene implementato, lascia che tutti usino "le loro cose"! Per me ha funzionato molto bene. Btw .: Sul sito di OSS Nokalva è possibile trovare almeno due libri scaricabili gratuitamente su ASN.1 (uno di Larmouth e l'altro di Dubuisson).

IMHO la maggior parte degli altri prodotti cerca solo di essere ancora un altro generatore di stub RPC, pompando molta aria nel problema della serializzazione. Beh, se ne ha bisogno, potrebbe andare bene. Ma a me sembrano reinvenzioni di Sun-RPC (dalla fine degli anni '80), ma, ehi, anche questo ha funzionato bene.


7

Microsoft's Bond ( https://github.com/Microsoft/bond ) è molto impressionante per prestazioni, funzionalità e documentazione. Tuttavia, al momento (13 febbraio 2015) non supporta molte piattaforme di destinazione. Posso solo presumere che sia perché è molto nuovo. attualmente supporta python, c # e c ++. Viene utilizzato dalla SM ovunque. L'ho provato, per me come sviluppatore ac # usare bond è meglio che usare protobuf, tuttavia ho usato anche parsimonia, l'unico problema che ho dovuto affrontare è stato con la documentazione, ho dovuto provare molte cose per capire come vanno le cose.

Poche risorse su Bond sono le seguenti ( https://news.ycombinator.com/item?id=8866694 , https://news.ycombinator.com/item?id=8866848 , https://microsoft.github.io/ bond / why_bond.html )


5

Per le prestazioni, un punto dati è il benchmark jvm-serializer : è abbastanza specifico, piccoli messaggi, ma potrebbe aiutare se si utilizza la piattaforma Java. Penso che le prestazioni in generale spesso non saranno la differenza più importante. Inoltre: NON prendere MAI le parole degli autori come vangelo; molte affermazioni pubblicizzate sono fasulle (il sito msgpack ad esempio ha alcune affermazioni dubbie; potrebbe essere veloce, ma le informazioni sono molto imprecise, il caso d'uso non molto realistico).

Una grande differenza è se uno schema deve essere utilizzato (PB, Thrift almeno; Avro potrebbe essere opzionale; ASN.1 penso anche; MsgPack, non necessariamente).

Inoltre: secondo me è bene poter utilizzare un design modulare e stratificato; cioè, il livello RPC non dovrebbe dettare il formato dei dati, la serializzazione. Sfortunatamente la maggior parte dei candidati li raggruppa strettamente.

Infine, nella scelta del formato dei dati, le prestazioni al giorno d'oggi non precludono l'utilizzo di formati testuali. Ci sono parser JSON velocissimi (e parser xml in streaming piuttosto veloci); e quando si considera l'interoperabilità dai linguaggi di scripting e la facilità d'uso, i formati binari e i protocolli potrebbero non essere la scelta migliore.


Grazie per aver condiviso le esperienze, ma penso di aver ancora bisogno del formato binario (ho un'enorme quantità di dati) e probabilmente rimarrò con Avro.
andreypopp

Sì, allora potrebbe avere senso. Potresti voler usare la compressione in ogni caso, indipendentemente dal formato da usare (LZF è carino poiché è molto veloce da comprimere / decomprimere, rispetto a gzip / deflate).
StaxMan
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.