所有的代码分析基于pinpoint 1.6.2
在上篇文章agent追踪
已经分析到部分代码,这里进行一个详细的介绍。
一、入口####
在每次追踪完毕后,需要调用这个方法trace.traceBlockEnd()
,此方法内部使用storage.store(spanEvent)
来持久化SpanEvent。
这里使用的storage是由StorageFactory创建的,而StorageFactory的实现也有好多,如下:
而配置文件默认的是profiler.io.buffering.enable=true
,所以使用的是BufferedStorageFactory
。
跟Storage相关的配置有两个:
# 启用BufferedStorageFactory
profiler.io.buffering.enable=true
# How many spans to store if buffering enabled. 即缓存多少个才发送
profiler.io.buffering.buffersize=20
另外提一点,由于Store是附着于trace对象上的,而trace对象附着于ThreadLocal,故不存在线程安全问题
二、DataSender
Storage持有DataSender对象,DataSender有很多实现:
有一些在1.agent启动
中提到过,用于发送Agent描述和Agent监控信息。
这里,发送span使用的是DataSender是哪个呢?
从ApplicationContextModule
的配置中可以看到:
bind(DataSender.class).annotatedWith(SpanDataSender.class)
.toProvider(UdpSpanDataSenderProvider.class).in(Scopes.SINGLETON);
即使用的是UdpDataSender,其相关配置及解释如下:
# socket发送缓冲区大小(SO_SNDBUF),默认 1024 * 64 * 16
# profiler.spandatasender.socket.sendbuffersize=1048576
# socket读取超时时间(SO_TIMEOUT),默认1000 * 3
# profiler.spandatasender.socket.timeout=3000
# 暂未使用
profiler.spandatasender.chunk.size=16384
# 默认使用OIO方式发送
# profiler.spandatasender.socket.type=OIO
其发送的实现就是使用DatagramSocket直接发送。
但是,直接调用UdpDataSender.send
时,并不会直接发送数据,其内部使用了AsyncQueueingExecutor
来异步发送数据。
三、AsyncQueueingExecutor
字如其名,就是使用阻塞队列实现批量发送功能。
相关配置如下:
# Capacity of the SpanDataSender write queue. 即发送span是进行排队的,队列长度超过最大值后则拒绝发送
profiler.spandatasender.write.queue.size=5120
默认每次发送10个对象,通过回掉DataSender实现具体发送,回掉方法参见AbstractDataSender
:
final AsyncQueueingExecutor<Object> executor = new AsyncQueueingExecutor<Object>(queueSize, executorName);
executor.setListener(new AsyncQueueingExecutorListener<Object>() {
@Override
public void execute(Collection<Object> messageList) {
sendPacketN(messageList);
}
@Override
public void execute(Object message) {
sendPacket(message);
}
});
到这里,整个agent的数据和通信相关代码分析完毕