Python中使用gunicorn部署flask时遇到的redis连接数飙升问题如何解决?

小弟写了个简单的 flask 接口,其中使用了 redis,连接 redis 的语句写在全局里了,如下:
cache = redis.StrictRedis(‘127.0.0.1’, 6379)

然后使用 gunicorn 部署,部署命令是:
gunicorn --workers=9 --worker-class=gevent t_fl:app -b 0.0.0.0:5002

在高并发情况下(并发两千至五千)执行十万次请求,使用 info clients 命令查看 redis 的客户端连接数飙升到 3000 左右,严重拖慢了查询速度。请问有什么解决办法。
Python中使用gunicorn部署flask时遇到的redis连接数飙升问题如何解决?


5 回复

使用 Redis 连接池 ConnectionPool 设置最大连接数量


这个问题通常是因为Gunicorn的工作进程没有正确管理Redis连接池。每个工作进程启动时都会创建自己的连接池,当请求并发时会导致连接数激增。

核心解决方案是使用连接池并在进程间共享,或者改用单例模式管理Redis连接。这里推荐使用redis-py的连接池配合Flask应用上下文:

# app.py
from flask import Flask, g
import redis
from redis.connection import ConnectionPool

app = Flask(__name__)

# 全局连接池配置
REDIS_POOL = ConnectionPool(
    host='localhost',
    port=6379,
    max_connections=50,  # 控制总连接数
    decode_responses=True
)

def get_redis():
    """获取Redis连接(应用上下文内单例)"""
    if 'redis' not in g:
        g.redis = redis.Redis(connection_pool=REDIS_POOL)
    return g.redis

@app.teardown_appcontext
def close_redis(error):
    """请求结束时清理连接(实际归还到连接池)"""
    redis_client = g.pop('redis', None)
    if redis_client is not None:
        # Redis连接由连接池管理,这里不需要手动关闭
        pass

@app.route('/')
def index():
    redis_client = get_redis()
    # 使用redis_client进行操作...
    return 'OK'

if __name__ == '__main__':
    app.run()

关键点:

  1. 使用全局的ConnectionPool限制总连接数
  2. 通过Flask的g对象实现请求级别的连接复用
  3. Gunicorn配置建议:--workers=4 --threads=2(根据实际需求调整)

如果使用Celery或其他异步任务,需要单独配置它们的Redis连接池。

总结:用连接池替代每个请求新建连接。


如下声明之后,
rdp = redis.ConnectionPool(host=‘127.0.0.1’, port=6379,max_connections=10)
cache = redis.StrictRedis(connection_pool=rdp)

请求过来时会报错:
[2018-01-08 12:06:10,117] ERROR in app: Exception on / [POST]
Traceback (most recent call last):
File “/usr/lib64/python2.7/site-packages/flask/app.py”, line 1982, in wsgi_app
response = self.full_dispatch_request()
File “/usr/lib64/python2.7/site-packages/flask/app.py”, line 1614, in full_dispatch_request
rv = self.handle_user_exception(e)
File “/usr/lib64/python2.7/site-packages/flask/app.py”, line 1517, in handle_user_exception
reraise(exc_type, exc_value, tb)
File “/usr/lib64/python2.7/site-packages/flask/app.py”, line 1612, in full_dispatch_request
rv = self.dispatch_request()
File “/usr/lib64/python2.7/site-packages/flask/app.py”, line 1598, in dispatch_request
return self.view_functionsrule.endpoint
File “/opt/t_fl.py”, line 54, in index
timeout, endtime = get_timeout_endtime(GID)
File “/opt/t_fl.py”, line 20, in get_timeout_endtime
timeout_endtime = cache.get(gid)
File “/usr/lib/python2.7/site-packages/redis/client.py”, line 976, in get
return self.execute_command(‘GET’, name)
File “/usr/lib/python2.7/site-packages/redis/client.py”, line 665, in execute_command
connection = pool.get_connection(command_name, **options)
File “/usr/lib/python2.7/site-packages/redis/connection.py”, line 965, in get_connection
connection = self.make_connection()
File “/usr/lib/python2.7/site-packages/redis/connection.py”, line 981, in make_connection
raise ConnectionError(“Too many connections”)

gunicorn 使用 gevent 时–worker-connections 默认 1000,你可以把这个值设置小一些

我也碰到这个问题,请问楼主解决了没?

回到顶部