A simple and fast RPC framework
Project description
Yarr ain't RPC, Ritchie!
A simple RPC implementation using a binary serialization protocol. It supports the basic built-in types, numpy arrays work if available on both client and server. Hence, yarr is well equipped to efficiently handle large binary booty.
A friend asked me about RPC and large binary data in python. It sounded like a fun exercise so I charged forth. I choose to write my own serialization protocol to have more control and a bit more security than pickle. I also ran my benchmarks which pickle serialization and surprisingly yarr is not that slow. Lists and dict take the biggest hit, being ~ 2x slower compared to pickle.
Example
# server
yarr.yarr(('localhost', 8000), [print])
# client
yarr.call(('localhost', 8000), 'print', 'Ahoy Lads!')
Features
Compared to other RPC frameworks yarr has better support for native python types. It's speed depends on the connection. On localhost it appears to be 2-10 times faster than the other frameworks. Over LAN it's comparable to jsonrpc2-zeromq. Over internet the ZeroMQ based frameworks are twice as fast, but yarr is still on par with xmlrpc.
Here is a table comparing it to other RPC frameworks. Partial support is marked with p, usually due to type decay. The speed value is based on the benchmarks below. Feel free to add more.
yarr | xmlrpc | rpyc | jr2-zmq | spyne | 0rpc | |
---|---|---|---|---|---|---|
speed | 1.0 | 0.6 | 0.04 | 0.9 | 0.3 | 0.6 |
dependencies | 0 | 0 | 1 | 3 | 1 | 5 |
recursion | - | - | x | - | - | - |
bool | x | x | x | x | x | x |
int | x | x | x | x | x | x |
int64 | x | - | x | x | x | x |
bignum | x | - | x | x | - | - |
float | x | x | x | x | x | x |
complex | x | - | x | - | - | - |
str | x | x | x | x | x | x |
pep383 | x | - | - | x | - | - |
dict | x | p | x | p | x | x |
tupledict | x | - | x | - | p | - |
list | x | x | x | x | p | x |
tuple | x | p | x | p | x | p |
set | x | - | x | - | - | - |
bytes | x | p | x | - | x | x |
ndarray | x | - | x | - | - | - |
Xmlrpc is part of python's stdlib. Good enough for simple use-cases.
Rpyc is glacially slow but has almost perfect type support. Surprisingly it stumbles over pep 383. It's also one of the few frameworks that can handle recursion.
Jsonrpc2-zeromq has decent speed, though it is limited by it's protocol. There is no direct support for binary data. The base64 workaround works but impacts speed.
Spyne is a big project and can do a lot more than pure RPC. For this test MessagePack and ZeroMQ were used.
Zerorpc performance is below jsonrpc2-zeromq, which was unexpected given it's choice of protocols. A dict containing tuple keys crashes the server.
Benchmarks
The values below are in calls per second. This test was run over LAN with a server ping of 0.2 ms. The most recent framework versions (May 2020) were used. When running this benchmark over internet with a ping of 25 ms, yarr performance is roughly half of jsonrpc2-zeromq.
yarr | xmlrpc | rpyc | jr2-zmq | spyne | 0rpc | |
---|---|---|---|---|---|---|
none | 1291 | 746 | 56 | 1225 | 457 | 800 |
bool | 1254 | 746 | 54 | 1253 | 450 | 774 |
int | 1250 | 740 | 49 | 1263 | 448 | 769 |
int64 | 1238 | - | 47 | 1188 | 450 | 765 |
bignum | 1205 | - | 49 | 1165 | - | - |
float | 1211 | 750 | 52 | 1223 | 448 | 765 |
complex | 1236 | - | 54 | - | - | - |
str | 1204 | 770 | 54 | 1131 | 449 | 740 |
pep383 | 1236 | - | - | 1134 | - | - |
dict | 1214 | 741 | 54 | 1040 | 447 | 757 |
list | 1183 | 743 | 56 | 1141 | 449 | 759 |
tuple | 1186 | 714 | 63 | 1142 | 448 | 778 |
set | 1214 | - | 49 | - | - | - |
frozenset | 1189 | - | 54 | - | - | - |
bytes | 785 | 504 | 46 | 484 | 349 | 533 |
bytearray | 780 | 502 | 60 | 481 | 350 | 534 |
ndarray | 765 | - | 19 | - | - | - |
Protocol
The main design goals were simplicity and performance. There is no clever encoding scheme like MessagePack. Data is basically just dumped into the TCP socket without any transformations. Values are transferred as little endian, there really is no point in using network byte order these days.
In some cases messages can actually be bigger than in json, for example when it contains many short strings. However if the total size stays below the MTU there is be no big performance hit. I tried adding zlib compression and a persistent connection, but that did not have a big impact and made everything more complicated.
Bugs
- Not enough pirate-speak in documentation.
- Malicious data can cause crash.
- Recursive containers cause crash.
License
Do What The Fuck You Want To Public License
Everyone is permitted to copy and distribute verbatim or modified copies of this license document, and changing it is allowed as long as the name is changed.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.