flask+Gunicorn(gevent)+sqlalchemy 高并发的解决方法探究

时间:2024-03-23 18:48:38

使用Flask的做服务,可以以python code.py的方式运行,但这种方式不能用于生产环境,不稳定,比如说,每隔十几分钟,有一定概率遇到连接超时无返回的情况。

我这周做了一些调研,关于python flask做服务时,处理多线程,高并发的一些手段,主要包括以下的几个方面:

1,通过设置app.run()的参数,来达到多进程的效果。看一下app.run的具体参数:

flask+Gunicorn(gevent)+sqlalchemy 高并发的解决方法探究

通过官方文档,可以得出,我们可以通过threaded来实现多线程的目的。通过设置processes来达到多进程的目的。

但需要注意的是threaded与processes不能同时打开,如果同时设置的话,将会出现以下的错误:

flask+Gunicorn(gevent)+sqlalchemy 高并发的解决方法探究

2,使用gevent做协程,从而解决高并发的问题:

具体的代码如下:
flask+Gunicorn(gevent)+sqlalchemy 高并发的解决方法探究

然后通过这种方式包装WSGIServer((address, port), app).serve_forever()

通过python code.py的方法,来启动服务

3,通过Gunicorn(with gevent)的形式对app进行包装,从而来启动服务。

关于Gunicorn的参数如下:可以通过Gunicorn -h来查看,下面放部分参数

flask+Gunicorn(gevent)+sqlalchemy 高并发的解决方法探究

通过下面的代码,来进行启动代码:

gunicorn -c gun.py thread_explore:app

其中 gun.py是gunicorn的配置文件

thread_explore是服务的主程序

app是flask的app

gun.py的具体内容如下:

flask+Gunicorn(gevent)+sqlalchemy 高并发的解决方法探究

 

其中bind是服务的地址,具体形式:“address:port"

经过查阅资料,workers的数目并不是越大越好,通常是根据服务器的cpu个数来确定的,建议的个数为:

2*cpu个数+1

针对以上的各种思路,分别对其压测:

ab -n 1000 -c 20 

其中n代表请求的次数,-c指的是并发的数目

测试的结果如下:

flask+Gunicorn(gevent)+sqlalchemy 高并发的解决方法探究

 

通过以上的分析,以及查阅的资料,针对flaks的高并发状况,建议采取以下的思路:

Nginx + Gunicorn(with gevent) + Flask + scoped_session

在sqlalchemy走过的一些坑:

通常我们用 SQLAlchemy 写数据的时候要创建 Session 对象来维护数据库会话,用完了再关掉。但是这种在web大量的请求的情况下,会出现线程不安全的情况:

flask+Gunicorn(gevent)+sqlalchemy 高并发的解决方法探究

通过查阅sqlalchemy的官网文档,以及网上的一些帖子,可以发现,解决sqlalchemy的线程不安全问题,我们可以采用scoped_session的模式来解决。

来探究一下scoped_session到底怎么回事?

flask+Gunicorn(gevent)+sqlalchemy 高并发的解决方法探究

 

 

 

具体的地址:http://docs.sqlalchemy.org/en/latest/orm/contextual.html#using-thread-local-scope-with-web-applications

白话翻译一下就是:

通常我们在初始化 web 应用时通过scoped_session函数对原始的Session工厂进行处理,返回出一个ScopedSession工厂,在每个请求来的时候就可以通过这个工厂获得一个 scoped_session 对象。

这实际上实现了一种 registry 模式,它有个中心化的 registry 来保存已经创建的 session,并在你调用ScopedSession工厂的时候,在 registry 里面找找是不是之前已经为你创建过 session 了,如果有,就直接把这个 session 返回给你,如果没有,就创建一个新的 session,并注册到 registry 中以便你下次来要的时候给你。

这样,我们在整个请求的任意环节,都可以开开心心地随时通过工厂来获取一个 “新的”session 对象,而只要在请求处理完的时候移除这个 session 就可以了。

代码如下:

flask+Gunicorn(gevent)+sqlalchemy 高并发的解决方法探究