4. 服务目录数据库选型与配置:关系型数据库对比、连接池、读写分离与备份恢复

服务目录平台作为微服务治理的核心元数据中心,其数据库选型直接影响元数据查询延迟、事务一致性保障以及运维复杂度。本章从关系型数据库对比、连接池调优、读写分离架构、备份恢复策略四个维度展开,提供可落地的配置方案。

4.1 关系型数据库选型:PostgreSQL vs. MySQL

服务目录平台对数据库的核心需求包括:JSON/JSONB 原生支持(存储服务元数据)、高并发读(服务发现查询)、事务一致性(注册/注销操作)、扩展性(分片或读写分离)。PostgreSQL 与 MySQL 在以下维度存在显著差异:

对比维度 PostgreSQL MySQL (InnoDB)
JSON 支持 JSONB 二进制存储,支持 GIN 索引,高效查询嵌套字段 JSON 文本存储,仅支持虚拟列索引,性能较低
并发控制 MVCC 无读锁,支持可序列化快照隔离 (SSI) MVCC 但间隙锁/Next-Key Lock 在高并发下易死锁
扩展方式 逻辑复制 + 声明式分区,生态扩展丰富(PostGIS, pg_partman) 组复制 (MGR) + 分片 (MySQL Cluster),但分区功能较弱
全文检索 内置 tsvector/tsquery,支持中文分词扩展 需集成 Elasticsearch 或使用内置全文索引(中文支持弱)
运维成熟度 Patroni/Pgpool-II 高可用方案成熟,但学习曲线陡 Orchestrator/ProxySQL 生态完善,社区文档丰富
服务目录场景推荐 适合元数据复杂、需 JSONB 索引、事务隔离要求高的平台 适合读多写少、已有 MySQL 基础设施、运维团队偏好的团队
选型建议:若服务目录平台需要存储服务版本差异(JSONB Diff)、依赖拓扑图(递归 CTE)、或地理分布元数据(PostGIS),优先选择 PostgreSQL。若团队已深度绑定 MySQL 生态且元数据模型扁平,MySQL 8.0+ 也可胜任。
PostgreSQL vs MySQL 选型决策树 服务目录数据库选型 PostgreSQL 优先 MySQL 优先 需要 JSONB 索引 / 递归 CTE / PostGIS 事务隔离要求高(SSI) 团队有 PostgreSQL DBA 经验 元数据模型扁平,无复杂嵌套 已有 MySQL 基础设施 / ProxySQL 运维团队对 MySQL 更熟悉 推荐:PostgreSQL 14+ / Patroni 推荐:MySQL 8.0+ / MGR + ProxySQL 决策依据:JSONB 需求 → PostgreSQL;扁平元数据 + 现有 MySQL 生态 → MySQL

4.2 连接池配置:参数调优与最佳实践

连接池是数据库访问层的核心组件,直接影响服务目录 API 的响应延迟和吞吐量。以 HikariCP(Java 生态)和 PgBouncer(PostgreSQL 专用)为例:

4.2.1 连接池核心参数

参数 推荐值 说明
maximumPoolSize CPU 核心数 × 2 + 有效磁盘数 避免过多连接导致数据库上下文切换
minimumIdle 10 ~ 20 保持常驻连接,减少频繁创建开销
connectionTimeout 5000 ms 服务目录 API 要求快速失败,不宜过长
idleTimeout 600000 ms (10 min) 释放空闲连接,防止数据库端超时断开
maxLifetime 1800000 ms (30 min) 强制回收连接,避免长时间连接泄漏

4.2.2 连接池配置示例(HikariCP + PostgreSQL)

# application.yml (Spring Boot)
spring:
  datasource:
    url: jdbc:postgresql://pg-primary:5432/service_catalog
    username: catalog_user
    password: ${DB_PASSWORD}
    hikari:
      pool-name: CatalogPool
      maximum-pool-size: 30
      minimum-idle: 10
      connection-timeout: 5000
      idle-timeout: 600000
      max-lifetime: 1800000
      connection-test-query: SELECT 1
      validation-timeout: 3000
      leak-detection-threshold: 60000
避坑提示:不要将 maximumPoolSize 设置过大(如 100+),PostgreSQL 每个连接消耗约 10MB 内存,过多连接会导致 shared_buffers 争用和锁等待飙升。服务目录平台建议控制在 20~50 之间,配合 PgBouncer 做事务级连接复用。

4.3 读写分离方案:架构设计与流量分发

服务目录平台读多写少(查询元数据 : 注册/更新 ≈ 10:1),读写分离可显著降低主库负载。以下为基于 ProxySQL 的 MySQL 读写分离架构和基于 Pgpool-II 的 PostgreSQL 方案。

