Mysql Too many connections错误的解决办法

python使用多线程的时候,mysql报了[ERROR] (1040, ‘Too many connections’)错误,意思是连接数太多,记录下解决办法:

定位问题:

一、查看Mysql最大连接数
SHOW VARIABLES LIKE '%max_connections%';
Variable_name Value
centered max_connections centered 100
二、查看当前连接数
SHOW STATUS LIKE 'Threads%';
Variable_name Value 说明
Threads_cached 58
Threads_connected 57 当前打开的连接数,含休眠的连接数
Threads_created 3676
Threads_running 4 当前运行的连接数

当Threads_connected 超过max_connections 就会报错

解决办法:

一、增加最大连接数。
SET GLOBAL max_connections=1000; #重启Mysql后失效

修改mysql配置文件my.cnf,在[mysqld]段中添加或修改max_connections值:

max_connections=1000 #重启Mysql服务生效
二、缩短服务器关闭非交互连接之前等待活动的秒数。

查看当前连接数详情,可以发现有很多连接处于休眠状态,虽然没在运行,但依然会占用Mysql连接数

SELECT * FROM  information_schema.processlist;#查看当前连接
show global variables like 'wait_timeout';#
Variable_name Value 说明
wait_timeout 28800 mysql在关闭一个非交互的连接之前要等待的秒数,默认是28800s
set global WAIT_TIMEOUT=3600;

修改这个数值,表示mysql在关闭一个非交互连接之前要等待的秒数,至此可以让mysql自动关闭那些没用的连接,但要注意的是,正在使用的连接到了时间也会被关闭,因此要根据业务情况,谨慎使用。

三、优化代码逻辑:
  1. 使用连接池
    #连接池对象
    __pool = {}

    def __init__(self, conf=None):

        #数据库构造函数,从连接池中取出连接,并生成操作游标
        self.conn = DB.__getConn(conf)
        self.cursor = self.conn.cursor()

    def __del__(self):
        self.cursor.close()
        self.conn.close()

    @staticmethod
    def __getConn(conf=None):
        """
        @summary: 静态方法,从连接池中取出连接
        @return MySQLdb.connection
        """
        if not(conf):
            conf = config.DB

        key = "%s-%s" % (conf['host'], conf["dbname"])

        if DB.__pool.has_key(key)==False or not(DB.__pool[key]):
            DB.__pool[key] = PooledDB(creator=MySQLdb, mincached=1, maxcached=100,
                              host=conf['host'], port=conf['port'], user=conf['user'], passwd=conf['password'],
                              db=conf['dbname'], use_unicode=False, charset='utf8', cursorclass=DictCursor, setsession=['SET AUTOCOMMIT = 1'])
            DB.__pool[key].connection()

        return DB.__pool[key].connection()
  1. 每个线程初始化一次mysql连接,连接传入到业务逻辑中使用
class ThreadWorker(threading.Thread):
    def __init__(self,lock=None,q=None,tableConf=None,threadName=""):
        super(ThreadWorker, self).__init__()
        self.__testDB1 = dbmanager.DB(conf=config.TESTDB1)
        self.__testDB2 = dbmanager.DB(conf=config.TESTDB2)
        self.__testDB3 = dbmanager.DB(conf=config.TESTDB3)
        self.lock = lock
        self.queue = q
        self.tableConf = tableConf
        self.threadName = threadName

    def run(self):
        syncConf = {
            "test1":self.__testDB1,
            "test2":self.__testDB2,
            "test3":self.__testDB3,
        }
        targetDB = syncConf.get(self.tableConf.get("targetDb"))

        #检查入库是否正确
        dbCheck = check_target_db(targetDB)
        if not dbCheck:
            return

        try:
            ConsumerClass(targetDB=targetDB,lock=self.lock,q=self.queue,tableConf=self.tableConf,threadName=self.threadName).entrance()
        except Exception as e:
            log.logger.exception(e)
  1. mysql连接数计算方式
    最大连接数是全局配置,如果创建了多个数据库,每个数据库的连接数相加之后超过最大连接数,上述testDB1-3存在于同一个mysql服务,线程数为15,启动一次产生的连接数为3*15=45。当业务较多时,要及时修改最大连接数。

你可能感兴趣的:(python,mysql,mysql,数据库)