前言
原理图
- 通过ServiceManager.boot[加载,准备,启动,完成]实现所有BootService的初始化和运行前准备工作
字典相关bootService如下:
类名 | 作用 |
---|
ServiceAndEndpointRegisterClient | 与服务端进行定时注册,基于服务端响应更新本地字典信息 |
源码分析一ServiceManager
- 通过SPI加载所有bootService并完成加载service集合的生命周期调用
- loadAllServices通过spi加载bootService同时处理DefaultImplementor和OverrideImplementor注解
- DefaultImplementor注解: 目标类名为bootService自身
- OverrideImplementor注解: 目标类名为bootService上OverrideImplementor注解指定的类名
public enum ServiceManager {
单例模式
INSTANCE;
spi加载的bootservice集合
private Map<Class, BootService> bootedServices = Collections.emptyMap();
引导程序入口
public void boot() {
基于java原生SPI加载/resources/META-INF.services/org.skywalking.apm.agent.core.boot.BootService
bootedServices = loadAllServices();
遍历处理service的prepare
prepare();
遍历处理service的boot
startup();
遍历处理service的onComplete
onComplete();
}
正文一服务注册发现
源码分析一ServiceAndEndpointRegisterClient生命周期
- prepare方法中注册grpc事件监听器(回调statusChanged)
- boot启动ServiceAndEndpointRegisterClient核心任务调度,每3秒执行一次,负责服务注册,数据同步,字典维护
- 如果服务端返回ServiceResetCommandExecutor则coolDownStartTime为当前时间
- 则10分钟后执行服务注册等逻辑
- SERVICE_ID还不存在则先向服务注册service
- SERVICE_INSTANCE_ID还不存在 则先向服务端注册SERVICE_INSTANCE
- 发送心跳
- 处理心跳Commands回调,[实际只有ServiceResetCommandExecutor有处理逻辑]
- 维护NetworkAddressDictionary和EndpointNameDictionary字典
public class ServiceAndEndpointRegisterClient implements BootService, Runnable, GRPCChannelListener {
private static final ILog logger = LogManager.getLogger(ServiceAndEndpointRegisterClient.class);
private static String INSTANCE_UUID;
private static List<KeyStringValuePair> SERVICE_INSTANCE_PROPERTIES;
private volatile GRPCChannelStatus status = GRPCChannelStatus.DISCONNECT;
private volatile RegisterGrpc.RegisterBlockingStub registerBlockingStub;
private volatile ServiceInstancePingGrpc.ServiceInstancePingBlockingStub serviceInstancePingStub;
private volatile ScheduledFuture<?> applicationRegisterFuture;
private volatile long coolDownStartTime = -1;
@Override
public void statusChanged(GRPCChannelStatus status) {
grpc事件触发修改stub服务
if (GRPCChannelStatus.CONNECTED.equals(status)) {
Channel channel = ServiceManager.INSTANCE.findService(GRPCChannelManager.class).getChannel();
registerBlockingStub = RegisterGrpc.newBlockingStub(channel);
serviceInstancePingStub = ServiceInstancePingGrpc.newBlockingStub(channel);
} else {
registerBlockingStub = null;
serviceInstancePingStub = null;
}
this.status = status;
}
@Override
public void prepare() throws Throwable {
向grpc通道注册grpc事件监听器
ServiceManager.INSTANCE.findService(GRPCChannelManager.class).addChannelListener(this);
INSTANCE_UUID = StringUtil.isEmpty(Config.Agent.INSTANCE_UUID) ? UUID.randomUUID().toString()
.replaceAll("-", "") : Config.Agent.INSTANCE_UUID;
SERVICE_INSTANCE_PROPERTIES = new ArrayList<KeyStringValuePair>();
for (String key : Config.Agent.INSTANCE_PROPERTIES.keySet()) {
SERVICE_INSTANCE_PROPERTIES.add(KeyStringValuePair.newBuilder()
.setKey(key).setValue(Config.Agent.INSTANCE_PROPERTIES.get(key)).build());
}
}
@Override
public void boot() throws Throwable {
启动service执行任务
applicationRegisterFuture = Executors
.newSingleThreadScheduledExecutor(new DefaultNamedThreadFactory("ServiceAndEndpointRegisterClient"))
.scheduleAtFixedRate(new RunnableWithExceptionProtection(this, new RunnableWithExceptionProtection.CallbackWhenException() {
@Override
public void handle(Throwable t) {
logger.error("unexpected exception.", t);
每三秒执行一次调度
}
}), 0, Config.Collector.APP_AND_SERVICE_REGISTER_CHECK_INTERVAL, TimeUnit.SECONDS);
}
@Override
public void onComplete() throws Throwable {
}
@Override
public void shutdown() throws Throwable {
applicationRegisterFuture.cancel(true);
}
@Override
public void run() {
logger.debug("ServiceAndEndpointRegisterClient running, status:{}.", status);
if (coolDownStartTime > 0) {
final long coolDownDurationInMillis = TimeUnit.MINUTES.toMillis(Config.Agent.COOL_DOWN_THRESHOLD);
服务端返回ServiceResetCommandExecutor则执行10分钟hold
if (System.currentTimeMillis() - coolDownStartTime < coolDownDurationInMillis) {
logger.warn("The agent is cooling down, won't register itself");
return;
} else {
超过10分钟后则允许重新注册
logger.warn("The agent is re-registering itself to backend");
}
}
coolDownStartTime = -1;
boolean shouldTry = true;
while (GRPCChannelStatus.CONNECTED.equals(status) && shouldTry) {
shouldTry = false;
try {
SERVICE_ID还不存在则先向服务注册service 由于定时调度存在,如果SERVICE_ID不存在则轮询请求服务端
if (RemoteDownstreamConfig.Agent.SERVICE_ID == DictionaryUtil.nullValue()) {
if (registerBlockingStub != null) {
ServiceRegisterMapping serviceRegisterMapping = registerBlockingStub.withDeadlineAfter(GRPC_UPSTREAM_TIMEOUT, TimeUnit.SECONDS).doServiceRegister(
Services.newBuilder().addServices(Service.newBuilder().setServiceName(Config.Agent.SERVICE_NAME)).build());
if (serviceRegisterMapping != null) {
for (KeyIntValuePair registered : serviceRegisterMapping.getServicesList()) {
if (Config.Agent.SERVICE_NAME.equals(registered.getKey())) {
更新自己的serviceId
RemoteDownstreamConfig.Agent.SERVICE_ID = registered.getValue();
shouldTry = true;
}
}
}
}
} else {
if (registerBlockingStub != null) {
SERVICE_INSTANCE_ID还不存在 则先向服务端注册SERVICE_INSTANCE
if (RemoteDownstreamConfig.Agent.SERVICE_INSTANCE_ID == DictionaryUtil.nullValue()) {
ServiceInstanceRegisterMapping instanceMapping = registerBlockingStub.withDeadlineAfter(GRPC_UPSTREAM_TIMEOUT, TimeUnit.SECONDS)
.doServiceInstanceRegister(ServiceInstances.newBuilder()
.addInstances(
ServiceInstance.newBuilder()
.setServiceId(RemoteDownstreamConfig.Agent.SERVICE_ID)
.setInstanceUUID(INSTANCE_UUID)
.setTime(System.currentTimeMillis())
.addAllProperties(OSUtil.buildOSInfo())
.addAllProperties(SERVICE_INSTANCE_PROPERTIES)
).build());
for (KeyIntValuePair serviceInstance : instanceMapping.getServiceInstancesList()) {
if (INSTANCE_UUID.equals(serviceInstance.getKey())) {
int serviceInstanceId = serviceInstance.getValue();
if (serviceInstanceId != DictionaryUtil.nullValue()) {
RemoteDownstreamConfig.Agent.SERVICE_INSTANCE_ID = serviceInstanceId;
RemoteDownstreamConfig.Agent.INSTANCE_REGISTERED_TIME = System.currentTimeMillis();
}
}
}
} else {
3秒一次发送心跳
final Commands commands = serviceInstancePingStub.withDeadlineAfter(GRPC_UPSTREAM_TIMEOUT, TimeUnit.SECONDS)
.doPing(ServiceInstancePingPkg.newBuilder()
.setServiceInstanceId(RemoteDownstreamConfig.Agent.SERVICE_INSTANCE_ID)
.setTime(System.currentTimeMillis())
.setServiceInstanceUUID(INSTANCE_UUID)
.build());
同步NetworkAddress并更新本地字典
NetworkAddressDictionary.INSTANCE.syncRemoteDictionary(registerBlockingStub.withDeadlineAfter(GRPC_UPSTREAM_TIMEOUT, TimeUnit.SECONDS));
同步EndpointName并更新本地字典 [EndpointName来源于span创建时业务侧定义的operationName]
EndpointNameDictionary.INSTANCE.syncRemoteDictionary(registerBlockingStub.withDeadlineAfter(GRPC_UPSTREAM_TIMEOUT, TimeUnit.SECONDS));
ServiceManager.INSTANCE.findService(CommandService.class).receiveCommand(commands);
}
}
}
} catch (Throwable t) {
logger.error(t, "ServiceAndEndpointRegisterClient execute fail.");
ServiceManager.INSTANCE.findService(GRPCChannelManager.class).reportError(t);
}
}
}
public void coolDown() {
this.coolDownStartTime = System.currentTimeMillis();
}
}
总结
- 通过serviceManager加载启动主动BootService
- ServiceAndEndpointRegisterClient负责服务和服务实例注册,地址和端点同步,本地字典维护以及心跳请求的逻辑