refactor: 流量系统重构 — 增量累加算法 + 日粒度缓冲 + 旧详单清理
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 7m16s
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字段、数据初始化、日流量表)
This commit is contained in:
@@ -0,0 +1,57 @@
|
||||
## Why
|
||||
|
||||
当前流量数据处理存在两个架构性问题:
|
||||
|
||||
1. **流量详单无差别写 DB**(P2-26):每次轮询无条件调用 `insertDataUsageRecord()`,即使增量为 0 也写记录,大量卡每日产生大量无意义记录,数据库膨胀。
|
||||
2. **月流量直接覆盖**(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` 配置不受影响
|
||||
Reference in New Issue
Block a user