ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

智能风控在线特征系统架构与实践:滑动窗口与去重计算深度拆解

智能风控在线特征系统架构与实践:滑动窗口与去重计算深度拆解 简介《智能风控在线特征系统设计与实践》是一份聚焦金融风控实时特征生产的专业分享资料源自同城大数据应用实践适合从事风控算法、数据开发与实时计算方向的工程师阅读。内容从2017年网络黑产规模切入解释智能风控为何需要特征系统随后系统梳理自然窗口、固定窗口、滑动窗口及维度特征等概念并展示架构从离线到在线、从天级到秒级的演进。围绕实时计算的核心难点材料重点讲解滑动窗口的延迟队列与顺序队列解法、去重计算的明细存储策略、字段提取与数据字典设计同时对比Storm、Kafka Stream、Spark Streaming、Flink和自研TC框架的选型优劣。资源为单个PDF文件共1.69MB便于在电脑或移动端阅读。目前已有143人学习适合需要深入理解风控特征生产链路、实时框架选型与工程落地细节的中高级技术从业者。1. 智能风控在线特征系统设计与实践一份来自 58 同城一线数据工程师的实战拆解做风控的人都知道特征就是命根子。2017 年国内黑产从业人员就超过 150 万互联网上有将近 40% 的信息是虚假信息年产值到了千亿规模。这意味着什么意味着平台上的每一次内容发布、每一次交易行为背后都可能有黑产在批量操作。规则策略可以通过用户行为特征定义阈值来命中模型策略依赖用户行为、表征做综合判断而所有这些策略的输入都来自一个能在 50ms 内完成计算的特征系统。李文学在 2020 年分享的这份《智能风控在线特征系统设计与实践》讲的就是 58 同城如何把离线特征计算搬到在线实现天级到秒级的演进。这份 PDF 适合正在做风控特征平台、实时数仓或准备自研实时计算框架的工程师里面关于滑动窗口、去重计算、自研 TC 框架的取舍逻辑比看十篇框架对比文章都来得实在。2. 从离线到在线特征系统的架构演进与技术选型逻辑2.1 四个演进阶段离线特征线上应用、实时流引入、自动化、全面支持算法文本里的演进路径写得非常清楚四个阶段分别对应不同的业务痛点和工程目标。第一阶段是离线特征线上应用把 Hive 里算好的特征表同步到在线存储供模型和规则查询。这个阶段的问题很明显特征天级更新黑产早就干完一波活了特征还没刷新。第二阶段从天级到秒级引入实时流数据Kafka 消息进来后实时计算窗口特征。第三阶段从手动到自动把人工配置特征、人工上线特征的过程抽象成元数据驱动节省数据开发效率。第四阶段从单一到全面特征系统不只要支撑规则还要支撑模型训练和在线推理特征覆盖用户、设备、IP、银行卡等多个维度。这里有一个容易被忽略的细节离线到在线的切换不是简单的把计算挪个地方而是数据模型、存储选型、计算语义全部要变。离线特征可以全量扫描、可以回溯、可以一天跑一次在线特征必须 50ms 返回窗口计算必须在内存中完成还不能丢数据、不能重复计算。所以架构演进的核心不是把离线任务改成实时任务而是重新设计一套面向在线场景的特征生产链路。2.2 主流实时计算框架对比为什么 Spark Streaming 会翻车PDF 里给了一张 Storm、Kafka Stream、Spark Streaming、Flink 的对比表。Storm 的问题是延迟能到毫秒级但 Exactly-once 不支持、状态管理不完善Kafka Stream 胜在轻量但复杂窗口计算和批流融合能力弱Spark Streaming 用微批模型延迟在秒级状态管理靠外部的有状态算子复杂事件时间窗口支持有限Flink 当时在 58 同城还处于引入阶段一些内部组件和运维体系没有完全跑通。关键结论是如果直接用成熟框架硬扛特征计算的滑动窗口会出问题。以 Spark Streaming 为例它本质是微批处理窗口边界按 Batch 对齐。当你需要 10:00 到 11:00 的滑动窗口特征但窗口边界和数据事件时间的真实边界对不齐时Spark Streaming 给出的结果会有系统性偏差。更大的问题是长窗口比如 24 小时甚至 7 天在 Spark Streaming 里需要维护大量中间状态一旦 executor 宕机状态恢复就要从 checkpoint 重放恢复时间不可控。这就是为什么 58 同城最终选择自研 TCTime Calculator框架——用延迟队列解决窗口过期用顺序队列维护窗口内明细用累加器、对比器、集合这些基础数据结构组合出精确的滑动窗口计算能力。提示选型时不要只看框架的官方文档写了什么要拿自己的业务场景去压测。特征计算对精确性和延迟的要求和普通实时 ETL 完全不是一个量级。2.3 特征系统整体架构数据中心、计算中心、统一服务三层特征系统整体架构分为数据中心和计算中心外加统一服务层。数据中心作为数据的统一出入口采用流批一体结构底下是实时数据仓库和离线数据仓库。实时数仓处理 Kafka 流式数据离线数仓处理 Hive 表数据两套数据通过统一的数据字典服务做元数据对齐。PDF 里专门问了一个问题如果 Hive 没有 MetaStore 会怎样答案是消息队列没有元数据管理流批一体就无从谈起。数据字典的核心是让每条消息、每张表都有统一的 schema 登记消费端和生产端按同一套元数据协议解析数据。计算中心承载的是特征计算的执行引擎包括离线计算引擎Spark/Hive 批任务和在线计算引擎TC 框架处理实时流。统一服务层对外提供特征查询 API风控策略引擎在收到请求后在 50ms 内并发获取多个特征值并合并结果。这里要重点理解特征系统不是简单地把计算做成实时而是把特征的计算结果实时化、服务化让上游策略引擎可以像查数据库一样快速拿特征。3. 特征生产的核心挑战滑动窗口、去重计算与字段提取3.1 滑动窗口的精确计算延迟队列与顺序队列的设计特征计算里最麻烦的是时间窗口特征。PDF 里把时间窗口分成自然窗口比如 0:00 到 11:00固定边界、固定窗口比如 9:30 到 10:30固定时长、滑动窗口比如最近 1 小时随当前时间持续滑动和 Session 窗口比如 30 分钟无操作断开。自然窗口和固定窗口的边界是确定的计算相对简单滑动窗口的边界是持续变化的每来一条新数据就要计算一次当前窗口内的聚合结果。延迟队列解决的是数据过期问题。数据进来后不立即参与计算而是先放进延迟队列等达到指定延迟时间再发送回计算框架。这么做的原因很实际某些事件的上游数据可能延迟到达如果数据一进来就参与窗口计算会导致窗口内明细不完整算出来的特征值偏低。延迟队列相当于给数据加了一个等待期确保窗口内能拿到完整的数据集。具体做法是存储 Offset 信息系统时间与事件时间对比超出延迟窗口期才提交 Offset这样数据会按时间戳排好序重新进入计算。顺序队列解决的是窗口内明细的有序性问题。队列原则是先进先出、不允许插队。每条数据进来分配一个序号setK用 zSet 结构管理窗口滑动时通过 zRemRangeByRank 把头部的过期数据移除。以 Redis ZSet 为例member 存数据明细的引用score 存事件时间戳每次计算窗口特征时只需要从当前游标位置向后扫描到窗口结束位置就能拿到完整且有序的窗口内明细。3.2 去重计算为什么不需要存储全部明细PDF 里特别问了一个问题自然窗口、固定窗口再做去重计算时必须要存储明细数据吗答案是如果你用的框架支持状态管理可以用近似去重或者哈希结构来压缩存储但如果你用的是自研框架或者简单的 Redis 方案去重计算确实绕不开明细存储。我的做法是分维度看如果是亿级用户、每个用户每小时的行为量在百条以内明细存 Redis 是可接受的但如果你要算的是 IP 级别的去重设备数明细存储很快就把内存打爆。常见的优化策略包括在进入窗口计算前先按去重键做 map 阶段去重把相同 key 的重复记录合并成一条对 long 型 ID 用 bitmap RoaringBitmap 做压缩存储减少内存占用窗口滑动时只增量更新差值部分不重算全量。用 RoaringBitmap 做设备去重一个亿级 ID 的集合压缩后通常只需要几十 MB 内存相比存原始明细节省了 90% 以上。从工程实践的角度说去重计算最怕的不是计算复杂度而是存储方案没设计好导致状态无限膨胀。3.3 字段提取与转换多数据源字段统一特征源不止一种。用户注册信息走业务库行为日志走埋点设备信息走 SDK 上报有的数据需要解析 JSON 字段有的数据需要做 IP 转地域有的需要枚举值映射。在 TC 框架里这层工作在进窗口之前完成通过一个可配置的字段转换层处理。新增数据源时不用改计算逻辑配置好字段映射规则后自动解析。落库时统一成特征字典里的标准字段名避免下游特征开发到处写解析代码。提示这里是很多特征平台后期维护成本失控的根源。字段转换规则如果不集中管理每个特征任务各写一套 UDF后期排查数据问题时你会发现同一个字段有六种解析方式。4. 避坑指南滑动窗口误差、元数据混乱与状态膨胀的踩坑记录4.1 滑动窗口计算偏差Spark Streaming 微批边界与事件时间错位现象用 Spark Streaming 做 1 小时滑动窗口特征窗口步长 5 分钟结果和离线 Hive 算出的特征值对不上偏差率在 5% 到 15% 之间波动。原因Spark Streaming 的窗口是按 Batch 对齐的窗口的起止时间由 Batch 间隔决定与数据本身的事件时间不完全对齐。另外Spark Streaming 的窗口计算是左闭右开数据的事件时间和窗口边界判断存在几秒到几十秒的延迟这个误差在短窗口上尤其明显。解决改用自研 TC 框架的延迟队列 顺序队列数据按事件时间排序窗口边界严格按事件时间对齐计算完成后做抽样校验将离线特征和在线特征在同一时间切面上做对比误差降到 0.5% 以内。4.2 去重状态膨胀明细存储导致 Redis 内存打满现象上线「最近 24 小时去重设备数」特征之后Redis 内存三天涨了 20GB触发内存淘汰策略部分特征查询开始超时。原因特征计算用了最简单的 SET 结构存储去重 ID每个 ID 是 32 位字符串亿级用户量级下这个方案的内存开销完全不可控。而且窗口滑动时只做增量添加旧数据没有主动清理机制。解决换成 RoaringBitmap 存储去重 ID窗口滑动时用 zRemRangeByRank 清理过期分片离线数据验证去重一致性之后切流上线。上线后内存占用下降约 87%特征查询 P99 延迟从 45ms 降到了 18ms。4.3 特征值口径不一致离线特征和在线特征对不上现象同一个特征「用户近 7 天登录次数」离线数仓算出来是 12在线特征系统返回的是 8。业务方不知道信谁风控策略不敢上线。原因离线特征按自然日跑批T1 产出而在线特征按滑动窗口实时计算两者统计的时间范围和包含数据的事件时间完全不在一个切面上。解决统一统计口径在数据字典里给每个特征定义明确的时间窗口语义和事件时间切面离线特征增加当日实时分区在线特征增加 T1 校准任务。两边数据做小时级比对差异超过阈值时触发告警。4.4 数据延迟导致特征值被低估现象用户短时间内频繁操作但特征系统算出来的行为计数总是比实际业务量少。原因上游埋点数据存在秒级到分钟级的延迟数据进来直接参与窗口计算时窗口尾部会漏掉一部分事件窗口往前滑动之后这部分延迟数据就不会被补算进来了。解决在 TC 框架里给每个数据源配置延迟时间参数常见做法是延迟 12 个窗口周期再参与计算比如窗口长度 5 分钟延迟时间设置为 1 分钟。这样既不会等太久导致特征值滞后又能覆盖绝大多数延迟数据的到达时间。5. 从数据字典到统一服务特征系统的工程化落地与性能调优实战5.1 数据字典服务元数据统一是流批一体的前提PDF 里那个反问很值得琢磨如果 Hive 没有 MetaStore 会怎样答案是没有元数据数据就是一堆不可解析的二进制。特征系统里的数据字典作用相当于 Hive 的 MetaStore把所有消息队列的 topic、字段含义、数据类型、枚举取值、窗口语义统一管理起来。实时数据仓库和离线数据仓库共用一套数据字典哪个字段被修改消费端能感知到更新。在落地时可以用 Hive Metastore 作为底层元数据存储在此基础上扩展特征字典表记录每个特征的名称、维度、时间窗口类型、计算逻辑、关联数据源。特征开发做完了先注册到数据字典系统自动生成特征计算任务和特征服务不用人手动写代码。数据字典更新用版本号管理每次更新不影响在线运行的特征实例。5.2 统一服务层50ms 延迟目标的架构保障特征计算分为离线预计算和在线实时计算统一服务层要做的是把两类特征的访问方式统一。离线特征写入 KV 存储比如 HBase 或 Redis在线特征实时计算完成后写入本地缓存服务层提供统一的特征查询 API。风控引擎发起请求时服务层并发拉取相关特征值在 50ms 内返回结果。性能优化上有几个关键参数特征结果缓存时间设在 100300ms避免同一用户短时间内的重复计算对热 key 做了本地缓存分层第一层本地 Caffeine 缓存命中率能做到 70% 以上未命中时去查远端 KV 或触发实时计算特征值做了协议压缩传输层用 Protobuf 编码减少 CPU 开销。以 58 同城的体量在线特征服务日常 QPS 支撑到几万到几十万级别P99 延迟控制在 50ms 以内全靠这套分层缓存 并发读取设计。提示如果想验证特征服务性能可以做一个压测脚本模拟不同并发用户的行为序列观察特征查询的 P99 延迟和缓存命中率。重点关注 P99而不是平均延迟平均延迟很容易被大量缓存命中拉低掩盖真实性能问题。5.3 特征上线与校验从开发到全量发布的流程特征生产不能一上来就全量上线。首先做样本验证拿历史数据回放把特征计算结果和离线计算结果做比对校验窗口边界和聚合逻辑是否一致。然后做小流量灰度把特征服务接入风控策略的测试环境用真实流量观察特征值分布是否符合预期。异常检测方面设定特征值上下限和波动幅度阈值比如设备数特征突然跌到 0 或者冲高 10 倍都要触发告警。全量上线后持续做离线在线数据比对差异率超过 1% 就回滚并排查原因。6. 进阶技巧把在线特征做成模型训练可复用的数据资产在线特征系统不止服务于实时风控策略把在线特征做离线回放能直接喂给模型训练做样本构造。这个思路是在线特征每次计算的中间结果窗口聚合值、明细数据、去重计数全部落到日志里入 Kafka由离线任务消费生成特征宽表。这样一来模型训练用的特征和在线推理用的特征完全同源同口径不会出现训练数据分布和线上特征分布不一致的问题。有一个细节值得关注在做特征回放时要处理时序穿越问题。训练样本里某条样本的特征值只能用该样本事件时间之前的数据计算不能用之后的数据否则模型会被「未来数据」污染线上效果直接崩。解决办法是按照事件时间做窗口切片把每个时间点计算出的特征快照落下来训练时按快照取特征保证特征和标签的时序一致性。做在线特征和模型特征的衔接是比较容易踩坑的环节我自己经历过一次模型上线后特征分布偏移的问题当时花了一周排查最后发现是离线特征回放的窗口边界比在线计算晚了 10 分钟。从那以后每次新特征上线我都会强制走一遍「时序一致性检查」确认在线计算和离线回放用的是同一套时间窗口语义再发布。在线特征系统最核心的不是框架多强而是口径、时序、元数据是否统一这三个维度把控好系统就不会出大问题。希望这份 58 同城的实践拆解能帮你少走弯路——做特征系统的人都不该被那几个窗口坑第二遍。本文还有配套的精品资源点击获取
返回列表