1.1. Abstract

端到端链路追踪,包括broswer、apps、backend服务。

near real-time:实时上报,可以实时查询+分析性能数据,每天 十亿 条trace

三大挑战:

1.2. Introduction

每个用户操作,如loading a page on Facebook.com,都需要贯穿客户端、网络、后端服务的复杂操作。

一些偶然因素也会影响性能,比如部署代码、修改配置、分用户测试(AB分流)、数据中心硬件设施特性不同 等等。

Canopy是个普适的 performance traces 性能追踪框架,在X-Trace Dapper之上加以扩展。核心是全系统传递每次请求的identifier,根据identifier进行数据关联。有三大挑战:

Canopy搞了个pipline。rd或中间件通过canopy api将上报性能数据,canopy把这些数据映射成一种灵活的事件表示(数据结构是?)。pipline实时接收这些事件;把事件重新组织成一个更高层的追踪模型,以方便查询及分析;从追踪模型中提取用户自定义特征数据;把结果集输出 用于定制化的聚合展示。

Canopy运行了2年,13亿条trace,129 performance datasets ranging from high-level end-to-end metrics to specific customized use cases (少了点啊)。

主要贡献下面三点:

一种解耦设计:将追踪行为(应该是说埋点方式?)与追踪模型解耦,两者可以分别演进

一个完整pipline,将trace转化成基于用户特征的数据集,便于快速分析

一组可定制化的追踪组件,对同一份数据可提供不同展示view

1.3. Motivation

曾经facebook内部有很多个追踪组件,都有特定用途且难于扩展,比如前段的、rpc的、app的。【TODO,MTrace是不是能打通其他 端trace组件?做个模型转换 或 先简单做个id关联】

Figure_1_case

在例子中,Canopy看到最近一段时间,加载图片的TP数据极具上涨到了300ms (TP同比也是异常链路分析的来源)

而后对整个链路环节分段分析,找到哪几个服务的环比有了变更(我们现在只有TP环比对比,但没有和异常链路结合在一起)

最终问题原因是early flush未命中,导致web多了一次远程请求(像这种问题,如果不是end-to-end,只看后端的单条链路,是看不出来的 )

The page load regression corresponded to a 5% drop in CSS prediction accuracy and an additional 10kB of CSS before the page could display (1d); this unnecessary CSS took the place of useful resources, forcing clients to wait for the next batch of resources before the page could display (an early flush miss).

1.4. Design

ab

①为啥API要不一样?e.g. counters, logs, causal dependencies。接口类型上看确实比trace api好理解,但这就是所谓的“允许各个组件独立演进”么?

⑤⑥Canopy’s tailer 聚集这些events,且会存储原生trace events (估计是临时缓存,不是持久化存储)

⑦当tailer判断一条trace的所有event都已经接收到了,这些events会被遗弃塞进queue里,等待下一步处理

⑧生成结构化的trace数据,将这一堆event映射到trace model

⑨执行用户提交的特征提取方程,feature lambdas,

⑩pipes将数据输出到用户指定存储。(是不是解决了存储空间浪费问题??只有用户关心的trace被留了下来,其余trace都过滤丢掉了。 做好难度还是挺大的,处理速度慢实时性就会差;让这么多RD整明白也需要很好的产品设计)

而后用户执行查询、view展示、数据分析。

所以数据提取方程是基于同一份结构化数据来跑的,只读不写可并行。 有点像kafka多consumer消费。会不会出现互相影响?比如有个特征提取方程计算特别慢?如果过了time scales就不管了呗?

requests fan out and in traceid都会传下去,也就是说trace不是树形?

所有数据会封装成结构松散的events

Figure_3_event_idl

tailer是分布式的,根据traceId做分片处理event

会有一份数据pipe到Scuba,一个适用于性能数据存储的内存数据库

1.4.1. Instrumentation APIs

There are several reasons decoupling instrumentation APIs is a successful approach.

对于一个特定场景,rd只会使用到几个固定api,减少理解成本

封装好的少量api屏蔽了底层实现细节,埋点更鲁棒

api不绑定顶层trace模型,所以兼容性好。向上更容易对接新组件,向下也可以去集成第三方追踪组件,比如htrace或Cassandra tracing

1.4.2. Trace Events

收集到的埋点数据会表示成events,events可组成一个DAG:directed, acyclic graph 有向无环图,所以不一定是树。所以这确实是个minimal assumptions about execution models,能囊括mq这种模型

在同一个处理线程中,使用序列号和时间戳 来排序events;如果发生远程交互,会传递client event的id,这个event也会在client和server两端都记录,通过这个id来关联

1.4.3. Modeled Traces

会把events处理表示成更高层的trace model,屏蔽掉不同组件、不同版本的event差异。

model有四部分:execution units, blocks, points, and edges

这四种类型并不是收集event的时候就指定的,而是会维护一个event到类型之间的映射。比如 有明确开始和结束事件的计算片段 会被映射成block;一次队列操作会映射 enqueue、dequeue、完成操作 三种event

edges不止可以描述调用关系,也可以用来表示像mq这种关联关系。

每个event都可以关联性能数据,比如messages, labels, stack traces, sets of values, and counters

1.4.4. Trace Datasets

Row

dataset的一行可以是一条trace中的特征元素,比如 这条trace的全请求耗时、国家、浏览器型号;也可以是(TraceID, PagePieceID)对应的一些元素

Feature

每列都是个feature,可以是个简单提取出来的lable,也能是个聚合计算出来的值,甚至能算两个points间固定path上的聚合指标。列可以是numerics, strings, stacktraces, sets, and lists等

Extraction

从trace中提取feature 是 提取方程(feature extraction functions)的行为:f: Trace -> Collection<Row>

要求:

Analysis

Figure_4_usage_count_of_column

plots the usage frequency for 2,852 columns from 45 datasets, aggregated over 6 months of queries to Canopy’s main dataset-querying UI. The most popular column is page load latency from the main Canopy dataset, used by 23,224 queries. However, most columns contributed to fewer than 100 queries, with a median of 70

1.5. Implementation

1.5.1. Client

Figure_5_compoments

在第二步,颁发token(traceid)是有频率限制的,默认5个每秒,拿到token的请求才会生成trace。

也有低频api采集不到等问题,也支持自定义采样策略,但除了概率、qps等策略外,还支持按feature来匹配采样策略(比如哪个user的所有请求都上报)