web端通过redis监听订阅实现监测xxljob执行器jar包对应的服务器资源包括内存,cpu使用情况,平均负载
文章目录
- web端通过redis监听订阅实现监测xxljob执行器jar包对应的服务器资源包括内存,cpu使用情况,平均负载
- 前言
- 一、xxljob是什么?
- 二、使用步骤
- 1.在core公共端定义实体类
- 2.执行器端定义Server类
- 3.在core公共端定义获取服务器资源的工具类OSUtils
- 4.core公共端创建监听容器RedisListenerConfig
- 5.core公共端自定义监听器MessageReceive
- 6.core公共端定义获取map中内容ServerHelper类
- 7.在web端定义获取资源列表的Control:EsourceMonitorController
前言
通过redis的监听机制,可以实现监听多个执行器的资源变化
一、xxljob是什么?
XXL-JOB是一个轻量级分布式任务调度平台,主打特点是平台化,易部署,开发迅速、学习简单、轻量级、易扩展,代码仍在持续更新中。
调度中心: 任务调度控制台,平台自身并不承担业务逻辑,只是负责任务的统一管理和调度执行,并且提供任务管理平台
执行器: 负责接收“调度中心”的调度并执行,可直接部署执行器,也可以将执行器集成到现有业务项目中。 通过将任务的调度控制和任务的执行解耦,业务使用只需要关注业务逻辑的开发。
XXL-JOB主要提供了任务的动态配置管理、任务监控和统计报表以及调度日志几大功能模块,支持多种运行模式和路由策略,可基于对应执行器机器集群数量进行简单分片数据处理。
二、使用步骤
这里的结构为web端和executor执行器端都引入公共端core
<dependency> <groupId>ssssss.ssss</groupId> <artifactId>core</artifactId> </dependency>
1.在core公共端定义实体类
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class ServerInfoVO {
/**
* xxljob名
*/
private String serverCode;
/**
* 服务器ip
*/
private String serverIp;
/**
* cpu使用情况
*/
private String cpuUse;
/**
* 内存情况
*/
private String menUse;
/**
* 平均负载
*/
private String load;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date updateTime;
}
2.执行器端定义Server类
@Slf4j
@Component
public class Server implements ApplicationRunner {
@Resource
private StringRedisTemplate stringRedisTemplate;
/**
* 发送消息的渠道名
*/
public static final String CPU_HEART = "CPU_HEART";
/**
* 执行器名称,可任意取名,不唯一
*/
private String title="easy";
/**
* 若部署多个执行器,都部署在一个服务器上的话需要改变端口号
*/
@Value("${xxl.job.executor.port}")
private String port;
@Override
public void run(ApplicationArguments args) throws Exception {
startup();
}
private void startup(){
try {
heartbeat();
log.info("start Quartz server...");
} catch (Exception e) {
log.error("start Quartz failed : " + e.getMessage(), e);
}
}
/**
* 单独开线程执行
*/
private void heartbeat() {
ThreadFactory threadFactory = new ThreadFactoryBuilder()
.setDaemon(true)
.setNameFormat("executor-heart-Thread")
.build();
ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(1, threadFactory);
executor.setRemoveOnCancelPolicy(true);
Runnable heartBeatThread = heartBeatThread();
/**
* command:执行线程
* initialDelay:初始化延时
* period:前一次执行结束到下一次执行开始的间隔时间(间隔执行延迟时间)
* unit:计时单位
* 延迟一分钟,每分钟执行一次任务
*/
executor.scheduleAtFixedRate(heartBeatThread, 1, 1, TimeUnit.MINUTES);
}
/**
* heartbeat thread implement
* @return
*/
private Runnable heartBeatThread(){
log.info("start heart beat thread...");
return () -> {
ServerInfoVO serverInfoVO = ServerInfoVO.builder()
.serverIp(IpUtils.getHost()+"-"+port)//如果在同一服务器部署多个执行器的话ip会重复,所以这里加上了端口
.serverCode(title)//执行器名称
.cpuUse(OSUtils.cpuUsage()+"%")
.menUse(OSUtils.memoryUsage()+"%")
.load(OSUtils.loadAverage())
.updateTime(new Date())
.build();
//向redis发生消息
stringRedisTemplate.convertAndSend(CPU_HEART,JSONObject.toJSONString(serverInfoVO));
};
}
}
3.在core公共端定义获取服务器资源的工具类OSUtils
@Slf4j
public class OSUtils {
private static final SystemInfo SI = new SystemInfo();
private static HardwareAbstractionLayer hal = SI.getHardware();
public static final String TWO_DECIMAL = "0.00";
/**
* whether is windows
* @return true if windows
*/
public static boolean isWindows() {
return getOSName().startsWith("Windows");
}
/**
* get current OS name
* @return current OS name
*/
public static String getOSName() {
return System.getProperty("os.name");
}
/**
* get memory usage
* Keep 2 decimal
* @return percent %
*/
public static String memoryUsage() {
GlobalMemory memory = hal.getMemory();
double memoryUsage = (memory.getTotal() - memory.getAvailable() ) * 0.1 / memory.getTotal() * 10*100;
DecimalFormat df = new DecimalFormat(TWO_DECIMAL);
df.setRoundingMode(RoundingMode.HALF_UP);
return df.format(memoryUsage);
}
/**
* load average
*
* @return load average
*/
public static String loadAverage() {
double loadAverage = hal.getProcessor().getSystemLoadAverage(2)[1];
DecimalFormat df = new DecimalFormat(TWO_DECIMAL);
df.setRoundingMode(RoundingMode.HALF_UP);
return df.format(loadAverage);
}
/**
* get cpu usage
*
* @return cpu usage
*/
public static String cpuUsage() {
CentralProcessor processor = hal.getProcessor();
double cpuUsage = processor.getSystemCpuLoad()*100;
DecimalFormat df = new DecimalFormat(TWO_DECIMAL);
df.setRoundingMode(RoundingMode.HALF_UP);
return df.format(cpuUsage);
}
}
4.core公共端创建监听容器RedisListenerConfig
RedisMessageListenerContainer的监听流程:
用于消息监听,需要将 Topic和MessageListener 注册到 RedisMessageListenerContainer 中。
当 Topic 上有消息时,由 RedisMessageListenerContainer 通知 MessageListener,MessageListener通过 onMessage 方法拿到消息后,自行处理。
@Slf4j
@Configuration
public class RedisListenerConfig {
/**
* 监听容器
*
* @param connectionFactory connectionFactory
* @return RedisMessageListenerContainer
*/
@Bean
RedisMessageListenerContainer container(RedisConnectionFactory connectionFactory,MessageReceive listenerAdapter){
RedisMessageListenerContainer container = new RedisMessageListenerContainer();
container.setConnectionFactory(connectionFactory);
container.addMessageListener(listenerAdapter,new PatternTopic(RedisChannelConstant.CPU_HEART));
return container;
}
}
5.core公共端自定义监听器MessageReceive
通过 onMessage 方法拿到消息后,自行处理,写入我们的处理逻辑。
@Component
public class MessageReceive implements MessageListener {
@Override
public void onMessage(Message message, byte[] bytes) {
try {
//获取消息转化为实体类。存入map中
ServerInfoVO serverInfoVO = JSON.parseObject(message.toString(),ServerInfoVO.class);
ServerHelper.put(serverInfoVO.getServerIp(),serverInfoVO);
}catch (Exception e){
e.printStackTrace();
}
}
}
6.core公共端定义获取map中内容ServerHelper类
public class ServerHelper {
private static final Map<String, ServerInfoVO> maps = new ConcurrentHashMap<>();
public static void put(String key, ServerInfoVO serverInfoVO) {
maps.put(key, serverInfoVO);
}
public static List<ServerInfoVO> get() {
List<ServerInfoVO> list = new ArrayList<>();
Collection<ServerInfoVO> collection = maps.values();
for (ServerInfoVO serverInfoVO : collection) {
serverInfoVO.setServerIp(null);
long differ = new Date().getTime() - Objects.requireNonNull(serverInfoVO.getUpdateTime()).getTime();
if (differ > 100000) {
maps.remove(serverInfoVO.getServerCode());
continue;
}
list.add(serverInfoVO);
}
return list;
}
}
7.在web端定义获取资源列表的Control:EsourceMonitorController
public class getResourceMonitorController {
/**
* 资源统计-资源监控列表
*/
@PostMapping("getResourceMonitor")
public Result getResourceMonitor(){
return Result.success(ServerHelper.get());
}
}