目录
心跳检查任务类开胃菜(ClientBeatCheckTaskV2)
真正的心跳检查任务 InstanceBeatCheckTask
心跳检查任务初始化
public class IpPortBasedClient extends AbstractClient {
....
/**
* Init client.
*/
public void init() {
if (ephemeral) {
//这里开始创建心跳检查任务并加入定时任务执行
beatCheckTask = new ClientBeatCheckTaskV2(this);
HealthCheckReactor.scheduleCheck(beatCheckTask);
} else {
healthCheckTaskV2 = new HealthCheckTaskV2(this);
HealthCheckReactor.scheduleCheck(healthCheckTaskV2);
}
}
....
}
心跳检查任务类开胃菜(ClientBeatCheckTaskV2)
public class ClientBeatCheckTaskV2 extends AbstractExecuteTask implements BeatCheckTask, NacosHealthCheckTask {
// 客户端对象
private final IpPortBasedClient client;
//就是 client.getResponsibleId
private final String taskId;
//任务拦截器链
private final InstanceBeatCheckTaskInterceptorChain interceptorChain;
public ClientBeatCheckTaskV2(IpPortBasedClient client) {
this.client = client;
this.taskId = client.getResponsibleId();
//稍后单独解读
this.interceptorChain = InstanceBeatCheckTaskInterceptorChain.getInstance();
}
public GlobalConfig getGlobalConfig() {
return ApplicationUtils.getBean(GlobalConfig.class);
}
@Override
public String taskKey() {
return KeyBuilder.buildServiceMetaKey(client.getClientId(),
String.valueOf(client.isEphemeral()));
}
...
//健康检查
@Override
public void doHealthCheck() {
try {
//轮询该客户端发布的所有服务列表
Collection<Service> services = client.getAllPublishedService();
for (Service each : services) {
//获取服务下的实例信息
HealthCheckInstancePublishInfo instance =
(HealthCheckInstancePublishInfo) client
.getInstancePublishInfo(each);
//拦截器链处理完InstanceBeatCheckTask后执行
// InstanceBeatCheckTask.passIntercept()方法
interceptorChain.doInterceptor(new InstanceBeatCheckTask(client, each,
instance));
}
} catch (Exception e) {
Loggers.SRV_LOG.warn("Exception while processing client beat time out.", e);
}
}
//定时任务的执行入口
@Override
public void run() {
doHealthCheck();
}
@Override
public void passIntercept() {
doHealthCheck();
}
@Override
public void afterIntercept() {
}
}
我们看到执行心跳检查任务是在ClientBeatCheckTaskV2 里面嵌入一个新的InstanceBeatCheckTask任务真正的心跳检查逻辑是在InstanceBeatCheckTask上的拦截器都执行完毕后再执行InstanceBeatCheckTask的passIntercept方法完成一次心跳检查
接下来我们先看InstanceBeatCheckTask再看看他上面的拦截器是什么怎么执行的。
真正的心跳检查任务 InstanceBeatCheckTask
public class InstanceBeatCheckTask implements Interceptable {
private static final List<InstanceBeatChecker> CHECKERS = new LinkedList<>();
//客户端
private final IpPortBasedClient client;
//服务
private final Service service;
//发布的服务
private final HealthCheckInstancePublishInfo instancePublishInfo;
//
// 心跳检查列表
static {
CHECKERS.add(new UnhealthyInstanceChecker());
CHECKERS.add(new ExpiredInstanceChecker());
//使用java spi 扩展机制用户可以再META-INF/services下创建
//InstanceBeatChecker的实现类实现用户自定义扩展
CHECKERS.addAll(NacosServiceLoader.load(InstanceBeatChecker.class));
}
public InstanceBeatCheckTask(IpPortBasedClient client, Service service, HealthCheckInstancePublishInfo instancePublishInfo) {
this.client = client;
this.service = service;
this.instancePublishInfo = instancePublishInfo;
}
//任务上的拦截器执行完毕后逐个拦截器执行
@Override
public void passIntercept() {
for (InstanceBeatChecker each : CHECKERS) {
each.doCheck(client, service, instancePublishInfo);
}
}
@Override
public void afterIntercept() {
}
...
}
心跳检查实际上是一个checker 列表 逐个执行
除了前面2个检查器外,第三个是使用java spi 扩展机制用户可以再META-INF/services下创建
InstanceBeatChecker的实现类实现用户自定义扩展实例的检查机UnhealthyInstanceChecker :检查心跳超时时间
public class UnhealthyInstanceChecker implements InstanceBeatChecker {
@Override
public void doCheck(Client client, Service service, HealthCheckInstancePublishInfo
instance) {
//原来是健康现在是不健康的条件判断
if (instance.isHealthy() && isUnhealthy(service, instance)) {
changeHealthyStatus(client, service, instance);
}
}
//距离上次心跳时间已经超过超时时间
private boolean isUnhealthy(Service service, HealthCheckInstancePublishInfo
instance) {
long beatTimeout = getTimeout(service, instance);
return System.currentTimeMillis() - instance.getLastHeartBeatTime() >
beatTimeout;
}
//从扩展数据中去超时时间(这块不细讲,知道下就行后面学习了InstanceMetadata后就很容易 )
//如果没有取到则设置默认值15s
private long getTimeout(Service service, InstancePublishInfo instance) {
Optional<Object> timeout = getTimeoutFromMetadata(service, instance);
if (!timeout.isPresent()) {
timeout =
Optional.ofNullable(instance.getExtendDatum().、
get(PreservedMetadataKeys.HEART_BEAT_TIMEOUT));
}
return timeout.map(ConvertUtils::toLong).
orElse(Constants.DEFAULT_HEART_BEAT_TIMEOUT);
}
....
//实例健康状态设置为false 并发布服务和客户端变更事件
private void changeHealthyStatus(Client client, Service service,
HealthCheckInstancePublishInfo instance) {
instance.setHealthy(false);
NotifyCenter.publishEvent(new ServiceEvent.ServiceChangedEvent(service));
NotifyCenter.publishEvent(new ClientEvent.ClientChangedEvent(client));
}
}
public class ExpiredInstanceChecker implements InstanceBeatChecker {
@Override
public void doCheck(Client client, Service service, HealthCheckInstancePublishInfo
instance) {
// 过期实例配置 默认是true
boolean expireInstance =
ApplicationUtils.getBean(GlobalConfig.class).isExpireInstance();
if (expireInstance && isExpireInstance(service, instance)) {
deleteIp(client, service, instance);
}
}
//优先从元数据获取deleteiptimeout 参数否则设置默认值30s
//超过deleteiptimeout 时间则代表过期实例
private boolean isExpireInstance(Service service, HealthCheckInstancePublishInfo
instance) {
long deleteTimeout = getTimeout(service, instance);
return System.currentTimeMillis() - instance.getLastHeartBeatTime() >
deleteTimeout;
}
...
private void deleteIp(Client client, Service service, InstancePublishInfo instance) {
//从客户端的服务列表移除该服务
client.removeServiceInstance(service);
NotifyCenter.publishEvent(new
ClientOperationEvent.ClientDeregisterServiceEvent(service,
client.getClientId()));
NotifyCenter.publishEvent(new MetadataEvent.InstanceMetadataEvent(service,
instance.getMetadataId(), true));
}
}
使用spi机制的除了上面的心跳检查器,接下来要解读的拦截器链也同样采用了spi机制
上面再讲到 ClientBeatCheckTaskV2 构造器里面的初始化语句
this.interceptorChain = InstanceBeatCheckTaskInterceptorChain.getInstance();
我们进入代码看一下是怎么实例化的
SPI机制加载拦截器链
public class InstanceBeatCheckTaskInterceptorChain extends AbstractNamingInterceptorChain<InstanceBeatCheckTask> {
private static final InstanceBeatCheckTaskInterceptorChain INSTANCE = new InstanceBeatCheckTaskInterceptorChain();
private InstanceBeatCheckTaskInterceptorChain() {
super(AbstractBeatCheckInterceptor.class);
}
public static InstanceBeatCheckTaskInterceptorChain getInstance() {
return INSTANCE;
}
}
public abstract class AbstractNamingInterceptorChain<T extends Interceptable>
implements NacosNamingInterceptorChain<T> {
private final List<NacosNamingInterceptor<T>> interceptors;
protected AbstractNamingInterceptorChain(Class<? extends NacosNamingInterceptor<T>>
clazz) {
this.interceptors = new LinkedList<>();
//使用了spi机制加载用户自定义的拦截器
interceptors.addAll(NacosServiceLoader.load(clazz));
interceptors.sort(Comparator.comparingInt(NacosNamingInterceptor::order));
}
}
最终使用 interceptors.addAll(NacosServiceLoader.load(clazz));加载用户在
/META-INF/services/com.alibaba.nacos.naming.healthcheck.heartbeat.AbstractBeatCheckInterceptor
com.alibaba.nacos.naming.healthcheck.heartbeat.ServiceEnableBeatCheckInterceptor
com.alibaba.nacos.naming.healthcheck.heartbeat.InstanceEnableBeatCheckInterceptor
com.alibaba.nacos.naming.healthcheck.heartbeat.InstanceBeatCheckResponsibleInterceptor
拦截器链执行
public abstract class AbstractNamingInterceptorChain<T extends Interceptable>
implements NacosNamingInterceptorChain<T> {
private final List<NacosNamingInterceptor<T>> interceptors;
protected AbstractNamingInterceptorChain(Class<? extends NacosNamingInterceptor<T>> clazz) {
this.interceptors = new LinkedList<>();
interceptors.addAll(NacosServiceLoader.load(clazz));
interceptors.sort(Comparator.comparingInt(NacosNamingInterceptor::order));
}
protected List<NacosNamingInterceptor<T>> getInterceptors() {
return interceptors;
}
@Override
public void addInterceptor(NacosNamingInterceptor<T> interceptor) {
interceptors.add(interceptor);
interceptors.sort(Comparator.comparingInt(NacosNamingInterceptor::order));
}
@Override
public void doInterceptor(T object) {
for (NacosNamingInterceptor<T> each : interceptors) {
//校验拦截器是否支持拦截该对象
if (!each.isInterceptType(object.getClass())) {
continue;
}
//成功拦截返回并执行对象的afterIntercept()
if (each.intercept(object)) {
object.afterIntercept();
return;
}
}
//通过了拦截
object.passIntercept();
}
}
3种拦截器
public class ServiceEnableBeatCheckInterceptor extends AbstractBeatCheckInterceptor {
//判断对该服务是否启动了客户端心跳
@Override
public boolean intercept(InstanceBeatCheckTask object) {
NamingMetadataManager metadataManager =
ApplicationUtils.getBean(NamingMetadataManager.class);
Optional<ServiceMetadata> metadata =
metadataManager.getServiceMetadata(object.getService());
if (metadata.isPresent() &&
metadata.get().getExtendData().containsKey(
UtilsAndCommons.ENABLE_CLIENT_BEAT)) {
return Boolean.parseBoolean(metadata.get().getExtendData().、
get(UtilsAndCommons.ENABLE_CLIENT_BEAT));
}
return false;
}
@Override
public int order() {
return Integer.MIN_VALUE;
}
}
public class InstanceEnableBeatCheckInterceptor extends AbstractBeatCheckInterceptor {
//检查实例的元数据是否启用了心跳检查
@Override
public boolean intercept(InstanceBeatCheckTask object) {
NamingMetadataManager metadataManager =
ApplicationUtils.getBean(NamingMetadataManager.class);
HealthCheckInstancePublishInfo instance = object.getInstancePublishInfo();
Optional<InstanceMetadata> metadata =
metadataManager.getInstanceMetadata(object.getService(),
instance.getMetadataId());
if (metadata.isPresent() &&
metadata.get().getExtendData().containsKey(、
UtilsAndCommons.ENABLE_CLIENT_BEAT)) {
return ConvertUtils.toBoolean(metadata.get().getExtendData().、
get(UtilsAndCommons.ENABLE_CLIENT_BEAT).toString());
}
if (instance.getExtendDatum().containsKey(
UtilsAndCommons.ENABLE_CLIENT_BEAT)) {
return ConvertUtils.toBoolean(instance.getExtendDatum().
get(UtilsAndCommons.ENABLE_CLIENT_BEAT).toString());
}
return false;
}
@Override
public int order() {
return Integer.MIN_VALUE + 1;
}
}
public class InstanceBeatCheckResponsibleInterceptor extends AbstractBeatCheckInterceptor {
//心跳检查任务是否由该服务器负责
@Override
public boolean intercept(InstanceBeatCheckTask object) {
return !ApplicationUtils.getBean(DistroMapper.class).
responsible(object.getClient().getResponsibleId());
}
@Override
public int order() {
//应该第一优先级运行
return Integer.MIN_VALUE + 2;
}
}
微信扫一扫加入讨论组备注nacos