CaiWuXiTong/docs/业务数据分层存储.md

9.8 KiB
Raw Permalink Blame History

业务数据分层存储与迁移清单

结论

caiwu_business_mirror 继续作为唯一的中央同步入口,但不再要求所有数据都以 MariaDB 行存表长期保存:

  • MariaDB 保存同步状态、权限/配置、小型维表、当前态业务表和页面直接使用的汇总表;
  • ClickHouse 保存订单、退款、推广费用、原始账单等大事实表,承担筛选、聚合和历史明细查询;
  • 七牛 S3 兼容对象存储保存按稳定哈希分区生成的不可变 Parquet,作为重建和灾难恢复层;
  • 页面只能经过固定 Repository 读取服务层,不能直接访问上游,也不能自行选择数据库。

列式迁移采用 MariaDB 旧表 -> ClickHouse 新代次 -> 行数/唯一键对账 -> Parquet 分区归档 -> 页面切换 -> 观察 -> 旧表清理。任何一步失败都保留 MariaDB 原表和当前页面链路。

2026-09-07 生产只读盘点

本次通过生产 information_schema 与当前代码引用交叉核对。生产部署 SHA 为 f0150f1c4971c807239e216398df32ec1751d121;服务器 500 GiB 系统盘当时约有 385 GiB 可用。caiwu_business_mirror 有 65 张物理表,InnoDB 估算约 5172 万行、51.4 GiB(数据 32.2 GiB、索引 19.2 GiB)。InnoDB TABLE_ROWS 是估算值,迁移验收必须使用精确 COUNT(*) 与唯一键计数。

占用最大的表如下:

表 估算行数 总占用 当前真实用途 处理
ops_jst_sku_map 2492 万 28.1 GiB 当前页面没有查询,只曾被推广费用页误当作就绪条件 立即停止后续同步;现有表保留,完成 Parquet 归档后再申请删除
store_report_bill_rows 1385 万 7.8 GiB 只用于生成 store_report_daily_rows,页面不应扫描原始行 页面改读日汇总;原始层迁入 ClickHouse 并归档后,仅保留必要增量窗口
ops_item_sales_cost_ratio 289 万 3.6 GiB 推广费用页面 迁入 ClickHouse;页面查询验收后切换
ops_jst_original_bill_info 184 万估算 / 已处理 208 万 2.3 GiB 新登记的通用原始账单,当前无页面直读,首次同步已暂停 不再向 MariaDB 续传;先用现有 208 万行验证列式迁移,不重新读取上游
ops_jst_orders 112 万 1.7 GiB 售后费用 与订单明细、退款表作为同一激活组迁入 ClickHouse
ops_jst_order_item 158 万 1.7 GiB 售后费用 同上
ops_jst_return_refund_info 113 万 1.6 GiB 售后费用、非京喜退款 同上
ops_jst_return_refund_item 135 万 1.3 GiB 售后费用、非京喜退款 同上
ops_jst_sku 50 万 778 MiB 商品资料及订单行补充 作为高频维表留在 MariaDB
ops_work_order_form_value 41 万 436 MiB 协同工单当前态 留在 MariaDB,继续观察增速
js_fys_ticketing_install_view 24 万 400 MiB 安装明细 留在 MariaDB;达到阈值后再单独迁移

前三个可清理的 MariaDB 原始层合计约 38.2 GiB,但只能在归档对象存在、对象大小/逻辑校验通过、页面或同步器不再读取且获得生产删除授权后清理。当前迁移和部署不会自动删除这些表。

页面与数据层映射

代码当前登记 51 个固定上游数据集,另有 PostgreSQL 连接器动态登记的店铺账号维表。完整逐数据集策略由 config/business_data.php 强制登记;新增固定数据集若未登记,business-data:plan 返回失败。

页面/业务域 数据集 目标层 说明
公司、店铺、商标 fys_companyInfo、fys_shopInfo、fys_TrademarkInfo MariaDB 维表 行数小、点查与关联频繁
店铺经营报表 store_report_lifecycle_rows + store_report_daily_rows MariaDB 维表/汇总 页面已改为共享日汇总,不依赖 runtime/bills.sqlite,不扫描原始账单
普通商品资料 jst_sku + 采购价镜像 MariaDB 维表/服务表 约 55 万商品仍适合行存筛选;保留现有完整导出校准
推广费用 ads_itemid_sales_cost_ratio_v2_di ClickHouse 事实表 jst_skumap 不再作为页面就绪条件
售后费用、非京喜退款 订单、订单明细、退款主表、退款明细 ClickHouse 事实表 + MariaDB SKU/仓库/店铺维表 四张事实表必须成组对账和切换,不能逐张切换造成跨库半成品
原始账单 jst_originalBillInfo ClickHouse + Parquet 当前无页面直读;先迁移已保留部分验证压缩率和恢复能力
营销账户账单 淘宝、拼多多、阿里巴巴、京东账单 MariaDB 服务表 当前单表约 2 万至 21 万行,先保留;按增速和查询成本复评
供应商应付、板材、封边条、库存 对应 finance_*、pm_*、结算表 MariaDB 服务表/汇总 当前规模可控;不做无收益的跨库改写
安装明细 安装视图与明细 MariaDB 服务表 当前约 408 MiB,页面需要稳定分页与详情点查
协同工单、小额打款 工单主/子/表单/映射 MariaDB 当前态 更新频繁且需要当前态精确读取
快递资料 快递、网点、账户、扩展 MariaDB 维表 小型主数据
动态店铺账号数据集 database_4 动态登记表 MariaDB 外部维表 未经单独评审不得自动进入列式层

