HeartBeatTask发送心跳的后台线程相关设计
1.封装后台线程BaseDaemonThread
public abstract class BaseDaemonThread extends Thread {
protected BaseDaemonThread(Runnable runnable) {
super(runnable);
this.setDaemon(true);
}
protected BaseDaemonThread(String threadName) {
super();
this.setName(threadName);
this.setDaemon(true);
}
}
2.基于BaseDaemonThread设计基础BaseHeartBeatTask设计
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.dolphinscheduler.common.model;
import org.apache.dolphinscheduler.common.lifecycle.ServerLifeCycleManager;
import org.apache.dolphinscheduler.common.thread.BaseDaemonThread;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public abstract class BaseHeartBeatTask<T> extends BaseDaemonThread {
private final String threadName;
private final long heartBeatInterval;
protected boolean runningFlag;
public BaseHeartBeatTask(String threadName, long heartBeatInterval) {
super(threadName);
this.threadName = threadName;
this.heartBeatInterval = heartBeatInterval;
this.runningFlag = true;
}
@Override
public synchronized void start() {
log.info("Starting {}...", threadName);
super.start();
log.info("Started {}, heartBeatInterval: {}...", threadName, heartBeatInterval);
}
@Override
public void run() {
while (runningFlag) {
try {
if (!ServerLifeCycleManager.isRunning()) {
log.info("The current server status is {}, will not write heartBeatInfo into registry",
ServerLifeCycleManager.getServerStatus());
continue;
}
T heartBeat = getHeartBeat();
writeHeartBeat(heartBeat);
} catch (Exception ex) {
log.error("{} task execute failed", threadName, ex);
} finally {
try {
Thread.sleep(heartBeatInterval);
} catch (InterruptedException e) {
handleInterruptException(e);
}
}
}
}
public void shutdown() {
runningFlag = false;
log.warn("{} finished...", threadName);
}
private void handleInterruptException(InterruptedException ex) {
log.warn("{} has been interrupted", threadName, ex);
Thread.currentThread().interrupt();
}
public abstract T getHeartBeat();
public abstract void writeHeartBeat(T heartBeat);
}
3.告警心跳Task的设计AlertHeartbeatTask
继承BaseHeartBeatTask,并用了父类BaseHeartBeatTask的方法
package org.apache.dolphinscheduler.alert.registry;
import org.apache.dolphinscheduler.alert.config.AlertConfig;
import org.apache.dolphinscheduler.common.model.AlertServerHeartBeat;
import org.apache.dolphinscheduler.common.model.BaseHeartBeatTask;
import org.apache.dolphinscheduler.common.utils.JSONUtils;
import org.apache.dolphinscheduler.common.utils.OSUtils;
import org.apache.dolphinscheduler.registry.api.RegistryClient;
import org.apache.dolphinscheduler.registry.api.enums.RegistryNodeType;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
@Slf4j
@Component
public class AlertHeartbeatTask extends BaseHeartBeatTask<AlertServerHeartBeat> {
private final AlertConfig alertConfig;
private final Integer processId;
private final RegistryClient registryClient;
private final String heartBeatPath;
private final long startupTime;
public AlertHeartbeatTask(AlertConfig alertConfig,
RegistryClient registryClient) {
super("AlertHeartbeatTask", alertConfig.getHeartbeatInterval().toMillis());
this.startupTime = System.currentTimeMillis();
this.alertConfig = alertConfig;
this.registryClient = registryClient;
this.heartBeatPath =
RegistryNodeType.ALERT_SERVER.getRegistryPath() + "/" + alertConfig.getAlertServerAddress();
this.processId = OSUtils.getProcessID();
}
@Override
public AlertServerHeartBeat getHeartBeat() {
return AlertServerHeartBeat.builder()
.processId(processId)
.startupTime(startupTime)
.reportTime(System.currentTimeMillis())
.cpuUsage(OSUtils.cpuUsagePercentage())
.memoryUsage(OSUtils.memoryUsagePercentage())
.availablePhysicalMemorySize(OSUtils.availablePhysicalMemorySize())
.alertServerAddress(alertConfig.getAlertServerAddress())
.build();
}
@Override
public void writeHeartBeat(AlertServerHeartBeat heartBeat) {
String heartBeatJson = JSONUtils.toJsonString(heartBeat);
registryClient.persistEphemeral(heartBeatPath, heartBeatJson);
log.debug("Success write master heartBeatInfo into registry, masterRegistryPath: {}, heartBeatInfo: {}",
heartBeatPath, heartBeatJson);
}
}
4.告警心跳客户端AlertRegistryClient的设计
@Slf4j
@Service
public class AlertRegistryClient implements AutoCloseable {
@Autowired
private RegistryClient registryClient;
@Autowired
private AlertConfig alertConfig;
private AlertHeartbeatTask alertHeartbeatTask;
public void start() {
log.info("AlertRegistryClient starting...");
registryClient.getLock(RegistryNodeType.ALERT_LOCK.getRegistryPath());
alertHeartbeatTask = new AlertHeartbeatTask(alertConfig, registryClient);
alertHeartbeatTask.start();
// start heartbeat task
log.info("AlertRegistryClient started...");
}
@Override
public void close() {
log.info("AlertRegistryClient closing...");
alertHeartbeatTask.shutdown();
registryClient.releaseLock(RegistryNodeType.ALERT_LOCK.getRegistryPath());
log.info("AlertRegistryClient closed...");
}
}
5.心跳任务开启的时机(应用启动类)
package org.apache.dolphinscheduler.alert;
import org.apache.dolphinscheduler.alert.plugin.AlertPluginManager;
import org.apache.dolphinscheduler.alert.registry.AlertRegistryClient;
import org.apache.dolphinscheduler.alert.rpc.AlertRpcServer;
import org.apache.dolphinscheduler.alert.service.AlertBootstrapService;
import org.apache.dolphinscheduler.common.constants.Constants;
import org.apache.dolphinscheduler.common.lifecycle.ServerLifeCycleManager;
import org.apache.dolphinscheduler.common.thread.ThreadUtils;
import javax.annotation.PreDestroy;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.event.EventListener;
@SpringBootApplication
@ComponentScan("org.apache.dolphinscheduler")
@Slf4j
public class AlertServer {
@Autowired
private AlertBootstrapService alertBootstrapService;
@Autowired
private AlertRpcServer alertRpcServer;
@Autowired
private AlertPluginManager alertPluginManager;
@Autowired
private AlertRegistryClient alertRegistryClient;
public static void main(String[] args) {
Thread.currentThread().setName(Constants.THREAD_NAME_ALERT_SERVER);
new SpringApplicationBuilder(AlertServer.class).run(args);
}
@EventListener
public void run(ApplicationReadyEvent readyEvent) {
log.info("Alert server is staring ...");
alertPluginManager.start(); // 插件管理者启动
alertRegistryClient.start(); // 客户端注册启动
alertBootstrapService.start();
alertRpcServer.start();
log.info("Alert server is started ...");
}
@PreDestroy
public void close() {
destroy("alert server destroy");
}
/**
* gracefully stop
*
* @param cause stop cause
*/
public void destroy(String cause) {
try {
// set stop signal is true
// execute only once
if (!ServerLifeCycleManager.toStopped()) {
log.warn("AlterServer is already stopped");
return;
}
log.info("Alert server is stopping, cause: {}", cause);
try (
AlertRpcServer closedAlertRpcServer = alertRpcServer;
AlertBootstrapService closedAlertBootstrapService = alertBootstrapService;
AlertRegistryClient closedAlertRegistryClient = alertRegistryClient) {
// close resource
}
// thread sleep 3 seconds for thread quietly stop
ThreadUtils.sleep(Constants.SERVER_CLOSE_WAIT_TIME.toMillis());
log.info("Alter server stopped, cause: {}", cause);
} catch (Exception e) {
log.error("Alert server stop failed, cause: {}", cause, e);
}
}
}
原创:做时间的朋友