将一个基于 Tornado 框架的 Python REST-ful 服务改成非阻塞模型

泡菜刘 发布于 2016/11/06 23:27
阅读 92
收藏 0

将一个基于 Tornado 框架的 Python REST-ful 服务改成非阻塞模型,该服务主要业务为按照特定逻辑访问 SQLServer DB以及MemCache缓存。

设计到的类库如下:

pymssql  2.1.0  (如果使用python 3.5 需要升级到 >= 2.1.2,目前stable为 2.1.3)

pyodbc    3.0.10 (https://github.com/mkleehammer/pyodbc

bmemcached :https://github.com/jaysonsantos/python-binary-memcached

改造要求如下:

1. 多线程异步模型

我们目前使用的是多进程模型(一台主机上部署几十个Tornado进程),我们希望使用Python 3.5中引入的异步特性,结合 Tornado ,将服务改成多线程异步模型;


2.SQL Server DB 实现连接池

每一个Tornado进程都是无状态的,根据每次HTTP请求来获取目标DB信息,然后连接DB进行数据操作;将程序改成多线程模型以后,需要建立起针对DB的连接池,我们后端有上千个DB实例;

3.尽量提高程序的并发度,可以根据系统CPU数量自动调整

需要明确程序并发数量的瓶颈,以及并发数量可调整

4. 提供部署脚本

改造完成后要提供相应的升级类库的脚本,便于自动化升级

加载中
0
zhw2101024
zhw2101024
阻塞改成非阻塞,一般是把请求放在消息队列,再处理的。要做这方面的代码改造吗?还是用上python 3.5的特性和多线程就可以?
泡菜刘
泡菜刘
回复@zhw2101024 : 我们不是要引入消息队列,类似于我们要把处理消息的程序做成异步
0
泡菜刘
泡菜刘
@zhw2101024 这个服务是我们自己的基础中间件,我们想要提高基础中间件的并发处理能力。你可以先给个方案看看
0
BossHX
BossHX
python有GIL的限制多线程(系统级别线程,非类似gevent的协程)异步模型性能不会优于单线程异步。你们是想重构之后用一个进程撑以前多个进程的并发量吗?然后重构的技术栈必须按照你们的来吗或者你们的需求是优化而非重构?
0
泡菜刘
泡菜刘
@BossHX 是的,我们的目的是一个进程支持多个进程的并发量,但是由于使用pymmsql来访问SQLServer DB导致block整个主线程;我这边获取的资料想要把DB阻塞操作改成非阻塞的只能使用threadpool,然后结合tornado的run_on_executor 来实现。 只能在我们的代码基础上进行优化,不能更换技术栈。我现在的预想也是使用 Tornado 主循环接受处理请求,但是将block的操作放入Threadpool中。如果gevent可以比threadpool做的更好,当然可以使用gevent。
0
kaxifa
kaxifa

引用来自“泡菜刘”的评论

@BossHX 是的,我们的目的是一个进程支持多个进程的并发量,但是由于使用pymmsql来访问SQLServer DB导致block整个主线程;我这边获取的资料想要把DB阻塞操作改成非阻塞的只能使用threadpool,然后结合tornado的run_on_executor 来实现。 只能在我们的代码基础上进行优化,不能更换技术栈。我现在的预想也是使用 Tornado 主循环接受处理请求,但是将block的操作放入Threadpool中。如果gevent可以比threadpool做的更好,当然可以使用gevent。
我这边也遇到跟你类似的问题,目前已经解决并且上到生产环境。我采用的技术是gevent + tornado + cx_Oracle +memcache. 由于Oracle的OCI不支持异步,导致数据库不返回的时候造成整个进程阻塞不可用。问题解决后,单个数据库操作不返回的时候,整个进程依然可用,能应对一定量的高并发。采用多线程的时候,要千万小心线程安全方面的问题,而这个问题很可能造成在高并发下请求跟响应不匹配的致命错误,而我就遇到了,当然也解决了。如果你觉得靠谱,可以考虑让我试试看。
0
泡菜刘
泡菜刘
@zhw2101024 目前决定采用Gevent来实现,不考虑消息队列
0
壮士
壮士
Threadpool 也不会解决你的问题嘛,如果数据库太慢,线程建立太多GIL调度线程会把你拖的更慢~年初的时候我就已经试过了,你要用异步方有两个办法: 1. 数据库本身需要支持异步操作,不仅仅是开连接池的问题. 我找过几异步mysql库,基本都是用线程模拟异步,如果在Python这一端开来线程就意义不大了. 目前支持异步的操作的数据库好像是postgresql,但我没有尝试过,mysql目前都不支持异步。 2. 使用没有GIL的环境建立数据库操作比如,C\C++, Java, C# 一类的,再对外开放接口,使用tornado的异步httpclient去调用。这样一来整个tornado都是建立在异步环境上的,基本上是不可能堵死。 第二个方案只不过是把线程池从Python端移到了其它环境中,本质上并没有什么改变,不过比起简单粗暴的在Python中直开接线程,效果还是有一些的~但回到本质上来说如果你数据库太慢第二种方案的连接数也会撑暴数据库~ 我们也碰到这个问题~年初的时候就搞过一下~可以交流一下~
0
zhw2101024
zhw2101024
我们对mongo用得比较多,可扩展性是很强的,可以简单通过增加分区应对高并发
0
泡菜刘
泡菜刘
@壮士 是的,threadpool是不解决问题,你可以看看Gevent,直接替换python的socket改成异步的
0
壮士
壮士

引用来自“泡菜刘”的评论

@壮士 是的,threadpool是不解决问题,你可以看看Gevent,直接替换python的socket改成异步的
我们现在的Python环境全都已经换成了3.5了~已经不用Gevent了~
返回顶部
顶部