[开发]SplitDB 控制台 — 使用说明

👑Lv.11 元老 🌞 骨干会员
2026-10-24 00:19:54

本文由 FlintHub 开发文档归档发布。原始文档日期见标题前缀,来源:暂存20260913/docs/SplitDB引擎控制台使用说明 (2).md。

SplitDB 控制台 — 使用说明

版本:FlintHub 1.0(P30 拆分重构 + P41 智能扩容与归档)| 后台路径:/admin/database/overview(数据管理 → SplitDB 概览)与 /admin/database/settings(数据管理 → SplitDB 设置)

前置条件:管理员登录 + 30 分钟二次密码验证(与既有后台一致)

配套文档:update/SplitDB控制台拆分与操作日志改造计划.md(P30 设计与决策)、update/SplitDB引擎控制台改造计划.md(P29 原始设计)、update/智能扩容与归档改造计划.md(P41 设计与决策)


一、核心原理(必读:扩容零迁移)

桶数增加后旧数据原地不动,不进行任何数据迁移或重哈希:

场景路由规则说明
写入新帖(扩容后)新增桶编号范围 SPLITDB_PREV_BUCKET_SIZE + (id % (SPLITDB_BUCKET_SIZE - PREV))[P41/D3] 扩容后所有新主题帖全部进入新增桶范围(32→64 后新帖进桶 32..63),旧桶不再接收任何新主题帖;判定依据 SPLITDB_LAST_EXPANSION_AT(帖子创建时间 ≥ 扩容时间戳)
写入新帖(未扩容/历史导入)id % SPLITDB_BUCKET_SIZE从未扩容(常量 0)或历史帖导入(created_at 早于扩容时间戳)回退旧哈希,与旧行为完全一致
写入回复跟随父帖 bucket_path旧帖的回复和编辑仍留在原桶,不受路由影响
读取以 main_index.bucket_path 为唯一依据不重新计算哈希,旧帖永远留在旧桶,读取不受影响

  • 32 → 64 桶后:旧帖继续留在旧桶(冻结只收回复),新帖进入新增桶范围;零停机、零搬家、零迁移脚本;
  • 桶数只增不减(32 → 64 → 128 → 256),历史数据零迁移(白皮书 5.2 既定设计);
  • 扩容动作由 updateBucketSize() 统一落盘三个常量:SPLITDB_BUCKET_SIZE / SPLITDB_LAST_EXPANSION_AT(时间戳)/ SPLITDB_PREV_BUCKET_SIZE(扩容前桶数)。

二、后台菜单结构(P30 重组)

数据管理
  ├─ SplitDB 概览 → /admin/database/overview   (只读监控)
  ├─ SplitDB 设置 → /admin/database/settings   (操作型)
  └─ 备份优化     → /admin/database             (备份/VACUUM/恢复)
站长工具
  ├─ 操作日志     → /admin/logs/audit           (审计日志查看)
  └─ 维护工具     → /admin/maintenance

旧路径 /admin/database/engine 已 302 重定向至 /admin/database/overview,旧链接不失效。


三、SplitDB 概览(只读监控)

数据项含义
当前配置桶数config.php 中 SPLITDB_BUCKET_SIZE 的当前值(文件优先)
当前季度ShardRouter::quarter(),如 2026Q3
分片分布统计当前季度 bucket/active/{季度}/{0..N}.sqlite 各桶 topic/reply 行数与文件大小
当前总帖子数topic_index 全量 COUNT
建议桶数<10万→32;10万~50万(含50万)→64;50万~200万(含200万)→128;>200万→256

  • 分片统计带 60s 控制台缓存(data/runtime/cache_engine_stats.json),避免 128/256 桶 × 多季度时页面退化;
  • 点「🔄 刷新统计」强制实时重算并回写缓存;
  • 单桶读取异常显示「读取异常」并跳过,不阻塞整页;
  • 本页纯只读、无 POST 操作;所有操作型功能在「SplitDB 设置」页。

四、SplitDB 设置(操作型)

① 桶数动态调整(核心操作)

  1. 下拉选择目标桶数(32 / 64 / 128 / 256,仅列出 2 的幂次方);
  2. 点「更新桶数」→ 确认弹窗 → 服务端校验:必须 ≥ 当前桶数(只允许增加,含白名单/只增不减双层兜底);
  3. 写 config.php 安全四步:备份(protected/backups/config.php.bak.{时间戳}.{随机})→ 正则替换常量行 → file_put_contents(LOCK_EX) → opcache_invalidate(绝对路径);
  4. 成功提示:"桶数已更新。新增数据将自动按新规则路由。旧数据不受影响。";
  5. 若 config.php 不可写(严格权限 VPS 的 0444/0644)→ 按钮置灰 + 提示「配置文件 config.php 不可写,请检查文件权限」。

⚠️ 改 config 生效时机:当前请求仍用旧常量,新值从下一请求起生效——属预期行为。

② 自动扩容设置(可选)

