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

有关优化代码和基础结构的建议

适用于此 Azure Well-Architected 框架性能效率清单建议:

PE:07 优化代码和基础结构。 使用性能较好的代码,并确保它将责任卸载到平台。 仅将代码和基础结构用于其核心目的,并且仅在必要时使用。

本指南介绍优化代码和基础结构性能的建议。 若要优化代码和基础结构,应仅将组件用于其核心目的,并且仅在必要时使用。 过度使用代码和基础结构时,会导致不必要的资源消耗、瓶颈和响应速度缓慢。 若要弥补这些低效问题,必须添加更多资源才能完成相同的任务。

定义

术语 定义
并发 当多个任务或进程同时执行但不一定同时执行时。
CPU 体系结构 影响计算机工作方式的组件和原则。
数据压缩 通过最小化冗余数据来减小文件大小的操作。
内存中用于运行时内存分配的区域。
内存泄漏 当工作负荷在不再需要内存后无法释放分配的内存时。
并行度 同时执行多个任务或进程时。

关键设计策略

优化代码和基础结构需要微调代码和支持基础结构,以提高性能效率。 它需要能够快速执行任务且不会浪费资源的高性能代码。 它需要设计良好的基础结构,该基础结构经过简化,以避免不必要的复杂性。 工作负荷应使用平台的固有功能。 这种方法有助于确保代码和基础结构主要用于其核心目的,并且仅在必要时使用。

优化代码性能

若要优化代码性能,请修改代码以减少资源使用量、最小化运行时并提高性能。 可以修改代码以提高软件程序的效率和速度。 不要用暴力破解来掩盖性能问题。 暴力破解意味着添加计算资源来补偿代码性能,例如添加额外的容量,而不是解决源问题。 需要解决优化性能问题。 优化代码性能时,它有助于最大程度地利用系统资源、缩短响应时间、减少延迟并增强用户体验。

检测代码

检测代码是指在运行时收集数据和监视代码性能的代码中添加代码片段或库的做法。 代码检测允许开发人员收集有关关键指标的信息,例如资源消耗 (CPU、内存使用情况) 和执行时间。 通过检测代码,开发人员可以深入了解代码热路径、识别性能瓶颈并优化代码以提高性能效率。

在理想环境中,应在软件开发生命周期的早期执行代码分析。 越早发现代码问题,修复它的成本越低。 你希望尽可能多地自动执行此代码分析。 使用动态和静态代码分析工具减少手动工作量。 但是,请记住,此测试仍然是模拟生产。 通过生产,可以最清楚地了解代码优化。

权衡:代码监视工具可能会增加成本。

确定热路径

通过检测代码,可以测量不同代码路径的资源消耗量。 这些度量可帮助你识别热路径。 热路径对性能和资源使用情况有显著影响。 它们是程序的关键或频繁执行的部分,需要高性能和低延迟。 若要识别代码热路径,请考虑以下步骤:

  • 分析运行时数据:收集运行时数据并对其进行分析,以确定消耗大量资源(例如 CPU、内存或 I/O 操作)的代码区域。 查找经常执行或需要很长时间才能完成的代码的模式或部分。

  • 衡量性能:使用分析工具或性能测试框架测量不同代码路径的执行时间和资源消耗量。 它有助于识别瓶颈和需要改进的领域。

  • 考虑业务逻辑和用户效应:根据不同代码路径与应用程序功能或关键业务操作的相关性评估它们的重要性。 确定哪些代码路径对于向用户提供价值或满足性能要求至关重要。

优化代码逻辑

