路线图
July 27, 2026 · View on GitHub
当前版本 v0.5.0。本文说明下一个版本要做什么、为什么是这些、以及每项的代价与风险。 已完成的版本保留在下方作为记录。
判断标准:一项工作能不能进下一个版本,看它是否阻挡「把星云放进一个真实生产 环境」。功能是否好看、是否对标竞品,都不是理由。
v0.4.0 与 v0.5.0 都与本文原先的规划不一致,而两次的原因不同。
v0.4.0 原本规划的是「规模与接入」,实际发的是「补齐文档写了但实现没有的地方」—— 核实文档承诺时接连撞出四处「说了没做」,其中一处是缺陷(测试态策略会真的拦线上 流量)。没被规划,但比规划里的事更该先做。
v0.5.0 则把顺延过来的三项都做完了,其中一项是推翻了自己的判断:此前多次说 「这台机器起不了 k8s」,实际能起 —— 受限的是估计,不是机器。
记这两笔是想说明本文的用法:它是当前的判断,不是承诺。撞到更该先做的事时 就改,但要说清楚为什么改。
0. 当前还有没有「规定了但没做」
没有了。 隐私设计里最后一处(数据主体权利接口)在 v0.4.0 补齐。
这一节此前写的是「pii 级别的数据目前是明文存储的」,那是 v0.3.0 要解决的第一
优先级问题,现已解决(HMAC 存储)。保留这段沿革是因为它说明了本文的用法:
这一节永远写「文档承诺了而实现没有」的最要紧那一处,而不是写下一个功能。
v0.4.0 的经验值得记下来:那一版一半的内容不在任何规划里,而是核实文档承诺时接连 撞出来的 —— 包括一个真缺陷(测试态策略会真的拦线上流量)。所以下一版开工前, 先做的事不是挑功能,而是再核一遍文档里的承诺。
当前已知的差距不在「说了没做」,而在「明确说了不做」—— 见威胁模型第四节:采集器入口无认证、控制面不做 TLS 终结、管理接口无全局限流。它们的处理方在部署侧,但采集器认证那条应当由项目解决, 理由见下方第 8 项。
v0.3.0 —— 主题:能进生产环境
四项,都属于「不做就不能上线」而不是「做了更好」。
1. 存储层的 pii 保护
做什么
- ClickHouse:
pii列改为存 HMAC-SHA256(密钥从NEBULA_HMAC_KEY注入,该变量gen-env.sh已经在生成,但目前只有采集器的hash动作在用) - 保留可查询性:风控要按
uid聚合,HMAC 后等值比较仍然成立,范围查询本来也不需要 - 告警表的
subject_key是运营要看的,不做 HMAC,继续靠分级脱敏 在读取时按角色控制 - PostgreSQL 的审计表已经只存掩码值,不需要改
为什么这样分
HMAC 是单向的,存了就查不回原值。对事件明细这是对的:它的用途是聚合统计, 不需要还原到人。对告警不行:运营处置告警时必须能看到是哪个账号,还原不了就没法处置。 所以两张表的策略必须不同 —— 一刀切会要么废掉风控,要么废掉隐私。
风险:密钥轮换会让新旧数据无法关联。需要在文档里写清楚这是不可逆的操作, 并提供「双写过渡期」的做法。
估算:schema 改动小,难点在迁移既有数据与文档。约 1–2 天。
2. 策略热更新
做什么:改完策略不重启 Flink 作业即可生效。
难点不在轮询,在于换策略时变量状态不能丢。
如果重载时重建变量图,所有窗口计数归零 —— 「IP 5 分钟内登录失败次数」在改完阈值的 那一刻变回 0,攻击正好在那个窗口里溜过去。改一个阈值的代价不该是丢掉全部在途状态。
设计:
VariableGraph.extendTo(newDefs, neededNames)
· 已存在的节点连同累积状态原样保留(定义可以换,Node 持有的是累积值,与定义字面无关)
· 新引入的变量建新节点 —— 必然冷启动,它此前没在算,没有历史可继承
· 不再被引用的变量**不删**:策略在 test / online 之间来回切是常见操作,
每切一次清空状态会让热更新失去意义。变量总数有上界(253),保留全部代价有限
· 重做拓扑排序(新变量可能插在已有变量之间),order 重建、nodes 不动
下发用 Flink 的 broadcast state:一个 source 轮询 /api/v2/metadata/version,
版本变了才拉全量并广播。用 broadcast 而不是每个算子各自轮询,是因为后者会让并行实例
在一小段时间内按不同版本的策略判定 —— 同一批事件的结果取决于它落在哪个实例上。
必须证明而不是声称:测试要构造「窗口内已累积 4 次 → 热更新 → 第 5 次事件」的场景, 断言计数是 5 而不是 1。
运维需要知道:新引入的变量要经过一个完整窗口期才给出有意义的值。这不是缺陷, 但不说清楚会被当成 bug。
估算:3–5 天。这是这个版本里最难的一项。
3. 控制面的限流与登录失败锁定
做什么
- 登录失败计数与锁定(按账号 + 按来源 IP 双维度,避免单一维度被绕过)
/checkRisk按服务令牌限流 —— 它是延迟敏感路径,一个失控的调用方能拖垮整条链路- 管理接口的全局限流
为什么现在做:认证已经落地,但没有任何暴力破解防护。Argon2id 让离线爆破变得
昂贵,但在线爆破只受限于网络带宽。SECURITY.md 里已经把这条列为「规划中」,
它是认证这块最后一个缺口。
估算:1–2 天。Redis 已经在,计数器直接用它。
4. 可观测性
做什么
- 引擎:变量计算耗时、各策略命中数、去重抑制数、迟到事件数,走 Flink 的 metrics
- 控制面:接口延迟与错误率(actuator 已在,补 Micrometer + Prometheus 端点)
采集器:补 Prometheus 端点✅ 已完成- 补齐
docs/operations/monitoring.md(当前 13 行占位)
为什么:出问题时现在没有任何手段判断「哪个变量算慢了」「哪条策略命中率突然异常」。 风控系统的失效往往是静默的 —— 策略不再命中不会报错,只是告警变少。没有指标就没人 会发现。
估算:2–3 天。
v0.4.0 —— 主题:补齐文档写了但实现没有的地方(已完成)
发出来的内容与原规划不同,原因见开头。四项都是同一个来源:去核实文档里的某句 承诺,发现不成立。
| 项 | 说明 |
|---|---|
| 序列检测(A 之后 N 秒内没有 B) | 参考引擎实现了、Java 引擎没有 —— 跨引擎语义不一致 |
| 采集器的 Prometheus 端点 | 监控文档如实标注过「尚未实现」 |
| 数据主体权利接口 | 隐私文档里最后一处「规定了但没做」 |
| 测试态策略不影响线上决策(缺陷) | 四处文档都写了这条语义,而 /checkRisk 从未过滤 |
另外还做了账号与令牌管理界面、表单化策略编辑器、威胁模型文档。
v0.5.0 —— 主题:规模与接入
5. Kubernetes 上的高可用
Helm chart 已完成,在单节点 k3s 上实测装通并验证了出厂资产导入。 容量规划也已按实测补齐。
剩下的是高可用,而这一项刻意留在 chart 之外:存储组件目前是单副本 StatefulSet, 生产上应当换成各自的 Operator(CloudNativePG、Altinity ClickHouse Operator、 Redpanda Operator)或托管服务 —— 在 Kubernetes 里自己维护有状态集群是另一个量级的 工作,不该由一份应用 chart 顺带承担。
引擎同理:当前是 Flink 的 session 集群,不是 Flink Kubernetes Operator,没有作业级的 自动恢复与滚动升级。
chart 的 README 里逐条写了「验证过什么 / 没验证过什么」。
6. Kafka 作为数据源
Kafka 输出已完成(franz-go,按主体分区)。当时那条「零依赖 vs 引入客户端库」的
取舍由项目决定为引入,理由与代价记在
internal/sink/kafka.go 与
CHANGELOG。
剩下的是把 Kafka 当输入:从既有主题消费事件,而不是只往里写。这样采集器能接在 别人已有的数据管道后面,而不要求上游改成推给采集器。
7. 序列检测 —— 已完成,但没有用 flink-cep
「A 之后 N 秒内没有 B」(延迟判定)与多步序列(A → B → C)都已实现,两个引擎共用 金标准向量对照。
本条原本写的是「引入 flink-cep」,查下来这条路走不通:
flink-cep 1.20.5 里没有 dynamic 包也没有 PatternProcessor —— 模式在构图时
编译进作业图。而 2.0 的策略是热更新的,改一条序列策略就得重启作业,连带丢掉全部
已累积的窗口状态。这与 v0.3.0 落地的热更新直接冲突。
更根本的一条:参考引擎(JS)必须实现同样的语义供金标准向量对照,它不可能用 Flink CEP。也就是说无论如何都要手写一份,引入 CEP 只是多一份需要与手写实现保持 一致的东西。
仍然没做的是分支(A 之后 B 或 C)。需要时写成多条策略 —— 那样每条的命中量还能 分别看到,而分支写法看不到。重复(A 出现 3 次以上)用内联计数器就能表达,不需要 序列构造。
8. 接入方式 —— 已完成
syslog(RFC 3164 / 5424,UDP 与 TCP)、HTTP 入口的共享令牌校验、 OpenResty 埋点都已落地。
Zeek 不需要单独的驱动:配成 JSON 日志后走 -source file 或 -source syslog 即可。
剩下的是把 Kafka 当输入(见上一条)。
不打算做的
写下来是为了让人不必反复问。
不做规则的可视化拖拽编排。 风控策略的表达力来自条件树的嵌套与算子语义, 拖拽界面要么表达不了复杂逻辑,要么复杂到不如直接写。表单化的编辑器足够。
不做自己的图表库。 1.x 有一个基于 D3 v3 的 5600 行单文件 BChart,这类东西的
维护成本远超收益。
不追求覆盖所有风控场景。 内置 170 条策略来自 1.x 某个站点的经验,它们是起点 而不是标准答案。项目的价值在于领域模型与引擎语义的正确性,不在于策略条数。
不做多租户。 会侵入领域模型的每一层。有这个需求时应该跑多套实例。
版本号与兼容性
0.x 阶段升 MINOR 就要预期可能需要改配置或改数据,详见发布流程 §1.2。
上面几项中会带来破坏性变更的:
- 存储层
pii保护 —— 既有数据需要迁移,或接受新旧数据无法关联 - 策略热更新 —— 元数据下发接口可能调整
离开 0.x 的条件见发布流程 §1.2,当前还差:CEP、第三方完成过端到端部署。