项说明
开关开启后由系统自动检测并扩容
触发阈值[P41] 数据量最大的桶的 topic 行数 ≥ 单桶容量(bucket_safe_capacity,见 ③)时触发(原"总帖数超阈值"口径已废弃,阈值改由「单桶容量」区块配置)
只读参考「当前总帖子数」仅作参考展示
24h 间隔距上次扩容不足 24 小时不执行(auto_expand_last_at 记录),防频繁扩容
防重入写 config 前强制 flock(data/lock/auto_expand.lock),获取失败立即放弃,防并发写坏/跳级扩容

触发点(双触发):

  1. SplitDB 设置页加载时(GET);
  2. cron_trigger.php(web 触发)与 cli/worker.php(常驻空闲回调,静态 60s 节流)消费末尾——无需管理员访问也能自动扩。

扩容动作:桶数 ×2(上限 256)→ 写 config(同安全四步,同步落盘 SPLITDB_LAST_EXPANSION_AT + SPLITDB_PREV_BUCKET_SIZE)→ AuditLog::log('auto_expand', ...) 记录 → 更新 auto_expand_last_at。

③ 单桶容量(智能扩容阈值,[P41])

  • 选项:3 万 / 5 万 / 8 万 / 10 万(下拉框),默认 5 万;提示语:"该值决定每个桶在触发扩容前可容纳的主题帖数量。若服务器内存较高(如 4GB 以上),可适当调高;若在低配环境(如 600M 空间),建议保持 3~5 万。"
  • 口径(D1):桶负载 = 仅该桶 topic 行数(主题帖数),回复不计入;
  • 触发规则联动:
  • 最大桶负载 ≥ 100% 容量 → 自动扩容(需 ② 开关开启);
  • 最大桶负载 ≥ 80% → 站点设置页顶部显示"⚠️ 建议扩容"提示条(D5);
  • 回复写入前,父帖所在桶负载 ≥ 90% → 紧急扩容(不受开关限制,24h 守卫 + flock 保护);
  • 回复写入前,父帖所在桶负载 ≥ 100% → 拒绝写入,提示"当前桶已满,请联系管理员扩容"。

④ 旧帖归档设置([P41])

  • 选项:关闭归档(0)/ 180 天 / 365 天 / 自定义(数字输入,0~3650),默认 365 天;
  • 超过设定天数的帖子自动标记 topic_index.is_archived = 1,进入归档只读状态:
  • 前台详情页顶部显示"该帖已归档(发布于 XXX 天前),无法回复或编辑"横幅;
  • 非管理员不显示回复框、不可回复/编辑;内容仍可完整查看,引用链接可手动粘贴到新帖;
  • 管理员豁免:可继续回复和编辑归档帖(服务端强制,非仅前端隐藏);
  • 标记方式(双保险):
  1. 每日定时脚本 cli/archive_mark.php(分批 5000 条/批,幂等,--dry-run 预览)——由 cron_trigger.php(web 可触发,适合无 crontab 的虚拟主机)或服务器 crontab 调用;
  2. 读取时惰性标记:详情页发现超期未归档帖时顺手置位,定时任务未跑也能即时生效。

⑤ 扩容记录

  • 本页展示 最近 10 条 扩容/调整记录(来源:audit_logs 中 action ∈ {auto_expand, admin_action, emergency_expand} 且 target_type='database'),显示时间/操作人/类型/详情/IP;
  • 完整历史请查看「站长工具 → 操作日志」页(可筛选日期与操作类型)。

⑥ 一致性检查(诊断工具)

  1. 选择检查范围:「当前季度(默认)/ 全部历史」;
  2. 点「开始检查」→ 遍历范围内全部桶,逐桶 COUNT topic/reply 汇总;
  3. 对照 topic_index / reply_index 全量行数:
  • 全部历史:严格对拍,不一致行红色高亮「⚠️ 不一致」;
  • 当前季度:索引为全量,结果仅作参考对照(标注说明);
  1. 单桶读取异常在页面底部红色提示桶文件清单。

五、操作日志页(/admin/logs/audit)

  • 功能:分页列出 audit_logs 表记录,显示 时间 / 管理员 / 操作类型 / 目标 / IP / 详情(详情超长截断,悬停查看全文);
  • 筛选:GET 表单,支持按操作类型(下拉)与日期(YYYY-MM-DD)筛选;分页条带参不丢条件;「清除筛选」一键还原;
  • 操作类型下拉:从 audit_logs 表 DISTINCT action 动态读取(新操作类型自动出现,免维护)+ 60s 文件缓存(data/runtime/cache_audit_actions.json),实测覆盖索引亚毫秒级;
  • 权限:仅管理员(need_admin,BaseController 构造器 + 30 分钟二次验证);
  • 系统任务(如自动扩容)无操作人时管理员列显示 -。

六、备份与优化(/admin/database)