优化代码逻辑是优化代码的结构和设计,以使用更少的资源执行任务。 改进的逻辑减少了不必要的操作。 它可加快执行速度,减少资源消耗。 应删除代码路径中可能影响性能的任何不必要的操作。 优先优化热路径,以查看最大的性能效率提升。 若要优化代码逻辑,请考虑以下策略:

  • 删除不必要的函数调用:查看代码并确定对所需功能不是必需的且可能对性能产生负面影响的任何函数。 例如,如果函数调用执行之前在代码中完成的验证,则可以删除不必要的验证函数调用。

  • 最小化日志记录操作:日志记录可用于调试和分析,但过多的日志记录可能会影响性能。 评估每个日志记录操作的必要性,并删除对性能分析不重要的任何不必要的日志记录调用。

  • 优化循环和条件:分析代码中的循环和条件,并确定可以消除的任何不必要的迭代或条件。 简化和优化这些结构可以提高代码的性能。 尽量减少循环中的函数调用,并消除冗余计算。 请考虑将计算移出循环或使用循环展开。

  • 减少不必要的数据处理:查看代码中是否存在任何不必要的数据处理操作,例如冗余计算或转换。 消除这些不必要的操作以提高代码的效率。

  • 优化数据结构。 若要有效地存储和检索数据,请选择适当的数据结构,例如数组、链接列表、树和哈希表。 为特定问题选择最佳数据结构。 合适的数据结构可提高应用程序性能。

  • 最小化网络请求:如果代码涉及发出网络请求,请尽量减少请求数并优化其使用情况。 尽可能批处理请求,并避免不必要的往返以提高性能。

  • 最小化分配:确定发生内存分配过多的区域。 通过减少不必要的分配并尽可能重用现有资源来优化代码。 通过最大程度地减少分配,可以提高内存效率和整体性能。 为编程语言使用适当的内存管理和垃圾回收策略。

  • 减小数据结构大小:评估数据结构(如类)的大小,并确定可以缩减的区域。 查看数据要求并消除任何不必要的字段或属性。 通过选择适当的数据类型并有效地打包数据来优化内存使用情况。

  • 使用性能优化的 SDK 和库。 使用本机 SDK 或性能优化库。 本机 SDK 旨在与平台或框架中的服务和资源进行交互。 例如,与使用自定义 API 访问相比,云原生 SDK 更适用于云服务数据平面。 SDK 擅长处理网络请求和优化交互。 性能优化库(如 Math.NET)包含性能优化函数。 正确应用函数后,可以提高工作负载的性能。

  • 跨领域实现:考虑交叉实现(如中间件或令牌检查)的影响,并评估它们是否对性能产生负面影响。

查看特定于你正在使用的编程语言的性能建议。 根据这些建议评估代码,以确定需要改进的地方。

权衡

  • 优化代码和热路径需要开发人员在识别代码效率低下方面的专业知识是主观的,并且可能是其他任务所需的高技能个人。
  • SDK 提供了便利,消除了与 API 交互的复杂性。 但 SDK 可能会限制自定义代码的控件和自定义选项。

优化内存管理

优化内存管理涉及优化工作负荷使用、分配和释放内存资源的方式,以提高效率。 适当的内存管理可以提高代码性能,因为它减少了内存操作的开销。 高效的内存使用可降低延迟、防止系统速度变慢或崩溃,并最大化计算任务的吞吐量。 请考虑以下策略来优化内存管理。

