2026-07-18-datasource-connection-pool-design.md 11 KB

数据源连接池与凭据安全设计

日期:2026-07-18 状态:已批准,进入实施计划

1. 目标

为 DataOps 平台接入的外部业务数据源建立统一、安全、可观测的连接池框架。 第一阶段走通 PostgreSQL 和 MySQL,部署边界为单台服务器、单个后端实例, 并为后续多副本部署保留配置与接口扩展能力。

本设计明确区分两类数据库连接:

  • 平台控制库:DataOps 自身使用的 PostgreSQL,保存用户、订单、流程版本、 工作台、知识库等平台数据。继续由 Flask-SQLAlchemy 管理,不建设额外的 数据源连接池管理层。
  • 业务数据源:通过 DataSource 定义接入的外部数据库。元数据采集、数据预览、 质量检查和 DataFlow 执行通过本设计的连接池管理器访问。

2. 范围

2.1 第一阶段范围

  • PostgreSQL 数据源,驱动为 postgresql+psycopg2
  • MySQL 数据源,驱动为 mysql+pymysql
  • 按数据源延迟创建和复用连接池。
  • 空闲池回收、配置变更失效、删除时排空。
  • 数据源凭据加密保存和历史明文凭据迁移。
  • 故障隔离、熔断、指标和管理员诊断。
  • 全本地隔离 Docker 验收环境。

2.2 暂不进入第一阶段

  • 多后端副本间的全局连接预算和共享状态。
  • PgBouncer 或其他外部连接代理。
  • Oracle、SQL Server、DB2、Sybase 等驱动的正式验收。
  • 跨实例分布式连接池、分布式锁或集中式连接代理。
  • 任意 SQLAlchemy driver name 和任意 connect_args 透传。

3. 总体架构

平台控制面
Flask-SQLAlchemy ──> 平台 PostgreSQL
仅使用框架连接管理,不进入 DataSource Pool Registry

业务数据面
DataSource API / 元数据采集 / 数据预览 / DataFlow
                    │
                    ▼
          DataSourceConnectionManager
          ├── DataSourceDefinitionRepository
          ├── CredentialProvider
          ├── PostgreSQLAdapter
          ├── MySQLAdapter
          ├── PoolRegistry
          ├── CircuitBreaker
          └── PoolMetrics
                    │
          ┌─────────┴─────────┐
          ▼                   ▼
 PostgreSQL 数据源池       MySQL 数据源池

业务模块只能通过 DataSourceConnectionManager 获取外部数据库连接,不得直接 读取数据源密码并调用 create_engine()。连接测试是唯一允许创建临时 Engine 的 入口,且必须使用 NullPool 并在完成后执行 dispose()

4. 数据源身份与连接池注册

每个数据源必须具有稳定 UUID,并以 data_source_uid 作为业务身份。池注册键由 以下内容组成:

data_source_uid
credential_version
connection_config_fingerprint

连接配置指纹由数据库类型、主机、端口、数据库名、Schema 和白名单安全选项生成, 不包含用户名、密码、连接 URL 或密文。

连接池按需创建:

  • 第一次采集、预览或 DataFlow 使用时创建。
  • 同一 Gunicorn Worker 内,同一注册键复用一个 SQLAlchemy Engine。
  • 数据源定义、凭据版本或安全配置变化后,旧注册键失效。
  • 数据源删除后,禁止新连接借出并排空旧池。
  • 空闲 15 分钟的池执行回收。
  • 每个 Worker 默认最多缓存 20 个空闲池。
  • 正在执行任务的池进入 draining,连接归还后再释放。

Gunicorn Worker 是独立进程。即使只有一个后端实例,各 Worker 仍拥有独立的 Pool Registry,第一阶段不尝试跨进程共享数据库连接。

5. 默认容量

单个数据源、单个 Worker 的默认参数:

pool_size=2
max_overflow=3
pool_timeout=10
pool_recycle=1800
pool_pre_ping=true
pool_use_lifo=true

采用 4 个 Worker 时,一个持续繁忙的数据源理论最大连接数为 20,常驻连接数 最大为 8。数据源可以配置受控的池大小覆盖值,但服务端必须限制上下限,不能直接 接受用户提交的任意连接数量。

