名单库(yidun-checker-namelist)
判断「这个手机号/设备/IP/账号是不是已在黑名单里」,并且要在毫秒级完成 —— 靠的是执行侧只读 Redis。
1. 业务定位
模型是一条链:名单组(ListGroup)→ 名单项(ListItem),再由 名单匹配器(ListChecker) 描述「从请求哪个字段取值 → 查哪个名单组 → 结果写到哪个字段」。
三个写入口:
| 写入方 | 场景 | 来源标识 |
|---|---|---|
| 策略中心 / 管理后台 | 人工维护名单 | 管理面接口 |
checker-rule | 规则命中自动加名单 | ListSourceEnum.RULE_HIT |
intelligent-risk 开放接口 | 客户 OpenAPI 加名单 | OPEN_API_ADD |
2. 架构与模块划分
| 模块 | 类型 | 职责 |
|---|---|---|
contract | jar | 跨端枚举:实体类型、名单类型、来源、密文格式、结果码 |
common | jar | 缓存 Key/分片工具 ListCacheKeyFactory、加密工具 |
domain | jar | 组/匹配器/名单项/操作记录/Outbox/命中统计 |
service/base、service/business | jar | DAO/Manager、事务与 outbox 事件发布 |
facade/dubbo-api、facade/dubbo-provider | Dubbo | 管理面(yd-mp-list_mgmt-dubbo) |
execution/dubbo-api、facade/dubbo-check-provider | Dubbo | 执行面(yd-mp-list_exe-dubbo) |
scheduler | app | yd-mp-list_skd:缓存 Bootstrap/增量同步、名单释放、命中统计 |
三段式架构:管理写库 + 事件同步缓存 + 执行读缓存。
3. 核心链路
双 generation 无锁切换是这套设计的核心:名单组元数据里保存 activeGeneration,同步时先写「非活跃代」的分片数据,写完后原子切换指针。读侧永远只读当前活跃代,因此不会读到「半新半旧」的数据。
4. 关键数据模型
| 对象 | 说明 |
|---|---|
ListGroup | 真实存放名单项的库,区分黑/白/疑似 |
ListItem | 名单项,存储 AES 密文 + md5 摘要(不存明文) |
ListChecker | 匹配器:取值字段、目标名单组、结果写回字段 |
ListHitRecord | 命中记录,投递 Kafka 供统计与质检 |
| Outbox 表 | 事务内写入的缓存变更事件,保证「落库成功则同步一定能发生」 |
5. 存储与中间件
| 组件 | 用途 |
|---|---|
| MySQL | 名单配置与名单项主存储(密文 + md5)、outbox |
| Redis | 执行侧唯一数据源:分片 Set + group-meta hash |
| Kafka | 命中记录 Yidun_Mp_List_Hit |
| Elastic-Job | 增量同步、名单到期释放、命中统计 |
6. 设计模式与扩展点
| 扩展点 | 位置 | 说明 |
|---|---|---|
| 缓存 Key/分片 | ListCacheKeyFactory | 管理端、调度端、执行端三端必须一致,改这里等于改协议 |
| 匹配器类型 | ContentFormatEnum、实体类型枚举 | 新增字段类型需同步三端与元数据定义 |
| 到期释放 | scheduler 名单释放任务 | 支持临时封禁自动解封 |
| 导入导出 | 管理面导出/导入接口 | 大批量名单运维 |
7. 上下游依赖
| 方向 | 模块 | 说明 |
|---|---|---|
| 上游 | mplatform-strategy | 执行期经 ListServiceProxy 调用匹配 |
| 上游 | checker-rule | 自动加名单(RULE_HIT) |
| 上游 | intelligent-risk | 开放接口与业务侧名单管理 |
| 下游 | mplatform-meta | 字段 code ↔ jsonPath 翻译 |
| 下游 | mplatform-clickhouse | 命中统计入仓 |
8. 工程约束与变更红线
- 执行侧禁止回源 MySQL:只读 Redis,回源会在峰值打穿数据库。
- 缓存 Key 与分片规则三端一致:任何不一致都会导致「写了但查不到」。
- 名单项必须密文存储:明文入库是数据安全事故。
- generation 切换必须原子:手工清缓存会破坏一致性,正确做法是触发同步任务。
- 命中记录投递失败不影响判定:读链路不能因为 Kafka 异常而失败。
9. 关键代码索引
| 主题 | 路径 | 说明 |
|---|---|---|
| 执行契约 | yidun-checker-namelist/execution/dubbo-api/src/main/java/.../api/ListMatchService.java | 策略调用的匹配接口 |
| 匹配执行 | yidun-checker-namelist/facade/dubbo-check-provider/src/main/java/.../ListMatchServiceImpl.java | 执行实现 |
| Redis 读 | yidun-checker-namelist/facade/dubbo-check-provider/src/main/java/.../cache/match/RedisListMatchRepository.java | Lua SISMEMBER |
| 缓存 Key | yidun-checker-namelist/common/src/main/java/.../kits/ListCacheKeyFactory.java | Key 与分片唯一实现 |
| 增量同步 | yidun-checker-namelist/scheduler/src/main/java/.../ListCacheIncrementalSyncJob.java | outbox → Redis |
| 管理服务 | yidun-checker-namelist/service/business/src/main/java/.../service/impl/ListGroupServiceImpl.java | 名单组业务与事务 |
10. 排查要点
| 现象 | 定位 | 结论 |
|---|---|---|
| 名单加了但不命中 | 看 Redis 分片是否有该值、generation 是否切换 | 多为同步任务未执行或 Key 规则不一致 |
| 命中率异常升高 | 查名单来源分布 | 规则自动加名单(RULE_HIT)批量误加是常见原因 |
| 白名单不生效 | 看匹配器执行顺序与白/黑优先级 | 顺序错或匹配器未绑定该策略 |
| 名单项提前失效 | 看到期时间与释放任务 | 到期释放任务按配置执行,属预期行为 |
| 执行耗时上升 | 看 Redis 是否发生大 key 扫描 | 避免全量 SMEMBERS,只用 SISMEMBER |