论文笔记《Dapper, a Large-Scale Distributed Systems Tracing Infrastructure》
《Dapper, a Large-Scale Distributed Systems Tracing Infrastructure》论文笔记
dapper,大型分布式系统跟踪设施
1. 概述
通篇论文介绍了 Dapper 作为一款内部使用的应用级别监控系统,其低开销,应用程序级透明性以及在大规模系统上普遍部署的设计目标和抽象的实现概念的介绍;并针对应用场景与其他跟踪系统进行对比,和它们在概念上具有相似之处,但是做出了某些设计选择,例如使用概率采样和二次采样;最终介绍了这两年来的构建,部署和使用经验,讲述了目前遇到的问题和未来可努力的方向。
概括思维导图如下:
2. 基本要求
对于一个监控系统,最底线的是应该满足如下的需求:
2.1 各处部署
小部件也应该被监听到
2.2 持续监听
监听应一直开启
3. 设计目标
针对 Google 内部的需求场景, Dapper 提出以下的设计目标和相应的解决方案:
3.1 低能耗
这是最重要且最难解决的设计目标,针对高度优化的服务,能耗不够低会迫使其主动关闭监控
问题和解决方案
(1)span
创建耗时,降低span
占用空间
创建和销毁span
,并将它们记录到本地磁盘以进行后续收集是生成开销的最重要来源。根span
的创建和销毁平均需要204纳秒,而非根span
的相同操作则需要176纳秒。 区别在于为根span
分配全局唯一的trace-id
会增加成本。
存储库中的每个span
平均仅对应426个字节。 Dapper跟踪数据收集仅占我们正在监视的应用程序中网络活动的一小部分,不足Google生产环境中网络流量的0.01%。
(2)磁盘写入昂贵,合并磁盘写入操作
在Dapper的运行时库中,对本地磁盘的写入是最昂贵的操作
每次磁盘写入都会合并多个日志文件写入操作,并且相对于被跟踪的应用程序异步执行,因此减少了可见的开销。 但是,日志写入活动可能会对高吞吐量应用程序性能产生可察觉的影响,尤其是在跟踪所有请求的情况下。
(3)降低守护程序优先级
Dapper守护程序限制为内核调度程序中的最低优先级,以防CPU争用在高负载主机中出现
(4)采用较低的采样频率
使应用程序可以轻松使用注释API的全部带宽,而不必担心性能损失。
允许数据在被垃圾回收之前在主机的本地磁盘上保留的时间更长,这为收集基础结构提供了更大的灵活性。
(5)针对吞吐量,采用不同追踪采样策略
- 吞吐量大:均匀采样概率,每1024个采样一个,因为吞吐量大, 所以也不会丢失关键事件
- 吞吐量小:覆盖默认的采样概率,并避免用户手动干预
(6)控制数据文件到中央存储库的总大小,采用二次采样
将trace-id
进行散列函数映射到参数z 0<z<1
,若参数 z 小于配置参数,则保留到中央数据库,否则丢弃
3.2 应用级别透明
这是最具挑战性的目标,即应用程序级开发人员不需要知道监控系统的存在
使用小部分线程,控制流,RPC库
达到语言无关
带外数据跟踪收集
通过和 RPC 请求链路不同的通道来收集追踪信息,直接取消在RPC结果中嵌套信息
3.3 可扩展性
自适应采样
3.4 即时性
一分钟以内数据收集分析,对异常作出更快反应
和低能耗目标有相似部分。
Dapper 运行时最耗时的部分在 创建和销毁 spans 和 注释,以及将他们记录到本地磁盘。根 spans 比非根 span 花费更多时间,区别在于为根 spans 分配全局唯一的跟踪ID会增加成本。
磁盘IO 为最耗时的部分:合并多次写,异步执行
4. Dapper 实现
4.1 基本概念:trace 树和 span 跨度
Dapper 将一个请求看成是由trace-id
标记的根节点的trace
树
其子节点表示为space
跨度,标记了开始时间戳和结束时间戳,节点和节点之间的边表示父子关系,子节点还保留指向父节点span-id
的parent-id
综上id 均为 64位唯一整数
从数据结构看,Dapper 将服务调用抽象为树的节点,一个总服务是一颗多叉树。
从时间跨度上看,类似于 Chrome 浏览器的开发者工具里的 network 模块瀑布图:
除了一些自带的特定信息,我们还可以自定义一些自己所需要的键值对信息,但为了保证效率和可用性,其总体上有记录的上限
4.2 Dapper 详细实现
本地存储服务上下文信息:
当线程处理跟踪时,Dapper将跟踪服务的上下文信息附加到线程本地存储。上下文信息是span属性(如trace-id
和span-id
)的小型且易于复制的容器。
提供绑定上下文信息的回调:
Dapper确保所有这些回调都存储其创建者的上下文信息,并且在调用回调时,此上下文与相应的线程相关联。这样,用于跟踪重构的Dapper ids就能够透明地跟踪异步控制路径。
安全和隐私考虑
通过跟踪公共安全协议参数,Dapper用于监视应用程序是否通过适当级别的身份验证或加密来满足安全策略。
具有敏感数据的应用程序不会与未经授权的系统组件进行交互。
DAPI
Depot API
用于查找某一次的trace
或span
研发的对外暴露接口
当用户都某台计算机感兴趣时,也会对特定服务感兴趣,故将 主机 和 服务名 整合成 复合索引
4.3 Dapper 监控流程
-
span
跨度数据写入本地日志文件 -
Dapper 后台程序拉取收集信息
-
最后写入
Bigtable
中的一个单元中其中一个
trace
视为Bigtable
中的一行,每列对应一个span
效率:数据从写入二进制文件到中央存储库所需时间,一般不到15秒,98%小于2分钟,其他25%时间里,延迟可能会到一小时
4.3.1 带外监控收集*
不参与到RPC调用的请求链路中,为一条分支
不使用带内监控收集的原因有二:
- 带内收集方案(跟踪数据在RPC响应头中发送回)会影响应用程序的网络动态;RPC响应数据相对较小,通常小于10k,在这种情况下,带内Dapper跟踪数据会成为负担
- 其次,带内收集方案假定所有RPC都是完全嵌套的。我们发现,有许多中间件系统会在其所有后端都返回最终结果之前将结果返回给调用方。带内收集系统无法解决这种非嵌套的分布式执行模式。
4.4 Dapper 用户接口
- 时间窗口,节点信息,成本指标 过滤
- 性能摘要大表,可以排序和指定详情
- 中央图形化描述,高亮显示选中服务
- 矩形直方图显示 步骤1 中详细信息
- 全局时间线,折叠瀑布图
5. Dapper 应用场景
5.1 性能优化
用来识别关键路径上的不需要的串行请求,这些请求通常来自于他人编写的子系统
5.2 正确性
Google 广告投放团队存在主从数据库:
-
只读副本,廉价访问
-
读写主数据库,访问昂贵
Dapper 可以用于识别一些不必要地将查询发送给主服务器而不是副本的情况,从而进行副本读取修复
5.3 和修复长尾延迟结合
Dapper 和 解决长尾延迟 结合可以发现:
- 关键路径上网络性能的瞬时下降不会影响系统吞吐量,但是会对异常延迟产生深远影响
- 由于服务之间的意外交互,导致许多问题和昂贵的查询模式。但识别服务之间的交互是困难的
- 常见查询是从Dapper外部的安全日志存储库中收集的,并使用Dapper的唯一跟踪ID与Dapper存储库结合在一起
5.4 服务依赖推断
问题:服务与服务之间是动态依赖,即不是完全靠配置参数
使用了 Dapper 的内置功能,同样可以实现服务推断,发觉服务和服务之间是如何依赖的
6. 面临的问题和解决办法
-
对于共享服务在用户激增期间发生 灾难故障 的时候,对于总体汇总数据分析;Dapper 难以在10分钟之内对收集到的数据进行大容量分析
-
Dapper 目前还无法处理合并请求:将多个请求缓存起来合并到一起进行执行,一个 trace-id 中只有对应到合并请求中的一个 span,故需要考虑识别这种情况
-
对离线工作不能很好地支持,在这种情况下,初步解决办法:将跟踪ID与其他有意义的工作单元相关联,例如输入数据中的键(或键范围)或MapReduce分片。
-
定位根源:Dapper 并不总是可以发现根源的。一个请求总体过慢可能不是因为其本身,是因为前面有请求在排队;可以通过应用程序级分析观察到该变化,可以对两个时间重叠的请求进行采样,并观察整个系统的相对延迟。
-
记录核级别信息:将服务的CPU 等信息记录下来,但目前难以以一种通用且不干扰的方式将内核信息与跟踪上下文信息关联
目前折中方式是:将内核参数信息快照与用户级别的活跃跨度相关联