skywalking agent 初始化, 数据上报

skywalking agent 初始化

核心概念

  • BootService: 启动各个grpc客户端接口, 包含完整生命周期, prepare -> boot -> onComplete -> shutdown, 包含 TraceSegmentServiceClient, ServiceManagementClient 等等
  • ServiceManager: 管理各种 BootService

入口类: SkyWalkingAgent, 通过使用 javaagent 的引导 SkyWalkingAgent#premain 方法进入, 并调用 ServiceManager.INSTANCE.boot(); 来启动各种 BootService

public static void premain(String agentArgs, Instrumentation instrumentation) throws PluginException {
    ...
    try {
    // 简单的调用各个booService 进行 prepare -> boot -> onComplete 操作
        ServiceManager.INSTANCE.boot();
    } catch (Exception e) {
        LOGGER.error(e, "Skywalking agent boot failure.");
    }
    // 注册关闭钩子
    Runtime.getRuntime()
            .addShutdownHook(new Thread(ServiceManager.INSTANCE::shutdown, "skywalking service shutdown thread"));
    ...
}

java agent

使用 javaagent 需要几个步骤:

  1. 定义一个 MANIFEST.MF 文件,必须包含 Premain-Class 选项,通常也会加入Can-Redefine-Classes 和 Can-Retransform-Classes 选项。
  2. 创建一个Premain-Class 指定的类,类中包含 premain 方法,方法逻辑由用户自己确定。
  3. 将 premain 的类和 MANIFEST.MF 文件打成 jar 包。
  4. 使用参数 -javaagent:/jar包路径=[agentArgs 参数] 启动要代理的方法。

==premain== 方法用于 main 执行之前的预处理, 用于类的增强

字段如下描述, args 参数通过 -javaagent:xxx.jar==yyy 传入字符串, 如果需要修改字节码, 必须使用方式1, JVM 会优先加载 1 签名的方法,加载成功忽略 2,如果1 没有,加载 2 方法

// 1 
public static void premain(String args, Instrumentation instrumentation)
// 2
public static void premain(String args)

探针 , 服务端的通信流程

上报信息分为 "注册通信" , "数据上报" 两部分

agent 包中和服务端的相关 grpc 通信服务类

  • EventReportServiceClient: 服务事件上报(服务启动, 关闭)
  • LogReportServiceClient: 日志上报
  • ServiceManagementClient: 服务实例信息, 心跳上报
  • TraceSegmentServiceClient: TraceSegment 上报
  • JVMMetricsSender: jvm 信息上报

注册通信

用于上报服务的相关信息, 包含 服务名称, 实例信息, 核心逻辑在 ServiceManagementClient#run,

心跳定时器初始化在 prepare 中完成, 30 秒 执行一次

@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
    );
}

上报主体逻辑, 心跳部分 keepAlive 每30秒执行1次, 而实例信息上报 30(collector.heartbeat_period) * 10(collector.properties_report_period_factor) 一次, 这有效避免了服务端信息丢失时, 无法收集的情况

if (Math.abs(sendPropertiesCounter.getAndAdd(1)) % Config.Collector.PROPERTIES_REPORT_PERIOD_FACTOR == 0) {
    managementServiceBlockingStub
        .withDeadlineAfter(GRPC_UPSTREAM_TIMEOUT, TimeUnit.SECONDS)
        .reportInstanceProperties(InstanceProperties.newBuilder()
                                                    // 服务名称则是通过 agent.config 配置文件写入
                                                    .setService(Config.Agent.SERVICE_NAME)
                                                    // 实例名称如果没配置的话, 则会在 ServiceInstanceGenerator#prepare 中自动生成
                                                    .setServiceInstance(Config.Agent.INSTANCE_NAME)
                                                    // 服务属性通过 agent.config 配置文件写入
                                                    .addAllProperties(OSUtil.buildOSInfo(
                                                        Config.OsInfo.IPV4_LIST_SIZE))
                                                    .addAllProperties(SERVICE_INSTANCE_PROPERTIES)
                                                    .addAllProperties(LoadedLibraryCollector.buildJVMInfo())
                                                    .build());
} else {
    final Commands commands = managementServiceBlockingStub.withDeadlineAfter(
        GRPC_UPSTREAM_TIMEOUT, TimeUnit.SECONDS
    ).keepAlive(InstancePingPkg.newBuilder()
                               .setService(Config.Agent.SERVICE_NAME)
                               .setServiceInstance(Config.Agent.INSTANCE_NAME)
                               .build());

    ServiceManager.INSTANCE.findService(CommandService.class).receiveCommand(commands);
}

实例属性的 Protobuf 消息定义

message InstanceProperties {
    string service = 1;
    string serviceInstance = 2;
    repeated KeyStringValuePair properties = 3;
}

message KeyStringValuePair {
    string key = 1;
    string value = 2;
}

// grpc 服务定义
service ManagementService {
    // 上报实例消息
    rpc reportInstanceProperties (InstanceProperties) returns (Commands) {
    }

    // 保持心跳
    rpc keepAlive (InstancePingPkg) returns (Commands) {

    }
}

Endpoint收集部分呢, 8.7.0 未找到书中提及的 Endpoint 发送, 看起来是和 Trace 一起发送解析了, 这块到服务端再看下

jvm 信息上报

主体代码入口 JVMService#run, 执行流程

  1. JVMService#boot 中定义了名称为 JVMService-produce 的 Executor(每 1 秒执行一次) , 对应生产者
  2. 定义 JVMService-consume 的 Executor(每 1 秒执行一次) , 类为 JVMMetricsSender, 对应消费者
  3. JVMService#run 收集 jvm 信息 封装成 JVMMetric, 塞到 JVMMetricsSender#LinkedBlockingQueue 中完成生产行为
  4. JVMMetricsSender#run 将消息通过 grpc发送到服务端, 完成消费行为

数据上报

TraceSegment 的上报通过 TraceSegmentServiceClient 完成, 这块上个部分已大体有说明了, 这里主要关注下 初始化部分

 @Override
public void boot() {
    lastLogTime = System.currentTimeMillis();
    segmentUplinkedCounter = 0;
    segmentAbandonedCounter = 0;
    // 初始化, channel 为 5, buffer 为300 的 DataCarrier, 使用失败重试策略
    carrier = new DataCarrier<>(CHANNEL_SIZE, BUFFER_SIZE, BufferStrategy.IF_POSSIBLE);
    // 初始化 ConsumerThread 进行 TraceSegment 发送
    carrier.consume(this, 1);
}

@Override
public void onComplete() {
    // 添加监听器到 TracingContext, 用于 Trace 完成时通知执行 consume
    TracingContext.ListenerManager.add(this);
}

@Override
public void shutdown() {
    TracingContext.ListenerManager.remove(this);
    carrier.shutdownConsumers();
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,463评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,868评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,213评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,666评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,759评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,725评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,716评论 3 415
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,484评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,928评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,233评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,393评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,073评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,718评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,308评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,538评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,338评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,260评论 2 352