您现在访问的是微软AZURE全球版技术文档网站,若需要访问由世纪互联运营的MICROSOFT AZURE中国区技术文档网站,请访问 https://docs.azure.cn.

监视 Azure Kubernetes 服务中的微服务体系结构 (AKS)

本文介绍了有关监视 Azure Kubernetes Service (AKS) 上运行的微服务应用程序的最佳实践。

任何复杂的应用程序偶尔都会出现错误。 在微服务应用程序中,需要跟踪几十甚至几百个服务发生的情况。 若要了解所发生的情况,必须通过应用程序收集遥测数据。 可以将遥测数据分为日志和指标。

日志 是运行应用程序时发生的事件的文本形式记录。 日志包括应用程序日志(跟踪语句)或 Web 服务器日志等。 日志主要用于取证和根本原因分析。

指标是可以分析的数字值。 可以使用指标实时(或接近实时)观察系统,或者分析不同时间段的性能趋势。 若要理解系统整体,必须从物理基础结构到应用程序,在体系结构的各个级别收集指标,包括:

  • 节点级 指标,包括 CPU、内存、网络、磁盘和文件系统的使用情况。 借助系统指标可以了解群集中每个节点的资源分配,以及排查异常。

  • 容器 指标。 对于容器化应用程序,你需要在容器级别收集指标,而不只是在 VM 级别收集指标。

  • 应用程序 指标。 包括用于了解服务行为的任何指标。 示例包括排队的入站 HTTP 请求数、请求延迟或消息队列长度。 应用程序还可以创建特定于域的自定义指标,例如每分钟处理的业务事务数。

  • 相关服务 指标。 服务可能会调用外部服务或终结点,例如托管的 PaaS 服务或 SaaS 服务。 第三方服务不一定提供任何指标。 如果未提供,则必须依赖自己的应用程序指标来跟踪有关延迟和错误率的统计信息。

监视群集状态

使用 Azure Monitor 来监视群集的整体运行状况。 以下屏幕截图显示了用户部署的 pod 中出现严重错误的群集。

Azure Monitor 仪表板的屏幕截图

从这里,可以进一步深入了解问题。 例如,如果 pod 状态为 ImagePullBackoff ,则表示 Kubernetes 无法从注册表中提取容器映像。 这可能是由于容器标记无效或尝试从注册表中提取身份验证错误引起的。

请注意,容器崩溃会将容器状态置于 State = Waiting 中,并将置于 Reason = CrashLoopBackOff 。 对于盒是副本集的一部分并且重试策略为的典型方案 Always ,此情况不会在群集状态中显示为错误。 但是,您可以运行查询或设置此条件的警报。 有关详细信息,请参阅 了解 AKS 群集性能与容器 Azure Monitor

指标

建议使用 Azure Monitor 来收集和查看 AKS 群集和任何其他依赖 Azure 服务的指标。

  • 对于群集和容器指标,启用 容器 Azure Monitor。 启用此功能后,Azure Monitor 通过 Kubernetes 指标 API 从控制器、节点和容器中收集内存和处理器指标。 有关可通过 Azure Monitor 容器使用的指标的详细信息,请参阅 使用容器 Azure Monitor 了解 AKS 群集性能

  • 使用 Application Insights 收集应用程序指标。 Application Insights 是一项可扩展应用程序性能管理 (APM) 服务。 若要使用它,请在应用程序中安装检测包。 此包可监视应用,并将遥测数据发送到 Application Insights 服务。 此外,它还可以从宿主环境提取遥测数据。 然后,将数据发送到 Azure Monitor。 Application Insights 还提供内置关联和依赖项跟踪 (请参阅) 下面的 分布式跟踪

Application Insights 的最大吞吐量每秒测量一次,并会限制数据速率是否超出限制。 有关详细信息,请参阅 Application Insights 限制。 为每个环境创建不同的 Application Insights 实例,使开发/测试环境不会与用于配额的生产遥测竞争。

单个操作可能生成多个遥测事件,因此,如果应用程序遇到较大的流量,可能会受到限制。 若要缓解此问题,可以执行采样来减少遥测流量。 弊端是指标的精确度会下降。 有关详细信息,请参阅 Application Insights 中的采样。 也可以通过预先聚合指标来减少数据量 — 即,计算平均值和标准偏差等统计值,然后发送这些值而不是原始遥测数据。 以下博客文章介绍了大规模使用 Application Insights 的方法:Azure Monitoring and Analytics at Scale(大规模使用 Azure 监视和分析)。

