你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn

性能效率清单

性能效率是指你的工作负荷能够以有效的方式进行缩放以满足用户对其的需求,并且是Microsoft Azure Well-Architected 框架的一个支柱。 使用此清单可查看应用程序体系结构的性能效率。

应用程序设计

对工作负荷进行分区。 将流程的各部分设计为相互独立且可以分解。 最大程度地缩小各部分的大小,同时应遵循进行问题隔离所需的常用规则,以及单独责任原则。 这样可以让组件的各部分采用适当的方式进行分布,从而最大程度地利用每个计算单元(例如角色或数据库服务器)。 此外,可以更方便地缩放应用程序(只需添加特定资源的更多实例即可)。 对于复杂的域,请考虑采用微服务体系结构

针对缩放进行设计。 缩放可以让应用程序应对不同的负载,只需增加和减小角色、队列和所使用的其他服务的实例数目即可。 但是,应用程序在设计时必须充分考虑这一点。 例如,应用程序及其使用的服务必须是无状态的,这样才能将请求路由到任何实例。 这也会阻止添加或删除特定实例,从而对当前用户造成不利影响。 还应该在添加和删除实例时实现实例的配置或自动检测,以便应用程序中的代码可以执行所需的路由。 例如,Web 应用程序可能会通过轮循方法使用一组队列来路由请求,将请求路由到通过辅助角色运行的后台服务。 若要成功地路由请求并对应用程序上的负载进行平衡,该 Web 应用程序必须能够检测到队列数目的变化。

按单元进行缩放。 为了应对业务增长情况,需要按计划添加更多资源。 对于每个资源,应该知道缩放上限,并使用分片或分解方式来应对这些限制。 按照定义好的资源集来确定系统的缩放单元。 这会使横向扩展操作更加容易,不容易对应用程序造成不利影响(整个系统的某些部分缺乏资源时,会对应用程序施加限制)。 例如,添加 x 个 Web 和辅助角色可能需要使用 y 个额外的队列和 z 个存储帐户来处理这些角色所造成的额外工作负荷。 因此缩放单元可能包含 x 个 Web 和辅助角色、y 个队列和 z 个存储帐户。 设计应用程序时,应确保其能够轻松地通过添加一个或多个缩放单元来进行缩放。 请考虑使用 部署戳记模式 来部署缩放单位。

避免客户端关联。 在可能的情况下,应确保应用程序不需要关联。 因此,请求能够路由到任何实例,与实例的数目无关。 这样还可以避免为每个用户存储、检索和维护状态信息的开销。

充分利用平台自动缩放功能。 在托管平台支持自动缩放功能(例如 Azure 自动缩放)的情况下,应尽量使用该功能而不使用自定义机制或第三方机制,除非内在机制无法满足要求。 尽可能使用计划的缩放规则,确保资源在开始使用时没有延迟,但应根据需要向规则中添加反应性的自动缩放,以应对需求方面的意外变化。 可以在经典部署模型中使用自动缩放操作来调整自动缩放,并向规则中添加自定义计数器。 有关详细信息,请参阅 Auto-scaling guidance(自动缩放指南)。

将占用大量CPU 和 i/o 的任务作为后台任务卸载。 如果某项服务请求预计需要较长时间才能运行完毕或需要使用大量的资源,则应将该请求的处理操作卸载到单独的任务中。 使用辅助角色或后台作业(具体取决于托管平台)来执行这些任务。 此策略使服务能够继续接收更多的请求并保持响应状态。 有关详细信息,请参阅后台作业指南

分发后台任务的工作负荷。 存在许多后台任务时,或者这些任务需要相当长的时间或相当多的资源时,可将这些工作分散到多个计算单元(例如辅助角色或后台作业)中。 如需一种可能的解决方案,请参阅使用者竞争模式

考虑转向 无共享的 体系结构。 非共享体系结构使用独立的和自足的节点,这些节点不存在争用情况(例如共享服务或存储)。 从理论上讲,此类系统几乎可以无限地进行扩展。 虽然完全的非共享方法对于大多数应用程序来说并不实际,但这提供了一种思路,即如何进行设计才能获得更好的缩放性。 例如,避免使用服务器端会话状态、客户端关联和数据分区,这是一个非常好的示例。

数据管理

使用数据分区。 将数据划分到多个数据库和数据库服务器中,或者将应用程序设计为使用数据存储服务,而该服务能够以透明方式提供此分区功能(此类例子包括 Azure SQL 数据库弹性数据库和 Azure 表存储)。 这种方法可以使性能最大化,并使缩放更轻松。 存在各种不同的分区技术,例如水平分区、垂直分区和功能分区。 可以将这些技术组合起来使用,以便实现最佳效益,例如提高查询性能、简化缩放、提高管理的灵活性、提高可用性,以及使存储类型与所要存储的数据更匹配。 另外,还需要根据不同类型的数据来使用不同类型的数据存储,而在选择存储类型时,还要看这些类型可以针对特定类型的数据优化到何种程度。 例如,可以使用表存储、文档数据库或列系列的数据存储来代替关系数据库,或者在使用时像重视关系数据库一样重视这些数据库。 有关详细信息,请参阅数据分区指南

