更轻松地集成数据以进行风险决策

eBay 面临的一个持续性挑战是防范网络攻击,这也是所有电子商务平台面临的共同问题。这些攻击包括但不限于账户接管、串通、洗钱等。此类违规行为可能会给买家和卖家以及 eBay 公司带来经济或非物质损失。因此,二十多年来,实时数据驱动的风险控制一直是 eBay 平台的重要组成部分。

从技术角度来看,风险控制是一个综合系统,由许多组件组成,这些组件延伸并集成到几乎所有业务流程,例如商品列表、商品查看、结账和付款处理。从业务角度来看,风险控制不仅涉及构建此类功能的工程师,还涉及调查风险事件、分析风险趋势、设计风险政策以及使用基础设施部署规则和配置的分析团队。

这个基础设施的核心是我们的“决策引擎”。它就像法律体系中的法官,根据既定的规则判断某些用户行为是否有风险,然后发出“通过”或“阻止”的操作以供执行。从技术上讲,它的功能类似于 CPU 对计算机的贡献:它评估分析团队(如软件程序员)规定的风险策略规则(如 CPU 指令)并集成各种输入数据(如 i/o 读取),并执行操作(如 i/o 写入)。

图 1:高级风险决策架构

221122 VarHub 技术博客 v1 inc 1600x 图片 2

图 2:从用户角度看的计算机系统架构

因此,风险决策引擎架构(图 1)与计算机架构(图 2)类似。但主要区别在于风险数据源集成远比计算机复杂。只有少数类型的 I/O 设备(内存、SATA 设备、PCI 设备等)具有标准化的访问协议。然而,风险数据源非常庞大:有数百个具有各种数据结构和模式的数据库,以及数千个具有任意请求/响应有效负载结构的业务域服务。所有这些不同的数据(在数据字段的粒度级别)都需要与决策引擎集成并被决策引擎理解。因此,需要每个源进行集成,以确保每个数据源都能正常工作。

另一方面,数据集成对性能的要求非常严格。通常,来自上游业务应用程序的风险评估请求需要在几百毫秒内处理完成。平均而言,一个风险评估请求会触发数百条规则的执行。每条规则会通过数据集成机制从各种数据源中获取 5 到 20 个变量(决策引擎中的标准数据单位)。即使我们在多条规则中减去重复的变量,风险评估请求所需的变量总数仍可能超过 100 个。这意味着,我们需要在几百毫秒内从各种数据源完成 100 多个变量的数据获取。然而,由于线程资源、变量间依赖关系、规则执行顺序等多重限制,我们无法简单地并行一次性获取这 100 多个变量。所有这些都意味着高效、高性能的数据集成对于风险决策的成功至关重要。

为简单起见,数据集成机制早已嵌入决策引擎内部,作为一个名为规则业务对象 (RBO) 的大型 Java 包。如图 3 所示,变量作为 getter 方法封装在数百个具体的 RBO 类中。每个 RBO 类通常以专用方式与数据源集成,包含所有必要的代码和依赖包,用于初始化、网络连接管理、线程、序列化/反序列化、有效负载解析等目的。

221122 VarHub 技术博客 v1 inc 1600x 图片 3

图3 决策数据集成机制

这种直接嵌入集成模式在风险规则政策相对稳定、新变量逐渐引入的情况下,效果很好。但随着 eBay 风险政策开始加速,尤其是 eBay 托管支付推出后,需要集成的变量越来越多,时间要求也越来越严格。我们开始看到一系列重大挑战:

  • 引入新变量或数据源意味着 RBO 中的代码发生更改,因此决策引擎需要完整的开发周期,包括设计、编码、质量保证、审查、部署、监控等。这可能需要几周到几个月的时间,耗费大量的开发精力。因此,我们的风险分析团队无法及时部署新规则以尽早阻止风险活动。

  • 代码修改可能会引入 bug,代码修改引入的依赖包也可能导致冲突或其他意外问题,严重的生产问题(如内存泄漏或线程泄漏)甚至可能导致规则执行核心停止,从而导致整个决策引擎宕机,整个决策引擎变得越来越脆弱。

