django 重写 mysql 连接库实现连接池

问题

django 项目使用 gunicorn + gevent 部署,并设置 CONN_MAX_AGE 会导致 mysql 数据库连接数飙升,在高并发模式可能会出现 too many connections 错误。该怎么解决这个问题呢?首先看下 django 源码,找到问题的根源。

本文 django 版本为 2.2.3。

问题分析

首先查看连接部分源码:

# django/db/backends/mysql/base.py

class DatabaseWrapper(BaseDatabaseWrapper):
vendor = 'mysql'
...
...
...
def get_new_connection(self, conn_params):
# 每次查询都会重新建立连接
return Database.connect(**conn_params)
...
...
...

再查看其基类 BaseDatabaseWrapper

# django/db/backends/base/base.py

class BaseDatabaseWrapper:
"""Represent a database connection."""
# Mapping of Field objects to their column types.
data_types = {}
...
...
... def _close(self):
if self.connection is not None:
with self.wrap_database_errors:
# 每次查询完又要调用 close 关闭连接
return self.connection.close()
...
...
...

查看源码发现 django 连接 mysql 时没有使用连接池,导致每次数据库操作都要新建新的连接并查询完后关闭,更坑的是按照 django 的官方文档设置 CONN_MAX_AGE 参数是为了复用连接,然后设置了 CONN_MAX_AGE 后,每个新连接查询完后并不会 close 掉,而是一直在那占着。

问题解决

通过重写 django 官方 mysql 连接库实现连接池解决。

settings.py 配置


...
DATABASES = {
'default': {
'ENGINE': 'db_pool.mysql', # 重写 mysql 连接库实现连接池
'NAME': 'devops',
'USER': 'devops',
'PASSWORD': 'devops',
'HOST': '192.168.223.111',
'PORT': '3306',
'CONN_MAX_AGE': 600,
# 数据库连接池大小,mysql 总连接数大小为:连接池大小 * 服务进程数
'DB_POOL_SIZE': 20, # 默认 5 个
'OPTIONS': {
'init_command': "SET sql_mode='STRICT_TRANS_TABLES'",
},
}
}
...

目录结构

db_pool/
├── __init__.py
└── mysql
├── base.py
└── __init__.py
  • db_pool 位于 django 项目根目录

base.py

# -*- coding: utf-8 -*-
import random
from django.core.exceptions import ImproperlyConfigured try:
import MySQLdb as Database
except ImportError as err:
raise ImproperlyConfigured(
'Error loading MySQLdb module.\n'
'Did you install mysqlclient?'
) from err from django.db.backends.mysql.base import *
from django.db.backends.mysql.base import DatabaseWrapper as _DatabaseWrapper DEFAULT_DB_POOL_SIZE = 5 class DatabaseWrapper(_DatabaseWrapper):
def get_new_connection(self, conn_params):
# 获取 DATABASES 配置字典中的 DB_POOL_SIZE 参数
pool_size = self.settings_dict.get('DB_POOL_SIZE') or DEFAULT_DB_POOL_SIZE
return ConnectPool.instance(conn_params, pool_size).get_connection() def _close(self):
return None # 覆盖掉原来的 close 方法,查询结束后连接不会自动关闭 class ConnectPool(object):
def __init__(self, conn_params, pool_size):
self.conn_params = conn_params
self.pool_size = pool_size
self.connects = [] # 实现连接池的单例
@staticmethod
def instance(conn_params, pool_size):
if not hasattr(ConnectPool, '_instance'):
ConnectPool._instance = ConnectPool(conn_params, pool_size)
return ConnectPool._instance def get_connection(self):
if len(self.connects) < self.pool_size:
new_connect = Database.connect(**self.conn_params)
self.connects.append(new_connect)
return new_connect
index = random.randint(0, self.pool_size - 1) # 随机返回连接池中的连接
try:
# 检测连接是否有效,去掉性能更好,但建议保留
self.connects[index].ping()
except Exception:
self.connects[index] = Database.connect(**self.conn_params)
return self.connects[index]

总结

利用连接池 + 假关闭的方式解决过高连接数的问题。

