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

用于优化代码和基础结构的体系结构策略

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

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

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

定义

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

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

优化代码性能

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

检测代码

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

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

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

识别热路径

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

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

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

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

优化代码逻辑

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

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

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

  • 优化循环和条件:分析代码中的循环和条件,并确定可以消除的任何不必要的迭代或条件。 简化和优化这些结构可以提高代码的性能。 最大程度地减少循环中的函数调用,并消除冗余计算。 请考虑在循环外部移动计算或使用循环取消滚动。

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

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

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

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

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

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

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

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

权衡

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

优化内存管理

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

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

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

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

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

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

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

通过将内存转储分析合并到软件开发生命周期中,可以放大应用程序的可靠性和效率。 这有助于降低生产中与内存相关的问题的可能性。

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

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

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

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

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

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

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

使用并发和并行度

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

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

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

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

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

    许多框架和库为异步编程提供内置支持。 例如,在 .NET 平台中,可以使用 Task-Based 异步模式Event-Based 异步模式等模式实现异步作。 异步编程的特定实现因应用程序的编程语言、平台和要求而异。

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

使用连接池

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

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

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

风险:连接池可以创建 池碎片 并降低性能。

优化后台作业

许多应用程序需要独立于 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 探查器 来帮助优化热路径。

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

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

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

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

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

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

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

性能效率清单

请参阅完整的建议集。