最近在调整游戏的后台架构,之前因为需要快速出产品,所以整个代码都揉成一团,也基本没有做任何分层处理。现在服务器端的开发也开始逐渐招进来,所以打算打算换一套统一的架构,以后做新游戏只要做其中的业务逻辑即可。
其实之前在腾讯的时候,基本不会用到message queue这种,所有的分布式处理都是由自己写c++ server来互相通信的。这样的处理虽然开发量稍微大一点,但是性能和灵活性确实很高。
现在自己在外面做,虽然自己已经封装了一套server的框架出来,但是毕竟还有太多的轮子需要自己制造,所以就想到了之前一直有了解过celery,来看一下这种基于message queue的任务系统能达到什么性能。
RabbitMQ
celery首推的mq是rabbitmq,所以需要先安装一下:
在mac下用brew 安装:
brew install rabbitmq
安装成功之后,即可启动server了。
不过在这之前,我们先把后台管理的插件打开:
rabbitmq-plugins enable rabbitmq_management
之后执行如下命令,启动server:
rabbitmq-server
这个时候就可以通过 http://127.0.0.1:15672/ 来访问后台管理端了,默认的用户名和密码是guest guest,可以自己在页面上修改。截图如下:
Redis
celery也支持redis作为broker和backend,所以redis也需要安装一下,这里就不赘述了
Celery
安装命令为:
pip install celery
性能测试
新建 t.py:
from celery import Celery app = Celery(backend='amqp', broker='amqp://') @app.task def add(x, y): return x + y
以及测试文件 test.py:
import time from t import add t1 = time.time() result = add.delay(1, 2) print result.get() print time.time() - t1
启动celery worker:
celery -A t worker --loglevel=info -c 2
执行 python test.py 输出结果为:
0.545017004013
修改 t.py 为:
from celery import Celery app = Celery(backend='redis', broker='redis://') @app.task def add(x, y): return x + y
测试结果为:
0.603708028793
无论是rabbitmq还是redis,性能都慢的让人无法接受,最终还是放弃了用celery做任务分布的想法,还是老老实实的用server通信吧。
Jeffrey4l on #
可能是和CPU有关?我在服务器上和自己笔记本上做相同的测试结果是服务器: 0.08笔记本: 0.3-0.5
Reply
Dante on #
嗯,有可能,我之前也是在centos上跑出来的性能比笔记本上高几倍。不过即使在mac上,试了一下自己写的纯python server,也就1ms的事。
Reply
Poser on #
用单台笔记本来做这个本来应该用于服务器集群的mq,是否欠妥当?就像你单机上跑hadoop,确实不如直接操刀上手的。性能扩展不用这么搞吧,将程序模块化,将来将“server通信”直接替换成 mq 就行,不用改多少结构和代码的
Reply
Dante on #
嗯,确实很多东西没有考虑,不过mq的性能量级还是有体现的,在笔记本上跑的纯python server,差不多是1ms返回
Reply
bensonjia on #
推荐使用zeromq。
Reply
Dante on #
zeromq确实极快无比,不过其实他已经不能算是mq了。。如果只是简单的client-server模式的话,和自己封装一层socket recv的方式是一样的。不过话说回来,用zmq直接替换socket看起来也是不错的选择。
Reply
muxueqz on #
其实我觉得Celery的意义不在于响应快,而是异步+横向扩展能力
Reply
Dante on #
嗯是的,只是顺便测试了下
Reply
genius-he on #
请教楼主一个问题,就是说 socket的链接,本质上是在TCP/IP一层,或者类似企鹅利用UDP封装了一层,然后在上层进行可靠性校验。那么我的问题时,redis本质上底层也是socket的链接,那么对于单机的redis和在文章结尾中你提到的server通信的区别是什么呢?如果是基础的server通信,跑上面的一个testcase耗时是怎样的呢?
Reply
Dante on #
本质都是socket,我的意思是说用上面的这套框架,其内部帮你做了很多不需要做的事情,比如存储,路由 等等,相应的也会降低性能。所以如果明确自己的需求,那么就可以用完全自己定制的方案,不浪费多余的性能。
Reply
genius-he on #
bingo,感谢up主的解惑 thx:)
Reply
何世友Ernest on #
看celery源码:https://github.com/celery/celery/blob/master/celery/result.py#L125def get(self, timeout=None, propagate=True, interval=0.5,你这属于调用不当。
Reply
Dante on #
赞,感谢指正。也就是结果获取是轮询的,而不是事件通知? 这样的实现似乎满足不了远程返回结果的需求。。
Reply
何世友Ernest on #
这是celery实现的比较挫的地方,也是因为官方根本不情愿给这个方法,因为会变成sync。如果要返回结果可以考虑callback。不过用celery的话真的是不大考虑实时获取结果,事务性较强的还是同步好了,直接rpc。
Reply
Ping on #
这种异步任务调度,就是用来拿性能换负载的东西。跟你应用场景不搭。
Reply
最励志官网 on #
网站真不错 最励志网http://www.zuilizhi.net/?
Reply
歪妖内涵网 on #
过来支持一下 值得收藏分享
Reply
justin on #
你好,我觉得调用get,然后来计算响应时间是不对的,这就等于让CPU一直等待结果完成,其实可以通过周期性ready()调用来检验过程是否处理完毕。
Reply
Dante on #
嗯,只是有时候请求只能顺序执行,所以我想得到的其实是调用方总共要等待的时间,而无论内部的实现。
Reply
justin on #
那我理解你的用意, 抱歉我理解错了。
Reply
Dante on #
没关系,不同的角度而已
Reply
小苍MM on #
我也想了解了解!!!先顶一个
Reply
ashui on #
这样测试明显有问题啊。。python冷启动是要时间的,正常的服务器端程序肯定不会每次都冷启动。
Reply