5

我目前正在开发一个服务器应用程序,如果我们同意尝试并保持一定水平的服务。我们要保证的服务级别是:如果服务器接受请求并且服务器向客户端发送确认,我们希望保证请求会发生,即使服务器崩溃。由于请求可以长时间运行并且确认时间需要很短,我们通过持久化请求来实现这一点,然后向客户端发送确认,然后执行各种操作来满足请求。随着动作的执行,它们也会被持久化,因此服务器在启动时知道请求的状态,并且还有与外部系统的各种协调机制来检查我们的日志的准确性。

这一切似乎都运行得很好,但我们很难有任何信念这样说,因为我们发现测试我们的容错代码非常困难。到目前为止,我们已经提出了两种策略,但都不是完全令人满意的:

  • 让外部进程监视服务器代码,然后尝试在外部进程认为是测试中的适当点时将其终止
  • 向应用程序添加代码,使其在某个已知的关键点崩溃

我对第一个策略的问题是外部进程无法知道应用程序的确切状态,因此我们不能确定我们是否遇到了代码中最有问题的点。我对第二种策略的问题,虽然它可以更好地控制故障是否发生,但我不喜欢在我的应用程序中注入故障的代码,即使是可选编译等。我担心过分看故障太容易了注入点并将其滑入生产环境。

4

4 回答 4

3

我认为有三种方法可以解决这个问题,如果可以的话,我可以建议对这些不同的代码进行一套全面的集成测试,使用依赖注入或工厂对象在这些集成期间产生破坏的操作。

其次,使用随机 kill -9 运行应用程序并禁用网络接口可能是测试这些东西的好方法。

我还建议测试文件系统故障。你将如何做到这一点取决于你的操作系统,在 Solaris 或 FreeBSD 上,我会在一个文件中创建一个 zfs 文件系统,然后在应用程序运行时 rm 文件。

如果您使用的是数据库代码,那么我建议您也测试数据库的失败。

依赖注入的另一种替代方法,也可能是我将使用的解决方案,是拦截器,您可以在代码中启用崩溃测试拦截器,它们会知道应用程序的状态并在正确的时间引入上面列出的故障,或者您可以使用任何其他可能要创建。它不需要更改您现有的代码,只需要一些额外的代码来包装它。

于 2010-05-03T09:26:15.030 回答
2

第一点的一个可能答案是在您的外部过程中进行多次实验,以便增加影响代码有问题部分的可能性。然后您可以分析核心转储文件以确定代码实际崩溃的位置。

另一种方法是通过存根库或内核调用来增加可观察性和/或可命令性,即,无需修改应用程序代码。

您可以在 Wikipedia 的故障注入页面上找到一些资源,特别是在软件实现的故障注入部分。

于 2010-05-03T09:36:21.637 回答
2

您对故障注入的担忧不是基本问题。您只需要一种万无一失的方法来防止此类代码最终在部署中结束。一种方法是将故障注入器设计为调试器。即错误是由您的进程外部的进程注入的。这已经提供了一定程度的隔离。此外,大多数操作系统提供某种访问控制,除非特别启用,否则会阻止调试。在最原始的形式中,它是通过将其限制为root,在其他操作系统上它需要特定的“调试权限”。自然,在生产中没有人会拥有它,因此您的故障注入器甚至无法在生产中运行。

实际上,故障注入器可以在特定地址(即函数甚至代码行)设置断点。然后,您可以对此做出反应,例如,在某个断点被击中 3 次后终止进程。

于 2010-05-03T09:52:57.527 回答
1

我正要写和贾斯汀一样的东西:)

我建议在测试期间替换的组件可能是日志记录组件(如果你有一个,如果没有,我强烈建议实现一个......)。用生成错误的代码替换它相对容易,并且记录器通常会获得足够的信息来了解当前的应用程序状态。

此外,确保测试代码不会投入生产似乎也是可行的。不过,我不鼓励条件编译,而是使用一些配置文件来选择日志记录组件。

使用“随机”杀死可能有助于检测错误,但由于其不确定性,因此不太适合系统测试。因此我不会将它用于自动测试。

于 2010-05-03T09:37:25.103 回答