简介
ToRPC(Tornado + RPC) 是一个的基于Tornado IOLoop的异步TCP和双向通信的RPC的Python实现。ToRPC非常轻量级,性能优秀(尤其是在PyPy环境下)。
特性
- 异步 tcp 通信
- 异步、双向 rpc
地址:
背景
在Python中,消息队列、RPC框架都有很多,很多框架的完成度和稳定性都不错了,但是速度却不尽人意(真的就是慢),于是产生了造一个轮子的想法————一款可以压榨服务器资源的RPC框架。
对比多款框架后,发现了,它是基于Cython、Gevent、MsgPack完成的一款,它的简洁和高性能吸引了我,再使用过程中,我试图再优化的时候,发现基本上已经达到CPU和网络I/O的瓶颈。
因为使用Cython和gevent,后者底层也是C语言实现的,那么CPU消耗是没有的办法的时候,将MsgPack换成速度更快的marshal速度提升了10%左右,但是流量随之增加了,最后还要考虑marshal跨版本时的兼容问题(ToRPC目前也是marshal)。
既然达到瓶颈了,试试别的框架吧,后来又找到了。 根据这个代码,Python部分的Echo servers的性能顺序是这样的:
- pypy+tornado
- python+gevent(无greenlet)
- python+tornado
- python+gevent
- pypy+twisted
结论是pypy配合event-driven的tornado性能最好,它的速度和Golang(1.5)及C++ + epoll更接近。而我自己又在pypy下测试了的tornado、twisted、eventlet,还是tornado最快。最后的抉择是使用tornado,思路是单进程、纯异步(这不就是nodejs么)。
简化Tornado的IOStream
在tornado下的rpc服务器已经有, 而比较server_tornado.py
和server_tornado_iostream.py
之后,发现IOStream非常影响性能。而且msgpack-rpc-python
正好使用了IOStream,并且不支持双向RPC。 好吧,是时候去简化IOStream了。一开始将IOStream中的_read_buffer
和_write_buffer
从collections.deque()
换成Queue
之后,性能却更差了。 索性还是不换了,直接撸纯event-driven,简化大量API之后,新的轮子比自带IOStream在效率上还是有很大的提升。
双向RPC支持
ToRPC主要的特色是支持双向的RPC,client
可以调用server
的同时也可以使用server
调用client
。 最后为了让多个client
之间相互调用而不需要开多个RPC服务器,引入了一个RPC服务注册的机制,实现了任何两个RPC client
可以通过RPC server
中转实现RPC调用,当然这样会让RPC server
的负担更重了。双向RPC的使用方法在文件夹中。
ToRPC的使用
ToRPC支持在RPC、TCP应用中使用callback
方式,同样也支持返回Future
,这使得Tornado中concurrent的方式可以在ToRPC中使用。
from torpc import RPCClientdef result_callback(f): print(f.result())@gen.coroutinedef using_gen_style(): want_to_say = 'way to explore' ret = yield rc.call('echo', want_to_say) assert ret == want_to_say print('gen_style complete')rc = RPCClient(('127.0.0.1', 5000))rc.call('echo', 'hello world', callback=result_callback)future = rc.call('echo', 'code for fun')future.add_done_callback(result_callback)using_gen_style()
性能
系统: CentOS 6.6 x64<br/> 处理器: Intel i5-3470 3.20GHz<br/> 内存: 8 GB 1600 MHz DDR3
到目前来看,ToRPC虽然是东拼西凑的一个轮子,但是它的性能是有目共睹的,尤其是在PyPy环境下。
msgpack-rpc-python
和mprpc
的结果可以从下方链接进入。
参考项目
最后,ToRPC仍有很多很多不足的地方,如果发现问题或者有好的想法可以提或者提交,文件夹下有使用方法。