笔记
- 三个需求:低损耗、应用透明的、大范围部署。借鉴Magpie、X-Trace的设计:sampling, 在少量的公共库上做 instrumentation
- 设计之初作为自给自足的监控工具(self-contained tracing tool),最终进化为监控平台(monitoring platform)
- 以通用搜索为例,用户的一次搜索涉及到众多子系统(索引、广告等)数千台机器的协同工作。用户对搜索延迟敏感,要找出哪个子系统是延迟的关键路径非常困难,一是难以确切的知道用到了哪些子系统;二是几乎没有人对每个系统的内部细节都很清楚;三是机器和服务的共享,应用之间会相互干扰。由此说明了全链路监控的重要性。两点要求:无所不在的部署和持续的监控。
- 设计目标:低损耗(Low overhead)、应用层透明(Application-level transparency)、可扩展(Scalability)。应用层透明的做法:只对公共库插桩。低损耗和可扩展的做法:自适应采样。
- 文章贡献:多年实际系统验证的经验总结。采样实现低开销至关重要;怎么做到应用层透明。
- 把一次请求的相关信息关联起来的两个办法:黑盒(black-box)、基于标注(annotation-based)。黑盒的有优点是可移植性好,缺点是需要记录更多的数据以获得足够的精度,因为它依赖的于统计推论。基于标注的办法缺点是需要对程序插桩,google有着统一的公共库(线程模型、控制流、rpc),在少量的公共库上插桩即可做到,可见统一中台的重要性。
- Dapper的数据模型:树型结构(trees)、spans、annotations。树的每一个节点是一个span,记录有三个信息:span name、span id、parent id。整颗树共用一个trace id。span的时间戳信息:start、client send、server recv、server send、client recv、end,此外开发者可选增加annotation。理解,一个span如果有n个子span,那么client send、server recv、server send、client recv会重复n遍。特别注意span的信息可能来自于多台机器。
- 插桩点:线程私有存储trace context;控制流库(control flow library)插桩保证延迟计算、异步调用等回调使用其创建者的trace context;rpc库插桩传递trace id和span id。
- Dapper的三层收集框架:1)插桩代码写trace到本地文件;2)Dapper collectors从机器上的Dapper deamon读数据;3)写入到Bigtable,rowkey为traceid,column为spanid。收集延迟:中位数延迟小于15s。98th延迟 75%的时间小于2分钟,但有25%的时间延迟几个小时。why???
- Dapper是一种带外收集策略。原因有二,一是带内收集会影响应用程序的网络动态。二是有些情况无法带内收集,例如有些中间件在后端结果返回前就已经结束了。
- 安全和隐私考虑:Dapper不记录payload,而是提供annotation的可选方法,让程序开发者自主记录数据到span。此外Dapper记录的数据提供了安全审计等方面的便利。
- Dapper运行时库的插桩代码量:C++小于1000行,Java小于800行。key-value的annotation再增加500行。
- span创建和销毁开销:176ns和204ns(带traceid的生成)
- annoation开销:span未被采样则仅仅线程私有变量的查找开销9ns。被采样annotation为字符串情况下平均40ns开销。
- 写磁盘开销:合并写请求和异步写策略。
- 收集开销:Dapper daemon CPU使用率小于0.3%,网络开销小于0.01%,一个span平均426字节
- 对应用的影响:1/16采样率对应用的延迟和吞吐率几乎无影响。
- 自适应采样率方案:by a desired rate of sampled traces per unit time
- 二级采样:collector对span的traceid计算一个概率,低于配置的值才写入bigtable。这种策略要么保留了整个trace,要么丢弃。
- DAPI:traceid访问、批量访问、索引访问。
- Dapper不能处理的情况:合并请求(例如磁盘写)、批量任务(例如MapReduce)、根因分析、记录内核级信息。
- 分布式跟踪领域,一些系统专注于故障定位,一些针对于性能优化。Dapper确实用于发现系统问题,但更多的用于发现性能问题,以及提高对大规模复杂系统的理解。