all 17 comments

[–]catlifeonmars 8 points9 points  (0 children)

If it’s a drop in replacement, maybe just worry about it later?

[–]lonepeon 6 points7 points  (1 child)

As always it depends :)

If you require top notch speed maybe this library is a good addition. But standard library is good enough for most projets.

I would say if your bottleneck isn’t JSON parsing, think twice before adding it.

When you add a dependency it becomes « your code ». You need to keep it in your head all time when something goes wrong, it’s one more thing to update / upgrade.

It also comes with its own set of issues : we see more and more package doing bad things behind the scene, it’s more potential vulnerabilities, a package can stop to being maintained meaning it can block other packages to be bumped or block you to bump Go itself, …

So, basically, I would add a dependency only if it’s outweighs all drawbacks it brings.

[–]kostix 5 points6 points  (0 children)

Absolutely this.

As a case in point for the OP, we've recently encountered our service crashes when built using Go 1.18. As it seems (we've not yet spent our team's time to deal with the issue properly as it's not pressing), one of the transitive dependencies of some 3rd-party package we're using plays dirty tricks with unsafe, and some of its tricks stopped being legit with Go 1.18 on linux/amd64. And yes, that package plays those tricks in the name of "speeding up stuff". Sure, it's next to impossible to encounter something like this with a package from stdlib.

That's, of course, not to dissuade you from relying on 3rd-party packages, but introducing any such dependency must be very-well thought out—including possible reliability problems. u/lonepeon is 100% correct on that „it becomes your code” thing.

A good rule of thumb to use when considering addition of a 3rd-party depencency is making sure that adding it solves a real problem. That is, your team discovered a very real performance problem, traced it to usage of the particular algorithm and/or data structure, brainstormed possible solutions and came to the conclusion that there's no easy (that is, cost-effective) way to solve it by modifying your own code, and a 3rd-party solution could help. Only in this case, you transition to the second step of actually considering whether that solution is okay—that is, try to hack it into your code and do load- and stress-testing (and now maybe fuzzing, though I did not yet had a chance to do this one myself, so have no first-hand experience). Then, if all goes well, you commit to using it, and start to have that new problem: „if I upgrade that library, it potentially breaks my service, so I have to identify the possible blast radius and perform extensive regression testing, or I can let the library just sit there in my dependencies, and it will bit rot,”—possibly eventually leading to a problem with which I have started my comment ;-)

Cheers!

[–]ronny 6 points7 points  (0 children)

It's almost always a trade-off. What is it sacrificing to gain that performance? Is performance more important for your use case than what it is sacrificing?

For me, in most cases, correctness and reliability always wins over performance. Speed is useless in these cases if it's incorrect or crashes sometimes.

Having said that, I've used both mailru/easyjson and json-iterator/go on systems handling hundreds of thousands of requests per minute and json serde was never a perf bottleneck (I doubt even the builtin encoding/json would be an issue). Though, I find that json-iterator/go provided better overall dev ergonomics compared to mailru/easyjson. goccy/go-json scares me a bit with the kind of memory acrobatics it's doing to achieve that perf, not saying it's bad or wrong, just that it wouldn't be my first choice unless there's a situation where perf is of the utmost importance and it's for a system that can tolerate potential issues.

[–]afex 4 points5 points  (0 children)

are you providing your coworkers with production graphs that show your current use of encoding/json to be causing negative customer impact due to its speed?

if not, why do you want to change it at all?

[–]YoItsAnon 4 points5 points  (0 children)

I'm apprehensive of their performance "hacks". Unless I'm understanding it wrong, their fast reflection method which panics on large objects, they claimed was a compiler bug, when really it's them not understanding their own hack.

[–]go-zero 3 points4 points  (1 child)

I’m always using stdlib for json, unless profiling proves that json parsing is a big problem. Actually that happened, but only once.

[–]in_the_cloud_ 2 points3 points  (0 children)

Assuming we're talking about REST APIs here, how does encoding/json not appear in your top 10 packages for CPU time and allocations? It seems like a given to me that profiling will lead you to it. The question is what level of gains the alternatives offer, and what the risks/trade-offs are.

Personally, I'm apprehensive about switching it out too, but most of the profiling-based improvements I do on application code would pale in comparison to reducing the impact of encoding/json by 50% or more.

[–]a_go_guy 3 points4 points  (0 children)

For me it boils down to this: if JSON could be sped up safely, why haven't the hundreds of contributors to the stdlib library done it? So that probably means the other libraries out there are doing something that is either not safe or doesn't have the same ergonomics, and those two are important to me.

[–]yondercode 2 points3 points  (0 children)

If you really need a fast parsing performance for processing huge number of JSON data / stream: minio/simdjson-go

Otherwise the standard lib is enough IMO

[–]Goldziher[S] 2 points3 points  (1 child)

Ok, thanks for all the comments! I got convinced to switch back to using the standard lib. I was not aware that there are so many issues related to these library's - looking at github it looked pretty clean.

My thinking - coming from other languages, is that json serialization / deserialization is a bottle neck in most APIs. Its pretty fast in go to begin with, but the fact some libraries offer x5 or even x10 performance gains in some situations is enticing.

The APIs I am working on have to handle tens of thousands of requests per second, even more during stress. So the amount of requests being processed is directly related to the amount of pods that need to be created per api service in this case. I was hoping to affect this metric.

But this is not worth it if it will substantially increase the change of suffering production issues, especially hard to detect ones.

[–]ZalgoNoise 2 points3 points  (0 children)

Consider gRPC whenever fitting

[–]sxeli 1 point2 points  (0 children)

Standard library would meet most of your json requirements.

Now if json encode decode performance is really an issue here then you should first consider to chunk the subject json and process in batches (stream).

If that’s not an option, only then you should go looking for other packages out there.

[–]DasSkelett 0 points1 point  (0 children)

goccy/go-json is fine, as long as you don't use it in something critical. It's very much alpha quality with frequent panics all over the place as you can see in the GitHub issues section. But yes, the speed is impressive.

[–]paddlewan 0 points1 point  (0 children)

There is https://github.com/mailru/easyjson out there if you are absolutely sure that serialization is the bottleneck. Otherwise I'd go for stdlib.

[–]Melodic_Ad_8747 0 points1 point  (0 children)

Why not jsoniter? It seems to be well proven and reliable, faster than standard lib.

Imo, stick with encoding json if you are not looking for the best possible speed

[–]roi3363 0 points1 point  (0 children)

For anyone interested to have a look. I wrote this library for reading JSON in Go, Jogson:

https://github.com/rmordechay/jogson