本文介绍连接池的工作原理 mssql-django 以及如何为 Django 应用程序配置连接池。
连接池的工作原理
默认情况下, mssql-django 使用 pyodbc 的内置连接池。 当 Django 关闭连接时,pyodbc 会将其返回到池,而不是关闭基础 ODBC 连接。 后续连接请求重复使用共用连接,从而减少建立新数据库连接的开销。
配置连接池
连接池通过 DATABASE_CONNECTION_POOLING 设置进行控制,该设置位于 settings.py 的模块级别(位于 DATABASES 字典之外):
DATABASES = {
"default": {
"ENGINE": "mssql",
"NAME": "<your-database>",
"USER": "<your-username>",
"PASSWORD": "<your-password>",
"HOST": "<your-server>",
"PORT": "1433",
"OPTIONS": {
"driver": "ODBC Driver 18 for SQL Server",
},
},
}
# Set to False to disable pyodbc's connection pooling
DATABASE_CONNECTION_POOLING = False
| 价值 | Behavior |
|---|---|
True(默认值) |
连接池已启用。 关闭的连接将返回到池。 |
False |
连接池已禁用。 每个连接在释放时都会被完全关闭。 |
何时禁用连接池
请考虑在以下情况下禁用连接池:
- 基于令牌的身份验证:使用过期的访问令牌时,共用连接可能会保留过时的令牌。
- 调试连接问题:禁用连接池可简化故障排除,因为这样能确保每个请求都会创建一个新连接。
- 短生命周期进程:对于只执行少量查询便退出的脚本或管理命令,连接池没有任何益处。
连接重试设置
无论连接池设置如何,都可以配置连接尝试失败时的重试行为。 有关重试和超时选项的完整列表,请参阅 配置参考。
DATABASES = {
"default": {
"ENGINE": "mssql",
"NAME": "<your-database>",
"USER": "<your-username>",
"PASSWORD": "<your-password>",
"HOST": "<your-server>",
"PORT": "1433",
"OPTIONS": {
"driver": "ODBC Driver 18 for SQL Server",
"connection_retries": 3,
"connection_retry_backoff_time": 10,
"connection_timeout": 30,
},
},
}
Django 的 CONN_MAX_AGE
Django 还提供一个 CONN_MAX_AGE 设置,用于控制 Django 在关闭数据库连接之前保持打开状态的时间。 此设置与 pyodbc 的连接池配合使用:
DATABASES = {
"default": {
"ENGINE": "mssql",
"NAME": "<your-database>",
"USER": "<your-username>",
"PASSWORD": "<your-password>",
"HOST": "<your-server>",
"PORT": "1433",
"CONN_MAX_AGE": 600, # Keep connections open for 10 minutes
"OPTIONS": {
"driver": "ODBC Driver 18 for SQL Server",
},
},
}
有关详细信息 CONN_MAX_AGE,请参阅 Django 数据库设置文档。
实用的起点:
-
CONN_MAX_AGE=0:最安全用于调试和短期作业。 -
CONN_MAX_AGE=600:对于许多 Web 应用来说,是个不错的默认选择。 -
CONN_MAX_AGE=3600:经过负载测试后,对于稳定的高吞吐量服务是合理的。
Note
使用 ASGI 服务器(如 Daphne 或 Uvicorn)或线程部署时,永久性连接可能会跨异步上下文泄漏。 如果你将 CONN_MAX_AGE 与 ASGI 服务器一起使用,请设置 CONN_HEALTH_CHECKS = True(Django 4.1 及更高版本),并在真实并发场景下进行测试。 有关详细信息,请参阅有关 连接管理的 Django 文档。
CONN_HEALTH_CHECKS 在重复使用之前验证共用连接。 如果 Django 检测到过时的连接,则会以透明方式打开一个新的连接。 这会增加每次请求的少量检查开销,而且对于长期运行的进程来说,通常值得启用。