在生产中组织安全测试。 第二部分



在本文的这一部分,我们将继续考虑生产中的各种类型的测试。 那些跳过第一部分的人可以在这里阅读。 对于其余的-欢迎猫。

生产测试:发布


部署后测试服务后,必须准备发布
重要的是要注意,在此阶段,只有在可持续失败的情况下才可以回滚更改,例如:

  • 服务故障循环;
  • 超过上游上游大量连接的等待时间,导致错误发生率大幅增加;
  • 无法接受的配置更改,例如,环境变量中缺少导致服务失败的秘密密钥(通常最好避免使用环境变量,但这是另一个讨论的主题)。

部署阶段进行全面的测试可以使我理想地最小化或完全避免在发布阶段出现令人不快的意外情况。 但是,对于安全发布新代码,有许多建议。

金丝雀部署


金丝雀部署是生产中服务的部分发布 。 随着基本健康检查的通过,当前生产环境中的一小部分流量将发送到已下达的部分。 在处理流量时会监视服务各部分的结果,将指标与参考指标(与金丝雀无关)进行比较,如果指标超出可接受的阈值,则会执行回滚到先前状态的操作。 尽管在发布服务器软件时通常使用这种方法,但是客户端软件的Canary测试也变得越来越普遍。

各种因素影响将用于金丝雀部署的流量。 在许多公司中,服务的发布部分首先仅接收内部用户流量(所谓的“狗食”)。 如果未观察到错误,那么将添加一小部分生产环境流量,然后执行完整部署。 如果金丝雀部署结果无效, 建议您回滚到以前的状态,并且Spinnaker之类的工具内置了对自动分析和回滚功能的支持。

金丝雀测试存在一些问题, 本文对它们进行了较为完整的概述。

监控方式


在生产中产品部署的每个阶段,监视都是绝对必要的过程,但是此功能在发布阶段尤其重要。 监视非常适合于获取有关系统性能的一般级别的信息。 但是监视世界上的所有内容可能不是最佳解决方案。 逐点执行有效的监视,这使您可以识别系统可持续失败的一小部分模式或一组基本指标。 此类故障模式的示例可以是:

  • 错误率增加;
  • 在特定端点上整个服务中处理请求的整体速度降低,或者甚至更糟的是,完全停止工作;
  • 延迟增加。

观察到任何这些可持续失败模式都是立即回滚到以前的状态或回滚新发布的软件的基础。 重要的是要记住,此阶段的监视不太可能是完整的和指示性的。 许多人认为,监视期间监视的理想信号数量是3到5,但绝对不超过7-10。 Kraken Facebook白皮书提供以下解决方案:

“借助易于配置的监视组件可以解决该问题,该监视组件具有两个基本指标(Web服务器响应时间的第99个百分位和致命HTTP错误的发生频率),这些指标客观地描述了用户交互的质量。”

最好在系统设计期间确定在发布阶段监视的系统和应用程序指示符集。

异常追踪


我们正在谈论在发布阶段跟踪异常,尽管似乎在部署阶段和发布之后这同样有用。 异常跟踪工具通常不能保证与某些其他系统监视工具相同的完整性,准确性和覆盖范围,但是它们仍然非常有用。

开源工具(例如Sentry )显示有关传入请求的高级信息,并创建跟踪数据和局部变量的堆栈,这大大简化了调试过程,通常包括查看事件日志。 在对不需要完全回滚到先前状态的问题进行排序和优先级排序时(例如,引发异常的临界情况),异常跟踪也很有用。

流量整形


调整流量(流量重新分配)不是一种独立的测试形式,而是一种支持金丝雀方法和分阶段发布新代码的工具。 实际上,通过更新负载平衡器配置可以确保流量整形,这使您可以逐渐将更多流量重定向到新发布的版本。

此方法对于新软件的分阶段部署(与常规部署分开)也很有用。 考虑一个例子。 Imgix需要在2016年6月部署一个全新的基础架构。 在对具有一定数量暗流量的新基础架构进行首次测试之后,他们开始在生产中进行部署,最初将大约1%的生产环境流量重定向到新堆栈。 然后,经过几周的时间,到达新堆栈的数据量增加了(解决了整个过程中的问题),直到开始处理100%的流量为止。

服务网格体系结构的普及引发了对代理服务器的新兴趣。 结果,旧的代理(nginx,HAProxy)和新的代理(Envoy,Conduit)都增加了对新功能的支持,以试图超越竞争对手。 在我看来,在产品发布阶段自动执行从0到100%的流量重新分配的未来即将来临。

生产测试:发布后


发布后测试是在成功发布代码之后执行的检查。 在此阶段,您可以确保代码整体正确,已在生产中成功发布并正确处理了流量。 部署的代码可直接或间接用于实际环境中,以服务实际客户或执行对业务有重大影响的任务。