后续多副本阶段使用以下公式重新计算单数据源连接预算:

副本数 × Worker 数 × (pool_size + max_overflow)

6. 驱动适配

Adapter 负责:

  • 校验数据源类型和连接字段。
  • 构建 SQLAlchemy URL。
  • 生成驱动专属白名单参数。
  • 创建 Engine。
  • 执行 SELECT 1 探测。
  • 将驱动异常转换为稳定的平台错误。
  • 提供数据库标识符引用和只读事务能力。

PostgreSQL 默认启用 TCP keepalive:

connect_timeout=5
keepalives=1
keepalives_idle=30
keepalives_interval=10
keepalives_count=3

MySQL 默认设置:

connect_timeout=5
read_timeout=30
write_timeout=30
charset=utf8mb4

SSL 和证书参数只能从明确白名单读取,不允许任意驱动参数透传。前端传入的 type 必须映射到平台内部 Adapter,不能直接成为 SQLAlchemy driver name。

7. 凭据模型

平台 PostgreSQL 新增 datasource_credentials

id
data_source_uid
credential_version
encrypted_payload
nonce
key_version
status
created_at
retired_at

encrypted_payload 包含用户名、密码和必要的认证选项。Neo4j DataSource 节点 只保存:

uid
type
host
port
database
schema
credential_ref
credential_version
业务描述和治理属性

凭据使用 AES-256-GCM 加密:

  • 主密钥由 DATASOURCE_CREDENTIAL_MASTER_KEY 环境变量注入。
  • 每条凭据使用独立随机 nonce。
  • data_source_uid + credential_version 作为附加认证数据。
  • key_version 为后续主密钥轮换保留。
  • 主密钥不写入代码、数据库、镜像或日志。
  • 缺少主密钥或解密失败时,数据源功能失败关闭,但平台控制面仍可启动。

API、日志、异常、Neo4j 查询结果和诊断接口均不得返回用户名、密码、密文、 带凭据的 URL 或完整连接串。数据源列表只返回 credential_configured 等布尔状态。

8. 数据源变更流程

8.1 创建

  1. 校验类型,只允许 PostgreSQL 或 MySQL。
  2. 校验主机、端口、数据库名和安全选项。
  3. 使用 NullPool 临时 Engine 测试连接,随后关闭。
  4. 将凭据加密写入平台 PostgreSQL。
  5. 在 Neo4j 保存不含密码的数据源定义及凭据引用。
  6. 成功后允许 Pool Registry 按 UID 延迟创建连接池。

8.2 修改

  1. 创建不可变的新凭据版本。
  2. 更新 Neo4j 数据源定义和 credential_version
  3. 将旧连接池标记为 draining
  4. 后续请求使用新注册键创建连接池。
  5. 旧凭据标记为 retired

修改失败时,数据源继续引用原有有效版本。PostgreSQL 与 Neo4j 之间使用现有 Outbox 和补偿巡检实现最终一致性。

8.3 删除

  1. 禁止新连接借出。
  2. 等待已借出连接在限定时间内归还。
  3. 到期后强制释放 Engine。
  4. 删除或归档 Neo4j 数据源定义。
  5. 将凭据标记为 revoked
  6. 记录不含敏感数据的审计事件。

9. 连接获取接口

业务模块使用统一的上下文接口:

with data_source_manager.connect(
    data_source_uid,
    purpose="metadata_preview",
) as connection:
    ...

管理器依次完成定义读取、凭据获取、Adapter 选择、池注册、连接借出和归还。 业务模块不持有 Engine,不负责连接池配置,也不能访问凭据明文。

purpose 使用平台枚举,第一阶段至少包括:

  • connection_test
  • metadata_collection
  • metadata_preview
  • quality_check
  • dataflow_read
  • dataflow_write

dataflow_write 外默认使用只读事务。写入任务必须显式提交,异常时回滚。

10. 故障隔离与熔断

每个数据源独立维护状态:

