数据库集成
本文引用的文件
- db_driver.v
- db_runtime.v
- db_runtime_pool.v
- db_runtime_state.v
- db_runtime_dispatch.v
- vhttpd.example.toml
- db-upstream.toml
- db-upstream-pg.toml
- README.md(PHP 包)
- vhttpd-db.php
- CONFIGURATION_MODEL_V2.md
目录
简介
本文件系统性说明 VHTTPD 的数据库集成能力,重点覆盖连接池配置与管理、驱动支持、查询执行与优化、事务管理、健康检查、缓存策略与一致性保证,并提供 PHP 与原生 V 语言的访问示例。同时给出连接池调优、性能监控与故障排除等运维建议。
项目结构
VHTTPD 的数据库子系统由“运行时服务 + 驱动抽象 + 调度与状态”三部分构成: - 运行时服务:监听 Unix Socket,接收来自 PHP 或上游的 JSON 帧请求,分派到具体操作。 - 驱动抽象:对 MySQL/PostgreSQL 进行统一封装,提供连接池、会话、事务、参数化查询等能力。 - 调度与状态:负责连接获取/释放、事务会话跟踪、错误计数、快照导出等。
graph TB
subgraph "应用层"
PHP["PHP 客户端<br/>DbGateway Client / PDO 适配"]
WPBridge["WordPress 桥接<br/>vhttpd-db.php"]
end
subgraph "VHTTPD 数据库运行时"
Listener["Unix Socket 监听器"]
Codec["JSON 帧编解码"]
Dispatch["调度器<br/>db_runtime_dispatch"]
State["状态与统计<br/>db_runtime_state"]
PoolMgr["连接池管理<br/>db_runtime_pool"]
Driver["驱动实现<br/>db_driver"]
end
subgraph "外部数据库"
MySQL["MySQL"]
PG["PostgreSQL"]
end
PHP --> Listener
WPBridge --> Listener
Listener --> Codec --> Dispatch
Dispatch --> PoolMgr
PoolMgr --> Driver
Driver --> MySQL
Driver --> PG
Dispatch --> State
图表来源 - db_runtime.v:643-704 - db_runtime_dispatch.v:10-201 - db_runtime_pool.v:5-143 - db_driver.v:1-132
章节来源 - db_runtime.v:1-108 - db_runtime_dispatch.v:1-212 - db_runtime_pool.v:1-155 - db_driver.v:1-132
核心组件
- 驱动抽象与连接池
- 统一接口:DbPoolHandle/DbSessionHandle,暴露 open/acquire/release/ping/begin/commit/rollback/query/execute 等方法。
- 驱动支持:MySQL、PostgreSQL(别名 pg/pg/postgres/postgresql 归一化为 pgsql)。
- 能力声明:pool/transactions/parameters/prepared/savepoints 等特性按驱动返回。
- 运行时服务
- Unix Socket 监听,4 字节长度前缀 + JSON 体协议。
- 操作集:ping、begin_transaction、commit、rollback、query、execute。
- 事务会话:以 session_id 绑定连接,提交/回滚后复用或回收。
- 调度与状态
- 连接获取/释放、失败重试、观察指标记录、活跃事务计数、启动/停止标记。
- 快照导出:包含 driver/host/port/database/pool_size/pool_ready/started_at_unix/total_queries/failed_queries 等。
章节来源 - db_driver.v:6-87 - db_driver.v:89-132 - db_runtime.v:86-108 - db_runtime.v:397-609 - db_runtime_state.v:10-94
架构总览
下图展示从 PHP 客户端到数据库驱动的完整调用链,包括连接池、事务与会话复用。
sequenceDiagram
participant App as "PHP 应用"
participant Client as "DbGateway Client"
participant Sock as "Unix Socket 监听"
participant Disp as "调度器(db_runtime_dispatch)"
participant Pool as "连接池管理(db_runtime_pool)"
participant Drv as "驱动(db_driver)"
participant DB as "MySQL/PostgreSQL"
App->>Client : "发起 query/execute/事务"
Client->>Sock : "发送 JSON 帧(含 pool/session_id/sql/params)"
Sock->>Disp : "解析并分发 op"
alt 非事务
Disp->>Pool : "acquire()"
Pool->>Drv : "acquire() -> DbSessionHandle"
Drv->>DB : "执行 SQL"
DB-->>Drv : "结果"
Drv-->>Pool : "返回结果"
Pool-->>Disp : "会话句柄"
Disp-->>Client : "rows/affected_rows"
Disp->>Pool : "release(session_id='')"
else 事务
Disp->>Pool : "acquire()"
Pool->>Drv : "begin()"
Drv->>DB : "BEGIN"
DB-->>Drv : "OK"
Disp->>Disp : "生成 session_id 并跟踪"
loop 多次 execute/query
Disp->>Pool : "acquire(session_id)"
Pool->>Drv : "使用已跟踪连接"
Drv->>DB : "执行 SQL"
DB-->>Drv : "结果"
Drv-->>Pool : "结果"
Pool-->>Disp : "会话句柄"
Disp-->>Client : "返回结果"
end
alt commit
Disp->>Pool : "commit()"
Pool->>Drv : "COMMIT"
Drv->>DB : "提交"
DB-->>Drv : "OK"
Disp->>Pool : "finalize_tx(reusable=true)"
else rollback
Disp->>Pool : "rollback()"
Pool->>Drv : "ROLLBACK"
Drv->>DB : "回滚"
DB-->>Drv : "OK"
Disp->>Pool : "finalize_tx(reusable=true)"
end
end
图表来源 - db_runtime.v:643-704 - db_runtime_dispatch.v:10-201 - db_runtime_pool.v:58-123 - db_driver.v:146-266
详细组件分析
驱动与连接池(MySQL/PostgreSQL)
- 驱动名称归一化:pg/pg/postgres/postgresql → pgsql;mysql → mysql;空值默认 mysql。
- 连接池打开:根据 driver 选择对应后端,设置 host/port/database/username/password/pool_size。
- 会话生命周期:acquire/release/close/ping/begin/commit/rollback/reset_for_pool。
- 查询与执行:
- 无参路径直接执行,有参路径走预处理语句(MySQL 通过 prepare/bind/execute;PostgreSQL 通过 exec_param_many_result)。
- 结果统一为列名映射的行集合,兼容两库差异。
classDiagram
class DbDriverName {
+normalize(name) string
+capabilities(name) DbDriverCapabilities
}
class DbPoolHandle {
+driver string
+open(settings) DbPoolHandle
+close() void
+acquire() DbSessionHandle
+release(session) void
}
class DbSessionHandle {
+driver string
+close() !
+ping() !bool
+begin() !
+commit() !
+rollback() !
+reset_for_pool() !
+query(sql, params) DbQueryResult
+execute(sql, params) DbExecResult
}
class DbQueryResult {
+columns []string
+rows []map[string]string
}
class DbExecResult {
+affected_rows int
+last_insert_id i64
+has_last_insert_id bool
}
DbPoolHandle --> DbSessionHandle : "acquire/release"
DbSessionHandle --> DbQueryResult : "query"
DbSessionHandle --> DbExecResult : "execute"
图表来源 - db_driver.v:6-87 - db_driver.v:89-132 - db_driver.v:146-266 - db_driver.v:329-421
章节来源 - db_driver.v:44-87 - db_driver.v:89-132 - db_driver.v:146-266 - db_driver.v:329-421
运行时服务与协议
- 协议格式:4 字节长度前缀 + JSON 体。
- 请求字段:version/mode/op/pool/session_id/sql/params/timeout_ms。
- 响应字段:ok/error/driver/pong/session_id/rows/affected_rows/last_insert_id。
- 健康检查:op=ping 会尝试从池中取连接并 ping,失败则记录错误。
flowchart TD
Start(["收到帧"]) --> Decode["解析 JSON 请求"]
Decode --> ModeCheck{"mode == 'db' ?"}
ModeCheck --> |否| ErrMode["返回 invalid_mode"]
ModeCheck --> |是| OpDispatch["按 op 分发"]
OpDispatch --> Ping["op=ping<br/>获取连接并 ping"]
OpDispatch --> TxBegin["op=begin_transaction<br/>获取连接+BEGIN<br/>生成 session_id 并跟踪"]
OpDispatch --> TxCommit["op=commit<br/>若无 session_id 直接 OK<br/>否则 COMMIT 并 finalize_tx"]
OpDispatch --> TxRollback["op=rollback<br/>若无 session_id 直接 OK<br/>否则 ROLLBACK 并 finalize_tx"]
OpDispatch --> Query["op=query<br/>获取连接(可带 session_id)<br/>执行并返回 rows"]
OpDispatch --> Exec["op=execute<br/>获取连接(可带 session_id)<br/>执行并返回 affected_rows/last_insert_id"]
OpDispatch --> Unknown["unsupported_op"]
Ping --> Resp["写回响应"]
TxBegin --> Resp
TxCommit --> Resp
TxRollback --> Resp
Query --> Resp
Exec --> Resp
Unknown --> Resp
ErrMode --> End(["结束"])
Resp --> End
图表来源 - db_runtime.v:611-658 - db_runtime.v:397-609
章节来源 - db_runtime.v:611-658 - db_runtime.v:397-609
调度与状态管理
- 连接获取:优先复用事务会话连接;否则从池中 acquire。
- 连接释放:非事务连接立即 release;事务连接在 finalize_tx 中根据 reusable 决定是否归还池。
- 失败处理:连接丢失时触发 discard_conn 并尝试重建单连接探测,再决定是否替换池。
- 统计与快照:累计 total_queries/total_executes/failed_queries,active_transactions 计数,导出 ready/capabilities 等。
章节来源 - db_runtime_pool.v:5-143 - db_runtime_state.v:10-94 - db_runtime_dispatch.v:10-201
健康检查与可用性
- 进程级就绪:db_runtime_mark_started/mark_stopped 控制 started 标志。
- 连接级就绪:db_runtime_ensure_pool 确保池可用;ping 操作验证底层连通性。
- 快照导出:包含 enabled/compiled/socket/driver/host/port/database/pool_size/pool_ready/started_at_unix/ready/capabilities 等。
章节来源 - db_runtime.v:206-231 - db_runtime.v:233-267 - db_runtime.v:110-157
依赖关系分析
- 运行时服务依赖调度器,调度器依赖连接池管理,连接池管理依赖驱动抽象。
- 驱动抽象依赖 db.mysql 与 db.pg 两个底层库。
- 状态模块对外暴露 snapshot_json 与各项计数器方法,供上层观测。
graph LR
Runtime["db_runtime.v"] --> Dispatch["db_runtime_dispatch.v"]
Dispatch --> PoolMgr["db_runtime_pool.v"]
PoolMgr --> Driver["db_driver.v"]
Driver --> MySQLLib["db.mysql"]
Driver --> PGLib["db.pg"]
State["db_runtime_state.v"] --> Runtime
图表来源 - db_runtime.v:1-108 - db_runtime_dispatch.v:1-212 - db_runtime_pool.v:1-155 - db_driver.v:1-132 - db_runtime_state.v:1-105
章节来源 - db_runtime.v:1-108 - db_runtime_dispatch.v:1-212 - db_runtime_pool.v:1-155 - db_driver.v:1-132 - db_runtime_state.v:1-105
性能与调优
- 连接数控制
- 通过 pool_size 控制最大并发连接数,避免数据库过载。
- 对于高并发场景,适当增大 pool_size 并结合数据库侧 max_connections 限制。
- 连接复用
- 非事务连接每次请求结束后立即释放回池,减少握手开销。
- 事务连接在提交/回滚后可复用,降低频繁创建连接的代价。
- 健康检查
- 定期 ping 或基于 idle_ping_ms 机制保持连接活性,避免冷连接失效。
- 查询优化
- 使用参数化查询(prepared statements),避免 SQL 注入并提升执行计划重用。
- 批量操作可通过多次 execute 组合业务逻辑,注意事务边界与锁竞争。
- 监控指标
- 关注 total_queries/total_executes/failed_queries/active_transactions 等指标,结合事件日志定位瓶颈。
- 超时与重试
- 合理设置 timeout_ms,避免长尾请求阻塞;连接丢失自动重试一次,提高鲁棒性。
[本节为通用指导,不直接分析具体文件]
故障排除指南
- 常见问题
- 无法连接:检查 socket 路径、driver/host/port/database/username/password 配置是否正确。
- 连接池耗尽:增大 pool_size 或优化慢查询,避免长时间持有连接。
- 事务泄漏:确保每个 begin 都有对应的 commit/rollback,避免 session_id 未释放。
- 连接断开:启用 ping 或 idle_ping_ms,必要时调整网络超时。
- 诊断步骤
- 查看运行时快照:enabled/pool_ready/started/last_error 等字段。
- 观察事件日志:db.started/db.error 等事件,定位异常时间点。
- 检查活跃事务:active_transactions 是否持续增长。
- 恢复策略
- 重启数据库运行时服务,清理残留会话。
- 动态替换损坏的连接池,确保新连接可用后再切换。
章节来源 - db_runtime.v:110-157 - db_runtime.v:643-704 - db_runtime_pool.v:75-103
结论
VHTTPD 的数据库集成通过统一的驱动抽象与连接池管理,提供了跨 MySQL/PostgreSQL 的一致 API,支持参数化查询、事务与会话复用,并通过 Unix Socket + JSON 帧协议与 PHP 应用解耦。配合健康检查、监控指标与故障恢复策略,可在生产环境获得稳定高效的数据库访问能力。
[本节为总结,不直接分析具体文件]
附录:配置与示例
支持的数据库类型与驱动
- MySQL:driver=mysql,端口默认 3306。
- PostgreSQL:driver=pgsql(也接受 pg/postgres/postgresql 别名),端口默认 5432。
章节来源 - db_driver.v:44-87 - db_driver.v:89-132
连接池配置(V1/V2 示例)
- V1 示例(MySQL)
- db-upstream.toml
- V1 示例(PostgreSQL)
- db-upstream-pg.toml
- V2 资源模型(推荐)
- CONFIGURATION_MODEL_V2.md
章节来源 - db-upstream.toml:15-27 - db-upstream-pg.toml:15-27 - CONFIGURATION_MODEL_V2.md:349-374
PHP 访问示例
- DbGateway Client 基本用法(query/execute/事务)
- README.md(PHP 包)
- PDO 风格适配
- README.md(PHP 包)
- WordPress 桥接(自动注入 Wpdb)
- vhttpd-db.php
章节来源 - README.md(PHP 包):507-568 - vhttpd-db.php:42-92
原生 V 语言访问示例
- 通过驱动抽象直接构建连接池与会话,执行 query/execute 与事务。
- db_driver.v
- 通过运行时服务与调度器完成请求分发与状态统计。
- db_runtime.v
- db_runtime_dispatch.v
章节来源 - db_driver.v:89-132 - db_runtime.v:397-609 - db_runtime_dispatch.v:10-201
缓存策略与数据一致性
- 缓存与数据库分离:缓存用于读多写少数据的加速,数据库保证强一致。
- 一致性建议:
- 写路径先更新数据库,再失效相关缓存键。
- 读路径允许短暂不一致时采用版本号或时间戳校验。
- 关键业务尽量绕过缓存,直接读数据库。
- 运行时缓存(可选):通过同一 JSON 帧协议访问内存缓存,适合本地对象缓存与短 TTL 场景。
[本节为通用指导,不直接分析具体文件]