SkyWalking源码-- Agent 链路数据发送

459 阅读4分钟

本文基于 SkyWalking-Java-agent 8.15.0 版本

客户端信息上报

ServiceManagementClient

服务管理客户端,作用主要有

  • 将当前 Agent Client 的基本信息汇报给 OAP
  • 和 OAP 保持心跳

image.png

共实现了三个接口

  • BootService:agent服务接口
  • GRPCChannelListener:gRpc 的Channel监听接口
  • Runnalbe:JDK 的 Runnable 接口

一个注解:@DefaultImplementor 默认实现

GRPCChannelListener

实现 GRPCChannelListenerstatusChanged 状态改变方法,当gRpc Channel 的连接状态(GRPCChannelStatus)发生变化时,会通过回调该方法,实现状态变更的消息通知。

@Override  
public void statusChanged(GRPCChannelStatus status) {  
    if (GRPCChannelStatus.CONNECTED.equals(status)) {  
        // 找到 GRPCChannelManager 服务,拿到网络连接  
        Channel channel = ServiceManager.INSTANCE.findService(GRPCChannelManager.class).getChannel();  
        // grpc 的 stub 可以理解为 protobuf 中定义的 XxxService  
        managementServiceBlockingStub = ManagementServiceGrpc.newBlockingStub(channel);  
    } else {  
        managementServiceBlockingStub = null;  
    }  
    this.status = status;  
}  
  

BootService

实现 BootService 生命周期不同阶段:

  • prepare(准备阶段)
    • 将自身添加到 Channel 监听器里
    • 把配置文件中的 Agent Client 信息放入集合,等待发送
  • boot(启动阶段)
    • 创建心跳定时任务的单线程周期性线程池
    • Config.Collector.HEARTBEAT_PERIOD:心跳周期,默认 30s
  • onComplete(启动完成阶段)
    • 不做任何操作
  • shutdown(关闭阶段)
    • 取消心跳
    • 基于线程的中断机制:
      • 尝试取消执行此任务。
      • 如果任务已经完成、已经取消或由于其他原因无法取消,则此尝试将失败。
      • 如果成功,并且在调用cancel时此任务尚未启动,则此任务不应运行。
      • 如果任务已经启动,那么mayinterruptirunning参数决定是否应该中断执行该任务的线程以尝试停止该任务。
      • 在此方法返回后,对isDone的后续调用将始终返回true。如果此方法返回true,后续对isCancelled的调用将始终返回true
@Override  
public void prepare() {  
    // 将自身添加到 Channel 监听器里  
    ServiceManager.INSTANCE.findService(GRPCChannelManager.class).addChannelListener(this);  
    // 把配置文件中的 Agent Client 信息放入集合,等待发送  
    SERVICE_INSTANCE_PROPERTIES = InstanceJsonPropertiesUtil.parseProperties();  
}  
  
@Override  
public void boot() {  
    // 心跳  
    heartbeatFuture = Executors.newSingleThreadScheduledExecutor(  
        new DefaultNamedThreadFactory("ServiceManagementClient")  
    ).scheduleAtFixedRate(  
        new RunnableWithExceptionProtection(  
            this,  
            t -> LOGGER.error("unexpected exception.", t)  
        ), 0, Config.Collector.HEARTBEAT_PERIOD,  
        TimeUnit.SECONDS  
    );  
}
@Override  
public void onComplete() {  
}  
  
@Override  
public void shutdown() {  
    // 取消心跳
    heartbeatFuture.cancel(true);  
}

采集信息上传

image.png

TraceSegmentServiceClient

  • 将 TraceSegment 发送到 OAP
  • 采用 gRpc 将采集到的信息上传到 gRpc 服务端
  • 每次发送必须强制等待所有数据都发送完毕

image.png

共实现了四个接口

  • TracingContextListener:Trace 链路上下文监听
  • BootService:agent服务接口
  • GRPCChannelListener:gRpc 的Channel监听接口
  • IConsumer<T>:consumer 接口

一个注解:@DefaultImplementor 默认实现

TracingContextListener

实现 TracingContextListener 的 afterFinished 方法,

@Override  
public void afterFinished(TraceSegment traceSegment) {  
    if (traceSegment.isIgnore()) {  
        return;  
    }  
    if (!carrier.produce(traceSegment)) {  
        if (LOGGER.isDebugEnable()) {  
            LOGGER.debug("One trace segment has been abandoned, cause by buffer is full.");  
        }  
    }  
}

GRPCChannelListener

实现 GRPCChannelListenerstatusChanged 状态改变方法

@Override  
public void statusChanged(GRPCChannelStatus status) {  
    if (CONNECTED.equals(status)) {  
        Channel channel = ServiceManager.INSTANCE.findService(GRPCChannelManager.class).getChannel();  
        serviceStub = TraceSegmentReportServiceGrpc.newStub(channel);  
    }  
    this.status = status;  
}

BootService

实现 BootService 生命周期不同阶段: 其中:

  • lastLogTime:上一次打印传输 TraceSegment 情况的日志的时间
  • segmentUplinkedCounter:成功发送的 TraceSegment 数量
  • segmentAbandonedCounter:因网络原因丢弃的 TraceSegment 数量
  • carrier:数据缓存
@Override  
public void prepare() {  
    ServiceManager.INSTANCE.findService(GRPCChannelManager.class).addChannelListener(this);  
}  
  