最终一致性设计。 最终一致性可以改进缩放性能,因为在分区跨多个存储时它可以减少进行相关数据的同步所需的时间,或者根本不需要此方面的时间。 代价是,数据在读取时并不是始终一致的,有时写入操作也会导致冲突。 在需要频繁读取相同的数据而不需要频繁写入这些数据的情况下,最终一致性是理想的标准。 有关详细信息,请参阅 数据一致性入门

减少组件和服务之间的聊天式交互。 避免设计交互功能,防止应用程序向服务进行多次调用(每次调用返回少量数据)而不是单次调用(一次调用返回所有数据)。 调用具有明显延迟的服务或组件时,尽可能将多个相关的操作组合到单个请求中。 这可以更轻松地监视性能并优化复杂操作。 例如,使用数据库中存储的过程来封装复杂的逻辑,减少往返次数和资源锁定次数。

使用队列来平衡高速数据写入的负载。 对某项服务的需求激增可能会导致该服务不堪重负,引发越来越严重的故障。 为了防止这种情况,可考虑实施基于队列的负载均衡模式。 使用队列在任务与所调用的服务之间充当缓冲。 这可以平缓暂时性的超载,否则可能导致服务故障或任务超时。

最小化数据存储中的负载。 数据存储通常是处理瓶颈,也是一种昂贵的资源,并且通常不容易横向扩展。如果可能,请从数据存储中删除逻辑 (例如处理 XML 文档或 JSON 对象) ,并在应用程序中执行处理。 例如,可以在应用程序层中对 XML 进行序列化或反序列化处理,然后将其以数据存储固有的形式进行传递,而不必将 XML 传递到数据库(不是作为用于存储的不透明字符串)。 通常情况下,对应用程序进行向外缩放比对数据存储进行向外缩放要容易得多,因此应尽量在应用程序中进行计算密集型处理。

最大程度减少检索的数据卷。 通过指定列并使用条件来选择行,检索需要的数据。 使用表值参数和适当的隔离级别。 使用实体标记等机制,以免检索不必要的数据。

充分利用缓存。 尽可能使用缓存,减少用于生成数据或交付数据的资源和服务的负载。 缓存通常适用于相对静态的数据,或者需要进行充分处理才能获得的数据。 在可能情况下,应在应用程序每个层级的所有级别进行缓存,包括在访问数据和生成用户界面时进行缓存。 有关详细信息,请参阅Caching 指南

处理数据增长和留存。 随着时间的推移,应用程序所存储的数据量会逐渐增长。 此增长会增加存储成本,并在访问数据时增加延迟,从而影响应用程序的吞吐量和性能。 可以定期将某些不再访问的旧数据存档,或者将很少被访问的数据移到更经济有效的长期存储中,即使后者的访问延迟较高。

使用有效的二进制格式优化数据传输对象 (DTO)。 DTO 会在应用程序的各层之间传递很多次。 最大程度地减小大小可以降低对资源和网络造成的负载压力。 不过,在每个使用数据的位置将数据转换成所需格式时,需要对收益和开销进行权衡。 采用一种互操作性最强的格式,方便组件的重复使用。

设置缓存控制。 将应用程序设计和配置为尽可能使用输出缓存或片段缓存,以降低处理负载。

启用客户端缓存。 对于能够缓存的内容,Web 应用程序应启用缓存设置。 通常情况下,将默认禁用此功能。 将服务器配置为提供合适的缓存控制标头,以便在代理服务器和客户端上缓存内容。

使用 Azure Blob 存储和 Azure 内容分发网络减少应用程序上的负载。 考虑在 Blob 存储中存储静态的或相对静态的公共内容,例如图像、资源、脚本和样式表。 针对每个请求动态生成此类内容会导致应用程序超载,而此方法则可减轻应用程序的这种超载情况。 另外,请考虑使用内容分发网络来缓存此内容并将其传送到客户端。 使用内容分发网络可以提高客户端的性能,因为内容是从地理位置最近且包含内容分发网络缓存的数据中心传递的。 有关详细信息,请参阅 内容分发网络指南

优化和调整 SQL 查询和索引。 某些 T-SQL 语句或构造可能会影响性能,这种不利影响可以通过优化存储过程中的代码来减轻。 例如,应避免将 datetime 类型转换成 varchar 后又与 datetime 文本值进行比较。 应改用日期/时间比较函数。 缺少合适的索引也会降低查询执行速度。 如果使用对象/关系映射框架,则需了解其工作原理以及其可能会对数据访问层的性能造成何种影响。 有关详细信息,请参阅查询优化

请考虑反规范化数据。 数据规范化有助于避免重复和不一致。 但是,维护多个索引、检查引用完整性、对小块数据进行多次访问以及通过联接表来重组数据会造成各种开销,从而影响性能。 考虑是否可以增加存储容量并进行复制,以便降低对数据存储的负载压力。 另外,也可以考虑是否可以依靠应用程序自身(通常更容易进行缩放)来接管相关任务(如管理引用完整性)以降低对数据存储的负载压力。 有关详细信息,请参阅数据分区指南

实现

