ebay官网,ebay官网app下载

TIKTOK资讯 2年前 (2022) code
32 0

eBay 的通知平台团队通过在应用程序级别注入故障来构建容错、有弹性的系统。

ebay官网,ebay官网app下载

背景

故意破坏我们试图修复的东西可能听起来很矛盾,但有时,这是最有效的方法。故障注入是我们故意将故障引入系统的过程。我们可以通过注入的故障观察系统行为,以确定系统的弱点。在行业内,故障注入是构建容错、弹性系统的一种常见做法。

eBay通知平台团队从不同的角度在eBay的通知平台上实践了故障注入的思想。该平台负责向第三方应用推送平台通知,提供商品价格、商品库存状态、支付状态等最新变化。它是一个高度分布式的大型系统,依赖于许多外部依赖项,包括分布式存储、消息队列、推送通知端点等。这些依赖服务中的任何故障都会直接影响系统的稳定性,因此在包含这些依赖项故障的系统中进行实验以了解行为并减轻任何弱点是非常有价值的。

为实现这一点,故障通过代码检测在应用程序级别进行模拟注入。据我们所知,我们是业界第一个正式和广泛实践这个想法的人,在具有各种故意设计的故障的关键任务系统上进行实验。

应用程序级别与基础架构级别

没有统一的方法来注入这些故障。业内最直接、最普遍的方法是直接制造真正的故障。比如引入http断开连接或超时错误,一种选择是关闭网络或暂时关闭下游服务;要引入磁盘已满错误,一种选择是在文件系统中创建一堆文件。我们可以把这看作是基础设施层面的故障注入,如果从这个角度来思考,必然会驱使我们为基础设施资源制造具体的故障。制造故障将直接损害基础设施资源;在前面的示例中,关闭网络显然会导致很多问题。如果共享资源,这将给依赖它的其他服务带来额外的影响和风险。如果资源是专用的,则会增加成本。

但是有一种不同的方法来解决这个问题:如果我们在应用程序级别创建故障,而不是在基础架构级别创建故障怎么办?这将使我们能够模拟我们希望与应用程序 API 一起使用的故障,以与基础设施资源进行对话。比如注入http超时故障,我们在http客户端库中加入latency;为了模拟内部服务错误,我们用 500 http状态码模拟响应码。故障仅限于 API 级别,不会损害底层基础设施资源。通过这种方式,我们找到了一种经济实惠、安全且可重用的故障注入方式。

由于我们的服务是基于 Java 的应用程序,因此我们提供了 Java 代理。在其中,我们检测了依赖服务的客户端库的类文件,以引入我们定义的不同类型的故障。当我们的服务通过检测 API 与底层资源通信时,会引发引入的错误。由于更改了代码,故障并没有真正发生在我们的依赖服务中,但效果是模拟的,使我们能够在没有风险的情况下进行实验。

ebay官网,ebay官网app下载

仪器仪表

通过检测来模拟客户端库的故障具有挑战性。我们的主要任务是强制调用的方法经历失败。一种方法是将失败直接注入方法,例如,在方法主体中抛出异常。另一种方法调用改变输入参数的值或状态来驱动方法进入失败执行路径。我们的项目中存在三种检测模式。

1.阻塞或中断方法逻辑

这种类型的检测很简单,因为 API 可以抛出异常或休眠一段时间以模拟错误或超时。

ebay官网,ebay官网app下载

2.改变方法参数的状态

在某些情况下,故障的模拟将取决于输入参数的具体状态。例如,下面的方法逻辑取决于response.getStatusCode()的返回值。如果该值不等于 200,将触发失败逻辑。因此,如果我们想用故障代码模拟故障,那么我们需要找到一种方法来更改将从response.getStatusCode()返回的响应状态。

我们实现这一点的方法是添加检测代码片段以抛出特定定义的异常,并让异常携带我们需要模拟的响应代码。同时,我们通过在方法中添加 try-catch 块来检测该方法,以专门捕获我们抛出的异常并返回 catch 块中的代码。通过这样做,我们改变了方法执行路径以返回指定的值。

ebay官网,ebay官网app下载

3.替换方法参数的值

与上面的示例相反,有时方法逻辑将取决于参数的值。所以如果你想模拟一个故障,那么你需要改变输入参数的值。要更改参数的值,我们需要先知道参数的名称,然后注入代码以用参数的名称替换参数的值。这并不容易,因为参数名称只能在运行时知道。所以我们利用 Java 反射来获取运行时参数的名称。

ebay官网,ebay官网app下载

为了实现上述三种类型的检测,我们创建了一个 Java 代理。在代理中,我们实现了一个类加载器,它将检测应用程序代码中利用的方法的代码。我们还创建了一个注释来指示将检测哪个方法,并将检测逻辑放在注释的方法中。这是一个例子:

ebay官网,ebay官网app下载

在上面的代码片段中,我们想为org.asynchttpclient.providers.netty.future.NettyResponseFuture.done()提供检测逻辑. 所以我们要做的是创建一个具有相同签名的新方法,并使其被@Enforce注解,这是用户定义的Java注解,用于指示故障注入的检测逻辑。注释有两个字段:值和类型。值字段是我们要检测的方法的类名。(我们稍后会讨论类型字段。)当加载代理时,定义的类加载器将找到所有被@Enforce 注释的方法,并将方法中定义的检测逻辑注入到要检测的方法中。@Enforce 的 type 字段有两个值 runtime(default value) 和 static。在上面的示例中,我们使用 Java 代码实现了检测逻辑。但是我们仍然有可能需要为检测逻辑提供字符串文字。这是一个例子:

ebay官网,ebay官网app下载

自定义类加载器

现在我们已经在 J?ava 代理中实现了检测逻辑。然而,我们仍然需要创建一个自定义的类加载器,以将检测逻辑注入到我们想要注入故障的客户端库的目标方法中。类加载器利用工具库 Javassist,它可以操纵 Java 字节码来转换目标方法的类文件以包含定义的错误。

ebay官网,ebay官网app下载

通过上面描述的实现,我们已经通过检测为我们所依赖的三个资源的以下客户端库注入了故障。

  • 推送通知端点:
    • 客户端库:async-http-client 1.8.3
    • 故障类型:
      • 暂停
      • 例外
      • 响应状态码
  • 消息队列:
    • 客户端库:kafka-client 2.5.1
    • 故障类型:
      • 暂停
      • 例外
  • 分布式商店(由 eBay 内部构建):
    • 客户端库:monster-java-client 3.4.4.2-RELEASE
    • 故障类型:
      • 暂停
      • 例外

配置管理

为了在运行时动态更改故障注入的配置,我们在 Java 代理中实现了一个配置管理控制台。由于我们的服务是一个 Web 应用程序,我们可以检测javax.servlet.http.HttpServlet.service(HttpServletRequest, HttpServletResponse)来公开配置管理的端点。端点会渲染一个配置页面,让开发者在运行时配置故障注入的属性。例如,开发人员可以全局启用或禁用故障注入和故障的其他子类型;例如,AyncHttpClient的超时。

ebay官网,ebay官网app下载

下一步是什么

我们将在更多的客户端库和故障类别中扩展应用级故障注入的范围,以丰富我们服务在不同故障情况下的实验场景。同时,由于通过配置管理控制台配置故障设置只能在实例级别触发,我们将找到一种方法将更改广播到整个集群。

作者:Wei Chen

出处:https://tech.ebayinc.com/engineering/how-ebays-notification-platform-used-fault-injection-in-new-ways/

相关文章