1
tanywei 2014-12-05 10:54:57 +08:00
不知道什么是celery?
|
2
binux 2014-12-05 10:59:15 +08:00
如果数据库block了,异步也没用,所有人都卡而已。你应该优化数据库
|
3
davidli 2014-12-05 11:19:23 +08:00
同1楼, 用celery.
|
4
ryanking8215 OP 感觉celery好重量级啊。
能不能用tornado.cocurrent.run_on_executor()和coroutine连接起来呢?是不是用这种方法解决的? |
5
lianghui 2014-12-05 14:07:33 +08:00
不知道你要做什么玩意,如果你的负载有4k req/s, 就告诉一个方法如何用tornado 和数据库异步落地架构(当然不是搞个什么python mysql异步库版本之类的)
|
6
ryanking8215 OP @lianghui 不做什么玩意,就是评估一下,如果用tornado做一个api服务,需要用到数据库,但是我对sql不熟,所以想用orm来解决数据库的问题,我想知道在这样情况下,orm是同步的,但是web framework是异步的,如何来协调。再比如我用asyncio呢?如何和sqlalchemy配合使用?
"就告诉一个方法如何用tornado 和数据库异步落地架构" 就是这个问题。 |
7
zhouquanbest 2014-12-05 14:22:55 +08:00
Celery是最优解
当然 如果你能处理好session的问题(即不要让一个进程里的所有Request都是用一个session) 可以用Douban的黑科技Greenify做到Mysqldb异步 |
8
lianghui 2014-12-05 15:03:03 +08:00
|
9
zhouquanbest 2014-12-05 15:33:00 +08:00
|
10
zenliver 2014-12-05 15:46:44 +08:00
用celery只是绕过了这个问题, 而不是解决了, 找找有没有人实现过, 没有, 自己轮一个吧, 用tornado ioloop 以及iostream去处理io,,,good luck
|
11
ryanking8215 OP @zhouquanbest ORM一般都有连接池,难道连接池是分进程的?就算是非阻塞架构的,例如nodejs 上的sequelizejs,也有连接池,一个sql请求由于某些问题会阻塞(不是阻塞式api),其他请求会用连接池里的继续用。和进程没有关系啊。就算mysql的driver是异步的,但ORM的api不是啊,例如不能yield的。
@lianghui ORM不是sqlalchemy最好了吗?其他的ORM,也是同步类型的,和sqlalchemy没区别啊,难道有异步的ORM吗? 起因是这次有个项目使用nodejs+sequelize来做的,由于nodejs的并发模型一致性,其他的组件通过promise或者callback都能集成起来,或者本来就是自然的。 但是python就不是,并发模型有可多线程,可多进程,可twisted的callback或者deferred,可tornado,gevent的coroutine,现在asyncio的coroutine又和tornado和gevent是不同的,在这种多样选择下,各种并发模型不同的库如何配合起来呢?这个是不是pythoner的痛点之一呢? 当然nodejs是好坑的,包括很多第三方的库,本着多学一点的原则,所以想和大家探讨探讨。 |
12
ryanking8215 OP @binux 数据库block,肯定是数据库的设计有问题,但是在ORM在请求时是同步socket,由于网络问题也会block,那tornado的异步就没有意义了。
|
13
zenliver 2014-12-05 15:52:58 +08:00
https://github.com/mayflaver/AsyncTorndb 这是我轮的一个 不过还是有些问题, 仅供参考
|
14
binux 2014-12-05 15:56:30 +08:00
@ryanking8215 只能说 tornado 不认为连 mysql 都要堵是个问题。
|
15
lianghui 2014-12-05 15:59:07 +08:00
@zhouquanbest
先说最简单的方法, 使用OpenResty lua 编写数据库落地接口 tornado 优化一个能够长连接的http client 或者直接使用自带的异步client 发送请求 如 req: /query?op=user.find_by_user&uid=1222 res : {"uid" : 1222, "name", ...... } req /execute?op=user.save&data=<User.as_json> req: 200 0k 这类架构 数据库使用openresty 作为dbproxy 上面的例子中使用的http协议,数据可是用json或者google protobuf(这个比较高效) 效率在 3k-4k req/s ### 使用长连接 如果绝对http协议不够高效,那么使用tcp自行封装一个简单长连接的协议。 不过这样dbproxy serverlength需要使用c++之类的做个异步server了。协议可以选高效的二进制协议 protobuf只是一个选择。 如 req: {"op": "user.find_by_uid", "data": {"uid": 12}}\r\n 使用这类行协议 回复如下: 7200 ok 23{"uid" : 1222, "name", ...... } 回复消息定义首4位标识消息状态长度 上面是状态200 msg为 ok 之间是空格分隔 然后紧接着32位标识数据长度,后面自定义解析的raw数据,觉得要省事可以使用protobuf。 这类优化后到 5-6k req/s问题不大。但这时,妈蛋去多关心你的数据库压力,然后去优化吧。 |
16
lianghui 2014-12-05 16:07:17 +08:00
@ryanking8215 抱歉呀,sqlalchemy没用过,做游戏的,不关心这类的,更喜欢直接使用data-mapper模式。
http://martinfowler.com/eaaCatalog/dataMapper.html 推荐看这位作者企业架构书 http://www.amazon.com/Patterns-Enterprise-Application-Architecture-Martin/dp/0321127420 |
17
ryanking8215 OP @lianghui RPC?就好比tornado收到request后,和后端的db_proxy通信,db_proxy可以用啥哈nodejs+sequelize也可以啊,那就没有这个问题了,呵呵。大概你们做游戏的都是分层的,如果只是撸个blog,那就太厚了,这儿问题还是存在的。
|
18
openroc 2014-12-05 17:02:40 +08:00
用nodejs吧,异步到你爽YY~~
|
19
qbeenslee 2014-12-05 17:12:25 +08:00
可以开ThreadPool来异步处理
|
20
ryanking8215 OP @qbeenslee 貌似只能这样了
|
21
qbeenslee 2014-12-05 17:25:31 +08:00
@ryanking8215 楼主在tornado上可以多多交流, 我最近也想用tornado做毕业设计...
|
22
halfelf 2014-12-05 19:45:28 +08:00
有没有人用过gevent + sqla + pymsql
|
23
sujin190 2014-12-05 21:24:20 +08:00
|
24
sujin190 2014-12-05 21:25:56 +08:00
使用greenlet实现异步,和pymongo的motor的实现机理一样,现在用在自己项目中
|
25
ponyfk 2014-12-05 22:14:44 +08:00
一定要用orm的话, 我推荐 ponyorm(配合ultramysql) + gevent + flask 完美解决异步
|
27
sujin190 2014-12-05 22:28:43 +08:00
@zenliver mysql协议是二进制解析的,有非常多的自己读取,每次调用iostream的read其实是效率非常低的
|
29
zhicheng 2014-12-07 21:03:06 +08:00 2
这个问题不用太担心,
一,一般 WebServer 和 DB 都是局域网直连,网络性能损失很小,在要求不是极高的情况下,能够满足需求。 二,因为 RDBMS 的特殊性,目前一个连接并不能同时执行多个请求。所以如果使用非阻塞IO,不仅会导致前端非常复杂,并且依然会卡在一个执行时间超长的 SQL 上,除非针对每次请求创建一个 DB 连接,这样一定程度上增加了 latency 和 DB 的负荷。 三,如果用多核 CPU (现在几乎全部都是)的服务器,可以同时创建多个 Web Server 的进程,能够缓解DB阻塞的问题。 四,不建议自己实现 DB Driver ,除非你知道你在做什么。 五,自己实现协议和DB的,都是走火入魔的标志。 |
30
ryanking8215 OP @zhicheng
一. 提出tornado,就是想探讨一下非阻塞模型下如何使用同步ORM的问题,不是说一定不能直接使用。只是如果后端没有压榨出non-blocking的效率,于心不忍。 二. 不是有连接池吗? 三. 同意,单线程的无法使用多核,需要多进程加入。目前看来,除了自带调度器的golang,erlang啥的,其他的语言要网络io的高并发,就是多进程+单线程的事件循环了。 四. 看个人角度了,对有些人来说是对的,对某些人来说这句话是错的。 五. 同上 |
31
zhicheng 2014-12-07 23:26:13 +08:00
一,如果实在想解决这个问题,中间加一层 API ,负责处理 Web Server 和 DB 的连接。
二,连接池确实能解决一定问题。 三,这跟是否自带调度器无关,而是因为 Python 有 GIL 。我现在在 C 部分的代码,即使多线程也是每个线程使用一个 event loop 。跟进程模型几乎一样的,只是节省了共享内存的部分。 四,如果你写过类似的,就会知道,像这样的产品,从开始到可用,最少需要一年的时间。 五,同上。 六,优秀的工程师必备条件之一就是不要高估自己的能力。 |
32
zhouquanbest 2014-12-08 00:24:32 +08:00
@lianghui
这确实是个解法 和celery一回事 就是让db操作和tornado分离 好像百度是这么干的吧 不过小项目这样做也挺累 Tornado麻烦在于 小项目sql也堵死你 只能提前优化 异步真是不能省心 |
33
toooddchen 2014-12-08 00:42:27 +08:00
tornado和sqlalchemy的使用, 对你提到的非阻塞特性没有什么影响.
db访问层面阻塞了, 不会影响tornado对其它请求的处理. 影响单线程ioloop性能的, 是cpu密集的操作, db访问不属于这一类. |
34
MasterYoda 2014-12-08 09:57:04 +08:00
@toooddchen
你起一个tornado进程,然后来一个复杂的sql查询请求,阻塞后再来别的请求看看影响它对其它请求的 处理不。 |
35
ryanking8215 OP @MasterYoda 同意,其实time.sleep()就可以了
@toooddchen 为什么cpu密集操作会影响eventloop性能呢?因为event loop无法及时“归位”,同理,同步的ORM会阻塞当前执行的协程。影响event loop性能的不单单是cpu密集操作,比如time.sleep()。这是那啥充分必要条件,好久没整,整不清楚了。 |
36
beef9999 2014-12-17 11:32:27 +08:00
没错,tornado的特性之一是异步非阻塞,但是这不是根本,根本上来说它是一个使用了epoll的web server,能保证大量网络连接送到python代码的get或者Post的这个过程是高效的,只要你不阻塞get 或者post,剩下的你想干什么都行。不阻塞的方法很多,你可以用异步调用,这样语法就比较难看,即使是用了生成器,还是很反直觉,另外在python 2还有raise Return(response)这种诡异的东西。当然这些都不是问题,最主要的问题是很多ORM数据库不支持异步,所以最佳实践还应该是去开线程,使用线程池。tornado能够支持线程,并且经过仔细编写的代码也是能够达到线程安全的。最后有人说用gevent,理论可以,这样你就能写出不阻塞的同步代码,也支持数据库了。但是怎么集成tornado是个问题,目前看到的似乎没有成熟的项目
|
37
Pegasus 2016-01-19 15:49:50 +08:00 1
http://techspot.zzzeek.org/2015/02/15/asynchronous-python-and-databases/
这个是 SQLArchemy 作者的文章,可以看看为什么不推荐使用异步的 orm |
38
dantangfan 2016-02-17 20:12:44 +08:00
@Pegasus 只是不推荐 python 实现的异步吧
|