除了这些与生产力相关的挑战之外,治理问题也随之出现。多年来,随着成千上万个变量的集成,搜索和识别用户需要的特定变量变得非常困难。随着时间的推移,我们无法跟踪每个变量的配置文件,其中包括引入变量的原因、数据源是什么、应用了哪些清理等详细信息。重建配置文件也不容易,因为有关变量的大多数事实都嵌入到了 RBO Java 代码中,而且通常以一种难以理解的复杂方式。

重构:变量中心作为数据访问层

为了应对上述挑战,以及为了风险决策平台的长期可扩展性,我们决定对其进行重构。我们选择的方向是将数据访问/集成与决策的规则执行核心分离。图 4 说明了这个想法。

221122 VarHub 技术博客 v1 inc 1600x 图像 4

图 4 将数据访问与决策引擎分离

通过将重型数据集成部分从决策引擎中移出,并将其放置在我们称之为 Variable Hub 的专用应用程序中,我们可以解决几个挑战:

  • 引入新变量或新数据源只需要在变量中心上进行更改,而无需在决策引擎上进行更改。这可以避免决策引擎复杂且耗时的升级。变量中心仅包含与集成相关的代码,因此升级起来更轻松、更容易。这当然可以大大减少开发工作量和上市时间。本质上,我们将一体化应用程序拆分为两个具有独立维护路径的独立应用程序。

  • 新变量引入的任何潜在生产错误都只会影响变量中心,而不会传播到决策引擎。虽然这不能消除所有问题,但确实可以在发生某些系统异常时将影响降至最低。更轻量级的应用程序也意味着更低的加固和维护成本。

这是使决策生态系统更具可扩展性的良好起点。然而,重构就像从低速档换到高速档。随着我们不断添加新变量的 Java 代码,变量中心应用程序的整体复杂性仍将不断增长。迟早,我们会再次遇到同样的挑战。

为了防止我们成为这个持续陷阱的受害者,我们需要采取一种根本不同的方法。

变量积分模式

如果我们回顾计算机应用软件的历史,尤其是那些与我们的日常生活更相关的软件,我们会看到从离线软件到在线软件的重大转变。曾经是 Windows 桌面应用程序(例如个人联系人管理器或富文本文字处理器)现在可以被由 HTML 和 Javascript 技术支持的 Web 应用程序取代。毕竟,大多数应用程序不需要花哨的视觉效果或极高的性能。HTML 和 Javascript 等动态语言可以轻松完成此类任务。最重要的是,它们开发速度快、易于修改,并且无需烦人的安装或升级。

我们通过研究底层数据集成 Java 代码调查了大量现有变量。结果让我们感到高兴,超过 95% 的变量由属于一小组常见操作的逻辑组成。它们倾向于:

  • 查询基于 SQL 的数据库

  • 查询 RESTful 服务

  • 从查询结果中提取数据字段

  • 应用一些常见的格式或操作,例如日期时间转换、字符串处理等。

  • 应用一些算术运算

  • 应用条件、分支和循环操作

使用功能丰富的面向对象编程语言(如 Java)为每个变量重复编写上述简单逻辑肯定是过度的,因为此类语言需要繁重的工作流程,包括类层次结构设计、git 分支和合并、同行代码审查、严格的 CICD、打包、部署和监控等步骤。与 Web 应用程序一样,采用一些动态脚本来表示这些基本操作组合将以低成本为我们带来巨大的收益,因为我们可以省去这些步骤。

我们从这一点开始,但这将我们引向下一个问题:我们应该选择哪种脚本语言?好吧,在我们开始搜寻之前,我们必须满足一些标准,其中三个尤其重要:

  • 它必须与 JVM 兼容,因为我们的容器变量中心是一个 Java 应用程序。

  • 它必须是动态语言,意味着不需要编译。并且可以自由地热加载或卸载而不留下任何痕迹。

  • 其功能必须仅限于上述操作。用户不应编写会影响系统稳定性或性能的脚本。语言不得包含任何内存分配、线程创建、进程终止等内容。

