背景
金融风控特征是在金融领域中用于评估和管理风险的关键指标。它们帮助金融机构识别潜在风险,降低损失,并采取措施规避风险。例如,用户最后一次授信提交时间就是一个重要的金融风控特征。
金融风控实时特征场景是一个典型的大数据实时业务场景。为了应对这一挑战,风控团队采用了业界常用的 Lambda 架构和 Kappa 架构。对于7天内的实时特征,使用 Kappa 架构;而对于超过7天的特征,则采用 Lambda 架构。
实时特征的 Lambda 架构
在 Lambda 架构中,所有原始数据都来自同一个数据源(如日志、业务 Binlog等),然后分为两条链路进行处理。第一条是实时链路,通过流计算处理,将数据写入实时存储系统。第二条是离线链路,将数据处理并归档至 Hive。最后,在查询层根据特定逻辑合并离线数据和实时数据,然后将结果输出给应用方。为了提高吞吐量和并发性能,通常会在中间加入一层缓存。
然而,Lambda 架构也存在一些问题。首先,由于数据需要在多个系统中存储,因此会增加冗余存储的成本。其次,计算逻辑需要在流处理和批处理两个框架中分别实现和运行,导致开发成本较高。最后,由于计算逻辑分布在不同的框架中,因此在进行调试和问题排查时可能会比较复杂,从而增加了维护成本。
实时特征的 Kappa 架构
Kappa 架构可以被视为Lambda架构的简化版本,它去除了 Lambda 架构中的批处理部分。在 Kappa 架构中,消息队列被用作一种存储机制。当需要对数据进行修改或重新处理历史数据时,只需从消息队列中重新读取数据即可。这使得开发者只需维护一套流计算逻辑,从而降低了开发和运维成本。
然而,Kappa 架构也存在一些明显的问题。首先,其能够回溯的数据量受到消息队列存储能力的限制。其次,流处理的重新计算吞吐量较低,可能导致回溯时间过长,特别是当需要回溯的数据量较大时。
在金融风控部门,离线和实时特征的开发由两个不同的团队负责。这进一步放大了 Lambda 架构存在的问题。对于同时包含实时和离线特征的需求,业务人员需要向两个团队提出需求,这不仅增加了沟通成本,而且更难保证逻辑的一致性。特征产出的时间取决于两个团队中最后一个完成任务的时间,如果其中一个团队的任务出现延迟,那么整个特征产出的时间也会相应延长,即使所需的逻辑非常简单。在金融业务快速发展的背景下,这是一个亟待解决的问题。
尽管 Kappa 架构为解决这一问题提供了一种可能的解决方案,但由于其受到消息队列存储能力和数据回溯时间长度的限制,它仅适用于短期状态的场景。
Lambda 架构所引发问题的根本原因在于实时(流)和离线(批)处理是分开进行的。目前,业界普遍认为将流处理和批处理合并为一种统一的处理方式是解决问题的有效方法,即所谓的"流批一体"。因此,我们的研究目标是以尽可能低的成本找到实现流批一体的方案,以提高在实时和离线场景下特征开发的效率。
调研过程
在流批一体的研究方面,各大公司都有各自的探索方向。这些研究方向主要可以分为两类:计算统一和存储统一。计算统一旨在解决计算口径的统一问题,希望通过一套逻辑既能执行批处理又能执行流处理。而存储统一则旨在解决数据孤岛问题,防止同一份数据被分散存储在不同的存储引擎中。
计算统一方案
数据开发平台计算统一核心设计思路
上图展示了公司数据开发平台以计算统一实现流批一体的核心设计思路。该平台利用 Flink 同时支持流处理和批处理的能力,并与数梦平台的离线调度和实时运维相结合,使得一套 Flink SQL 既可以执行周期性的批处理任务,也可以持续地进行实时计算。
然而,这种方案实际上仍然依赖于流批分离的基础架构。虽然我们的流逻辑也是基于 Flink 实现的,但我们并没有使用 Flink 的内置窗口逻辑,而是实现了一个与管理系统紧密集成的更为灵活的窗口架构。此外,我们的批处理任务是基于 Spark 执行的。考虑到这种方案的修改成本较高,可能不适合解决当前风控面临的问题,因此我们最终没有选择使用这种方案。
存储统一方案
数据湖
数据湖方案
我们采集的数据会被统一存储在一个数据湖中,并以增量的形式进行存储。无论是使用 Hive、Spark 还是 Flink 进行查询,都可以根据业务需求选择一个合适的产品来进行操作,这样既可以直接查询实时数据,也可以直接查询离线数据。
然而,数据湖也有一些缺点。首先,数据的增量写入方式无法满足实时性的要求。即使是开源的实时写入方式,也只是以微批增量的形式进行,还无法完全满足实时性的要求。其次,数据湖的查询性能较低。由于整个方案本质上都是离线计算引擎,因此只能支持较低的并发,并且单次查询的响应时间较长。
对于风控实时特征来说,通常对数据的延迟要求是秒级的,而对并发 QPS 的要求则是千级的。由于数据湖的数据写入及时性和查询性能都无法满足风控实时特征场景的要求,因此我们放弃了这种方案。不过,这仍然可以作为初期的一种解决思路。
Hologres
Hologres 搭建实时数仓应用场景
Hologres 是阿里巴巴自主研发的一站式实时数仓引擎,它能够支持海量数据的实时写入、实时更新、实时加工和实时分析。此外,它还支持标准的 SQL 语言(兼容 PostgreSQL 协议和语法,支持大部分 PostgreSQL 函数),可以进行PB级数据的多维分析和即席分析,并提供高并发低延迟的在线数据服务。Hologres还支持多种负载的细粒度隔离和企业级安全能力,并与 MaxCompute、Flink、DataWorks 等产品深度融合,为企业提供了离在线一体化的全栈数仓解决方案。
在我们对 Hologres 的调研中,特别关注的是其官方定义中提到的"支持海量数据的实时写入、实时加工、实时分析,且支持高并发低延迟的在线数据服务"。我们认为 Hologres 非常适合风控业务的场景,而且已经有公司将其作为实现实时数仓和解决流批一体问题的方案。
不过 Hologres 并未开源,我们公司内部也尚未引入这项技术。因此,使用 Hologres 作为我们的解决方案的可行性较低。
StarRocks OR ClickHouse
受 Hologres 实时数仓架构的启发,结合风控的实际业务场景,我们发现我们更需要的是一个高性能的 OLAP 引擎。除了基本的运维性能外,该引擎还需要具备实时写入、实时更新、实时分析、高并发和低延迟等特性,最好是我们公司大数据生态圈内的产品。经过筛选,我们最终在 StarRocks 和 ClickHouse 之间做出选择,并在下面的表格中对它们的关键功能进行了对比。
StarRocks 是一款高性能的分析型数据仓库,它使用了向量化、MPP架构、CBO、智能物化视图和可实时更新的列式存储引擎等技术,实现了多维、实时和高并发的数据分析。StarRocks 既支持从各种实时和离线的数据源高效导入数据,也支持直接分析数据湖上各种格式的数据。StarRocks 兼容 MySQL 协议,可以使用 MySQL 客户端和常用的BI工具进行连接。同时,StarRocks 还具有水平扩展、高可用、高可靠和易运维等特性。它广泛应用于实时数仓、OLAP报表和数据湖分析等场景。
|---------|---------------------------------------------------------------------|-------------------------|
| 对比项 | StarRocks | ClickHouse |
| 学习成本 | 支持MySQL协议 | SQL满足日常使用80%以上的语法 |
| 表Join功能 | 较好(通过星型模型适应维度变更) | 较差(通过拼宽表避免聚合操作) |
| 高并发QPS | 万级 | 百级 |
| 数据变更 | 支持(更简单,支持多种模型,其中主键模型适合我们的业务场景) | 支持(提供了多个业务引擎) |
| SSB测试 | 在 SSB 平面表上执行的 13 个查询中,ClickHouse 的响应时间是 StarRocks 的 2.2 倍,多表性能表现更佳。 | / |
| 数据导入 | 支持秒级的数据导入和实时更新,提供准实时的服务能力。 | 数据导入和更新相对较慢,更适合静态数据的分析。 |
| 集群扩展 | 在线弹性扩缩容 | 需要人工参与,运维成本高 |
| 运维 | 集团支持(2022年引入,并在用力推广支持) | 集团支持 |
在上表中,我们根据风控业务场景,对 StarRocks 和 ClickHouse 的关注功能进行了对比,基于各个维度的综合考量,我们最终决定使用 StarRocks 作为我们的落地验证选项。
StarRocks 验证
为了验证 StarRocks 在实时特征方面的可行性,我们遵循最小试错成本的原则,从流程可行性、查询性能可行性和数据写入性能可行性等方面进行了验证。
在这次验证中,我们选择了具有最多实时和离线特征的授信表作为数据源,其数据量达到了亿级,大小超过了20GB。
数据导入
- 批量数据导入(11分钟)及效果
批量数据导入 StarRocks 流程
效果
- 实时数据导入(延迟1s)及效果
实时数据导入 StarRocks 流程
效果
查询效率
因为 StarRocks 支持 MySQL 协议,所以可以直接使用 MySQL 客户端进行连接查询。
下表为各个场景下客户端单查效率:
|--------|------------|
| 场景 | 耗时(ms) |
| 命中前缀索引 | 20~30左右 |
| 命中二级索引 | 70~90左右 |
| 未命中索引 | 300~400左右 |
并发性能
为尽快获得 StarRocks 的压测结果,我们利用了公司数链平台已经支持的查询 StarRocks 服务功能,从而在不开发服务端的情况下对 StarRocks 进行压测。
我们的 StarRocks 集群配置是国内测试集群(3FE+5BE),测试场景是命中前缀索引。
|--------|-----|-----|-----|------|------|
| QPS | 100 | 500 | 800 | 1100 | 1500 |
| CPU利用率 | 5% | 20% | 30% | 40% | 60% |
当压力测试达到1500 QPS 时,数链服务承受了较大的压力,因此我们不得不停止测试,未能获得二级索引和未命中索引场景的测试数据。我们统计了当月13天的实时和离线特征的最大 QPS 为1109。
通过对数据导入、查询性能和并发性能等方面的验证,我们对 StarRocks 的性能有了初步认识,并且验证结果可达到服务实时特征的标准。因此,我们最终决定使用 StarRocks 实现流批一体,以解决风控实时特征流批分离的问题。
落地实现
架构设计
基于 StarRocks 新特征架构
在本次新增的模块中,数据层被划分为两个部分:全量部分(Batch)和增量部分(Stream)。全量部分将业务的存量数据一次性导入到 StarRocks 中,而增量部分则实时地将业务的变更数据导入到 StarRocks 的同一表中。
代理层和服务层是现有技术架构中的模块。在服务层中,我们添加了支持对 StarRocks 服务查询的功能,这样就可以通过一个 SQL 逻辑来查询业务表相关的实时特征,从而达到预期的目标。这一变化对上层应用方是无感知的。
初步验证之后,我们在服务层中实现了对 StarRock s查询特征的支持,并申请了一个独立的 StarRocks 集群(包括3个前端节点和5个后端节点)。
表设计
构建镜像表
从数据源维度可将数据区分为日志类数据和业务类数据两种。
|---------------|-----------|----------|
| 特点 | 日志类数据 | 业务类数据 |
| 数据结构 | 非结构化、半结构化 | 结构化 |
| 存储方式 | 时间维度增量存储 | 业务维度全量存储 |
| update和delete | 无 | 有 |
| 产生方式 | 日志或埋点 | 业务数据库 |
StarRocks 本质上是一个结构化的数据库,其中的主键模型设计实现很适用于数据实时和频繁更新的场景,因此非常适合用作业务表的镜像表。这样一来,我们就可以在一个存储引擎上处理业务表的全量数据,实现流批一体的效果。使用镜像表的另一个优点是,业务人员提供的业务表 SQL 逻辑可以直接应用于特征开发,无需进行任何逻辑转换,从而降低了逻辑失真的风险。
然而,StarRocks 镜像表的设计方案目前只能解决以业务数据库为数据源的特征实现问题。由于日志类数据是非结构化和半结构化的,且具有时间维度增量等特性,我们尚未找到一种使用 StarRocks 实现的高效灵活的解决方案。
不过目前所有的实时和离线特征中,以业务数据为数据源的特征占比高达86%,StarRocks 镜像表方案依旧有很大的实际应用价值。
分桶字段设计
为提高查询效率,StarRocks 采用了分区、分桶、算子向量化、CBO 优化器、 MPP 架构和 Pipeline 等设计。此外,其主键模型通过 delete-and-insert 更新方式提高了更新的实时性。为了使 StarRocks 发挥更好的性能,我们针对风控特征业务场景定制设计了 StarRocks 表。
在风控特征查询场景中,大部分是高并发点查场景,特征的查询参数相对统一,通常是uid(用户ID)或bizId(订单号)等。例如,用户最后一次授信提交时间特征,是通过uid在授信业务表中查询用户对应的授信信息来获取最近一次授信时间。
一般引擎会通过建立索引来提高查询效率。传统数据库索引设计的目的是尽快定位到数据,但在大数据场景下,索引的主要目的是如何在大量数据中尽可能排除无关数据,然后在少量数据中定位到要查询的数据。
StarRocks 的分桶设计就是为实现这个目的。在表设计中,我们将 uid 或 bizId 等作为查询参数的字段进行哈希分桶,因为这些字段的基数都很大,不会出现数据倾斜现象。假设分桶数为N,当查询参数中包含分桶键字段时,每次查询可以排除掉N-1/N的数据量,从而提高查询效率。
虽然分桶可以提高查询效率,但过多的分桶会导致元数据压力较大,数据导入导出也会受到影响。我们根据官网推荐的"每个分桶的大小建议在100M-1G之间"(2.3版本)来设置分桶数,为了适应数据增长,通常会偏向下线一点。
如果将多个字段作为分桶键,每次查询必须带上所有的分桶键才能利用分桶的优势,这将降低灵活性和分桶利用率。所以,在表的分桶设计中,我们只使用一个字段进行分桶,这也更适合特征的点查场景。
服务表现
常规表现
按照已有实时+离线特征配置了同逻辑的34个 StarRocks 特征用于空跑验证。
|--------|--------|--------|------|
| 查询次数 | 99分位耗时 | 95分位耗时 | 平均耗时 |
| 779178 | 75ms | 55ms | 39ms |
压测表现
|-------|------|------|-----|------|
| 场景 | 分桶索引 | 二级索引 | 非索引 | 索引连表 |
| 最高QPS | 2300 | 18 | 10 | 1300 |
从服务端压力测试结果来看,在高并发环境下,StarRocks 在处理分桶索引和索引连接表的场景时表现良好,但在处理二级索引和非索引场景时则表现欠佳。
由于特征查询通常涉及高并发,因此在使用 StarRocks 提供特征服务时,我们主要依赖其能够高效处理分桶索引和索引连接表的能力。幸运的是,在特征业务中,一个业务表产生的特征查询参数相对统一,通常是 uid 或 bizId。这意味着每个业务表可以作为分桶键的字段是相对固定的。然而,如果确实出现了同一业务表的不同特征查询参数不一致的情况,我们可以采用"以空间换时间"的策略,即创建一个新的表,该表与原有表的结构相同,但分桶键不同。
为了确保用户仅能配置命中分桶键的特征,我们在特征管理页面上将 StarRocks 表与其分桶键进行绑定。当用户选择某个 StarRocks 表后,查询参数中的分桶键字段将成为必选项。
更新及时
制作一个特征 "select now() - max(update_time)", 通过获取当前时间和表中最大可查数据更新时间的差值来统计 StarRocks 的更新及时性。
|-------|-----------|-----------|-----------|------------|---------|
| 查询次数 | <=1s延迟占比 | <=2s延迟占比 | <=5s延迟占比 | <=10s延迟占比 | 最大延迟(s) |
| 52744 | 36.79% | 92.53% | 99.96% | 100% | 8 |
收益分析
效率提升
上述表格展示了两个真实的实时和离线需求排期耗时。使用 StarRocks 特征配置可以将效率提高80%以上。
在原有的开发模式下,实时和离线特征的离线部分通常需要等待资源排期,等待时间在2天到7天之间,因此需求的平均交付周期约为5天。而采用 StarRocks 开发,由于不再依赖离线排期,极大地缩短了开发周期。
能力提升
1、数据准确性变高
- 统一逻辑开发,不再需要实时和离线两套逻辑,数据口径统一,特征准确性提高。
2、实时特征能力增强
-
增加了对表 Join 特征的支持。
-
增加了对数据 delete 的支持。
-
支持丰富的数学函数、字符串函数、聚合函数、条件函数等可以做丰富的衍生能力,原来可能需要多个特征才能完成的需求,现在一个特征就可以了。
3、特征加工难度降低
-
StarRocks 支持 MySQL 协议,MySQL 是大家共识性比较高的语言,只要会 SQL 就可以配置特征,大大降低了特征配置的学习成本。
-
使用 StarRocks 构造的业务镜像表做数据源,降低了业务人员对数据的理解成本。
-
StarRocsk 支持即席查询,用户配置特征时,可以实时得到线上查询 SQL,并获取线上特征结果,根据实时反馈,调整特征配置,调试周期变短,增加了特征的容错性。
4、特征所需资源可控
- StarRocks 特征查询仅在进行时才消耗资源,避免了相同逻辑特征多次配置或未使用的特征配置造成的资源浪费。
未来规划
StarRocks 支持 MySQL 协议并支持即席查询,这降低了特征配置的学习成本,提高了系统的容错性。我们将鼓励业务人员自主配置和验证特征,以进一步提高工作效率,更快速地支持业务发展。
虽然 StarRocks 的特征功能已经上线,但目前我们只有一个独立的集群提供特征服务,其容灾能力还有待提高。未来,我们将增加备用集群或对集群进行分级特征管理,以提高服务的稳定性。
此外,我们使用 StarRocks 的设计主要解决了以业务表作为数据源的流批一体实现问题。然而,对于以日志或埋点作为数据源的场景,由于数据结构不稳定且数据量巨大等因素,我们尚未找到比 Lambda 架构更好的替代方案。面对这一挑战,我们将持续探索新的解决方案。