4.3.1 读写分离架构图

服务目录读写分离架构 服务目录 API 实例 ProxySQL / Pgpool-II 主库 (Primary) 写入:注册/更新/删除 从库 1 (Replica) 读取:元数据查询 从库 2 (Replica) 读取:审计/报表查询 流复制 流复制 读写分离流量规则 • INSERT / UPDATE / DELETE → 强制路由至主库 • SELECT(非事务内)→ 轮询或权重分发至从库 • 事务内读 → 保持主库,避免复制延迟导致的脏读 • 管理查询(SHOW / EXPLAIN)→ 指定从库,不干扰主库

4.3.2 ProxySQL 配置示例(MySQL 读写分离)

-- 添加主从节点
INSERT INTO mysql_servers (hostgroup_id, hostname, port, weight) VALUES (0, '192.168.1.10', 3306, 1);  -- 主库
INSERT INTO mysql_servers (hostgroup_id, hostname, port, weight) VALUES (1, '192.168.1.11', 3306, 2);  -- 从库1
INSERT INTO mysql_servers (hostgroup_id, hostname, port, weight) VALUES (1, '192.168.1.12', 3306, 1);  -- 从库2

-- 配置查询规则:写操作走主库,读操作走从库
INSERT INTO mysql_query_rules (rule_id, active, match_pattern, destination_hostgroup, apply)
VALUES (1, 1, '^SELECT .* FOR UPDATE', 0, 1);  -- 锁定读走主库
INSERT INTO mysql_query_rules (rule_id, active, match_pattern, destination_hostgroup, apply)
VALUES (2, 1, '^SELECT ', 1, 1);               -- 普通 SELECT 走从库
INSERT INTO mysql_query_rules (rule_id, active, match_pattern, destination_hostgroup, apply)
VALUES (3, 1, '.*', 0, 1);                     -- 其他所有语句走主库

LOAD MYSQL QUERY RULES TO RUN;
SAVE MYSQL QUERY RULES TO DISK;

4.4 数据库备份与恢复策略

服务目录平台的元数据一旦丢失,将导致全服务发现瘫痪。备份策略需覆盖 全量备份、增量备份、时间点恢复 (PITR) 三个层级。

4.4.1 备份策略对比

备份类型 频率 工具 恢复时间目标 (RTO) 恢复点目标 (RPO)
全量物理备份 每日 1 次(凌晨低峰) pg_basebackup / XtraBackup 2~4 小时 24 小时
增量 WAL 归档 连续(每 5 分钟) pg_receivewal / binlog 同步 30~60 分钟 5 分钟
逻辑备份 每周 1 次 pg_dump / mysqldump 4~8 小时 7 天

4.4.2 PostgreSQL 备份与 PITR 配置

# postgresql.conf 开启归档
archive_mode = on
archive_command = 'cp %p /archive/%f'
wal_level = replica
max_wal_senders = 5

# 全量备份脚本 (pg_basebackup)
pg_basebackup -D /backup/full_$(date +%Y%m%d) -Ft -z -P -h pg-primary -U backup_user

# 时间点恢复 (recovery.conf)
restore_command = 'cp /archive/%f %p'
recovery_target_time = '2025-03-20 14:30:00 UTC'
recovery_target_action = 'promote'

4.4.3 MySQL 备份与 binlog 恢复

# 全量备份 (XtraBackup)
xtrabackup --backup --target-dir=/backup/full_$(date +%Y%m%d) --host=mysql-primary --user=backup --password=xxx

# 增量备份 (基于 LSN)
xtrabackup --backup --target-dir=/backup/inc_$(date +%Y%m%d_%H) --incremental-basedir=/backup/full_20250320 --host=mysql-primary

# binlog 时间点恢复
mysqlbinlog --start-datetime="2025-03-20 14:00:00" --stop-datetime="2025-03-20 14:30:00" /var/log/mysql/binlog.000123 | mysql -u root -p
恢复演练建议:每月至少执行一次全量恢复演练,验证备份文件完整性和 PITR 精度。服务目录平台建议配置 异地备份(如 S3 或 NFS 远程挂载),防止单机房故障导致备份文件同时丢失。

4.5 本章小结

  • 选型:PostgreSQL 适合复杂元数据场景,MySQL 适合扁平模型与现有生态。
  • 连接池:HikariCP + PgBouncer 组合,maximumPoolSize 控制在 20~50。
  • 读写分离:ProxySQL / Pgpool-II 做流量分发,事务内读保持主库。
  • 备份恢复:全量 + WAL/binlog 增量 + 逻辑备份三层覆盖,RPO ≤ 5 分钟。