源码角度了解Skywalking之Skywalking是如何
源码角度了解Skywalking之Skywalking是如何进行JVM监控的
大家都知道Skywalking可以监控Java的JVM情况,包括垃圾回收情况等等,那么它是怎么实现的呢?今天就带大家一探究竟。
通过前几篇的文章我们知道,Skywalking启动的时候,会加载各种BootService实现类,而有关JVM的BootService实现类就是JVMServiceJVMService
JVMService可以看做一个定时器,它收集JVMcpu、内存、内存池和gc信息等等参数,并将收集到的信息通过GRPCChannelManager提供的通道发送给Collector,GRPCChannelManager这个类我们在上篇文章我们就进行了介绍,主要是用来建立连接管理通道的
JVMService实现BootService接口和Runnable接口
我们按照调用方法的顺序分析一下吧prepare()方法
JVMService的prepare()方法:publicstaticintBUFFERSIZE6010;publicvoidprepare()throwsThrowable{queuenewLinkedBlockingQueueJVMMetric(Config。Jvm。BUFFERSIZE);sendernewSender();ServiceManager。INSTANCE。findService(GRPCChannelManager。class)。addChannelListener(sender);}复制代码
准备阶段就是创建一个LinkedBlockingQueue类型的阻塞队列,队列大小为600,这个队列保存的是JVMMetric对象,然后创建了一个Sender对象,找到GRPCChannelManager对象,并把Sender对象加入监听类中。boot()方法
JVMService的boot()方法:publicvoidboot()throwsThrowable{collectMetricFutureExecutors。newSingleThreadScheduledExecutor(newDefaultNamedThreadFactory(JVMServiceproduce))。scheduleAtFixedRate(newRunnableWithExceptionProtection(this,newRunnableWithExceptionProtection。CallbackWhenException(){Overridepublicvoidhandle(Throwablet){logger。error(JVMServiceproducesmetricsfailure。,t);}}),0,1,TimeUnit。SECONDS);sendMetricFutureExecutors。newSingleThreadScheduledExecutor(newDefaultNamedThreadFactory(JVMServiceconsume))。scheduleAtFixedRate(newRunnableWithExceptionProtection(sender,newRunnableWithExceptionProtection。CallbackWhenException(){Overridepublicvoidhandle(Throwablet){logger。error(JVMServiceconsumesanduploadfailure。,t);}}),0,1,TimeUnit。SECONDS);}复制代码
boot()方法中定义两个定时线程池每隔一秒创建一个线程,一个是生产线程,一个是消费线程,生产者的逻辑对应JVMService的run()方法,而消费者的逻辑在Sender的run()方法中run()方法
JVMService的run()方法:publicvoidrun(){if(RemoteDownstreamConfig。Agent。SERVICEID!DictionaryUtil。nullValue()RemoteDownstreamConfig。Agent。SERVICEINSTANCEID!DictionaryUtil。nullValue()){longcurrentTimeMillisSystem。currentTimeMillis();try{JVMMetric。BuilderjvmBuilderJVMMetric。newBuilder();jvmBuilder。setTime(currentTimeMillis);jvmBuilder。setCpu(CPUProvider。INSTANCE。getCpuMetric());jvmBuilder。addAllMemory(MemoryProvider。INSTANCE。getMemoryMetricList());jvmBuilder。addAllMemoryPool(MemoryPoolProvider。INSTANCE。getMemoryPoolMetricsList());jvmBuilder。addAllGc(GCProvider。INSTANCE。getGCList());JVMMetricjvmMetricjvmBuilder。build();if(!queue。offer(jvmMetric)){queue。poll();queue。offer(jvmMetric);}}catch(Exceptione){logger。error(e,CollectJVMinfofail。);}}}复制代码
run()中的逻辑主要是创建JVMMetric对象,创建完成后放入队列中,从准备方法中我们知道队列大小设置是600,当队列满的时候,会取出最久的那个淘汰掉,然后放入新的JVMMetric对象到队尾。
从组装JVMMetric对象的过程我们可以看到,JVMMetric对象中包含了当前时间,CPU指标、内存指标还有垃圾回收指标。这三个指标的获取都是利用枚举实现的单例模式,然后getGCList()方法中调用了GCModule抽象类的getGCList()方法,在获取新生代和老年代垃圾回收器名称的时候定义了抽象方法,具体逻辑每个垃圾回收器重写各自的抽象方法,这是模板方法的体现Senderrun()方法:
Sender对象作为消费者,它的功能就是通过drainTo()方法来把队列中的数据转移到buffer集合中,然后发送到Collector中。总结
这篇文章我们讲了Skywalking是怎么进行JVM参数收集的,主要涉及到的类是JVMService,它的类定义了一个LinkedBlockingQueue类型的阻塞队列,长度是600,然后启动方法中启动了两个定时线程池创建了生产者JVMService线程和消费者Sender线程,JVMService作为生产者收集CPU、内存、垃圾回收信息等放入队列,Sender作为消费者从队列获取到所有JVM信息发送给Collector:heart:感谢大家
如果你觉得这篇内容对你挺有有帮助的话帮忙点点关注!