这些标准几乎过滤掉了所有选项,只剩下少数几个候选者。最后,我们决定自己设计和实现领域特定语言 (DSL)。这给了我们充分的自由和可控性,使脚本语言变得合适。不过,DSL 是一个单独的大主题,因此我们不会在本文中讨论它的细节。

采用这种新方法,我们的架构发生了变化(图5):

221122 VarHub 技术博客 v1 inc 1600x 图像 5

图5 采用DSL实现变量逻辑

只要我们确保内部 DSL 引擎稳定,变量中心就不需要频繁升级。当然,变量逻辑脚本必须正确编写,因此在加载之前需要验证。但我们可以为用户提供单独的工具,以便在非运行时环境中进行此类验证。

性能优化

正如我们在本文开头提到的,性能至关重要。典型的风险评估可能涉及 100 多个变量,需要在几百毫秒内完成。大多数变量都会产生网络往返延迟,以便从各种数据源获取数据。根据来源的性质,这种延迟范围可以从 ~20ms 到 ~100ms。

如果变量是按顺序提取的,100 个变量乘以 20 毫秒/变量将导致规则获取所有所需数据的总延迟为 2,000 毫秒。不幸的是,这慢得令人无法接受。当然,决策引擎中存在一些(虽然不是完全)并行度,因此可以同时提取多个变量。而且有些变量共享同一个数据源,所以实际情况并没有那么糟糕。但尽管如此,最长的线程可能涉及 10 到 20 个网络提取操作,这意味着总处理时间为 200 到 400 毫秒。这勉强满足“几百毫秒”评估响应延迟的要求,我们没有太多时间用于规则执行和下游数据源处理。

挑战在于,由于位于决策引擎和数据源之间,变量中心会引入额外的网络跳数,从而产生一些额外的延迟开销。此开销将进一步放大大约 10 到 20 倍(最长线程)。因此,如果我们不能将这个开销足够小,我们将无法确保我们期望的整体延迟性能。

由于网络跳跃不可避免,我们的重点是尽量减少网络协议栈开销,尤其是应用层。RESTful API 基于 HTTP 1.x,使用纯文本进行会话建立和数据传输。有效载荷序列化和反序列化会产生额外开销。

通过 gRPC 快速连接

gRPC 是一种流行的高性能远程过程调用 (RPC) 框架,由 Google 开源。它使用 HTTP/2 作为传输协议,使用 Protobuf 作为有效负载封装格式。HTTP/2 是二进制的、完全多路复用的,并使用标头压缩。Protobuf 还使用二进制编码而不是文本编码。这些组合使 gRPC 成为面向性能的微服务间连接的绝佳框架。

这完全符合我们的需要,因为决策引擎和变量中心之间的连接类似于微服务:请求/响应对密集但很小,只包含变量名称、键和结果。

另一个优势是,许多数据中心普遍使用的硬件负载均衡器 (LB) 不支持 HTTP/2。因此,我们必须设计和实现软件负载均衡机制。但这为什么是一个优势呢?这不会给软件 LB 带来更多工作量吗?好吧,让我们先看看架构:

221122 VarHub 技术博客 v1 inc 1600x 图像 6

图 6 REST 硬件 LB 与 gRPC 软件 LB

如您所见,我们采用分布式配置注册表来实现可靠的服务发现。端点选择和切换发生在客户端。开源 gRPC 客户端保留一个内部名称解析器,可以对其进行自定义以与注册表同步。

但是 gRPC 连接是直接的,而硬件 LB 本质上是另一个网络跳跃。因此,使用 gRPC,我们可以实现更好的延迟性能。在我们的案例中,正如我们测试的那样,使用 gRPC 的数据中心内请求/响应需要 2 到 5 毫秒,而使用 REST 通过 LB 则需要 10 到 20 毫秒。