如果你的数据速率太高,无法触发限制,采样或聚合是不可接受的,请考虑将指标导出到在群集中运行的时间序列数据库,如 PrometheusInfluxDB

  • InfluxDB 是基于推送的系统。 某个代理需要推送指标。 你可以使用 " 滴答堆栈" 来设置对 Kubernetes 的监视,并使用 Telegraf将其推送到 InfluxDB,这是用于收集和报告指标的代理。 InfluxDB 可用于不规则事件和字符串数据类型。

  • Prometheus 是基于提取的系统。 它定期从配置的位置擦除指标。 Prometheus 可以擦除 cAdvisor 或 kube-state-metrics 生成的指标。 kube-state-metrics 服务从 Kubernetes API 服务器收集指标,然后将这些指标提供给 Prometheus(或者与 Prometheus 客户端终结点兼容的擦除程序)。 对于系统指标,请使用 Node 导出程序,这是一个针对系统指标的 Prometheus 导出程序。 Prometheus 支持浮点数据,但不支持字符串数据,因此,它适合用于系统指标,而不适合用于日志。 Kubernetes 指标服务器 是资源使用情况数据的群集范围聚合器。

日志记录

下面是在微服务应用程序中进行日志记录的一些常见问题:

  • 了解客户端请求的端到端处理,其中可能会调用多个服务来处理单个请求。
  • 将来自多个服务的日志整合到单个聚合视图中。
  • 分析来自多个来源的日志,这些日志使用自己的日志记录架构或没有特定架构。 日志可能由你无法控制的第三方组件生成。
  • 与传统的固化结构相比,微服务体系结构生成的日志量更大,因为在事务中有更多服务、网络调用和步骤。 这意味着,记录自身可能是应用程序的性能或资源瓶颈。

对于基于 Kubernetes 的体系结构,还有一些挑战:

  • 容器可四处移动并可重新计划。
  • Kubernetes 有使用虚拟 IP 地址和端口映射的网络抽象。

在 Kubernetes 中,用于记录的标准方法是将日志写入 stdout 和 stderr。 容器引擎将这些流重定向到日志记录驱动程序。 为了便于查询,并防止在节点崩溃时可能丢失日志数据,通常的方法是从每个节点收集日志并将其发送到中央存储位置。

Azure Monitor 与 AKS 集成以支持此方法。 Azure Monitor 收集容器日志,并将它们发送到 Log Analytics 工作区。 在这里,你可以使用 Kusto 查询语言 来编写跨聚合日志的查询。 例如,下面是一个用于显示指定 pod 的容器日志的 Kusto 查询:

let ContainerIdList = KubePodInventory
| where ClusterName =~ '<cluster-name>'
| where Name =~ '<pod-name>'
| distinct ContainerID;
ContainerLog
| where ContainerID in (ContainerIdList)

Azure Monitor 是一种托管服务,配置 AKS 群集以使用 Azure Monitor 是 CLI 或资源管理器模板中的一个简单的配置开关。 (有关详细信息,请参阅 如何为容器启用 Azure Monitor) 。使用 Azure 监视的另一个优点是,它将 AKS 日志与其他 azure 平台日志合并,同时提供统一的监视体验。

Azure Monitor 按千兆字节 (GB) 的数据引入到服务中 (参阅 Azure Monitor 定价) 。 在极大的卷上,可能会考虑成本。 Kubernetes 生态系统提供许多开源备选方案。 例如,许多组织将 FluentdElasticsearch 配合使用。 Fluentd 是开源数据收集器,Elasticsearch 是用于搜索的文档数据库。 使用这些选项的挑战在于它们需要额外配置和管理群集。 对于生产工作负荷,可能需要尝试配置设置。 还需要监视日志记录基础结构的性能。

Application Insights

若要获得更丰富的日志数据,建议通过 Application Insights 检测代码。 这需要将 Application Insights 包添加到代码中并配置代码,以便将日志记录语句发送到 Application Insights。 详细信息依赖于平台,如 .NET、Java 或 Node.js。 Application Insights 包会将遥测数据发送到 Azure Monitor。

如果使用的是 .NET Core,还建议使用 Kubernetes 库的 Application Insights 。 此库丰富 Application Insights 带有其他信息的跟踪,例如容器、节点、pod、标签和副本集。

此方法的优点包括:

  • Application Insights 记录 HTTP 请求,包括延迟和结果代码。
  • 默认情况下启用分布式跟踪。
  • 跟踪包括操作 ID,因此你可以匹配特定操作的所有跟踪。
  • Application Insights 生成的跟踪通常包含附加的上下文信息。 例如,使用操作名称和类别(如)修饰 ASP.NET 跟踪, ControllerActionInvoker 这使你能够深入了解 ASP.NET 请求管道。
  • Application Insights 收集性能故障排除和优化的性能指标。