@Override  
public void boot() {  
    // 上一次打印传输 TraceSegment 情况的日志的时间
    lastLogTime = System.currentTimeMillis(); 
    // 成功发送的 TraceSegment 数量
    segmentUplinkedCounter = 0;  
    // 因网络原因丢弃的 TraceSegment 数量
    segmentAbandonedCounter = 0;  
    // 创建数据缓存
    carrier = new DataCarrier<>(CHANNEL_SIZE, BUFFER_SIZE, BufferStrategy.IF_POSSIBLE);  
    carrier.consume(this, 1);  
}  
  
@Override  
public void onComplete() {  
    TracingContext.ListenerManager.add(this);  
}  
  
@Override  
public void shutdown() {  
    TracingContext.ListenerManager.remove(this);  
    carrier.shutdownConsumers();  
}

IConsumer

实现 IConsumer 接口

@Override  
public void consume(List<TraceSegment> data) {  
    if (CONNECTED.equals(status)) {  
        final GRPCStreamServiceStatus status = new GRPCStreamServiceStatus(false);  
        StreamObserver<SegmentObject> upstreamSegmentStreamObserver = serviceStub.withDeadlineAfter(  
            Config.Collector.GRPC_UPSTREAM_TIMEOUT, TimeUnit.SECONDS  
        ).collect(new StreamObserver<Commands>() {  
            @Override  
            public void onNext(Commands commands) {  
                ServiceManager.INSTANCE.findService(CommandService.class)  
                                        .receiveCommand(commands);  
            }  

            @Override  
            public void onError(  
                Throwable throwable) {  
                status.finished();  
                if (LOGGER.isErrorEnable()) {  
                    LOGGER.error(  
                        throwable,  
                        "Send UpstreamSegment to collector fail with a grpc internal exception."  
                    );  
                }  
                ServiceManager.INSTANCE  
                    .findService(GRPCChannelManager.class)  
                    .reportError(throwable);  
            }  

            @Override  
            public void onCompleted() {  
                status.finished();  
                }  
            });  

        try {  
            for (TraceSegment segment : data) {  
                // 将 segment 对象转成 Protobuf对象
                SegmentObject upstreamSegment = segment.transform();  
                upstreamSegmentStreamObserver.onNext(upstreamSegment);  
            }  
        } catch (Throwable t) {  
            LOGGER.error(t, "Transform and send UpstreamSegment to collector fail.");  
        }  

        upstreamSegmentStreamObserver.onCompleted();  

        // 强制等待所有的 TraceSegment 都发送完成  
        status.wait4Finish();  
        // 上报的数量
        segmentUplinkedCounter += data.size();  
    } else {  
        // 抛弃的数量
        segmentAbandonedCounter += data.size();  
    }  

    printUplinkStatus();  
}

KafkaTraceSegmentServiceClient

  • 采用 Kafka 客户端将采集到的信息上传到 Kafka
  • 每条数据包装为一条 Kafka 消息同步发送

image.png

共实现了四个接口

  • TracingContextListener:Trace 链路上下文监听
  • BootService:agent服务接口
  • KafkaConnectionStatusListener:kafka 的连接状态监听接口
  • IConsumer<T>:consumer 接口

一个注解:@OverrideImplementor(TraceSegmentServiceClient.class) 覆盖实现

TracingContextListener

实现 TracingContextListener 的 afterFinished 方法

@Override  
public void afterFinished(final TraceSegment traceSegment) {  
    if (LOGGER.isDebugEnable()) {  
        LOGGER.debug("Trace segment reporting, traceId: {}", traceSegment.getTraceSegmentId());  
    }  

    if (traceSegment.isIgnore()) {  
        LOGGER.debug("Trace[TraceId={}] is ignored.", traceSegment.getTraceSegmentId());  
        return;  
    }  
    carrier.produce(traceSegment);  
}

KafkaConnectionStatusListener

实现 KafkaConnectionStatusListenerstatusChanged 状态改变方法

@Override  
public void onStatusChanged(KafkaConnectionStatus status) {  
    if (status == KafkaConnectionStatus.CONNECTED) {  
        producer = ServiceManager.INSTANCE.findService(KafkaProducerManager.class).getProducer();  
    }  
}

BootService

实现 BootService 生命周期不同阶段:

@Override  
public void prepare() {  
    KafkaProducerManager producerManager = ServiceManager.INSTANCE.findService(KafkaProducerManager.class);  
    producerManager.addListener(this);  
    topic = producerManager.formatTopicNameThenRegister(KafkaReporterPluginConfig.Plugin.Kafka.TOPIC_SEGMENT);  
}  
  
@Override  
public void boot() {  
    carrier = new DataCarrier<>(CHANNEL_SIZE, BUFFER_SIZE, BufferStrategy.IF_POSSIBLE);  
    carrier.consume(this, 1);  
}  
  
@Override  
public void onComplete() {  
    TracingContext.ListenerManager.add(this);  
}  
  
@Override  
public void shutdown() {  
    TracingContext.ListenerManager.remove(this);  
    carrier.shutdownConsumers();  
}

IConsumer

实现 IConsumer 接口

@Override  
public void consume(final List<TraceSegment> data) {  
    if (producer == null) {  
        return;  
    }  
    data.forEach(traceSegment -> {  
        // 将 segment 对象转成 Protobuf对象
        SegmentObject upstreamSegment = traceSegment.transform();  
        ProducerRecord<String, Bytes> record = new ProducerRecord<>(  
            topic,  
            upstreamSegment.getTraceSegmentId(),  
            Bytes.wrap(upstreamSegment.toByteArray())  
        );  
        producer.send(record, (m, e) -> {  
            if (Objects.nonNull(e)) {  
                LOGGER.error("Failed to report TraceSegment.", e);  
            }  
        });  
    });  
}