其他
链路追踪(Tracing)的前世今生(上)
作者:Java 研发专家-周东科
一、带着疑问看历史
二、黑盒模式探索
三、另一种思路
需要为每一个组件生成一个 component id。
对于每一个 http 请求生成一个唯一的 request id ,并且通过线程局部变量(ThreadLocal)传递下去。
对于请求内新起来的线程,需要修改线程创建类,把request id继续传递下去。
对于请求内产生的 rpc 调用,需要修改请求端代码,把 request id 信息带入 header,并在接收端解析这个header注入到线程本地变量。
每次调用到一个组件(component),就使用 (request id,component id) 组合记录一个 Trace Log。
四、重新构建调用链路
在调用链路内携带元数据(在调用链路传递的数据也称之为带内数据,in-bound data)
上报的链路信息不留存在调用链路内,收集链路信息的机制需要与应用本身正交(注:不在调用链路里面留存的链路数据,也称之为带外数据,out-of-bound data) 注入元数据的实体应该与收集报告的实体解偶。
Flags
一个 bit 数组,用于标记 TreeInfo、Destination、Options 是否使用。
TaskID
全局唯一的 id,用于标识唯一的调用链。
TreeInfo
ParentID -父节点 id,调用链内唯一。 OpID -当前操作 id,调用链内唯一。 EdgeType-NEXT 表示兄弟关系,DOWN 表示父子关系。
Destination
用于指定上报地址。
Options
预留字段,用于扩展。
五、大规模商用实践——Dapper
低开销(Low overhead):链路追踪系统需要保证对在线服务的的性能影响做到忽略不计的程度。即使是很小的监控消耗也会对一些高度优化过的服务有可觉察的影响,甚至迫使部署团队关闭追踪系统。
应用级透明化(Application-level transparecy):开发者不应该感知到链路追踪设施。如果链路追踪系统需要依赖应用级开发者协助才能够工作,那么这个链路追踪设施会变得非常最弱,而且经常会因为 bugs 或者疏忽导致无法正常工作。这违反了大范围部署的设计需求。
可伸缩性(Scalability):链路追踪系统需要能够满足 Google 未来几年的服务和集群的规模。
六、如何定义链路信息的?
span name: 易于阅读的名字,如图8中的 Frontend.Request。 span id: 一个64bit 的唯一标识符。 parent id: 父 span id。
七、如何实现应用级透明的?
当一个线程在处理链路追踪路径上时,Dapper 会把追踪上下文关联到线程本地存储。追踪上下文是一个小巧且容易复制的 span 信息容易。
如果计算过程是延迟的或者一步的,大多谷歌开发者会使用通用控制流库来构造回调函数,并使用线程池线程池或者其他执行器来调度。这样 Dapper 就可以保证所有的回调函数会在创建的时候存储追踪上下文,在回调函数被执行的时候追踪上下文关联到正确线程里面。
Google 几乎所有的线程内通信都是建立在一个 RPC 框架构建的,包括 C++ 和 Java 的实现。框架添加上了测量,用于定义所有 RPC 调用相关 span。在被跟踪的 RPC、span 和 trace的id 会从客户端传递到服务端。在Google 这个是非常必要的测量点。
八、结语
九、 联系我们