django 重写 mysql 连接库实现连接池的更多相关文章

  1. Qt动态连接库/静态连接库创建与使用,QLibrary动态加载库

    版权声明:若无来源注明,Techie亮博客文章均为原创. 转载请以链接形式标明本文标题和地址: 本文标题:Qt动态连接库/静态连接库创建与使用,QLibrary动态加载库     本文地址:https ...

  2. VC++静态连接库

    目录 第1章静态连接库    1 1.1 同名函数的选择    1 1.2 模块合并    2 1.2.1 模块替换    4 1.3 内联函数    4 第1章静态连接库 静态连接库与动态连接库一样 ...

  3. MySQL学习(六)——自定义连接池

    1.连接池概念 用池来管理Connection,这样可以重复使用Connection.有了池,我们就不用自己来创建Connection,而是通过池来获取Connection对象.当使用完Connect ...

  4. django更换ORM连接处理(连接池)转

    1 概述 在使用 Django 进行 Web 开发时, 我们避免不了与数据库打交道. 当并发量低的时候, 不会有任何问题. 但一旦并发量达到一定数量, 就会导致 数据库的连接数会被瞬时占满. 这将导致 ...

  5. mysql 的 java 连接库

    mysql 的 java 连接库 解压缩mysql-connector-java-5.1.30.zip 将要使用的是mysql-connector-java-5.1.30-bin-g.jar和mysq ...

  6. MySQL之长连接、短连接、连接池

    当数据库服务器和客户端位于不同的主机时,就需要建立网络连接来进行通信.客户端必须使用数据库连接来发送命令和接收应答.数据.通过提供给客户端数据库的驱动指定连接字符串后,客户端就可以和数据库建立连接了. ...

  7. 解决数据库连接池连接mysql时,每隔8小时mysql自动断开所有连接的问题

    解决数据库连接池连接mysql时,每隔8小时mysql自动断开所有连接的问题 最近有个问题非常讨厌,我们的工程中使用自己的连接池连接mysql数据库,可mysql数据库每隔8小时就会自动断开所有链接, ...

  8. php和mysql连接方式(短 长 池)

    一个php work进程只能处理一个请求,当完成一个请求了,才能处理下一次的请求 2.短连接: 执行到php关闭mysql连接的代码时,就断开,否则在处理本次请求结束的时候,释放mysql连接 实验: ...

  9. Mysql(九):Python连接MySQL数据库之pymysql模块使用

    Python3连接MySQL 本文介绍Python3连接MySQL的第三方库--PyMySQL的基本使用. PyMySQL介绍 PyMySQL 是在 Python3.x 版本中用于连接 MySQL 服 ...

随机推荐

  1. (63)C# 不安全代码unsafe

    unsafe fixed stackalloc void*

  2. <读书笔记>《锋利的jQuery》

    2016年4月3日 第4章 jq中的事件和动画 4.1 jq中的事件 (1)window.onload.$(documet).ready()的区别: 1.执行时机:window.onload需要整个页 ...

  3. 数论---lcm和gcd

    cd即最大公约数,lcm即最小公倍数. 首先给出a×b=gcd×lcm 证明:令gcd(a,b)=k,a=xk,b=yk,则a×b=xykk,而lcm=xyk,所以ab=gcd*lcm. 所以求lcm ...

  4. go 学习之函数

    个人把go函数理解分三种: 1.普通函数 普通函数声明: func name(parameter-list) (result-list) { body} package main import &qu ...

  5. Centos安装IDEA

    1.官网下载tar包 到https://www.jetbrains.com/idea 下载对应版本的文件 将其解压 tar zvxf idea下载文件.tar 进入到解压后文件夹的bin目录下执行 . ...

  6. Centos6安装mysql5.7最新版

    最近因为公司的服务器需要做基线和漏洞扫描,基线方面问题不大,按照报告上的加固建议,选一些权重高的问题处理一下就好了.但是漏洞扫描就比较坑了,扫出来了十几个高危和一百六十多个中危漏洞,不过还好漏洞基本上 ...

  7. VBA-数据库操作

    基本概念 1 怎么样才能操作数据库?使用ADO建立和数据库的连接,然后用ADO对象和sql语言对数据库进行操作. 2 SQL是什么?SQL(Structured Query Language)是一种查 ...

  8. bash date format

    Bash Date To format Bash Date to a required one, bash shell provides date command along with many fo ...

  9. MySQL系统架构

    已经很久没有写博客了,平时总感觉没有时间写,但是却有大把的时间去走神,去做一些无用的事情.写博客是挺锻炼人的一个过程,不仅锻炼写作能力,坚持写还能够大幅提升技术水平,写出来还能够有广大的网友帮助我们纠 ...

  10. 选择恐惧症的福音!教你认清MVC,MVP和MVVM(转:示例挺好,不太赞同画图)

    转自:http://zjutkz.net/2016/04/13/%E9%80%89%E6%8B%A9%E6%81%90%E6%83%A7%E7%97%87%E7%9A%84%E7%A6%8F%E9%9 ...