数据包
协议
协议如下表 | HEAD_0 | ... | HEAD_3 | protoVersion | serverVersion | length | |--------|--------|--------|--------|--------|--------| | char | ... | char | int | int | int | gfirefly框架是基于TCP协议的长连接,框架中没有使用keep-alive,那么网络异常断开(如网线突然拔掉)的时候,应用层是不知道,当我们自己使用的时候就必须加心跳包等机制来解决这个问题。另外数据加密没有放到协议层,那么需要加密数据只能在打包数据之前使用加密算法。
黏包
gfirefly中对底层的数据包进行了黏包处理,如上表所示,协议头定义了length,此时应用层就知道什么时候结束单个包的传输。见gfirefly/netconnect/protoc.py line 43:
def dataReceived(self, data):
length = self.factory.dataprotocl.getHeadlength()#获取协议头的长度
self.buff += data
while self.buff.__len__() >= length:
unpackdata = self.factory.dataprotocl.unpack(self.buff[:length])
if not unpackdata.get('result'):
log.msg('illegal data package --')
self.factory.connmanager.loseConnection(self.transport.sessionno)
break
command = unpackdata.get('command')
rlength = unpackdata.get('length')
request = self.buff[length:length+rlength]
if request.__len__()< rlength:
log.msg('some data lose')
break
网络
gfirefly 是由firefly修改而来,那么当底层网络模块由twisted 更换为 gevent的时候,加入了一个叫gtwisted的wrapper。实际上还是使用的gevent.StreamServer。还有一些用不爽的地方,而且一直没有修改,比如gtwisted/core/base.py line 122左右, getHost函数 手动返回"0.0.0.0"什么的。
rpc
length | data |
---|---|
int | string |
rpc的协议头如上表,其中data为dict经marshal的结果,marshal速度还算可以,我测试中marshal和msgpack速度不相上下,但是msgpack可以跨平台,呵呵。data的内部是这样的:{'_msgtype': _msgtype, '_key': _key, '_name': _name, '_args': args, '_kw': kw}
,看样子没什么特别之处。
分布式
gfirefly中实现了rpc的双向调用,使之实现分布式更容易一下。不过我测试双向RPC的效率却很低,qps大概在4000左右,而测试单向的mprpc qps达到1W8.
- gate节点为中心节点。
- 有child节点连接到gate,child之间相互通讯也是通过gate节点来中转。
缓存
框架封装了一个使用memcache的来缓存mysql数据的模块,数据查询仅限于有主键或者外键的表,不过也已经足够。不足的地方在于value保存的是一个很大的字典,每次调用修改一个字段的时候,需要修改存储的整个value,这样效率比较低。如果用redis的hset会好很多,另外我自己对比测试redis驱动和memcache驱动。结果如下
| redis-py | credis | memcache | pylibmc | |--------|--------|--------| | 2W+ | 4W+ | 2W+ | 5W+ | 补充:credis没有封装对命令的函数。
gevent中的坑
模拟大量登录时,程序变慢。官方的mysql采用的是mysql-python(底层是c/c++),在所有mysql驱动中算是很快的了,比umysql慢点,不过umysql不兼容DB-API 2.0。测试的时候gevent在调用里面查询的时候被阻塞住。之后用豆瓣的greenify并没有成功,最终换成了pymysql。memcache驱动换成了pylibmc,memcache足够快了,如果再用gevent只会拖慢速度,搜索得出的结果是gevent中会有大量的系统调用,==亚毫秒级不推荐用greenlet==。
万物归一
使用场景分析:这个框架只适用于一些简单的(游戏)服务器应用。python用起来很爽,不过速度是一个很大的问题,即使使用各种黑科技,可能也不尽人意啊,毕竟很多游戏服务器是 同时I/O和CPU密集的。