一、前言
为了提高Django的并发性能,所以使用gunicorn+gevent组合来启动Django,但在过程中遇到了一个问题,之前能正常使用的接口按新方法部署后一直在报超时,后面排查发现当项目代码执行到使用Mysqlclient创建数据库连接时就会卡住。
网上找了一圈发现了一个解决方案:
但使用时会报错,方法不好使,后面查阅pymysql的github:https://github.com/PyMySQL/mysqlclient/pull/285发现作者移除了上述的方法:
移除的原因作者也做了解释:
一句话概括:waiter不能完全解决gevent阻塞的问题,所以对此建议使用pymysql。
二、解决方案
因此我只好将代码中的所有mysqldb连接替换为了pymysql连接的方式,得以解决问题:
import pymysql from pymysql.cursors import DictCursor db_con = pymysql.connect(......).cursor()
可能还有其他的三方库或方案来解决此问题,但由于改动成本的原因还是选择了替换为pymysql。
三、pymysql和Mysqlclient区别
PyMySQL和Mysqlclient提供相同的功能——它们都是数据库连接器。
区别在于Mysqlclient是C扩展,PyMySQL是纯Python的实现,由此可以看出Mysqlclient的性能会由于PyMySQL,但由于Mysqlclient不支持gevent,所以在涉及到需要使用gevent时,还是得使用PyMySQL。
四、为什么要使用gunicorn+gevent
由于Python全局解释器锁的存在,Python的多线程更像是一种伪多线程,甚至就几乎等于Python是个单线程的程序。
所以在使用多线程时回发现CPU并不会被打满,因为在同一时刻,Python只会有一个线程在运行。所以为了提高Django的并发性能,需要采用多进程的方式来弥补这个问题,gunicorn是基于unix系统的一个 Python 的 WSGI HTTP 服务器,使用它可以很方便的管理我们的后端服务,它也兼容很多其他的框架。
另外使用gevent能更好对性能提升,gevent是python的一个并发框架,以协程(微线程)greenlet为核心,使用了epoll事件监听机制以及诸多其他优化而变得高效,Gevent 通过 Cython 调用 libev 来实现一个高效的 event loop 调度循环。同时类似于 Event,Gevent 也有自己的 monkey_patch,在打了补丁后,完全可以使用 python 线程的方式来无感知的使用协程,减少了开发成本: