构建 Netflix 分布式追踪(tracing)体系

浅殇忆流年 2020-10-27 10:41:24 ⋅ 1117 阅读

Maulik Pandey
https://mp.weixin.qq.com/s/NmGYfoJ7pw8CfRfUkc6o2Q

“为什么我的手机不能播放 Tiger King?”

— 一位 Twitter 网友留言

这是 Netflix on-call 工程师面临问题的一个例子:解决用户碰到的各种问题。排除这种分布式系统的故障非常困难。调查视频流故障需要检查用户账户的所有方面。在上一篇博文(1)中介绍了 Edgar,我们的流 sesion 故障排除工具。本文主要看我们是如何设计 Edgar 的追踪 (tracing) 基础设施。

(1) https://netflixtechblog.com/edgar-solving-mysteries-faster-with-observability-e1a76302c71f

分布式跟踪:提供大规模服务中故障排查的上下文

在使用 Edgar 之前,工程师必须从 Netflix 的各种微服务中筛选出大量的元数据和日志,以了解我们任何用户所经历的特定流媒体故障。重建流 session 是一个繁琐而耗时的过程,其中涉及到追踪 Netflix 应用、CDN 网络和后端微服务之间的所有交互(请求)。

这个过程从手动拉取作 session 的用户账户信息开始,并将所有的拼图碎片放在一起,希望由此产生的全景能够帮助解决用户问题。因此需要通过分布式请求追踪系统来提高生产力。

如果我们为每个流 session 提供一个ID,那么分布式追踪就可以通过提供服务拓扑、重试和错误标签以及所有服务调用的延迟测量来轻松重建会话失败。我们还可以通过将相关的跟踪与账户元数据和服务日志结合起来,获得有关流 session 的上下文信息。这种需求促使我们建立了 Edgar:一个分布式跟踪基础设施以及用户体验。

Edgar: a distributed tracing infrastructure and user experience.

图 1. 通过 Edgar 排查一个会话

4 年前,当开始构建 Edgar 时,能够满足我们需求的开源分布式追踪系统非常少。我们的策略是,在开源 trace 库成熟之前,使用 Netflix 专用工具来收集基于 Java 的流媒体服务的 trace 信息。

到 2017 年,Open-Tracing (1) 和 Open-Zipkin (2) 等开源项目已经足够成熟,可以在 Netflix 的混合运行环境中使用。我们选择了 Open-Zipkin。因为它能与我们基于 Spring Boot 的 Java 运行时环境有更好的集成。

我们使用 Mantis (3) 来处理收集到的数据,使用 Cassandra 来存储数据。分布式跟踪基础设施分为三个部分:跟踪工具库、 流式处理和存储。从各种微服务收集到的 trace 数据以流处理的方式进入数据存储中。下面的章节描述了构建这些组件的历程。

(1) https://opentracing.io/

(2) https://github.com/openzipkin

(3) https://netflixtechblog.com/open-sourcing-mantis-a-platform-for-building-cost-effective-realtime-operations-focused-5b8ff387813a

跟踪 Instrumentation:它将如何影响我们的服务?

这是我们工程团队在集成 tracer 库时提到的第一个问题。这是一个重要的问题,因为 tracer 库拦截了流经关键任务流服务的所有请求。对于 polyglot 运行时,安全集成和部署 tracer 库是我们的首要任务。我们理解工程师的运维负担,并专注于在运行时环境中提供高效的跟踪库集成,并赢得了工程师的信任。

分布式跟踪依赖于为本地进程间调用(IPC)和客户端调用远程微服务的任何任意请求传递的上下文。传递请求上下文,可以捕获运行时微服务之间调用的因果关系。

我们采用了 Open-Zipkin 的基于 B3 HTTP (1) 头的上下文传播机制。我们确保在各种集成的 Java 和 Node 运行时环境中,微服务之间正确传递了上下文传包头,这些环境既包括具有传统代码库的旧环境,也包括 Spring Boot 等新环境。

在面对 Python、NodeJS 和 Ruby on Rails 等环境的跟踪库时,执行我们文化中的自由与责任原则 (2) ,这些环境不属于集成的范围,我们松耦合但高内聚的工程团队,可以自由选择适合其运行时环境的跟踪库,并有责任确保正确的上下文传播和网络调用拦截器的集成。

(1) https://github.com/openzipkin/b3-propagation

(2) https://jobs.netflix.com/culture

我们的运行时环境集成注入了基础设施标签,如服务名称、自动伸缩组(ASG)和容器实例标识符。Edgar 使用这种基础设施标签模式来查询和加入带有日志数据的 trace 信息,以便对流 session 进行故障排除。

此外,由于标签的一致性,在 Edgar 中为不同的监控和部署系统提供深度链接变得很容易。在运行时环境集成到位后,我们必须设置一个合适的 trace 数据采样策略,以构建故障诊断功能。

流处理:采样,还是不采样?

这是我们在构建基础设施时考虑的最重要的问题,因为数据采样策略决定了记录、传输和存储的 trace 数量。宽松的跟踪数据采样策略,会在每个服务容器中产生大量的跟踪数据,并且会导致流服务的性能下降,因为跟踪库会消耗更多的 CPU、内存和网络资源。

宽松的采样策略的另一个影响是,需要可扩展的流处理和存储基础设施来处理增加的数据量。

大量取样的跟踪数据集对于故障诊断来说并不可靠,因为无法保证你想要的请求就在收集的样本中。我们需要一种周到的方法来收集微服务中的所有跟踪信息,同时保持基础设施运行的低操作复杂性。

大多数分布式跟踪系统在微服务调用图的请求摄取点强制执行采样策略。我们采取了一种基于头部的混合采样方法 (1),允许为特定的、可配置的请求集记录 100% 的跟踪,同时继续根据摄取点的策略集随机采样流量。

这种灵活性使得 tracer 库能够在关键任务流微服务中记录 100% 的 trace 信息,同时在离线批处理数据等辅助系统中 尽可能少的收集信息。我们的工程团队在考虑到由于跟踪而增加的资源使用率后,对其服务进行了性能调优。

(1) https://github.com/openzipkin-contrib/zipkin-secondary-sampling/blob/master/docs/design.md

下一个挑战是通过一个可扩展的数据处理平台来流式处理大量的跟踪数据。

Mantis 是我们处理 Netflix 运营数据的首选平台。我们选择 Mantis 作为传输和处理大量 trace 数据的主干,因为我们需要一个背压感知、可扩展的流处理系统。跟踪数据收集代理通过 Mantis Publish 库 (1) 将跟踪数据传输到 Mantis 作业集群。

(1) https://netflix.github.io/mantis/internals/mantis-publish/

我们对一个时间段的跨度进行缓冲,以便在第一个作业中收集一个跟踪的所有跨度。第二个作业从第一个作业中获取数据源,对数据进行尾部采样,并将 trace 写入存储系统。这种链式 Mantis 作业 (1) 的设置,使我们能够独立地扩展每个数据处理组件。

使用 Mantis 的另一个优势是能够使用 Mantis 查询语言 (MQL) (2) 在 Raven 中执行实时的临时数据探索。

(1) https://netflix.github.io/mantis/getting-started/concepts/#job-chaining

(2) https://netflix.github.io/mantis/reference/mql/

然而,如果你没有低成本的数据存储手段,拥有一个可扩展的流处理平台并没有什么帮助。

存储:尽量节约

由于 Elasticsearch 具备灵活的数据模型和查询能力,我们一开始就使用 Elasticsearch 作为数据存储。随着入驻更多的流媒体服务,trace 数据量开始成倍增长。由于高数据写入率导致 ElasticSearch 集群扩展的操作负担增加,这让我们感到很痛苦。数据读取查询需要越来越长的时间来完成,因为 ElasticSearch 集群使用了大量的计算资源来为新增的 trace 创建索引。

高数据摄取率最终降低了读写操作。我们通过迁移到 Cassandra 作为数据存储来解决这个问题,以处理高数据写入量。在 Cassandra 中使用简单的查找索引,使我们有能力在进行大量写入时保持可接受的读取延迟。

理论上,横向扩展可以让我们处理更高的写入率,并在 Cassandra 集群中保留更大量的数据。这意味着存储 trace 的成本与存储的数据量呈线性增长。我们需要确保存储成本的增长与存储的数据量呈亚线性关系。为了追求这个目标,我们概述了以下存储优化策略。

  1. 在 EC2 中使用更便宜的 Elastic Block Store(EBS) 卷而不是 SSD 实例存储。

  2. 采用更好的压缩技术来减少 trace 数据大小。

  3. 通过使用一些简单的基于规则的过滤器,只存储相关和有用的 trace 数据。

每当现有节点的 EC2 SSD 实例存储达到最大存储容量时,我们就会增加新的 Cassandra 节点。使用更便宜的 EBS 弹性卷,而不是 SSD 实例存储,是一个更合适的选择,因为 AWS 允许动态增加 EBS 卷的大小,而无需重新创建 EC2 节点。这使我们能够在不向现有集群添加新的 Cassandra 节点的情况下增加总存储容量。

2019 年,我们云数据库工程(CDE)团队的厉害的同事为我们的用例进行了 EBS 性能基准测试,并将现有集群迁移到使用 EBS 弹性卷。通过优化时间窗口压缩策略(TWCS)参数,他们减少了 Cassandra SSTable 文件的磁盘写入和合并操作,从而降低了 EBS 的 I/O 速率。

这种优化帮助我们减少了集群节点之间的数据复制网络流量,因为 SSTable 文件的创建频率低于之前的配置。此外,通过在 Cassandra 数据文件上启用 Zstd 块压缩,跟踪数据文件的大小减少了一半。有了这些优化后的 Cassandra 集群,现在运营集群的成本降低了 71%,而且可以比之前的配置多存储 35 倍的数据

我们观察到,Edgar 用户使用了不到 1% 的收集跟踪数据。这让我们相信,如果放弃那些用户不会关心的跟踪数据,可以减少写入压力,并在存储系统中保存更多的数据。

目前,我们在 Storage Mantis 工作中使用了一个简单的基于规则的过滤器,它可以保留 Edgar 中很少被查看的服务调用路径的有趣跟踪信息。该过滤器通过检查一个跟踪的所有缓冲跨度的警告、错误和重试标签,将一个跟踪限定为一个有趣的数据点。这种基于尾巴的采样方法在不影响用户体验的情况下,将跟踪数据量减少了 20%。

我们有机会使用基于机器学习的分类技术,来进一步减少跟踪数据量。

虽然已经取得了实质性的进展,但最近面临构建跟踪数据存储系统的另一个拐点。在 Edgar 上增加一些新的功能可能需要我们存储 10 倍于当前数据量的数据。

因此,目前正在试验一种新的数据网关的分层存储方式。这个数据网关提供了一个查询接口,抽象了从分层数据存储中读取和写入数据的复杂性。此外,数据网关将摄入的数据路由到 Cassandra 集群,并将压缩后的数据文件从 Cassandra 集群传输到 S3。我们计划将最近几个小时的数据保留在 Cassandra 集群中,其余数据保留在 S3 桶中,以便长期保留跟踪信息。

表格1:存储优化的时间表

其他收益

除了支持 Edgar 外,跟踪数据还用于以下使用场景。

应用程序健康监测

Trace 数据是 Telltale 用于监控 Netflix 宏观层面应用健康状况的关键信号。Telltale 使用 trace 中的关联信息来推断微服务拓扑,并将 trace 与 Atlas 的时间序列数据相关联。这种方法可以描绘出更丰富的应用健康状况的可观察性画像。

容错工程

我们的混沌工程团队使用 trace 来验证故障是否被正确注入,同时工程师通过故障注入测试(FIT)平台对其微服务进行压力测试。

地域容灾

需求工程团队利用跟踪数据来提高地域迁移期间伸缩的正确性。追踪提供了与微服务交互的设备类型的可见性,这样,当 AWS 区域迁移时,可以更好地解释这些服务需求的变化。

评估运行 A/B 测试的基础设施成本

数据科学和产品团队通过分析相关 A/B 测试名称的 trace 信息,评估微服务上运行 A/B 测试的效果。

下一步是什么?

随着 Netflix 的发展,系统的范围和复杂性不断增加。我们将专注于以下几个方面来扩展 Edgar。

  • 为收集所有运行时环境的 trace 提供良好的开发者体验。如果有简单的方法来尝试分布式跟踪,将吸引更多工程师用跟踪系统来检测他们的服务,并通过标记相关的元数据为每个请求提供额外的上下文。

  • 增强查询跟踪数据的分析能力,使公司的一些高阶用户能够针对特定的用例构建自己的仪表盘和系统。

  • 构建通用的能力,将来自指标、日志和跟踪系统的数据关联起来,为故障排除提供额外的上下文信息。

随着我们在构建分布式跟踪基础设施方面的进展,工程师继续依靠 Edgar 来解决诸如“为什么 Tiger King 在我的手机上不能播放”之类问题,我们的分布式追踪基础设施有助于确保 Netflix 用户继续享受像 Tiger King 这样的必看剧目!

英文原文:

https://netflixtechblog.com/building-netflixs-distributed-tracing-infrastructure-bb856c319304


全部评论: 0

    我有话说:

    Java并发解决方案:分布式应用限流实践

    任何限流都不是漫无目的的,也不是一个开关就可以解决的问题,常用的限流算法有:令牌桶,漏桶。在之前的文章中,也讲到过,但是那是基于单机场景来写。 之前文章:接口限流算法:漏桶算法&令牌桶算法 然而再牛逼的机器,再优化的设计,对于特殊场景我...

    Martian框架发布 3.0.3 版本,Redis分布式

    项目简介 Martian 是一个声明式 API 编程(DAP)框架,可以帮助你快速开发后端服务。 以HttpServer作为 http服务,彻底脱离Tomcat这一类的Web容器和Servlet,同时也让项目减少了几个依赖 声明式API,让Co...

    京东技术:Hystrix 分布式系统限流、降级、熔断框架

    Hystrix是Netflix开源的一款容错框架,包含常用的容错方法:线程隔离、信号量隔离、降级策略、熔断技术。

    「轻阅读」Dubbo 如何成为连接异构微服务体系的最佳服务开发框架

    要实现异构微服务体系间的共存或迁移,关键点在打通异构体系间的协议与服务发现,得益于 Dubbo 自身对多协议、多注册模型的支持

    Gradle 7.0 发布,自动化构建

    Gradle 7.0 现已发布。Gradle 是一个基于 Apache Ant 和 Apache Maven 概念的项目自动化构建工具

    Dapr 1.0 发布,分布式应用运行时

    Dapr 1.0 正式发布。 Dapr 是一个开源、可移植的、事件驱动的运行时,可以帮助开发人员构建在云和边缘上运行的弹性的、微服务的、无状态和有状态应用程序,并且关注于业务逻辑而不用考虑分布式相关

    用户体验设计干货笔记

    赵煜 前滴滴资深体验设计师 7年互联网产品设计经验,全链路体验+增长设计专家,曾负责滴滴拼车业务乘客侧效率革新工作、快车司乘评价体系优化工作、拼车新计价改革,业内首创“共乘”概念。深耕交互设计

    Apache Traffic Control 5.1.2 发布,高可扩分布式 CDN 解决方案

    Apache Traffic Control 5.1.2 现已发布。Apache Traffic Control 是一个分布式、可扩展的冗余解决方案,实现了现代 CDN 的所有核心功能,可

    运用Docker快速部署分布式项目

    快速搭建Docker分布式项目环境

    2018年8个技巧来构建更好的Node.js应用程序

    2018年8个技巧来构建更好的Node.js应用程序

    「开源资讯」Gradle 6.7 发布,增量构建改进

    Gradle 6.7 已经发布。Gradle 是一个基于 Apache Ant 和 Apache Maven 概念的项目自动化构建工具,支持依赖管理和多项目,类似 Maven,但比之简单轻便。它使用

    RocketMQ 分布式事务

    分布式事务先回顾一下事务,例如银行转账,A给B转100元,这个动作包括2个步骤:A账户减100元B账户加100......

    阿里技术:自底向上构建知识图谱全过程

    知识图谱的构建技术主要有自顶向下和自底向上两种。其中自顶向下构建是指借助百科类网站等结构化数据源,从高质量数据中提取本体和模式信息,加入到知识库里。

    Apache Maven 3.8.1 发布,项目管理和构建工具

    Apache Maven 3.8.1 发布了。Apache Maven 是一个项目管理和构建工具。基于项目对象模型(POM)的概念, Maven 可以从中心位置管理项目的构建、报告和文档

    CKEditor 5 v26.0.0 发布:具有可扩展的构建、内联部件样式和注释指南

    CKEditor 5 v26.0.0 已经发布,本次更新包括支持创建一个定制的编辑器构建、Mac上的按键管理、设计内联部件、编辑器占位符和一组关于使用协作特性注释的新指南等内容。 通过 DLL

    gulp.js 基于流的自动化构建工具,对小程序代码进行打包

    gulpjs是一个前端构建工具,与gruntjs相比,gulpjs无需写一大堆繁杂的配置参数,API也非常简单,学习起来很容易,而且gulpjs使用的是nodejs中stream来读取...