-
Notifications
You must be signed in to change notification settings - Fork 273
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Performance: Avoid converting responses to serde_json::Value #639
base: master
Are you sure you want to change the base?
Conversation
You could avoid all the generics with |
I had a similar idea initially, but my benchmarks showed that using
This was for a 1GB result. |
Yeah, that would be 3GB/s for a memcpy, which sounds about right for a payload of this size on a single thread. I would have expected |
Yeah, it's a very simple benchmark - can share it if you're interested. In the wild this has improved time-to-first-byte from around 26s to 19s for 4.5 GB responses. The time not spent in the actual rpc handler function has gone down from 14s to 8s. (of course having responses of that size it a problem in itself) |
What would need to happen to give the patch - or a variant of it - the best chances of making it into the next release that allows api changes like this? |
@tomusdrw Do you have thoughts on this? If this breaks API too much and has no chance of making it in, feel free to say so. I've since seen that https://github.com/paritytech/jsonrpsee does already not have the same overhead. |
Previously, all responses were converted to serde_json::Value before being serialized to string. Since jsonrpc does not inspect the result object in any way, this step could be skipped. Now, result objects are serialized to string much earlier and the Value step is skipped. This patch has large performance benefits for huge responses: In tests with 4.5 GB responses, the jsonrpc serialization overhead after returning from an rpc function was reduced by around 35%. Which means several seconds of speed-up in response times. To accomplish this while mostly retaining API compatibility, the traits RpcMethod, RpcMethodSync, RpcMethodSimple are now generic in their return type and are wrapped when added to an io handler. There's now a distinction between the parsed representation of jsonrpc responses (Output/Response) and result of rpc functions calls (WrapOutput/WrapResponse) to allow the latter to carry the pre-serialized strings. Review notes: - I'm not happy with the WrapOutput / WrapResponse names, glad for suggestions. - Similarly, rpc_wrap must be renamed and moved. - The http handler health request is now awkward, and must extract the result/error from the already-serialized response. Probably worth it. - The largest API breakage I could see is in the middleware, where the futures now return WrapOutput/WrapResult instead of Output/Result. - One could make WrapOutput just be String, but having a separate type is likely easier to read. See paritytech#212
b2e2892
to
1839c50
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lgtm! Will probably need a major version bump.
- WrapOutput -> SerializedOutput - WrapResponse -> SerializedResponse - RpcMethodWrapped -> RpcMethodWithSerializedOutput
I've done the renames. Do you have an idea for what to do about |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lgtm!
Co-authored-by: Tomasz Drwięga <[email protected]>
Co-authored-by: Tomasz Drwięga <[email protected]>
Previously, all responses were converted to serde_json::Value before being serialized into the response string. Since jsonrpc does not inspect the result object in any way, this step could be skipped.
Now, the response string is built from the result objects much earlier and the Value step is skipped.
This patch has large performance benefits for huge responses: In tests with 4.5 GB responses, the jsonrpc serialization overhead after returning from an rpc function was reduced by around 35%. Which means several seconds of speed-up in response time.
To accomplish this while mostly retaining API compatibility, the traits RpcMethod, RpcMethodSync, RpcMethodSimple are now generic in their return type and are wrapped when added to an io handler.
There's now a distinction between the parsed representation of jsonrpc responses (Output/Response) and the result of rpc function calls (WrapOutput/WrapResponse) to allow the latter to carry the pre-serialized strings.
Review notes:
See #212