按钮行为
立即备份全 data/ 目录 WAL checkpoint 后打包为 forum_backup_{时间戳}.zip
VACUUM 优化全部 SQLite 库 VACUUM + WAL checkpoint(大库耗时,建议低峰期)
上传并恢复上传 .zip 整包(还原 data/)或 .sqlite 单库(按命名规范映射),带路径穿越防护
备份列表文件名 / 大小 / 时间 / 下载 / 恢复 / 删除(分页)


七、安全设计要点

  1. 全部 POST 走 Csrf::verifyOrDie;桶数白名单 [32,64,128,256];阈值 intval;筛选参数白名单(action /^[a-z_]{1,32}$/、date /^\d{4}-\d{2}-\d{2}$/);备份文件名 basename 清洗 + 路径穿越防护;
  2. 写 config 前先备份;写失败不覆盖原文件并提示;opcache_invalidate(realpath(...)) 传绝对路径;
  3. 分片统计逐桶直接 PDO(不经 DBFactory 池,避免 LRU 8 句柄抖动)+ PRAGMA query_only 只读句柄 + 读完即关;
  4. 自动扩容 24h 守卫 + flock 防重入 + AuditLog 全记录;worker 常驻 60s 静态节流防死循环打 DB;
  5. AuditLog::query() 日期筛选参数绑定(LIKE 前缀命中 idx_audit_logs_created 索引);
  6. 仅管理员可访问全部后台页面(BaseController 构造器校验)。

八、维护命令速查

# 语法检查(改动文件)
php -l app/Controllers/Admin/DatabaseController.php
php -l app/Controllers/Admin/LogController.php
php -l app/Views/admin/database/overview.php
php -l app/Views/admin/database/settings.php
php -l app/Views/admin/logs/audit.php
php -l app/Helpers/AuditLog.php
php -l app/Views/admin/_sidebar.php

# 手动触发自动扩容(cron 模式 / CLI)
php cli/worker.php 0 --once        # --once 末尾会自动调用 maybeAutoExpand
php cron_trigger.php               # 仅 queue_mode=cron 时生效;顺带执行每日归档标记

# 旧帖归档标记(每日定时,幂等可重跑)
php cli/archive_mark.php           # 正式标记超期帖
php cli/archive_mark.php --dry-run # 仅预览待标记行数

# 查看审计日志
# 后台 → 站长工具 → 操作日志(/admin/logs/audit)

# 清除引擎统计缓存 / 操作类型缓存(异常时手动)
# 删除 data/runtime/cache_engine_stats.json 与 data/runtime/cache_audit_actions.json 即可(60s 自动过期)


九、常见问题(FAQ)

问题解答
扩容后旧帖找不到?不会。旧帖读取以 main_index.bucket_path 定位,与桶数无关;扩容只影响新帖路由
扩容后新帖进哪些桶?[P41/D3] 扩容后新主题帖全部进入新增桶编号范围(如 32→64 后进桶 32..63),旧桶冻结不再接收新主题帖(回复仍进旧桶)
想从 64 缩回 32?不允许(服务端强制只增不减)。缩桶需要重哈希迁移,违背零迁移设计
自动扩容为什么没触发?检查:① 开关是否开启 ② 数据量最大的桶的 topic 行数是否 ≥ 单桶容量 ③ 距上次扩容是否 <24h ④ 是否有其他扩容在进行(flock 被占)
建议扩容提示在哪?[P41/D5] 站点设置页(/admin/settings/basic)顶部,最大桶负载 ≥ 容量 80% 时显示"⚠️ 建议扩容"
归档帖还能回复/编辑吗?非管理员不能(详情页不显示回复框,服务端同样拦截);管理员豁免可继续回复和编辑
归档时间改了多久生效?每日定时脚本(cron_trigger 或 crontab)+ 详情页读取时惰性标记双保险,最迟一次访问即生效
归档标记跑得很慢?分批 5000 条/批上限(写放大红线),大库需多批;--dry-run 可先预览规模
概览页加载很慢?分片统计有 60s 缓存;若首次加载慢属正常(全桶逐文件 COUNT);「全部历史」一致性检查耗时更长属预期
桶数改了但新帖没进新桶?确认保存成功提示出现;PHP-FPM 下一请求才加载新常量(opcache 已失效);可查看 config.php 中 SPLITDB_BUCKET_SIZE 的值确认
config.php 不可写?检查文件权限(chmod 664/666 或赋予 Web 用户写权限),按钮置灰时无法调整桶数
旧链接 /admin/database/engine 还能用吗?能。已 302 重定向至 /admin/database/overview
操作日志看不到某类操作?操作类型下拉来自 audit_logs 表 DISTINCT action(60s 缓存),新类型最迟 60s 后出现;空结果请核对日期/类型筛选


使用说明完。P30 拆分设计详见 update/SplitDB控制台拆分与操作日志改造计划.md;P29 原始设计详见 update/SplitDB引擎控制台改造计划.md。

轻量级、高性能、零 MySQL 依赖的PHP社区系统。
| 浏览 2 次 | 回复 0 次

全部回复 (0)

暂无回复

请 登录