分布式链路追踪系统,链路的追踪大体流程如下:
- Agent 收集 Trace 数据。
- Agent 发送 Trace 数据给 Collector 。
- Collector 接收 Trace 数据。
- Collector 存储 Trace 数据到存储器,例如,数据库。
- Collector 接收到 TraceSegment 数据后,进行构建。
- 【蓝色流程】构建成功,进行流式处理,最终存储到存储器( 例如,ES / H2 )。
- 【粉色流程】构建失败,写入 Buffer 文件进行暂存。
- 【绿色流程】后台线程,定时读取 Buffer 文件,重新提交构建。
为什么构建会失败?
在 TraceSegment 里的数据结构,例如操作名( operationName
)和操作编号( operationId
) ,在 《SkyWalking 源码分析 —— Agent 收集 Trace 数据》 中我们可以看到,考虑到网络传输,优先使用 operationId
,若不存在( 例如操作还未注册,或者注册了 Agent 未同步到本地 ),则使用 operationName
。
但是,Collector 构建过程时,要求的是 operationId
,如果传递的是 operationName
时,需要将 operationName
转换成 operationId
。若此时 operationName
未注册时,则无法获取到 operationId
,导致构建失败。
在 《SkyWalking 源码分析 —— Agent DictionaryManager 字典管理》「2.2 操作的同步 API」 中,我们可以看到,operationName
的注册,是异步的过程。因而,即使构建的过程中,调用注册,也无法获得 operationId
TraceSegmentServiceHandler类 是Skywalking的collector 负责收集agent上报过来的traceSegment
在onNext函数中,segmentProducer.send 处理一条 TraceSegment
在send方法中,有SegmentParse的parse方法,对segment的处理
1.解析出segmentObject
2.判断如果没有预构建过,并且source来源是agent,就把segment写入到bufferFIle,然后return false
3.如果已经preBuild过,那么就 调用notifyListenerToBuild 来构建
prebuild方法:用于通过不同的监听器,对 TraceSegment 进行构建,生成不同的数据
分别根据不同的spanType,通知不同的Listener进行构建,包括ExitSpan, EntrySpan, LocalSpan
把traceSegment数据,写入到bufferFile文件
将 TraceSegment 写入 Buffer 文件,包括两个步骤:1)将 TraceSegment 写入 Data 文件;2)更新 Offset 文件的偏移
读取 Buffer 文件,将 TraceSegment 提交给 SegmentParse 重新解析与构建处理。另外该方法,会删除已经读取完成的 Data 文件
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
在预构建成功后,通知 Span 监听器们,去构建各自的数据,经过流式处理,最终存储到存储器。
存储分为ES和H2
一、先看下H2 文件数据库
二、EsDAO的实现,存储到ElasticSearch
三、mysql的存储