确定缩放配置文件
您希望您的应用程序在不过度配置资源的情况下满足其用户体验和性能目标。
下图显示了应用程序扩展配置文件的简化表示。该应用程序维护资源的基线水平,并使用自动缩放来响应需求变化。
平衡成本和用户体验
决定是否扩展您的应用程序从根本上说是平衡成本与用户体验。确定您可接受的最低性能水平,以及可能在哪里设置上限。这些阈值因应用程序而异,也可能在单个应用程序内的不同组件或服务中有所不同。
例如,面向消费者的 Web 或移动应用程序可能具有严格的延迟目标。研究表明,即使是很小的延迟也会对用户对您的应用的看法产生负面影响,从而导致转化率降低和注册量减少。因此,确保您的应用具有足够的服务能力以快速响应用户请求非常重要。在这种情况下,运行更多 Web 服务器的更高成本可能是合理的。
对于非业务关键型内部应用程序的成本性能比可能会有所不同,因为用户可能更能容忍小的延迟。因此,您的扩展配置文件可能不那么激进。在这种情况下,保持低成本可能比优化用户体验更重要。
设置基线资源
扩展配置文件的另一个关键组成部分是确定适当的最小资源集。
Compute Engine 虚拟机或 GKE 集群通常需要时间来扩展,因为需要创建和初始化新节点。因此,即使没有流量,也可能需要维护最少的资源集。同样,基线资源的范围受应用程序类型和流量配置文件的影响。
相反,App Engine、Cloud Functions 和 Cloud Run 等无服务器技术旨在扩展至零,并且即使在冷启动的情况下也能快速启动和扩展。根据应用程序的类型和流量配置文件,这些技术可以为您的应用程序的某些部分提供效率。
配置自动缩放
自动缩放可帮助您自动缩放应用消耗的计算资源。通常,当超出某些指标或满足条件时会发生自动缩放。例如,如果对 Web 层的请求延迟开始超过某个值,您可能希望自动添加更多机器以增加服务容量。
许多 Google Cloud 计算产品都具有自动扩缩功能。Cloud Run、Cloud Functions 和 App Engine 等无服务器托管服务旨在快速扩展。这些服务通常提供配置选项来限制或影响自动缩放行为,但通常,大部分自动缩放行为对操作员是隐藏的。
Compute Engine 和 GKE 提供了更多选项来控制扩展行为。借助 Compute Engine,您可以根据各种输入进行扩展,包括 Cloud Monitoring 自定义指标和负载平衡器服务容量。您可以设置缩放行为的最小和最大限制,并且可以定义具有多个信号的自动缩放策略来处理不同的场景。与 GKE 一样,您可以配置集群自动扩缩器以根据工作负载或 pod 指标或集群外部指标添加或删除节点。
我们建议您根据关键应用指标、成本配置文件以及定义的最低所需资源级别配置自动缩放行为。
最小化启动时间
为了使扩展有效,它必须足够快地发生以处理不断增加的负载。在添加计算或服务容量时尤其如此。
使用预烘焙的镜像
如果您的应用在 Compute Engine 虚拟机上运行,您可能需要安装软件并配置实例以运行您的应用。虽然您可以使用启动脚本来配置新实例,但更有效的方法是创建自定义映像。自定义映像是您使用特定于应用程序的软件和配置设置的启动磁盘。
有关管理映像的更多信息,请参阅映像管理最佳实践文章。
创建映像后,您可以定义实例模板。实例模板结合了启动磁盘映像、机器类型和其他实例属性。然后,您可以使用实例模板创建单个 VM 实例或托管实例组。实例模板是保存 VM 实例配置的便捷方式,以便您以后可以使用它来创建相同的新 VM 实例。
虽然创建自定义映像和实例模板可以提高您的部署速度,但也可能会增加维护成本,因为映像可能需要更频繁地更新。有关更多信息,请参阅平衡映像配置和部署速度文档。
容器化您的应用
构建自定义 VM 实例的另一种方法是将您的应用程序容器化。容器是一个轻量级的、独立的、可执行的软件包,包括运行应用程序所需的一切:代码、运行时、系统工具、系统库和设置。这些特性使容器化应用程序比虚拟机更便携、更易于部署和更易于大规模维护。容器通常也可以快速启动,这使得它们适用于可扩展和有弹性的应用程序。
Google Cloud 提供了多种服务来运行您的应用容器。Cloud Run 提供了一个无服务器的托管计算平台来托管您的无状态容器。App Engine 柔性环境将您的容器托管在托管平台即服务 (PaaS) 中。GKE 提供托管 Kubernetes 环境来托管和编排您的容器化应用程序。当您需要完全控制容器环境时,您还可以在 Compute Engine 上运行应用容器。
优化您的应用程序以实现快速启动
除了确保您的基础架构和应用程序可以尽可能高效地部署之外,确保您的应用程序快速上线也很重要。
适合您的应用的优化因应用的特性和执行平台而异。执行以下操作很重要:
- 通过分析启动时调用的应用程序的关键部分来查找并消除瓶颈。
- 通过实施延迟初始化(尤其是昂贵资源)等技术来减少初始启动时间。
- 最小化可能需要在启动时加载的应用程序依赖项。
喜欢模块化架构
您可以通过选择使组件能够独立部署、管理和扩展的架构来提高应用程序的灵活性。这种模式还可以通过消除单点故障来提高弹性。
将您的应用分解为独立的服务
如果您将应用程序设计为一组松散耦合的独立服务,则可以提高应用程序的灵活性。如果你采用松耦合的设计,它可以让你的服务独立发布和部署。除了许多其他好处之外,这种方法还使这些服务能够使用不同的技术堆栈并由不同的团队管理。这种松散耦合的方法是微服务和 SOA 等架构模式的关键主题。
当您考虑如何围绕服务划定界限时,可用性和可扩展性要求是关键维度。例如,如果给定组件的可用性要求或扩展配置文件与您的其他组件不同,则它可能是独立服务的良好候选者。
有关更多信息,请参阅将单体应用程序迁移到微服务。
以无状态为目标
无状态应用程序或服务不保留任何本地持久数据或状态。无状态模型确保您可以独立于先前的请求处理每个请求或与服务的交互。该模型促进了可扩展性和可恢复性,因为这意味着服务可以增长、缩小或重新启动,而不会丢失处理任何正在进行的进程或请求所需的数据。当您使用自动扩缩器时,无状态尤其重要,因为托管服务的实例、节点或 Pod 可能会被意外创建和销毁。
您的所有服务可能都不可能是无状态的。在这种情况下,需要明确说明需要状态的服务。通过确保无状态服务和有状态服务的清晰分离,您可以确保无状态服务的轻松可扩展性,同时为有状态服务采用更深思熟虑的方法。
管理服务之间的通信
分布式微服务架构的一个挑战是管理服务之间的通信。随着服务网络的增长,服务的相互依赖性也可能会增长。您不希望一个服务的故障导致其他服务的故障,有时称为级联故障。
您可以通过采用断路器模式、指数退避和优雅降级等技术来帮助减少过载服务或故障服务的流量。这些模式通过给过载的服务一个恢复的机会,或者通过优雅地处理错误状态来增加你的应用程序的弹性。有关更多信息,请参阅 Google SRE 书中的解决级联故障章节。
使用服务网格可以帮助您管理分布式服务的流量。服务网格是将服务链接在一起的软件,有助于将业务逻辑与网络分离。服务网格通常提供弹性功能,例如请求重试、故障转移和断路器。
使用适当的数据库和存储技术
某些数据库和存储类型难以扩展并具有弹性。确保您的数据库选择不会限制您的应用程序的可用性和可扩展性。
评估您的数据库需求
将您的应用程序设计为一组独立服务的模式也扩展到您的数据库和存储。为应用程序的不同部分选择不同类型的存储可能是合适的,这会导致异构存储。
传统应用程序通常专门使用关系数据库运行。关系数据库提供有用的功能,例如事务、强一致性、参照完整性和跨表的复杂查询。这些功能使关系数据库成为许多常见应用程序功能的不错选择。但是,关系数据库也有一些限制。它们通常难以扩展,并且需要在高可用性配置中进行仔细管理。关系数据库可能不是满足所有数据库需求的最佳选择。
非关系型数据库,通常称为 NoSQL 数据库,采用不同的方法。尽管细节因产品而异,但 NoSQL 数据库通常会牺牲关系数据库的某些功能,以提高可用性和更容易的可扩展性。根据 CAP 定理,NoSQL 数据库通常选择可用性而不是一致性。
NoSQL 数据库是否合适通常归结为所需的一致性程度。如果您的特定服务的数据模型不需要 RDBMS 的所有功能,并且可以设计为最终一致,那么选择 NoSQL 数据库可能会提供更高的可用性和可扩展性。
除了一系列关系数据库和 NoSQL 数据库之外,Google Cloud 还提供 Cloud Spanner,这是一个高度一致、高度可用且全球分布式的数据库,支持 SQL。有关在 GCP 上选择适当数据库的信息,请参阅 GCP 数据库。
实现缓存
缓存的主要目的是通过减少访问底层较慢存储层的需要来提高数据检索性能。
缓存通过减少对基于磁盘的存储的依赖来支持改进的可扩展性。由于可以从内存中处理请求,因此减少了到存储层的请求延迟,通常允许您的服务处理更多请求。此外,缓存可以减少应用程序下游服务(尤其是数据库)的负载,从而允许与该下游服务交互的其他组件也可以更轻松地扩展或完全扩展。
缓存还可以通过支持优雅降级等技术来提高弹性。如果底层存储层过载或不可用,缓存可以继续处理请求。即使从缓存返回的数据可能不完整或不是最新的,这在某些情况下也是可以接受的。
Memorystore for Redis 提供由 Redis 内存数据存储提供支持的完全托管服务。Memorystore for Redis 为频繁访问的数据提供低延迟访问和高吞吐量。它可以部署在提供跨区域复制和自动故障转移的高可用性配置中。
现代化您的开发流程和文化
DevOps 可以被视为广泛的流程、文化和工具集合,通过打破开发、运营和相关团队之间的孤岛,提高应用程序和功能的敏捷性并缩短上市时间。DevOps 技术旨在提高软件的质量和可靠性。
DevOps 的详细讨论超出了本文的范围,但与提高应用程序的可靠性和弹性相关的一些关键方面将在以下部分中讨论。有关更多详细信息,请参阅 Google Cloud DevOps 页面。
可测试性设计
自动化测试是现代软件交付实践的关键组成部分。执行一组全面的单元、集成和系统测试的能力对于验证您的应用程序是否按预期运行以及是否可以进入部署周期的下一阶段至关重要。可测试性是您的应用程序的关键设计标准。
我们建议您在大部分测试中使用单元测试,因为它们执行速度快且通常易于维护。我们还建议您自动化更高级别的集成和系统测试。如果您采用基础架构即代码技术,这些测试将大大简化,因为可以按需创建专用的测试环境和资源,然后在测试完成后将其拆除。
随着测试覆盖的代码库百分比的增加,您可以减少不确定性以及每次代码更改可能导致的可靠性下降。足够的测试覆盖率意味着您可以在可靠性低于可接受的水平之前进行更多更改。
自动化测试是持续集成的一个组成部分。对每个代码提交执行一组强大的自动化测试可以提供有关更改的快速反馈,从而提高软件的质量和可靠性。谷歌云原生工具(如 Cloud Build)和第三方工具(如 Jenkins)可以帮助您实施持续集成。
自动化您的部署
持续集成和全面的测试自动化让您对软件的稳定性充满信心。当它们到位时,您的下一步就是自动部署您的应用程序。部署自动化的级别取决于组织的成熟度。
选择适当的部署策略对于最大程度地降低与部署新软件相关的风险至关重要。通过正确的策略,您可以逐渐增加新版本向更多受众的曝光,并在此过程中验证行为。如果出现问题,您还可以为回滚设置明确的规定。
有关自动化部署的示例,请参阅使用 Spinnaker 在 GKE 上自动化 Canary 分析。
采用 SRE 实践来处理失败
对于大规模运行的分布式应用程序,一个或多个组件出现某种程度的故障是很常见的。如果您采用本文档中介绍的模式,您的应用程序可以更好地处理由有缺陷的软件版本、虚拟机意外终止甚至影响整个区域的基础架构中断造成的中断。
但是,即使经过精心设计的应用程序,您也不可避免地会遇到需要人工干预的意外事件。如果您采用结构化流程来管理这些事件,您可以大大减少它们的影响并更快地解决它们。此外,如果您检查事件的原因和响应,您可以帮助保护您的应用免受未来类似事件的影响。
管理事件和执行无可指责的事后分析的强大流程是 SRE 的关键原则。尽管实施 Google SRE 的完整实践对您的组织来说可能不切实际,但如果您采用最起码的指导方针,您就可以提高应用的弹性。SRE 书中的附录包含一些可以帮助您塑造流程的模板。
验证和审查您的架构
随着您的应用程序的发展,用户行为、流量配置文件甚至业务优先级都会发生变化。同样,您的应用程序所依赖的其他服务或基础设施也可以发展。因此,定期测试和验证应用程序的弹性和可扩展性非常重要。
测试你的应变能力
测试您的应用程序是否以您期望的方式响应故障至关重要。最重要的主题是避免失败的最好方法是引入失败并从中吸取教训。
模拟和引入故障很复杂。除了验证您的应用程序或服务的行为之外,您还必须确保生成预期的警报,并生成适当的指标。我们建议采用结构化方法,在这种方法中引入简单的故障,然后逐步升级。
例如,您可能会进行如下操作,在每个阶段验证和记录行为:
- 引入间歇性故障。
- 阻止访问服务的依赖项。
- 阻止所有网络通信。
- 终止主机。
有关详细信息,请参阅 Google Cloud Next 2019 中的破解您的系统以使其牢不可破的视频。
如果您使用像 Istio 这样的服务网格来管理您的应用程序服务,您可以在应用程序层注入故障而不是杀死 pod 或机器,或者您可以在 TCP 层注入损坏的数据包。您可以引入延迟来模拟网络延迟或过载的上游系统。您还可以引入中止,它模仿上游系统中的故障。
测试你的缩放行为
我们建议您使用自动化的非功能测试来验证您的应用程序是否按预期扩展。这种验证通常与性能或负载测试相结合。您可以使用 hey 等简单工具将负载发送到 Web 应用程序。有关显示如何针对 REST 端点进行负载测试的更详细示例,请参阅使用 Google Kubernetes Engine 进行分布式负载测试。
一种常见的方法是确保关键指标保持在不同负载的预期水平内。例如,如果您正在测试 Web 层的可伸缩性,您可能会针对大量用户请求测量平均请求延迟。同样,对于后端处理功能,您可以测量任务量突然增加时的平均任务处理时间。
此外,您希望您的测试能够衡量为处理测试负载而创建的资源数量是否在预期范围内。例如,您的测试可能会验证为处理某些后端任务而创建的 VM 数量不超过某个值。
测试边缘情况也很重要。当达到最大扩展限制时,您的应用或服务的行为是什么?如果您的服务正在缩小然后负载突然再次增加,会发生什么行为?有关这些主题的讨论,请参阅旺季生产准备的负载测试部分。
永远做架构
技术世界发展迅速,云计算尤其如此。新产品和功能频繁发布,新模式出现,用户和内部利益相关者的需求不断增长。
正如云原生架构博客文章所定义的原则,始终在寻找改进、简化和改进应用程序架构的方法。软件系统是有生命的东西,需要适应以反映您不断变化的优先事项。