这样,总体延迟开销可以降低到只有 20 到 30 毫秒。考虑到几百毫秒的预算,开销变得可以忽略不计,从而消除了我们对延迟性能的担忧。

另一个挑战出现了:正如我们上面简要提到的,许多变量共享同一个数据源,因此在重构之前,这些数据源的响应被缓存在决策引擎中,这样只执行一个查询,以避免不必要的开销和下游负载。由于变量逻辑脚本现在位于变量中心,我们自然也希望有一个内存缓存机制,以使性能达到标准。

但是,由于变量中心已并行化以实现可扩展性,因此源共享变量可能不会定向到同一实例。让我们假设一下。变量 A 定向到变量中心实例 1,后者依次查询数据源,将响应缓存在实例 1 上,然后进行一些处理并将结果返回给决策引擎。片刻之后,共享同一数据源的变量 B 定向到实例 5(由于负载平衡)。不幸的是,实例 5 没有缓存数据源响应。这意味着我们将不得不对数据源进行另一次冗余查询。

有人可能会建议使用 Redis 等分布式缓存来解决这个问题。但不幸的是,这又意味着缓存写入/读取需要另一次网络跳跃,其开销可能会抵消我们试图节省的数据源延迟。

我们考虑的另一个想法是变量中心实例之间的缓存同步。与我们的期望相反,缓存写入也是另一个导致延迟的网络跳跃。这使得很难知道大量实例中缓存可用性的精确时间,更不用说实现的艰巨复杂性了。

基于 gRPC 的会话保持

解决此问题的最佳方法是将共享相同数据源的变量定向到同一个实例。由于变量只在同一个风险评估请求内共享某些内容,而不是跨请求共享,因此我们可以简化方法:将与同一个风险评估请求(由请求 ID 标识)关联的变量定向到同一个实例。为了实现可扩展性和容错性,来自不同风险评估请求的变量仍应定向到不同的实例。我们将这种机制称为“粘性会话”。

在 HTTP 1.x / REST 世界中,这很难实现,因为硬件 LB 负责路由,我们对此几乎没有控制权。

再一次,gRPC 拯救了我们。开源 gRPC 客户端的良好可定制性使我们有机会根据需要更换端点选择机制。图 7 说明了我们的路由算法。

221122 VarHub 技术博客 v1 inc 1600x 图像 7

图 7 粘性循环路由算法

该算法的一个优点是,它不会破坏客户端-服务器通信的无状态模式,无论它最初看起来如何。每当一个实例发生故障时,客户端都会立即感知到,并且算法将选择一个新实例,就像任何其他无状态 LB 一样。唯一的区别是新实例没有缓存数据,因此对于该特定的不幸风险评估请求,性能会略有下降。不过,这是完全可以接受的,因为任何故障转移机制都会引入一些额外的延迟。

gRPC 连接与粘性会话的结合,加上各种其他调整,解决了我们最大的性能挑战。

结论

我们遇到并解决的问题远远超出了本文的范围;毕竟,这次重构工作是风险决策机制的一次根本性的架构转变。据我们所知,尽管业内其他一些公司也面临着生产力和性能方面的挑战,但决策引擎与数据访问相结合仍然是一种常见的架构。我们发现,业内几乎没有经验可以轻易利用,我们努力构建专用的数据访问中间件,以从根本上改善这种情况。我们已经完成了上述大部分工作,目前正在运行数百个基于脚本的变量,每天处理数十亿个请求,没有出现重大问题。我们正在努力从多方面进一步改善基础设施。

希望我们在这里分享的经验能对面临类似挑战或考虑类似举措的人有所帮助。我们也欢迎对此领域感兴趣的人加入我们,加入 eBay,与我们一起发挥影响力。

1720082182
#更轻松地集成数据以进行风险决策
2023-01-31 08:00:00

Leave a Reply

Your email address will not be published. Required fields are marked *

近期新闻​

编辑精选​