在此阶段进行任何测试的目的主要是在考虑各种可能的负载和流量模式的情况下验证系统的可操作性。 做到这一点的最佳方法是收集生产中发生的一切情况的书面证据,并将其用于调试和获得系统的完整图片。

功能标记或暗启动


我发现的有关成功使用功能标志的最古老的出版物大约是十年前出版的。 Featureflags.io提供了最全面的指导。

“功能标记是开发人员使用if-then语句标记新功能的一种方法,它可以更好地控制其发布。 通过标记功能并以这种方式隔离功能,开发人员可以启用或禁用此功能,而与部署状态无关。 这有效地将功能的发布与代码的部署分开。”

通过标记新代码,您可以根据需要测试其性能和生产性能。 特征标记是生产中普遍接受的测试类型之一,众所周知,并且经常在各种来源中进行 描述 。 可以在测试用于个人系统的数据库或软件的传输过程中使用此方法的事实鲜为人知。

文章作者很少写的是开发和使用功能标志的最佳方法。 不受控制地使用标志可能是一个严重的问题。 缺乏在指定时期后删除未使用的标志方面的纪律性有时会导致您必须进行全面审核并删除工作数月(如果不是数年)累积的过时标志。

A / B测试


A / B测试通常是作为实验分析的一部分进行的,不被视为生产中的测试。 因此,A / B考试不仅被广泛使用(有时甚至是一种可疑的方式),而且还得到了积极的 研究描述 (包括有关确定在线实验有效记分卡的文章)。 通常,A / B测试用于测试各种硬件配置或虚拟机。 它们通常被称为“调优”(例如,JVM调优),但是没有被归类为典型的A / B测试(尽管在测量方面,调优可以视为以相同的严格程度执行的A / B测试类型) 。

日志,事件,指标和跟踪


可以在此处阅读有关所谓的“三可观鲸”的日志,指标和分布式跟踪。

剖析


在某些情况下,要诊断性能问题,必须在生产中使用应用程序性能分析。 根据支持的语言和运行时,分析可能是一个相当简单的过程,其中只涉及向应用程序添加一行代码(对于Go, import _ "net/http/pprof" )。 另一方面,它可能需要使用许多工具或通过黑盒方法测试过程,并使用诸如火焰图的工具检查结果。

三通测试


许多人认为这样的测试就像是数据的影子重复一样,因为在两种情况下,生产环境流量都被发送到非生产集群或流程。 在我看来,区别在于将流量用于测试目的与将流量用于调试目的有些不同。

Etsy在其博客上写道,使用tee-tests作为验证工具(此示例确实类似于数据的影子重复)。
“这里tee可以理解为命令行上的tee命令。 我们基于现有的F5负载均衡器编写了一个iRule规则,以克隆定向到其中一个池的HTTP通信并将其重定向到另一个池。 因此,我们能够使用定向到我们的API群集的生产环境流量,并将其副本发送到实验性HHVM群集以及隔离的PHP群集进行比较。
事实证明,该技术非常有效。 他允许我们使用相同的流量配置文件比较两种配置的性能。”

但是,有时需要基于自治系统中生产环境流量的三通测试来进行调试 。 在这种情况下,可以更改自治系统以配置其他诊断信息的输出或其他编译过程(例如,使用流清洗工具),从而极大地简化了故障排除过程。 在这种情况下,应考虑使用tee测试,而不是调试工具 ,而不是验证

以前,此类调试类型在imgix中相对较少,但仍然使用,尤其是在调试对延迟敏感的应用程序时。

例如,以下是对2015年发生的这些事件之一的分析描述。 错误400很少发生,以至于在重现该问题时几乎看不到。 在十亿分之几的情况下,她只出现了几次。 白天他们很少。 结果,发现根本不可能可靠地重现该问题,因此有必要使用工作流量进行调试,以便有机会跟踪此错误的发生。 这是我的前同事对此写的:

“我选择了应该是内部的库,但最终我不得不根据系统提供的库创建自己的库。 在系统提供的版本中,定期发生的错误在流量很小的情况下没有出现。 但是,标题中的截短名称是真正的问题。

在接下来的两天中,我详细研究了与虚假错误400的增加频率相关的问题。该错误在很少的请求中得到体现,并且这种类型的问题很难诊断。 所有这些似乎都像大海捞针一样臭名昭著:每十亿分之一就遇到了这个问题。

定位错误源的第一步是获取导致错误响应的所有原始HTTP请求数据。 为了在连接到套接字时执行传入流量的发球测试,我将Unix域套接字端点添加到了渲染服务器。 这样做的目的是使我们能够快速轻松地打开和关闭暗流量,并直接在开发人员的计算机上进行测试。 为避免生产中出现问题,如果存在背压问题,则必须断开连接。 如果重复项无法处理任务,则将其断开连接。 在开发过程中的某些情况下,此套接字非常有用。 但是,这次,我们使用它来收集选定服务器上的传入流量,希望获得足够的请求以揭示导致出现错误错误400的模式。使用dsh和netcat,我能够相对容易地将传入流量输出到本地文件。