注意事项:

  • 如果数据速率超出最大限制,则 Application Insights 对遥测进行限制;有关详细信息,请参阅 Application Insights 限制。 单个操作可能生成多个遥测事件,因此,如果应用程序遇到较大的流量,可能会受到限制。
  • 由于 Application Insights 批处理数据,如果进程因未处理的异常而崩溃,则可能会丢失批处理。
  • Application Insights 根据数据量进行计费。 有关详细信息,请参阅在 Application Insights 中管理定价和数据量

结构化日志记录

若要使日志更易于分析,请尽可能使用结构化日志记录。 结构化日志记录是指应用程序以结构化格式(例如 JSON)编写日志的方法,而不是输出非结构化文本字符串。 有很多可用的结构化日志记录库。 例如,下面是一个使用适用于 .NET Core 的 Serilog 库 的日志记录语句:

public async Task<IActionResult> Put([FromBody]Delivery delivery, string id)
{
    logger.LogInformation("In Put action with delivery {Id}: {@DeliveryInfo}", id, delivery.ToLogInfo());

    ...
}

此处,对的调用 LogInformation 包含 Id 参数和 DeliveryInfo 参数。 对于结构化日志记录,这些值不会插入到消息字符串中。 相反,日志输出将如下所示:

{"@t":"2019-06-13T00:57:09.9932697Z","@mt":"In Put action with delivery {Id}: {@DeliveryInfo}","Id":"36585f2d-c1fa-4a3d-9e06-a7f40b7d04ef","DeliveryInfo":{...

这是一个 JSON 字符串,其中 " @t " 字段为时间戳," @mt " 是消息字符串,其余的键/值对是参数。 通过输出 JSON 格式,可以更轻松地以结构化的方式查询数据。 例如,以下 Log Analytics 用 Kusto 查询语言编写的查询将从名为的所有容器搜索此特定消息的实例 fabrikam-delivery

traces
| where customDimensions.["Kubernetes.Container.Name"] == "fabrikam-delivery"
| where customDimensions.["{OriginalFormat}"] == "In Put action with delivery {Id}: {@DeliveryInfo}"
| project message, customDimensions["Id"], customDimensions["@DeliveryInfo"]

查看 Azure 门户中的结果显示,它 DeliveryInfo 是包含模型的序列化表示形式的结构化记录 DeliveryInfo

Log Analytics 工作区的屏幕截图

下面是此示例中的 JSON:

{
    "Id": "36585f2d-c1fa-4a3d-9e06-a7f40b7d04ef",
    "Owner": {
        "UserId": "user id for logging",
        "AccountId": "52dadf0c-0067-43e7-af76-86e32b48bc5e"
    },
    "Pickup": {
        "Altitude": 0.29295161612934972,
        "Latitude": 0.26815900219052985,
        "Longitude": 0.79841844309047727
    },
    "Dropoff": {
        "Altitude": 0.31507750848078986,
        "Latitude": 0.753494655598651,
        "Longitude": 0.89352830773849423
    },
    "Deadline": "string",
    "Expedited": true,
    "ConfirmationRequired": 0,
    "DroneId": "AssignedDroneId01ba4d0b-c01a-4369-ba75-51bde0e76cc9"
}

上面的代码片段使用 Serilog 库,但也可以为其他语言使用结构化的日志记录库。 例如,下面是一个使用适用于 Java 的 SLF4J 库的示例:

MDC.put("DeliveryId", deliveryId);

log.info("In schedule delivery action with delivery request {}", externalDelivery.toString());

分布式跟踪

微服务的一大挑战是了解跨服务的事件流。 单个事务可能涉及对多个服务的调用。 若要重新构造整个步骤序列,每个服务应该传播一个关联 ID 用于充当该操作的唯一标识符。 该关联 ID 可以实现跨服务的分布式跟踪

接收客户端请求的第一个服务应生成关联 ID。 如果该服务对另一服务发出 HTTP 调用,它会在请求标头中放置关联 ID。 如果服务发送异步消息,它会将相关 ID 置于消息中。 下游服务继续传播关联 ID,以便可以流经整个系统。 此外,写入应用程序指标或日志事件的所有代码都应包含关联 ID。

关联服务调用后,可以计算操作指标,例如整个事务的端到端延迟、每秒成功的事务数和失败的事务百分比。 在应用程序日志中包含关联 ID 可以执行根本原因分析。 如果某个操作失败,你可以查找同一操作中包含的所有服务调用的日志语句。

建议为分布式跟踪使用 Application Insights。 Application Insights SDK 会自动将关联上下文注入 HTTP 标头,并在 Application Insights 日志中包含相关 ID。 某些服务可能仍需要显式传播相关标头,具体取决于所使用的框架和库。 有关详细信息,请参阅 Application Insights 中的遥测关联

实现分布式跟踪时的一些其他注意事项:

  • 现在有一个适用于相关 Id 的标准 HTTP 标头,已接受 W3C 提议 作为正式建议。 团队应该针对自定义标头值进行标准化。 选择可能由日志框架决定,如 Application Insights 或服务网格选择。

  • 对于异步消息,如果消息传递基础结构支持将元数据添加到消息,则应将关联 ID 包含为元数据。 否则,请将关联 ID 包含为消息架构的一部分。 例如, 通过服务总线消息传送来查看分布式跟踪和关联

  • 如果不包含单个不透明标识符,可以发送一个包含更丰富信息(例如调用方-被调用方关系)的关联上下文。

  • 如果使用 Istio 或 linkerd 作为服务网格,当通过服务网格代理路由 HTTP 调用时,这些技术会自动生成关联标头。 服务应转发关联标头。

分布式跟踪示例

此示例通过一组微服务执行分布式事务。 该示例取自 此处所述的引用实现。

无人机传递应用程序

在这种情况下,分布式事务具有以下步骤:

  1. 引入服务在服务总线队列中放置一条消息。
  2. 工作流服务将从队列中提取消息。
  3. 工作流服务调用三个后端服务来处理 (无人机计划程序、包和传递) 的请求。

以下屏幕截图显示了无人机传递应用程序的 应用程序映射 。 此图显示了对公共 API 终结点的调用,导致工作流涉及5个微服务。

应用程序映射

fabrikam-workflowfabrikam-ingestion 到服务总线队列的箭头显示发送和接收消息的位置。 不能从关系图中判断哪个服务正在发送消息,哪些服务正在接收 — 箭头,只显示这两个服务都在调用服务总线, — 但详细信息中提供了此信息:

应用程序映射详细信息的屏幕截图。

由于每个调用都包含一个操作 ID,因此你还可以查看单个事务中的端到端步骤,包括每个步骤的计时信息和 HTTP 调用。 下面是一个此类事务的可视化效果:

端对端事务

此可视化效果显示从引入服务到队列的步骤,从队列到工作流服务,以及从工作流服务到其他后端服务。 最后一步是将服务总线消息标记为 "已完成" 的工作流服务。

下面是当对后端服务的调用失败时的示例:

显示错误的应用程序映射

这表明,在查询期间 (36% ) 对无人机计划程序服务的调用失败。 在端到端事务视图中,它显示在向服务发送 HTTP PUT 请求时发生了异常。

端到端事务详细信息的屏幕截图,显示在向服务发送 HTTP PUT 请求时发生了异常。

进一步钻取时,异常将导致出现套接字异常 "无此类设备或地址"。

BackendServiceCallFailedException:没有此类设备或地址---u003e 系统。 System.net.http.httprequestexception:没有此类设备或地址---u003e 系统:无此类设备或地址

这是无法访问后端服务的提示。 此时,你可以使用 kubectl 来查看部署配置。 在此示例中,由于 Kubernetes 配置文件中存在错误,已关闭服务主机名。 Kubernetes 文档中的 调试服务 一文提供了有关诊断此类错误的提示。

下面是一些常见的错误原因:

  • 代码 bug。 它们可能会如下所示:
    • 异常。 查看 Application Insights 日志以查看异常详细信息。
    • 进程崩溃。 查看容器和 pod 状态,查看容器日志或 Application Insights 跟踪。
    • HTTP 5xx 错误
  • 资源耗尽:
    • 查找限制 (HTTP 429) 或请求超时。
    • 检查 CPU、内存和磁盘的容器指标
    • 查看容器和 pod 资源限制的配置。
  • 服务发现。 检查 Kubernetes 服务配置和端口映射。
  • API 不匹配。 查找 HTTP 400 错误。 如果对 Api 进行版本控制,请查看正在调用哪个版本。
  • 拉取容器映像时出错。 查看 pod 规范。 此外,请确保已授权群集从容器注册表中请求。
  • RBAC 问题。

后续步骤

详细了解支持在 AKS 上监视应用程序 Azure Monitor 中的功能:

有关使用指标进行性能优化的详细信息,请参阅 " 性能优化分布式应用程序"。