Skip to content

Commit 4aef3a6

Browse files
author
yangjingjing
committed
init blog
1 parent 8bb60cc commit 4aef3a6

File tree

3 files changed

+1619
-0
lines changed

3 files changed

+1619
-0
lines changed
Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
---
2+
layout: post
3+
categories: [Skywalking]
4+
description: none
5+
keywords: Skywalking
6+
---
7+
# Skywalking源码ContextManager
8+
9+
## 上下文适配器ContextManager
10+
TraceSegment及其所包含的Span都在同一个线程内,ContextManager使用ThreadLocal来管理TraceSegment的上下文(也就是AbstractTracerContext)
11+
12+
ContextManager中getOrCreate()方法:
13+
```
14+
/**
15+
* TraceSegment及其所包含的Span都在同一个线程内,ContextManager使用ThreadLocal来管理TraceSegment的上下文(AbstractTracerContext)
16+
* {@link ContextManager} controls the whole context of {@link TraceSegment}. Any {@link TraceSegment} relates to
17+
* single-thread, so this context use {@link ThreadLocal} to maintain the context, and make sure, since a {@link
18+
* TraceSegment} starts, all ChildOf spans are in the same context. <p> What is 'ChildOf'?
19+
* https://github.com/opentracing/specification/blob/master/specification.md#references-between-spans
20+
*
21+
* ContextManager代理了AbstractTracerContext主要的方法
22+
* <p> Also, {@link ContextManager} delegates to all {@link AbstractTracerContext}'s major methods.
23+
*/
24+
public class ContextManager implements BootService {
25+
26+
private static ThreadLocal<AbstractTracerContext> CONTEXT = new ThreadLocal<AbstractTracerContext>();
27+
28+
private static AbstractTracerContext getOrCreate(String operationName, boolean forceSampling) {
29+
// 从ThreadLocal中获取AbstractTracerContext,如果有就返回,没有就新建
30+
AbstractTracerContext context = CONTEXT.get();
31+
if (context == null) {
32+
// operationName为空创建IgnoredTracerContext
33+
if (StringUtil.isEmpty(operationName)) {
34+
if (LOGGER.isDebugEnable()) {
35+
LOGGER.debug("No operation name, ignore this trace.");
36+
}
37+
context = new IgnoredTracerContext();
38+
} else {
39+
// 调用ContextManagerExtendService的createTraceContext方法创建AbstractTracerContext,并设置到ThreadLocal中
40+
if (EXTEND_SERVICE == null) {
41+
EXTEND_SERVICE = ServiceManager.INSTANCE.findService(ContextManagerExtendService.class);
42+
}
43+
context = EXTEND_SERVICE.createTraceContext(operationName, forceSampling);
44+
45+
}
46+
CONTEXT.set(context);
47+
}
48+
return context;
49+
}
50+
51+
```
52+
getOrCreate()方法处理逻辑如下:
53+
54+
- 从ThreadLocal中获取AbstractTracerContext,如果有就返回,没有就新建
55+
- 如果operationName为空创建IgnoredTracerContext
56+
- 否则调用ContextManagerExtendService的createTraceContext()方法创建AbstractTracerContext,并设置到ThreadLocal中
57+
58+
ContextManagerExtendService的createTraceContext()方法代码如下:
59+
```
60+
@DefaultImplementor
61+
public class ContextManagerExtendService implements BootService, GRPCChannelListener {
62+
63+
/**
64+
* 哪些后缀的请求不需要追踪
65+
*/
66+
private volatile String[] ignoreSuffixArray = new String[0];
67+
68+
public AbstractTracerContext createTraceContext(String operationName, boolean forceSampling) {
69+
AbstractTracerContext context;
70+
/*
71+
* 如果OAP挂了不采样且网络连接断开,创建IgnoredTracerContext
72+
* Don't trace anything if the backend is not available.
73+
*/
74+
if (!Config.Agent.KEEP_TRACING && GRPCChannelStatus.DISCONNECT.equals(status)) {
75+
return new IgnoredTracerContext();
76+
}
77+
78+
int suffixIdx = operationName.lastIndexOf(".");
79+
// operationName的后缀名在ignoreSuffixArray中,创建IgnoredTracerContext
80+
if (suffixIdx > -1 && Arrays.stream(ignoreSuffixArray)
81+
.anyMatch(a -> a.equals(operationName.substring(suffixIdx)))) {
82+
context = new IgnoredTracerContext();
83+
} else {
84+
SamplingService samplingService = ServiceManager.INSTANCE.findService(SamplingService.class);
85+
// 如果是强制采样或尝试采样返回true,创建TracingContext
86+
if (forceSampling || samplingService.trySampling(operationName)) {
87+
context = new TracingContext(operationName, spanLimitWatcher);
88+
} else {
89+
context = new IgnoredTracerContext();
90+
}
91+
}
92+
93+
return context;
94+
}
95+
96+
```
97+
createTraceContext()方法处理逻辑如下:
98+
99+
- 如果OAP挂了不采样且网络连接断开,创建IgnoredTracerContext
100+
- 如果operationName的后缀名在ignoreSuffixArray中(指定哪些后缀的请求不需要追踪),创建IgnoredTracerContext
101+
- 如果是强制采样或尝试采样(SamplingService的trySampling()方法)返回true,创建TracingContext,否则创建IgnoredTracerContext
102+
103+
ContextManager中createEntrySpan()方法:
104+
```
105+
public class ContextManager implements BootService {
106+
107+
public static AbstractSpan createEntrySpan(String operationName, ContextCarrier carrier) {
108+
AbstractSpan span;
109+
AbstractTracerContext context;
110+
operationName = StringUtil.cut(operationName, OPERATION_NAME_THRESHOLD);
111+
if (carrier != null && carrier.isValid()) {
112+
SamplingService samplingService = ServiceManager.INSTANCE.findService(SamplingService.class);
113+
samplingService.forceSampled();
114+
// 一定要强制采样,因为链路中的前置TraceSegment已经存在,否则链路就可能会断开
115+
context = getOrCreate(operationName, true);
116+
span = context.createEntrySpan(operationName);
117+
context.extract(carrier);
118+
} else {
119+
// 不需要强制采样,根据采样率来决定当前链路是否要采样
120+
context = getOrCreate(operationName, false);
121+
span = context.createEntrySpan(operationName);
122+
}
123+
return span;
124+
}
125+
126+
```
127+
createEntrySpan()方法处理逻辑如下:
128+
129+
- 如果ContextCarrier不为空,强制采样,获取或创建TracingContext,创建EntrySpan,从ContextCarrier将数据提取出来放到TracingContext中
130+
- 如果ContextCarrier为空,不需要强制采样,根据采样率来决定当前链路是否要采样
131+
132+
当创建EntrySpan时有两种情况:
133+
134+
- 请求刚刚进来处于链路的第一个TraceSegment上,如上图左边的TraceSegment,此时不需要强制采样,根据采样率来决定当前链路是否要采样
135+
- 如上图右边的TraceSegment,左边TraceSegment的ExitSpan调用了右边的TraceSegment,上一个TraceSegment的数据需要传递到下一个TraceSegment,下游调用extract()方法从ContextCarrier将数据提取出来放到TracingContext中。此时一定要强制采样,因为链路中的前置TraceSegment已经存在,如果不强制采样,尝试采样(SamplingService的trySampling()方法)返回false,链路就断开了
136+
137+
ContextManager中创建LocalSpan和ExitSpan的方法:
138+
```
139+
public class ContextManager implements BootService {
140+
141+
public static AbstractSpan createLocalSpan(String operationName) {
142+
operationName = StringUtil.cut(operationName, OPERATION_NAME_THRESHOLD);
143+
AbstractTracerContext context = getOrCreate(operationName, false);
144+
return context.createLocalSpan(operationName);
145+
}
146+
147+
/**
148+
* 调用下一个受SkyWalking监控的进程,必须要ContextCarrier 比如调用Java服务
149+
*
150+
* @param operationName
151+
* @param carrier
152+
* @param remotePeer
153+
* @return
154+
*/
155+
public static AbstractSpan createExitSpan(String operationName, ContextCarrier carrier, String remotePeer) {
156+
if (carrier == null) {
157+
throw new IllegalArgumentException("ContextCarrier can't be null.");
158+
}
159+
operationName = StringUtil.cut(operationName, OPERATION_NAME_THRESHOLD);
160+
AbstractTracerContext context = getOrCreate(operationName, false);
161+
AbstractSpan span = context.createExitSpan(operationName, remotePeer);
162+
context.inject(carrier);
163+
return span;
164+
}
165+
166+
/**
167+
* 不需要往后传播的ExitSpan 比如调用MySQL
168+
*
169+
* @param operationName
170+
* @param remotePeer
171+
* @return
172+
*/
173+
public static AbstractSpan createExitSpan(String operationName, String remotePeer) {
174+
operationName = StringUtil.cut(operationName, OPERATION_NAME_THRESHOLD);
175+
AbstractTracerContext context = getOrCreate(operationName, false);
176+
return context.createExitSpan(operationName, remotePeer);
177+
}
178+
179+
```
180+
181+
182+
183+

0 commit comments

Comments
 (0)