大多数环境都花在收集这些数据上。 一旦有了足够的数据,我就可以使用netcat在本地系统上播放它,其配置已更改为显示大量调试信息。 一切顺利。 下一步是以最快的速度播放数据。 在这种情况下,带有条件检查的循环一次发送一次原始请求。 大约两个小时后,我设法达到了预期的效果。 日志中的数据显示缺少标题!

我用红黑木来传达标题。 这种结构将可比性视为身份,当对密钥有特殊要求时,它本身非常有用:在我们的情况下,HTTP标头不区分大小写。 最初,我们认为问题出在所使用的库的叶节点中。 添加顺序确实会影响基础树的构建顺序,而平衡红黑树是一个相当复杂的过程。 尽管这种情况不太可能发生,但并非不可能。 我切换到另一个红檀木实现。 它是在几年前修复的,所以我决定将其直接嵌入源代码中,以获取所需的确切版本。 但是,程序集选择了不同的版本,并且由于我指望使用的是新版本,所以最终我得到了错误的行为。

因此,可视化系统产生了500个错误,导致循环中断。 这就是为什么错误只会随着时间而发生。 对多个程序集进行循环处理后,来自它们的流量将重定向到其他路由,这增加了此服务器上问题的严重性。 我认为问题出在库中的假设被证明是错误的,并且反向开关解决了500个错误。

我又返回了400个错误:错误仍然存​​在,大约需要两个小时才能发现。 显然,更改库并不能解决问题,但是我确定所选的库足够可靠。 没有意识到选择的谬误,我没有做任何改变。 更详细地研究了这种情况后,我意识到正确的值存储在单个字符的标头中(例如,“ h:12345”)。 终于让我意识到h是Content-Length标头的结尾字符。 再次查看数据,我意识到Content-Length标头为空。

结果,整个问题就是读取标头时出现了一个偏差。 nginx / joyent HTTP分析器创建部分数据,每当部分标头字段比所需的时间短一个字符时,我发送的标头没有值,随后接收到一个包含正确值的单字符标头字段。 这是一种相当罕见的组合,因此其操作需要很长时间。 因此,每次出现一个字符的标头时,我都会增加数据收集的数量,应用建议的修复程序并成功运行脚本几个小时。
当然,可以检测到所提到的库故障的其他陷阱,但两个错误均已修复。”


涉及延迟敏感应用程序开发的工程师需要具有使用捕获的动态流量进行调试的能力,因为经常会发生无法在单元测试期间重现或无法使用监视工具检测到的错误(尤其是在日志记录严重延迟的情况下)。

混沌工程方法


混沌工程是一种基于分布式系统上的实验的方法,目的是确定其承受生产环境混乱条件的能力。

最初由Netflix的Chaos Monkey闻名的Chaos Engineering方法现已成为独立学科。 术语“混沌工程”是最近才出现的,但是故障测试是一种长期的实践。

术语“混沌测试”是指以下技术:

  • 禁用任意节点以确定系统对故障的抵抗力;
  • 引入错误(例如,增加延迟)以确认系统正确处理了这些错误;
  • 为了确定服务响应而强行违反网络。

大多数公司使用不够复杂和分层的操作环境来有效地进行混沌测试。 必须强调的是,在设置容错的基本功能之后,最好在系统中引入故障。 Gremlin 白皮书对混沌测试原理进行了相当全面的描述,并提供了准备该过程的说明。

“特别重要的是,混沌工程被认为是一门科学学科。 在该学科内,应用了高精度工程流程。
Chaos Engineering的任务是通过在系统上进行实验来告诉用户有关系统漏洞的新知识。 即使在造成严重故障之前,也必须找出生产中可能出现的所有隐藏问题。 只有这样,您才能有效消除系统中的所有弱点,并使其真正具有容错能力。”

结论


在生产中进行测试的目的不是要完全消除系统中所有可能的故障。 约翰·奥尔斯帕John Allspaw)说:
我们看到系统变得越来越容错-很棒。 但是我们必须承认:“越来越多”不等于“绝对”。 在任何复杂的系统中,故障都可能以最不可预测的方式发生(并将发生)。”

乍一看,在生产中进行测试似乎是一项相当复杂的任务,远远超出了大多数工程公司的能力。 而且,尽管这样的测试并非易事,并且伴随着一定的风险,但是如果您遵循所有规则,它将有助于实现当今无处不在的复杂分布式系统的可靠性。

Source: https://habr.com/ru/post/zh-CN418329/


All Articles