healthy
degraded
open
draining
closed
  • 单个数据源连接耗尽或宕机,不影响平台控制库和其他数据源。
  • 连续 3 次建连失败后熔断 30 秒。
  • 熔断结束后只允许一个半开放探测请求。
  • 探测成功恢复 healthy,失败继续熔断。
  • 借出等待超过 10 秒返回 DATASOURCE_POOL_TIMEOUT
  • 事务中断必须回滚,不自动重放数据源写操作。
  • 失效连接不再返回池中。

主要稳定错误码:

  • DATASOURCE_NOT_FOUND
  • DATASOURCE_TYPE_UNSUPPORTED
  • DATASOURCE_CREDENTIAL_UNAVAILABLE
  • DATASOURCE_CONNECTION_FAILED
  • DATASOURCE_POOL_TIMEOUT
  • DATASOURCE_CIRCUIT_OPEN
  • DATASOURCE_QUERY_TIMEOUT
  • DATASOURCE_READ_ONLY_VIOLATION

错误响应不包含驱动原始连接 URL 或凭据。

11. 监控与管理

管理员可以查看单个数据源的池摘要:

data_source_uid
database_type
pool_state
pool_size
checked_out
checked_in
overflow
checkout_wait_ms
last_used_at
consecutive_failures
circuit_open_until
credential_version

平台健康检查仅返回聚合数据:

active_pool_count
degraded_pool_count
open_circuit_count
checked_out_total
pool_timeout_total

指标至少覆盖:

  • 连接创建成功和失败次数。
  • Checkout 等待时间。
  • 当前占用、空闲和溢出连接数。
  • 池超时、连接失效和重建次数。
  • 查询耗时。
  • 空闲池回收次数。
  • 凭据版本导致的池重建次数。

所有日志使用数据源 UID 和错误分类;异常文本在写日志前统一脱敏。

12. 历史凭据迁移

迁移必须分两步:

  1. 只读报告:统计含明文凭据、缺少 UID 或配置不完整的数据源,只输出 UID 和问题 分类。
  2. 显式迁移:补齐 UID、加密凭据、写入凭据引用、验证可解密后删除 Neo4j 明文字段。

生产执行前必须单独备份 Neo4j 和平台 PostgreSQL。迁移过程不得在日志、报告或 异常中输出明文密码。迁移失败的数据源保持原状态并进入人工核查清单。

现有数据源保存、验证和连接测试接口必须先完成请求日志脱敏。数据源列表接口必须 在凭据迁移前就停止返回密码。

13. 本地隔离验收

Docker 测试栈新增两个业务数据源服务:

platform-postgres  平台控制库
source-postgres    PostgreSQL 验收数据源
source-mysql       MySQL 验收数据源

验收标准:

  1. PostgreSQL、MySQL 均可保存、测试、建池和执行查询。
  2. 同一数据源并发请求复用连接且不超过池上限。
  3. 50–100 个并发请求下无连接泄漏。
  4. 配置或密码修改后旧池失效,新池使用新版本。
  5. 空闲池到期释放,再次访问可重建。
  6. MySQL 停机不影响 PostgreSQL 数据源和平台功能。
  7. 数据源恢复后可通过半开放探测恢复。
  8. 删除数据源后连接池和凭据不可继续使用。
  9. API、日志、Neo4j 和异常中不存在明文密码。
  10. 后端重启后连接池按需重建。

测试包括:

  • AES-GCM 加密、篡改检测和密钥版本测试。
  • PostgreSQL、MySQL Adapter 合约测试。
  • Pool Registry 并发、回收和失效测试。
  • 熔断状态机测试。
  • 历史明文凭据迁移测试。
  • Docker 数据源宕机和恢复测试。
  • 前后端数据源管理接口验收。

14. 后续扩展

进入多副本阶段后再评估:

  • 按副本数重新计算连接预算。
  • PgBouncer。
  • 跨实例池状态聚合。
  • 数据源任务按 UID 路由。
  • Oracle、SQL Server 等额外 Adapter。

第一阶段的 Adapter、CredentialProvider、Pool Registry 和指标接口保持稳定, 多副本阶段不改变业务模块的连接获取接口。