All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 7m16s
核心改造: - 增量算法:流量计算从覆盖式改为增量累加(gateway - lastReading),支持上游运营商重置检测 - 日流量缓冲:insertDataUsageRecord 改为 Redis INCRBYFLOAT,每日凌晨落盘到 tb_card_daily_usage - 运营商:新增 data_reset_day 字段(联通=27,其余=1) - IoT卡:新增 last_gateway_reading_mb 字段存储上次网关读数 - 查询层:新建 TrafficQueryService 合并 Redis(今日)+ DB(历史)数据源 - 清理:删除 DataUsageRecord model/store,移除 polling_handler 旧引用 迁移:000094-000097(carrier字段、iot_card字段、数据初始化、日流量表)
4.8 KiB
4.8 KiB
Why
当前流量数据处理存在两个架构性问题:
- 流量详单无差别写 DB(P2-26):每次轮询无条件调用
insertDataUsageRecord(),即使增量为 0 也写记录,大量卡每日产生大量无意义记录,数据库膨胀。 - 月流量直接覆盖(P2-27):
calculateFlowUpdates()直接用网关返回值覆盖current_month_usage_mb。上游运营商按自然月重置(联通 27 号,移动/电信/广电 1 号),重置后网关返回 0,我们的套餐月用量也归零——但套餐周期未必与自然月一致,导致用量数据错误。
这是架构改造,涉及 DB 迁移 + Redis 引入 + 轮询核心路径修改,建议低峰期发布。
What Changes
- E-2 月流量改增量累加(先做):
tb_iot_card新增last_gateway_reading_mb字段记录上次网关读数,tb_carrier新增data_reset_day字段记录运营商月重置日。合并calculateFlowUpdates()和calculateFlowIncrement()为一个函数,改为增量算法:increment = 当前读数 - 上次读数,检测到上游重置时特殊处理。current_month_usage_mb从直接覆盖改为+= increment。跨自然月时current_month_usage_mb重置为 0(不再= gatewayFlowMB)。⚠️ 上线前需运行数据初始化脚本,将所有卡的last_gateway_reading_mb设为当前current_month_usage_mb。 - E-1 流量详单改日粒度缓冲:新建
tb_card_daily_usage表(每卡每天一条)。insertDataUsageRecord()改为只有增量 > 0 时写 Redis(INCRBYFLOAT),直接替换旧写入路径,不再写tb_data_usage_record。新增每日落盘 Asynq 定时任务,凌晨 2 点分批 SCAN 昨日 Redis key → 覆盖 UPSERT 到tb_card_daily_usage→ 删 key。 - E-3 流量查询层适配:新建
TrafficQueryService,查询时合并"今日 Redis + 历史 DB"两段数据。更新所有受影响的查询入口。 - 清理:删除
tb_data_usage_record相关代码(model、store、bootstrap 引用)。
Capabilities
New Capabilities
traffic-daily-buffer: 流量日粒度 Redis 缓冲 + 每日落盘机制traffic-query-service: 统一流量查询服务(Redis + DB 合并)
Modified Capabilities
package-usage-daily-record: 流量详单从无差别写 DB 改为 Redis 缓冲 + 日落盘(直接替换旧路径)carrier: 运营商新增data_reset_day字段(上游重置日)iot-card: IoT 卡新增last_gateway_reading_mb字段,月流量改为增量累加,跨自然月重置为 0
Impact
- DB 迁移:3 个迁移文件(
tb_carrier加字段、tb_iot_card加字段、新建tb_card_daily_usage表) - 数据初始化:上线前需运行脚本初始化
last_gateway_reading_mb - 修改文件:
internal/task/polling_handler.go(核心改动,合并两个增量计算函数)、internal/model/iot_card.go、internal/model/carrier.go、相关 DTO、运营商管理接口 - 新增文件:
internal/model/card_daily_usage.go、internal/store/postgres/card_daily_usage_store.go(落盘+查询共用)、internal/service/traffic/query_service.go、日落盘任务 handler - 删除文件:
internal/model/data_usage.go、internal/store/postgres/data_usage_record_store.go(旧流量详单代码) - 新增常量:Redis key(
traffic:daily:{card_id}:{date})、任务类型(TaskTypeDailyTrafficFlush) - Redis 新增用途:流量增量缓存(INCRBYFLOAT + 48h TTL)
- 轮询核心路径变更:高风险,需低峰期发布
受影响的查询接口(E-3 需逐一适配)
| # | 接口路径 | 文件 | 影响方式 |
|---|---|---|---|
| 1 | GET /api/admin/assets/:type/:id/realtime-status |
service/asset/service.go |
CurrentMonthUsageMB 语义变化 |
| 2 | GET /api/admin/assets/resolve/:identifier |
handler/admin/asset.go |
resolve 返回流量概况 |
| 3 | GET /api/admin/assets/device/:id/realtime-status |
service/asset/service.go |
设备级聚合绑定卡用量 |
| 4 | GET /api/c/v1/asset/info |
handler/app/client_asset.go |
C端首页流量数据 |
| 5 | GET /api/c/v1/asset/packages |
handler/app/client_asset.go |
C端套餐用量展示 |
| 6 | GET /api/c/v1/asset/refresh |
handler/app/client_asset.go |
C端手动刷新 |
| 7 | GET /api/admin/assets/:type/:id/packages |
service/asset/service.go |
管理端套餐列表 |
不受影响的模块(确认独立)
- 套餐级流量重置(
ResetService):操作PackageUsage.DataUsageMB,与卡级字段无关 - 套餐日记录(
tb_package_usage_daily_record):套餐级日记录,由UsageService.updateDailyRecord()写入,与卡级tb_card_daily_usage是两个不同维度 - 套餐创建/管理:
data_reset_cycle配置不受影响