The Benefit of Hindsight: Tracing Edge-Cases in Distributed Systems

针对利用tracing检测symptomatic edge cases存在的specificity和overhead的trade-off问题,本篇论文提出了retroactive sampling。 所有trace data都被记录在本地,只有检测到symptoms的时候才ingest/report。

现有的sampling的问题:

  • head sampling牺牲了edge-cases
  • tail sampling牺牲了overheads和scalability:它们必须trace all data并且ingest all trace data

Approach

论点一:It is not expensive to generate trace data

英特尔PT这样的新技术可以在5-15%的运行时开销下,在每个核心生成100-200MB/s的处理器遥测数据; 同样,安卓应用的method tracing技术可以在每个跟踪点< 1ns和运行时开销< 3%的overhead下,详尽记录所有函数的entries和exits。

方法一:nodes generate, but do not ingest, all trace data

论点二:Symptoms are locally observable

方法二:applications embed triggers that programmatically observe symptoms and signal after-the-fact that a trace is an edge-case

论点三:Triggers are local but trace data is distributed

也就是说需要解决关联问题。

方法三:requests propagate and deposit bread- crumbs so triggers can be shared with all relevant machines

论点四: Trace data will eventually expire

方法四: triggers are best effort; we assume we will see triggers quickly if at all

Design

Trace Coherence

这里虽然主要讲的是trace coherence,但实际讲的是怎么样解决:因为性能原因把trace一部分扔掉、导致trace失效的问题。

Efficient Data Management

Lazy ingestion极大地减少了从代理处发送至后端跟踪收集基础设施的跟踪数据量。 然而,在单个机器内,retroactive采样要求应用程序为所有请求生成跟踪数据到本地内存。 因此,Hindsight最敏感的性能瓶颈是在生成数据的客户端应用程序(tracepoint)和管理跟踪元数据的本地Hindsight代理之间。 论文在控制面和数据面之间建立了一个明确的分割,它将通用数据和效率聚集在数据平面,并将所有逻辑嵌入控制平面。

数据平面。 使用tracepoint,应用程序将跟踪数据写入一个被细分为buffers的大型共享内存池。 不同的线程写到不同的buffers; 每个buffer一次只能属于一个traceId,当buffer满了或active traceId发生变化时,线程会获得新buffer。 因此,缓冲区池不是按顺序消耗的,一个单一的跟踪可能被分割到几个不相邻的缓冲区。

控制平面。 Hindsight的代理程序封装了控制平面的活动,通过两个共享内存队列,不断地将缓冲区的元数据传给应用程序。 应用程序轮询可用的缓冲区,并push完整的缓冲区; 代理轮询完整的缓冲区,index metadata of full buffers grouped by traceId,并将清空的缓冲区推回给应用程序。

Hindsight的控制和数据区分产生了一个高效的代理实施,因为代理只接触元数据。

Triggers

通过将triggers与traces分离,我们可以根据超出单个trace的因素来实现更全面的trigger条件,并且trigger可以同时捕获多个相关的traces。 (是不是说就可以定义一个超级复杂的、跨traces的trigger) Hindsight使一个应用程序能够以原子方式触发一组相关的横向traceIds;在内部,该组作为一个整体被一致地收集。

Implementation

在每个时间点,一个buffer里只可能有来自一个request的trace。

Hindsight在内部维护线程本地状态,包括当前的traceId和一个指向缓冲区的指针。

我理解,面包屑(breadcrumb)的主要作用是减少搜索空间。实际上是一个pull的模型,触发trigger的agent通知coordinator,coordinator依据breadcrumbs去找集群之前处理过这个request的节点,去拉trace data 当一个请求到达一个节点时,它携带着前一个节点的面包屑。 在跟踪上下文反序列化的过程中,traceId和breadcrumb被写入共享内存的breadcrumb队列。 代理轮询这个队列,并将面包屑与缓冲区元数据一起索引。 代理不会转发或处理面包屑,直到用触发器明确地收集一个跟踪。 当一个请求离开一个节点时,它需要该节点的面包屑。 通过跟踪面包屑,我们可以从任何节点开始重新构建完整的请求图,包括具有任意并发性和扇出的请求。