7 ms·
This might be a contrarian view, maybe I'm misunderstanding it. To me, much of message passing is not performance critical, so it would be well served by JSON/Y
by drej 9y ago
This might be a contrarian view, maybe I'm misunderstanding it. To me, much of message passing is not performance critical, so it would be well served by JSON/YAML/XML for easy implementation/testing/debugging. If one needs performance, he can just send bytes over, which can be (de)serialised in a (couple) dozen SLOC. Sure, when you're talking about very complex structures, RPC, dynamic schemas etc., then you might opt for something like this, but let's be honest - that's quite a minority of current users, isn't it?
I never minded these frameworks, but then I wanted to write a few parsers for some file formats and they used Thrift/Flatbuffers to encode a few ints, which seemed like a major overkill. There was no RPC, no packet loss, no nothing.
- willvarfar 9y agoClearly there are needs for very efficient message parsing. That's why these serialization frameworks exist. I've got servers that spend too many cycles in serialization, so I pay careful attention to it. I put a lot of effort into using JSON despite the performance problems, and have pretty low-level code to read write it without too many allocations etc. Nothing thats easy on the eyes. But I'd hazard a guess that you're spot on regards the normal needs of normal programs. The vast majority of programs utilizing message-passing are not serialization-bound. For these programs I'd recommend JSON because it is easy for humans to inspect and debug, and there are plenty of libraries to choose from if you are not performance-sensitive. (YAML is hopeless regards security and XML is just horrid to look at when you're debugging).
- bborud 9y agoBeing able to inspect messages is down to the proper tooling. But I can certainly understand where you are coming from. I've designed several text based protocols in my time for that exact reason. And I still do for stuff that I positively know will never require any sort of performance (mostly on embedded systems, somewhat ironically since those are sometimes constrained down to just a few hundred bytes of memory :-))
- edem 9y agoWhen you start having polyglot microservices this all will make sense. For example protobuf gives you versioning and compiles to a dozen languages...just because it is not useful to you don't dismiss the idea. And since I'm part of the minority I'm happy to have libs like this around. Just a sidenote: this behavior of neglecting performance alltogether leads to systems which take ages to build and collapse under pressure.
- kybernetikos 9y ago> When you start having polyglot microservices this all will make sense. I'll be surprised if you use a language that has a good protobuf implementation that doesn't also have a good json/yaml/xml implementation. Incidentally, as far as I can tell, protobuf also neglects performance. For high performance you want as much of your message to be predictably positioned in the bytestream as possible, but protobuf uses a key-value style system which means you always have to look at each key-value pair to determine what it is and how big it is. This makes good sense for compatibility, but it's a definite trade off that limits how fast deserialization can be.
- artursapek 9y agoIf you use a type safe language, Protobuf gives you type safety. This helps a lot as a system grows complex. You don't get that with JSON/XML/etc.
- JBReefer 9y agoHuh? All (?) of the XML parsers/unmarshallers I've ever used have been type safe - certainly the built in ones in C#, Java, and Go.
- scottbez1 9y agoI think there's two distinct notions of type safety being discussed here: most deserializers in typed languages provide type safety once successfully deserialized, but the IDL/shared-schema approach helps guarantee that you'll be able to successfully deserialize the data into a type-safe representation in the first place. I can't speak to XML, but can say that even with "type safe" json serialization, I've seen several bugs due to some json libraries treating all numbers as doubles internally, meaning bad things happen when you're actually serializing integers larger than 52 bits (say, a nano timestamp). Sure, maybe it's a bug in the json library because the json spec doesn't establish any max precision for numbers, but it's not hard to run into it when different components/languages with independently implemented json libraries try to talk to each other. Shared schema approaches like proto also make it really hard to accidentally typo the name of the field, or accidentally try to read a field as a string rather than a list of strings. Just like I wouldn't consider code to be type safe if it passed data around as raw Objects and each usage cast it to the expected type, I wouldn't consider services that communicate with each other using independently (manually) implemented parsers/extractors as being type safe, even if the "meat" of the code is dealing with strongly typed data on either end.
- kentonv 9y agoYour view isn't contrarian at all -- in fact it's widely-held by smart people. But I'll present the counter-argument. True, in many use cases, performance is not critical. However, when you're doing big data processing or serving at scale, serialization performance does in fact start to matter a lot. If Google Search passed all backend messages as JSON rather than Protobuf, it would probably require 10x the hardware (we may be talking about millions of machines here) and wouldn't be able to respond as quickly. Similarly, Cloudflare couldn't handle its logging load without Cap'n Proto. Many times, companies who started small and thought performance didn't matter later found themselves needing to do massive, expensive rewrites in order to keep up with scale (e.g., famously, Twitter). Hand-written binary serializers may be easy to write initially, but they are very hard to maintain. Over time, you'll need to add and remove fields, while maintaining compatibility with old binaries already running in the wild, or compatibility across languages. It's very easy to screw this up with a hand-written encoder, but very easy to get right with Protobuf or Cap'n Proto. Finally, even if performance isn't an issue, you may find that type safety is useful. If you are writing code in a type-safe language, correctly dealing with JSON actually tends to be a huge pain involving lots of branching. By defining a schema upfront and generating code, you can get a much nicer interface. And if you're doing that anyway, then you might as well take advantage of the more-efficient encoding while you're at it -- it's easy to dump human-readable text for debugging when needed. (As of this release, Cap'n Proto ships with a library for converting to/from JSON, and there are lots of third-party libraries to do the same with Protobuf. Both libraries also have one-liner "dump a debug string" functions.)
- obstinate 9y agoOr, in slightly fewer words: there's a reason ethernet, IP, and UDP packets aren't encoded in JSON. It's that when you have to encode a lot of a thing, and the encoding is relatively expensive compared to the rest of the processing that needs to be done on that thing, having inexpensive encoding is important.
- thechao 9y agoA more approachable example: logging to a logging process in compute-heavy and/or time sensitive application (simulators, games, rasterizers, ...). In such situations the transport layer is usually bandwidth bound, so the use of a well-designed serialization layer (compression) is highly desireable. That being said, due to Zipf's law and the fact that whitespace delimiting is a pseudo-RLE compressor, I've found most binary serialization formats to be a wash compared to text.
- k_bx 9y agoThere's MessagePack for substential improvement of parsing speed and size of JSON while still being straight-forward to parse and debug. These guys (Capt'n'Proto) are for cases when that's not enough either. As I understood, Capt'n'Proto removes the need of parsing itself, so you don't have to parse a data structure into your language's structure if you want to access a field, you just keep your data as a binary blob in memory without copying or parsing the whole thing.
- Matthias247 9y agoIMHO performance is only one reason for using a system like Cap'n'Proto/grpc/Thrift vs some handwritten json/yaml/xml/binary protocol. Others reasons are: - Starting from an IDL you get a nice service contract. Which means both sides of the service (client & server implementors) get a strong description on how the service should behave and what they need to implement. The more roles you have (architects, client-implementors, service-implementors, testers, mock-service implementors), the more you profit from a good specification. - If you generate all the serialization/deserialization code you avoid the tedious handwriting of this code and the possibility of introducing errors in this. E.g. some misspelling of field names or functions or copy&paste errors can always occur and some of these errors are only detected late in the development process. These advantages might not be visible if you have a small service and development team - you might even experience an overhead compared to just "changing the client and server code", which are both under your control. But once you are working on a system with thousands of APIs you are quite happy if you don't have to care about handwriting serialization and RPC code and instead can focus on business logic. I personally was responsible for deploying a similar solution for an in-vehicle infotainment system with hundreds of services and around 4000 functions, which worked out really well.
- oaktowner 9y agoThanks for making the point about large teams -- I was coming here to make it myself. Even if you are using JSON, having a contract between client and server is super helpful. Out of curiosity, what format did your infotainment system for serialization?
- Matthias247 9y agoit's a proprietary binary serialization. However nothing revolutionary, just comparable to thrift and protobuf.
- cle 9y agoAnother advantage: using an IDL defines your contract in a way that is both language agnostic and portable, which is great for client support and for long-term maintenance.
- alfalfasprout 9y agoThe "you can just send bytes over" bit is kind of the whole point. While I use Google's flatbuffers instead of Capn'Proto due to easier use w/ in-memory buffers they more or less have the same design idea: the underlying data is little-endian and stored in machine native types. For my use case in electronic trading, a format like this is great b/c you don't waste many CPU cycles in decoding/encoding while at the same time you can take complex message structures and easily generate code stubs to read/write them in various languages. You change something? Just regenerate the code stub. You can even guarantee backwards compatibility if needed.
- deleted 9y ago[deleted]
- kentonv 9y agoI'd be curious what you mean by "easier use w/ in-memory buffers".
- kosma 9y agoI once worked on a rather convoluted bunch of microservices where 40% of CPU time was spend inside cJSON library. Cap'n Proto does exactly what you propose - sends bytes over, except in a documented, organized, forward- and backward-compatible manner, instead of a haphazard implementation burdened by technological debt.
- mhd 9y agoIn addition to the problem of premature binarification, I have the sneaking suspicion that a lot of the remaining use cases could well be handled by ASN.1.
- kstrauser 9y agoExperientially, nothing is handled well by ASN.1. Google for "asn.1 cve" and see how many security vulnerabilities are due to it being approximately impossible to parse correctly.
- rsynnott 9y agoOne advantage of things like Protobufs/Thrift/Avro/etc, beyond the performance (and the performance difference can be _huge_), is that they have a (generally upgradeable) schema; this is particularly handy when using strongly-typed languages. For JSON and YAML you, at best, can use a bolt-on schema checker thing. I'd also disagree that performance on message passing doesn't matter; depends how many messages you're passing :) I've seen CPU-bound systems which spend most of their CPU time decoding JSON.
- adrianmonk 9y agoI've found myself in all three situations: where performance didn't matter much and something like JSON or XML was fine, where performance mattered and a binary format was an obvious win, and one situation where serialized data needed to be as compact as possible and I could only achieve that by hand coding. To me, formats like JSON or XML have one clear advantage: debugging is easier. I can fire up a decoder for a binary format, but that slows down the investigation. That said, most binary formats have a schema file due to necessity of not serializing field names. That schema file makes it easy to have tools that spit out language bindings. And that reduces the tedium of actually writing code that uses (and validates) the data, so I generally prefer those formats for that reason.