调试内存问题。 内存转储是应用程序内存快照。 它们捕获应用程序在特定时间点的内存状态。 内存转储允许对内存相关问题进行追溯分析。 根据尝试诊断的问题的性质和可用的资源,选择适当的内存转储类型。 应使用微型转储进行常规调试,并使用完整转储来解决复杂的关键问题。 此策略在资源使用情况和诊断功能之间提供平衡。 许多代码托管服务都支持内存调试。 应首选支持内存分析的服务,而不是不支持内存分析的服务。 下面是调试内存问题的基本步骤:

  1. 捕获内存转储:首先设置在应用程序运行时捕获内存转储的机制。 可以手动、自动触发捕获,也可以在满足特定条件(如内存消耗过多) ) (触发。 某些云服务可能已提供此过程。

  2. 分析内存转储:收集内存转储后,对其进行分析。 许多工具可帮助你检查这些转储,例如适用于 Windows 应用程序的 WinDbg 或适用于基于 Unix 的系统的 GDB。

  3. 识别内存泄漏:专注于在分析期间识别内存泄漏。 如果应用程序分配了内存,但在不再需要内存时无法释放内存,则会出现内存泄漏。 搜索保留在内存中的对象或数据结构,即使它们应解除分配。

  4. 修复和测试:识别有问题的代码后,请集中精力解决内存问题。 解决方法可能涉及正确释放内存、优化数据结构或重新评估内存管理做法。 确认解决方案经过严格的测试,以确保其有效性。

  5. 迭代和监视:内存管理是一个连续的过程。 定期监视应用程序的内存使用情况,并持续收集生产中的内存转储。 定期重新访问分析和优化阶段,以确保内存问题不会随着后续代码修改而再次出现。

通过将内存转储分析纳入软件开发生命周期,可以增强应用程序的可靠性和效率。 它有助于减少生产中出现内存相关问题的可能性。

减少内存分配。 最大程度地减少内存分配,以减少代码的总体内存占用量。 工作负载可以有效地利用可用内存。 垃圾回收器回收未使用的内存需求更少,并且减少了垃圾回收周期的频率和持续时间。 内存分配可能成本高昂,尤其是在频繁执行这些分配时。 最大程度地减少内存分配,以便代码可以快速高效地运行。

缓存将经常访问的数据存储在靠近处理器的地方,从而提高性能。 最小化内存分配时,缓存空间的争用会减少,因此可以有效地利用缓存。 大量内存分配可能会降低应用程序性能并生成错误。 最小化内存分配的其他方法包括:

  • 局部变量:使用局部变量而不是全局变量来最大程度地减少内存消耗。

  • 延迟初始化:实现延迟初始化,以延迟创建对象或资源,直到需要它们。

  • 缓冲区:有效地管理缓冲区,以避免分配较大的内存缓冲区。

  • 对象池:考虑使用对象池来重用大型对象,而不是分配和解除分配它们。

有关详细信息,请参阅 减少内存分配Windows 系统上的大型对象堆

使用并发和并行

使用并发和并行涉及同时或以重叠方式执行多个任务或进程,以便有效地利用计算资源。 这些技术可增加工作负荷可以处理的总体吞吐量和任务数。 并发或并行运行任务时,它会减少应用程序的运行时,降低延迟并增加响应时间。 并发和并行支持高效利用计算资源,例如 CPU 核心或分布式系统。 并发性和并行性有效地在计算资源之间分配工作负载。

使用并行度。 并行度是系统在多个计算资源上同时触发多个任务或进程的能力。 并行度将工作负荷划分为并行运行的较小任务。 可以使用多处理或分布式计算等技术实现并行。 跨多核处理器分配任务以优化工作负载管理。 优化代码以利用 CPU 体系结构、线程模型和多核处理器。 并行运行代码时,性能会提高,因为工作负载分布在多个核心中。

使用并发。 并发是系统运行多个任务或进程的能力。 并发使程序的不同部分能够独立地取得进展,从而提高整体性能。 可以使用多线程处理等技术实现并发,其中多个线程在单个进程中并发运行。 还可以使用异步编程,其中任务是并发触发的。

  • 异步编程:异步编程是一种在不阻止main线程的情况下触发任务的方法。 异步编程使程序能够在等待长时间运行的操作完成时触发任务。 使用异步编程,程序可以启动多个任务并等待它们异步完成。 程序无需等待每个任务完成,即可转到下一个任务。

    有许多异步编程技术和模式,具体取决于编程语言和平台。 一种常见方法是在 C# 等语言中使用异步关键字和构造,如 asyncawait。 使用这些关键字,可以定义异步方法。 对于 HTTP 流量,请考虑使用 异步 Request-Reply 模式

    许多框架和库为异步编程提供内置支持。 例如,在 .NET 平台中,可以使用 基于任务的异步 模式和 基于事件的异步模式来实现异步操作。 异步编程的特定实现因编程语言、平台和应用程序的要求而异。

  • 队列:队列是位于请求组件 (生成者) 和处理组件 (工作负荷的使用者) 之间的存储缓冲区。 单个队列可以有多个使用者。 随着任务的增加,应缩放使用者以满足需求。 生成者将任务置于队列中。 队列存储任务,直到使用者具有容量。 队列通常是将工作移交给需求高峰的处理服务的最佳方式。 有关详细信息,请参阅 基于队列的负载调节模式存储队列和服务总线队列

使用连接池

连接池是重用已建立数据库连接而不是为每个请求创建新连接的做法。 与数据库建立连接可能很昂贵。 必须创建与远程数据库服务器的经过身份验证的网络连接。 对于频繁打开新连接的应用程序,数据库连接尤其昂贵。 连接池重复使用现有连接,并消除了为每个请求打开新连接的费用。 连接池可减少连接延迟,并启用高数据库吞吐量, (服务器上每秒) 事务数。 应选择可以处理比当前更多的连接的池大小。 目标是让连接池快速处理新的传入请求。

了解连接池限制。 某些服务会限制网络连接数。 超过此限制时,连接可能会减慢或终止。 可以使用连接池在启动时建立一组固定的连接,然后维护这些连接。 在许多情况下,默认池大小可能只包含几个在基本测试方案中快速执行的连接。 应用程序可能会在规模下耗尽默认池大小,并造成瓶颈。 应建立一个池大小,该大小映射到每个应用程序实例上支持的并发事务数。

测试连接池。 每个数据库和应用程序平台对设置和使用池的要求略有不同。 测试连接池,确保它在负载下高效工作。

风险:连接池可能会造成 池碎片 并降低性能。

优化后台作业

许多应用程序需要独立于 UI 运行的后台任务。 应用程序可以启动作业并继续处理来自用户的交互式请求。 后台作业的示例包括批处理作业、处理器密集型任务和长时间运行的进程(如工作流)。 后台任务不应阻止应用程序或导致系统加载时操作延迟导致不一致。 若要提高性能,可以缩放托管后台任务的计算实例。 有关详细信息,请参阅 后台作业缩放和性能注意事项

优化基础结构性能

优化基础结构性能意味着增强和调整基础结构元素,以确保峰值操作并为工作负荷充分利用资源。 通过微调基础结构,可以最大程度地减少浪费、减少滞后,并利用可用资源实现更多目标。 它可确保工作负载可靠快速地运行,从而改善用户体验并节省成本。 若要优化基础结构性能,请考虑以下策略:

添加使用限制。 可以对某些工作负荷组件实施使用限制。 例如,若要删除不稳定的 Pod,可以在 Azure Kubernetes 服务 (AKS) 中定义 Pod CPU 和内存限制。 若要优化性能,可以在 java 虚拟机 (VM) 中定义内存限制

简化基础结构。 简化工作负载,以减少交互、依赖项和兼容性问题的可能性。 简化工作负载时,可以优化内存、处理能力和存储的资源利用率。

减少负载。 若要减少工作负荷上的负载,请最大程度地减少对应用程序的需求,并使资源能够执行其主要任务。 例如,常见做法是避免在代码中或单个计算实例上运行安全解决方案。 相反,Web 服务器应为 HTTP 请求提供服务。 Web 应用程序防火墙和网关资源可以处理安全检查。 以下策略有助于减少工作负载上的负载:

  • 最终一致性:采用最终一致性模型,通过允许数据稍微过时来增强性能。 最终一致性可减少持续数据更新对 CPU 周期和网络带宽的即时需求。

  • 委托任务:将服务器任务委托给客户端或中介,例如搜索索引和缓存。 委托数据排序、筛选数据或呈现视图等任务。 卸载这些任务时,可以减少服务器上的工作负荷并提高性能。

优化网络。 若要优化工作负荷网络的性能,请配置和微调网络基础结构。 确保工作负载可以以最高效率级别运行。

  • 网络协议:升级到 HTTP/2 等新式协议,这样就可以通过单个连接发送多个请求。 新式协议可减少建立新连接的开销。

    权衡:新式协议可能会排除较旧的客户端。

  • 网络聊天性:将网络请求一起批处理以减少请求数。 与其发出多个小型请求,不如将它们合并为较大的请求,以减少网络开销。

  • 数据库查询:确保数据库查询仅检索必要的信息。 避免检索大量不必要的数据,这可能导致网络流量增加并降低性能。

  • 静态数据:利用内容分发网络缓存靠近用户的频繁访问的静态内容。 缓存数据时,数据不必经过长距离传输。 缓存可缩短响应时间并减少网络流量。

  • 日志收集:仅收集并保留满足要求所需的日志数据。 配置数据收集规则并实现设计注意事项,以优化 Log Analytics 成本。

  • 数据压缩:压缩和捆绑 HTTP 内容文件数据 ,以便在客户端和服务器之间快速传输。 压缩会收缩页面或 API 返回的数据,并发送回浏览器或客户端应用。 压缩可优化网络流量,从而加速应用程序通信。

    权衡:压缩增加了服务器端和客户端处理。 应用程序必须压缩、发送和解压缩数据。 多播通信或与多个收件人的通信可能会产生解压缩开销。 需要在实现数据压缩之前和之后测试和测量性能变化,以确定它是否适合你的工作负载。 有关详细信息,请参阅《ASP.NET Core 中的响应压缩》。

Azure 便利化

检测代码:Azure Monitor Application Insights 支持自动检测 (自动检测) 和手动检测应用程序代码。 自动输入可实现遥测收集,而无需接触应用程序的代码。 手动检测需要更改代码才能实现 Application Insights 或 OpenTelemetry API。 可以使用 Application Insights Profiler 来帮助优化热路径。

优化代码逻辑:Azure 为各种编程语言提供 SDK 和库,以便与 Azure 服务交互。 使用 SDK 简化应用程序与 Azure 资源之间的交互。 SDK 提供与 Azure 服务的最佳交互,从而减少延迟并提高效率。

优化内存管理:使用 Application Insights 的智能检测功能 分析内存消耗并帮助识别和解决内存泄漏问题。

Azure 应用服务具有探查器以及内存转储收集和分析功能。 App 服务自动调整功能可以自动获取 .NET 和 Java 应用的内存转储和配置文件跟踪。

使用并发和并行:不同的 Azure 服务为并发提供独特的支持,例如 Azure Cosmos DBAzure FunctionsBlob 存储。 对于并行性,服务 AKS 支持部署容器化应用程序,从而改进并行处理。

Azure Batch 是基于云的作业计划服务,可用于启用并行和高性能计算,而无需设置基础结构。 有关详细信息,请参阅 后台作业

优化基础结构性能:实现 Azure 资源管理器模板,以使用代码定义和部署基础结构。 使用这些模板实现高效、可重复且一致的资源部署。 Azure Policy提供治理功能,以确保资源部署符合组织最佳做法和标准。

对于异步编程,请使用可缩放的队列服务(如 Azure 队列存储和Azure 服务总线)来促进异步编程。 你可以对任务进行排队和独立处理。 为了支持异步操作,Azure 市场提供了可与 Azure 服务集成的第三方队列和工具。

性能效率清单

请参阅完整的一组建议。