查看性能对立模式。 请参阅云应用程序的性能对立模式,了解在应用程序承受压力时,可能导致可伸缩性问题的常见做法。

使用异步调用。 在访问可能会受 I/O 或网络带宽限制(或者存在明显延迟)的资源或服务时,尽可能使用异步代码,以免锁定调用线程。

避免锁定资源,改用优化方法。 千万不要锁定具有明显延迟的资源(例如存储或其他服务)的访问权限,因为这是导致性能不佳的主要原因。 始终使用优化方法来管理并发操作(例如针对存储的写入)。 使用存储层的功能来管理冲突。 在分布式应用程序中,数据可能要到最后才会一致。

将高延迟、低带宽网络上压缩性强的数据进行压缩。 在使用 Web 应用程序时,大多数情况下通过应用程序生成并通过网络传递的最大数据量来自对客户端请求的 HTTP 响应。 HTTP 压缩可以大大减少此方面的数据量,尤其是对静态内容而言。 这可以降低成本并减少网络的负载,虽然压缩动态内容会造成服务器上的负载部分过高。 在其他更通用化的环境中,数据压缩可以降低传输的数据量,并且会最大程度地缩短传输时间和降低成本,但压缩及解压缩过程会造成开销。 因此,只有在性能会明显提高的情况下,才应使用压缩。 其他序列化方法(例如 JSON 或二进制编码)可以降低负载大小,同时对性能的影响较小,而 XML 则可能提高负载。

将使用连接和资源的时间尽可能降至最低。 将连接和资源的维持时间降至所需的最低。 例如,尽可能晚地打开连接,并尽可能快地将其返回到连接池。 尽可能晚地获取资源,并尽可能快地释放它们。

最大程度减少所需的连接数。 服务连接会吸收资源。 限制所需的连接数,并确保尽可能重用现有连接。 例如,执行身份验证后可根据需要使用模拟,以便以特定身份来运行代码。 这种方式可以重用连接,从而充分利用连接池。

注意

某些服务的 API 会自动重用连接,前提是遵循了特定于服务的原则。 需要了解在什么情况下可以重用应用程序所使用的每项服务的连接,这一点很重要。

成批发送请求以优化网络使用情况。 例如,在访问队列时成批发送和读取消息,在访问存储或缓存时成批执行多个读取或写入操作。 这可以降低经过网络进行的调用的数目,从而最大程度地提高服务和数据存储的效率。

尽可能不要求存储服务器端会话状态。 服务器端会话状态管理通常要求客户端关联(即,将每个请求路由到相同的服务器实例),这会影响系统的缩放能力。 理想情况下,应该将客户端设计成相对于其所使用的服务器来说无状态。 但是,如果应用程序必须保留会话状态,则可将敏感数据或每个客户端的大量数据存储在分布式服务器端缓存中,以便应用程序的所有实例都可以访问该缓存。

优化表存储架构。 在使用表存储(例如 Azure 表存储,该存储要求每次查询都传递和处理表和列的名称)时,可考虑使用较短的名称以减少此开销。 不过,请不要使用过度精简的名称,否则会影响可读性或可管理性。

在部署过程中或在应用程序启动时创建资源依赖关系。 如果方法在调用时需要测试资源的存在,在资源不存在时会创建该资源,则应避免调用此类方法。 客户端库中的 CloudTable.CreateIfNotExistsCloudQueue.CreateIfNotExists Azure 存储遵循此模式。 如果在每次访问存储表或存储队列之前都调用这些方法,则可能会产生相当大的开销。 应该:

  • 在部署应用程序时或第一次启动时创建所需的资源(在 Web 或辅助角色的启动代码中针对每项资源调用一次 CreateIfNotExists 是可以接受的)。 不过,如果代码尝试访问不存在的资源,则必须处理可能会引发的异常。 遇到此类情况时,应该记录异常,并尽可能提醒操作员某项资源缺失。
  • 在某些情况下,可以通过异常处理代码来创建缺失的资源。 但这种方法应谨慎使用,因为该资源不存在可能意味着存在编程错误(例如,资源名称拼写错误),或者存在基础结构级的问题。

使用轻型框架。 在使用 API 和框架来尽量降低资源使用率、缩短执行时间以及减轻应用程序的总体负载压力时,请仔细选择 API 和框架。 例如,使用 Web API 来处理服务请求可以减少应用程序占用的空间并提高执行速度,但可能不适合需要额外 Windows Communication Foundation 功能的高级方案。

考虑尽量减少服务帐户数。 例如,可以使用特定的帐户来访问对连接有限制(或在所维持的连接数较少的情况下性能更佳)的资源或服务。 此方法常用于数据库之类的服务,但可能会影响相关功能,导致无法准确地审核操作(如果对原始用户进行了模拟)。

进行性能分析和负载测试(可以在开发过程中、测试例程中以及最终发布之前进行),确保应用程序的性能和缩放符合需要。 此测试应在与生产平台同类的硬件上进行,其数据和用户负载的类型和数量也应与在生产环境中会遇到的情况相同。 有关详细信息,请参阅 Testing the performance of a cloud service(测试云服务的性能)。