Django中Mysql Redis连接池

MySQL 连接

对Django服务进行压测,DB报错数据库连接数过多,如果设置MySQL的最大连接数为1000,很快连接数就会达到上限,调整到2000,也很快连接数达到上限。

xuetangx DB最大连接数2048

mysql> show variables like 'max_connections';
+-----------------+-------+
| Variable_name   | Value |
+-----------------+-------+
| max_connections | 2048   |
+-----------------+-------+
1 row in set (0.00 sec)

通过Django文档可以发现Django其实提供了一个连接池的另一种时间方式

Django的默认数据库连接

Django程序接受到请求之后,在第一次访问数据库的时候会创建一个数据库连接,直到请求结束,关闭数据库连接。(Django opens a connection to the database when it first makes a database query. It keeps this connection open and reuses it in subsequent requests.)下次请求也是如此。因此,这种情况下,随着访问的并发数越来越高,就会产生大量的数据库连接。也就是我们在压测时出现的情况。

使用CONN_MAX_AGE减少数据库请求(连接池)

每次请求都会创建新的数据库连接,这对于高并发的应用来说是不能接受的。因此在Django1.6时,提供了持久的数据库连接,通过DATABASE配置CONN_MAX_AGE来控制每个连接的最大存活时间。

The default value is 0, preserving the historical behavior of closing the database connection at the end of each request. To enable persistent connections, set CONN_MAX_AGE to a positive number of seconds. For unlimited persistent connections, set it to None.

这个参数的原理就是在每次创建完数据库连接之后,把连接放到一个Theard.local的实例中。在request请求开始结束的时候,打算关闭连接时会判断是否超过CONN_MAX_AGE设置这个有效期。超过则关闭。每次进行数据库请求的时候其实只是判断local中有没有已存在的连接,有则复用。

基于上述原因,Django中对于CONN_MAX_AGE的使用是有些限制的,使用不当,会适得其反。因为保存的连接是基于线程局部变量的,因此如果你部署方式采用多线程,必须要注意保证你的最大线程数不会多余数据库能支持的最大连接数(一个线程一个连接)。另外,如果使用开发模式运行程序(直接runserver的方式),建议不要设置CONN_MAX_AGE,因为这种情况下,每次请求都会创建一个Thread。同时如果你设置了CONN_MAX_AGE,将会导致你创建大量的不可复用的持久的连接。

CONN_MAX_AGE设置

CONN_MAX_AGE的时间怎么设置主要取决于数据库对空闲连接的管理,比如你的MySQL设置了空闲1分钟就关闭连接,那你的CONN_MAX_AGE就不能大于一分钟,不过DBA已经习惯了程序中的线程池的概念,会在数据库中设置一个较大的值。

Redis 连接

在做一个直播活动时,所有评论数据保存Redis,收到Redis服务报错:max number of clients reached

redis 127.0.0.1:6379> CONFIG GET maxclients
1) "maxclients"
2) "200"

发现设置的这个最大连接数太小了,因为每次request都会创建redis连接,几百个人同时使用就达到最大上线了。

Django-redis可以设置Redis连接池,并设置最大连接数,这样就能保证连接的复用和连接数的控制。

the default connection pool is simple. You can only customize the maximum number of connections in the pool, by setting CONNECTION_POOL_KWARGS in the CACHES setting。

CACHES = {
    "default": {
        "BACKEND": "django_redis.cache.RedisCache",
        ...
        "OPTIONS": {
            "CONNECTION_POOL_KWARGS": {"max_connections": 100}
        }
    }
}

END

原创文章,作者:kinpo, k,如若转载,请注明出处:https://www.yidc.net/archives/5196