feat: 实现 IoT 卡轮询系统(支持千万级卡规模)
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 6m35s

实现功能:
- 实名状态检查轮询(可配置间隔)
- 卡流量检查轮询(支持跨月流量追踪)
- 套餐检查与超额自动停机
- 分布式并发控制(Redis 信号量)
- 手动触发轮询(单卡/批量/条件筛选)
- 数据清理配置与执行
- 告警规则与历史记录
- 实时监控统计(队列/性能/并发)

性能优化:
- Redis 缓存卡信息,减少 DB 查询
- Pipeline 批量写入 Redis
- 异步流量记录写入
- 渐进式初始化(10万卡/批)

压测工具(scripts/benchmark/):
- Mock Gateway 模拟上游服务
- 测试卡生成器
- 配置初始化脚本
- 实时监控脚本

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-02-05 17:32:44 +08:00
parent b11edde720
commit 931e140e8e
104 changed files with 16883 additions and 87 deletions

View File

@@ -0,0 +1,226 @@
## ADDED Requirements
### Requirement: 并发配置初始化
系统 SHALL 在启动时从数据库加载并发配置到 Redis。
#### Scenario: 首次启动加载配置
- **WHEN** Worker 进程启动Redis 中没有并发配置
- **THEN** 系统从 tb_polling_concurrency_config 表读取所有配置,写入 Redispolling:concurrency:config:{type}
#### Scenario: 配置已存在则跳过
- **WHEN** Worker 进程启动Redis 中已有并发配置
- **THEN** 系统跳过初始化,使用 Redis 中的配置(避免覆盖运行时修改)
#### Scenario: 数据库无配置则使用默认值
- **WHEN** 数据库中没有并发配置记录
- **THEN** 系统使用默认值(实名检查:50、流量检查:50、套餐检查:30、停复机:10写入 Redis
### Requirement: 并发信号量获取
系统 SHALL 在任务执行前获取 Redis 信号量,控制并发数。
#### Scenario: 获取信号量成功
- **WHEN** 实名检查任务开始,当前并发数为 30最大并发数为 50
- **THEN** 系统执行 INCR polling:concurrency:current:realname返回值 31小于等于 50获取成功
#### Scenario: 并发已满拒绝执行
- **WHEN** 实名检查任务开始,当前并发数为 50最大并发数为 50
- **THEN** 系统执行 INCR 返回值 51大于 50立即 DECR 归还,任务返回 SkipRetry
#### Scenario: 信号量获取失败重试
- **WHEN** 任务在并发已满时被拒绝
- **THEN** 系统不重试直接返回等待下次调度周期10秒后再次尝试
#### Scenario: Redis 连接失败
- **WHEN** INCR 操作因 Redis 连接失败
- **THEN** 系统记录错误日志,任务失败,不执行业务逻辑
### Requirement: 并发信号量释放
系统 SHALL 在任务完成后释放 Redis 信号量。
#### Scenario: 任务成功完成释放
- **WHEN** 实名检查任务成功完成
- **THEN** 系统执行 DECR polling:concurrency:current:realname释放信号量
#### Scenario: 任务失败也释放
- **WHEN** 实名检查任务因 Gateway 超时失败
- **THEN** 系统在 defer 中执行 DECR确保信号量释放
#### Scenario: Panic 恢复后释放
- **WHEN** 任务执行中发生 panic
- **THEN** 系统在 recover 后执行 DECR防止信号量泄漏
#### Scenario: DECR 失败记录日志
- **WHEN** DECR 操作失败
- **THEN** 系统记录错误日志,包含 task_type、task_id便于排查信号量计数异常
### Requirement: 动态调整并发数
系统 SHALL 支持通过管理接口实时调整最大并发数,无需重启 Worker。
#### Scenario: 管理员提高并发数
- **WHEN** 管理员调用接口,将实名检查最大并发数从 50 提高到 80
- **THEN** 系统更新 RedisSET polling:concurrency:config:realname 80更新数据库配置表
#### Scenario: 管理员降低并发数
- **WHEN** 管理员调用接口,将流量检查最大并发数从 50 降低到 30
- **THEN** 系统更新 Redis 和数据库,当前正在执行的任务继续,新任务受新限制
#### Scenario: 调整后立即生效
- **WHEN** 并发数调整完成
- **THEN** 系统下次任务获取信号量时,使用新的最大并发数判断
#### Scenario: 并发数无效值校验
- **WHEN** 管理员尝试设置并发数为 0 或负数
- **THEN** 系统返回错误,提示并发数必须大于 0
#### Scenario: 并发数过大警告
- **WHEN** 管理员尝试设置并发数大于 200
- **THEN** 系统返回警告,提示过高并发可能打爆 Gateway建议值范围 10-100
### Requirement: 查询并发状态
系统 SHALL 提供接口查询各类型任务的并发配置和实时并发数。
#### Scenario: 查询所有类型并发状态
- **WHEN** 管理员请求查询并发状态
- **THEN** 系统返回所有类型realname、carddata、package、stoprestart的最大并发数和当前并发数
#### Scenario: 查询单个类型并发状态
- **WHEN** 管理员请求查询实名检查并发状态
- **THEN** 系统返回 max_concurrency=50、current_concurrency=30、usage_rate=60%
#### Scenario: 并发数异常检测
- **WHEN** 查询并发状态,发现当前并发数大于最大并发数
- **THEN** 系统返回警告标志,提示可能存在信号量泄漏
#### Scenario: 长时间满载告警
- **WHEN** 查询并发状态,某类型并发数连续 5 分钟保持满载usage_rate=100%
- **THEN** 系统返回建议,提示可能需要提高并发数或优化任务性能
### Requirement: 分类型并发控制
系统 SHALL 为不同任务类型(实名检查、流量检查、套餐检查、停复机)独立控制并发数。
#### Scenario: 实名检查独立控制
- **WHEN** 实名检查任务获取信号量
- **THEN** 系统使用 polling:concurrency:config:realname 和 polling:concurrency:current:realname
#### Scenario: 流量检查独立控制
- **WHEN** 流量检查任务获取信号量
- **THEN** 系统使用 polling:concurrency:config:carddata 和 polling:concurrency:current:carddata
#### Scenario: 套餐检查独立控制
- **WHEN** 套餐检查任务获取信号量
- **THEN** 系统使用 polling:concurrency:config:package 和 polling:concurrency:current:package
#### Scenario: 停复机独立控制
- **WHEN** 停复机任务获取信号量
- **THEN** 系统使用 polling:concurrency:config:stoprestart 和 polling:concurrency:current:stoprestart
#### Scenario: 互不影响
- **WHEN** 实名检查并发满载50/50流量检查并发正常30/50
- **THEN** 流量检查任务仍然可以正常获取信号量并执行,不受实名检查影响
### Requirement: 并发配置持久化
系统 SHALL 将并发配置变更持久化到数据库。
#### Scenario: 更新配置同步数据库
- **WHEN** 管理员调整并发数
- **THEN** 系统先更新 Redis再更新数据库UPDATE tb_polling_concurrency_config SET max_concurrency=? WHERE task_type=?
#### Scenario: 数据库更新失败回滚
- **WHEN** Redis 更新成功,但数据库更新失败
- **THEN** 系统回滚 Redis 配置到原值,返回错误
#### Scenario: 启动时以数据库为准
- **WHEN** Worker 进程重启Redis 和数据库配置不一致
- **THEN** 系统以数据库配置为准,覆盖 Redis
### Requirement: 并发监控统计
系统 SHALL 记录并发使用情况的监控统计。
#### Scenario: 记录峰值并发数
- **WHEN** 每次任务获取信号量成功
- **THEN** 系统更新 Redis Hashpolling:stats:concurrency:{type}),记录当前并发数,如果大于历史峰值则更新峰值
#### Scenario: 记录并发拒绝次数
- **WHEN** 任务因并发已满被拒绝
- **THEN** 系统增加 Redis Hash 的 reject_count_1h 计数
#### Scenario: 每小时重置统计
- **WHEN** 每小时整点
- **THEN** 系统重置 reject_count_1h保留 peak_concurrency持续统计
### Requirement: 信号量计数修复
系统 SHALL 提供接口修复异常的信号量计数。
#### Scenario: 手动重置计数器
- **WHEN** 管理员发现并发计数异常(如泄漏导致一直为 50 无法下降)
- **THEN** 管理员调用接口,系统将 polling:concurrency:current:{type} 重置为 0
#### Scenario: 自动检测修复
- **WHEN** 系统定期检查(每 5 分钟),发现当前并发数长时间不变且无任务执行
- **THEN** 系统记录警告日志,建议管理员检查并手动修复
#### Scenario: 修复操作记录日志
- **WHEN** 执行信号量重置
- **THEN** 系统记录操作日志,包含操作人、重置前值、重置后值、原因
### Requirement: 日志记录
系统 SHALL 记录并发控制的关键操作日志。
#### Scenario: 记录并发满载日志
- **WHEN** 任务因并发已满被拒绝
- **THEN** 系统记录 Info 日志,包含 task_type、current_concurrency、max_concurrency
#### Scenario: 记录配置变更日志
- **WHEN** 管理员调整并发数
- **THEN** 系统记录 Info 日志,包含 task_type、old_value、new_value、operator
#### Scenario: 记录信号量异常日志
- **WHEN** DECR 失败或检测到计数异常
- **THEN** 系统记录 Error 日志,包含详细上下文