已实现的安全边界

  1. business-data:plan 只读输出固定数据集、页面用途、目标层、同步策略、当前表体量与迁移阶段;固定数据集漏配或多配即失败。
  2. business-data:backfill-columnar <dataset> 只从现有 MariaDB 镜像按 _mirror_key 断点读取,不连接上游;读取范围固定在任务启动时的 _mirror_synced_at 截止点。
  3. ClickHouse 表使用 ReplacingMergeTree,以 (_mirror_generation, _mirror_key) 为排序/去重键,并按业务键哈希固定分为 32 个分区;同一代次内的业务键更新会被正确折叠,不同代次会同时保留。建表检查发现旧表缺少代次键时会拒绝继续回填,必须先以影子表完成可回滚修复。
  4. 回填结束同时核对截止点精确行数、ClickHouse FINAL 行数和唯一键数;不一致只记录失败,不切换页面。
  5. --archive 在对账后把 32 个哈希分区分别输出为 Parquet,经现有私有七牛 S3 磁盘流式上传;每个对象记录路径、行数、字节数和逻辑校验值。
  6. 本阶段没有“激活”或“删除”命令。页面切换与 MariaDB 清理必须在各 Repository 的 ClickHouse 查询完成真实页面验收后另行提交,避免有人只执行一条命令就绕过保护门。
  7. ClickHouse 凭据只生成在服务器权限为 600 的 runtime/clickhouse.env;Git、PR、日志和命令参数中不出现密码。

执行顺序

以下是上线后的运维顺序,不是普通开发机操作。生产迁移、回填、归档和删除分别需要对应授权。

# 1. 只读核对配置与现状
docker exec -u www-data caiwu_app php artisan business-data:plan

# 2. 用已经暂停的原始账单部分数据验证 ClickHouse,不访问上游
docker exec -u www-data caiwu_app php artisan business-data:backfill-columnar \
  operations_replica.rpt.jst_originalBillInfo --batch=5000 --max-batches=20

# 3. 对账完成后分区归档;仍不会删除 MariaDB 原表
docker exec -u www-data caiwu_app php artisan business-data:backfill-columnar \
  operations_replica.rpt.jst_originalBillInfo --batch=5000 --max-batches=0 --archive

随后按以下顺序推进:

  1. 记录 ClickHouse 实际压缩率、回填吞吐、CPU/内存峰值和对象存储归档大小;
  2. 为推广费用 Repository 增加列式读取,在相同筛选下对比首页、第二页、末页、金额汇总与无数据;
  3. 将订单/退款四张事实表作为一个激活组迁移并完成同口径页面验收;
  4. 将店铺报表原始层迁入 ClickHouse,确认日汇总可从归档或列式原始层重建;
  5. 至少观察一个完整增量周期,再提出精确旧表清理清单、备份位置和回滚方案;
  6. 获得删除授权后才逐表清理 MariaDB,清理后再次执行页面与归档恢复抽查。

容量与告警建议

  • MariaDB 镜像总量达到 80 GiB 或单表达到 5 GiB 时告警,不再自动扩大索引;
  • ClickHouse 数据卷达到 70% 时暂停新回填,优先确认归档与旧代次清理;
  • 对象存储按 数据集/代次/哈希分区 保留不可变对象,清单写入 business_data_archives;
  • 同步状态的 running 只代表任务游标,不代表页面已经切换;页面切换必须另有 active_generation 和验收记录;
  • 上游断线时保留 MariaDB/ClickHouse 上一代数据,不由 HTTP 请求回退直连上游。

本地协议验证

2026-09-07 使用与部署配置相同的 ClickHouse 26.8.2.7-alpine 完成两级验证:应用 HTTP 客户端健康检查成功;同一 _mirror_key 写入两个版本后,FINAL 只返回版本号较大的 1 行;金额为最新值;SELECT ... FORMAT Parquet 返回标准 PAR1 文件头。随后使用 2 行隔离 SQLite 镜像走通完整命令,结果为 exit=0 / phase=verified / source=2 / target=2 / archives=32 / files=32 / parquet_magic=50415231。验证结束已删除 ClickHouse 临时表和临时归档,并停止本地容器;未连接生产数据。

ClickHouse 官方说明中,MergeTree 数据以不可变数据片段写入并在后台合并;ReplacingMergeTree 的查询在需要即时去重时必须使用 FINAL。S3 表函数与 Parquet 格式支持从列式表导出和后续重建,本方案据此把服务存储与不可变归档分开: