暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

如何合理限制django 的数据库连接数?

写程序的日子 2020-07-08
1895

后文以django 连接mysql 为例,进行说明。

背景

django 的默认机制中,在查询时,会建立数据库连接,查询结束后,会断开数据库连接 —— 没有连接池的概念。

官方文档中描述,可以通过设置 CONN_MAX_AGE 让执行数据库查询后,不立即断开连接 —— 一定时间内保持连接,当新的查询任务在连接未断开时,可以复用此连接。这样的好处有:

  • 避免频繁的建立连接,断开连接,消耗数据库的资源

  • 避免大并发时,数据库连接数过多

目标:限制连接数

连接池的引入,可以在并发数高时,限制程序和数据库的连接数,避免数据库连接数太大的错误。

当django 面临高并发时,就会引发连接数过多的错误,此时我们可能会希望使用连接池(允许单个接口增加等待资源,以执行查询的时间)。

比如(特定场景):甲方给乙方提供了user_test 的账号,用于查询db_test数据库,但是限制了user_test 在 db_test 上的连接数。

此时,django 没有连接池的概念就对不上了:因为就算设置 CONN_MAX_AGE,也无法有效限制数据库连接数。

解决方案

限制线程数
  • 方法

在通过uwsgi 部署时,可以限制单个进程中线程数,通过限制整个应用的并发量来限制对于数据库的连接。

  • 优点

操作简单,实现方便

  • 缺点

并发能力大大降低。因为部分请求是不会实际发生数据库操作的,对于连接数的控制不够细腻。

第三方连接引擎
  • 方法

在settings.py 文件中,需要指定数据库驱动。例如默认的django.db.backends.mysql。

可以通过引入第三方的驱动,或者自己完成的驱动,来完成连接池的效果。

  • 优点

对连接数量的控制细腻,同时使用简单(自己完成不简单)

  • 缺点

难以把控第三方数据库驱动稳定性和正确性。以现在各方的资料博客显示,各个第三方库的维护大概就只有2-3次,当在企业级项目开发时,不敢使用(特别是django 3.0 开始对接 python 异步特性)

权限限制(推荐)
  • 方法

在进程启动时,初始化一个线程安全的队列,放入所有令牌。通过对令牌的获取,实现执行权限的限制,限制实际的操作并发数,来限制数据库连接数,同时保持了django 中提供的,CONN_MAX_AGE 断开了解的功能。

  • 优点

控制细腻,操作简单,不需要完成复杂的第三方数据库驱动

  • 缺点

方法属于用时限制,不能像第三方连接引擎一样,在底层实现限制,如果不能把握好对django orm 的执行过程(懒加载的详细),那么会造成无法有效限制数据库连接数。

代码尝试

针对第三种实现方式,队列限制的方式:


  1. queue = Queue()

  2. for i in range(10):

  3. queue.put(i)


  4. def limit(func):

  5. def wrapper(*args,**kwargs):

  6. i = queue.get()

  7. result = None

  8. message = None

  9. try:

  10. result = func(*args,**kwargs)

  11. except Exception as e:

  12. message = e

  13. logging.error(e)

  14. finally:

  15. queue.task_done()

  16. queue.put(i)

  17. if message is not None:

  18. raise Exception(message)

  19. else:

  20. return result


  21. return wrapper


  22. @limit

  23. def test_do(a):

  24. value = Teachers.objects.all()

  25. return value


  26. class Test(View):

  27. def get(self,requests):

  28. value = test_do("test")

  29. return JsonResponse({"key":value})

为何不引入数据库连接池?

django 作为一个大而全的框架,为什么没有使用连接池技术呢?

开发设计方,不会没想到我这个较低层面所看到的问题,那么未使用连接池,一定有他的原因,那么接下来可以查找两个线路,来回答:

  • 有什么办法可以简单有效的限制数据库连接数?

    查询过程中,找到的资料一直不够满意(不够简单),思考很久,找到了自己暂时满意的答案。

  • 此处,不使用连接池有什么好处?

    未使用连接池,是对数据库不太负责的方式,但是带来的好处是,可以应对较高的并发,把并发的压力主要交给数据库。而数据库的压力,可以通过读写分离,分库分表,来缓解 —— 这比尝试解决python 速度慢的问题,简单了不少,只是操作并不简单。

所以,一方面在使用时,想限制连接数,操作简单(还满足MVC ,把所有的数据库操作封装出来),而不限制连接数时,压力适当交给数据库,减少python 速度慢带来的影响。


文章转载自写程序的日子,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论