基于Java实现spark应用监控

最近需要实现这样一种功能,利用调度器将spark应用提交到yarn上执行,然后获取最后的执行状态。但是发现网上相关的案例非常少,大都让我们去看日志,显然在生产环境中这种做法是不合理的。

在网上找了半天,发现了一种利用yarn去监控应用的方案。所以我实现了第一种方案,获取这个应用的applicationId,就可以通过applicationId获取应用的状态,然后写一个子线程,不断去轮询获取yarn上指定应用的状态。

代码如下:

import java.io.IOException;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.yarn.api.records.ApplicationId;
import org.apache.hadoop.yarn.api.records.ApplicationReport;
import org.apache.hadoop.yarn.api.records.YarnApplicationState;
import org.apache.hadoop.yarn.client.api.YarnClient;
import org.apache.hadoop.yarn.exceptions.YarnException;
import org.apache.hadoop.yarn.util.ConverterUtils;

import lombok.extern.slf4j.Slf4j;
import redis.clients.jedis.Jedis;

/**
 * @Description yarn应用监控
 * 
 * @author Suntz
 * @Date 2021-3-23
 * 
 */
@Slf4j
public class YarnMonitorComponent extends Thread {

	private ApplicationId applicationId;
	
	

	public YarnMonitorComponent(String appId) {
		log.info("==================================");
		log.info("应用ID是:" + appId);
		log.info("==================================");

		this.applicationId = ConverterUtils.toApplicationId(appId);

	}

	@Override
	public void run() {
		while (true) {
			if (getState(applicationId).equals(YarnApplicationState.FINISHED)) {
				log.info("==================================");
				log.info("执行状态:应用执行成功");
				log.info("==================================");

			}
			if (getState(applicationId).equals(YarnApplicationState.FAILED)) {
				log.info("==================================");
				log.info("执行状态:应用执行失败");
				log.info("==================================");
			}
			if (getState(applicationId).equals(YarnApplicationState.KILLED)) {
				log.info("==================================");
				log.info("应用被终止");
				log.info("==================================");
			}

		}
	}

	private YarnApplicationState getState(ApplicationId applicationId) {
		YarnClient client = YarnClient.createYarnClient();
		Configuration conf = new Configuration();
		client.init(conf);
		client.start();
		// ApplicationId appId = ConverterUtils.toApplicationId(appId);
		YarnApplicationState yarnApplicationState = null;
		try {
			ApplicationReport applicationReport = client.getApplicationReport(applicationId);
			yarnApplicationState = applicationReport.getYarnApplicationState();
		} catch (YarnException | IOException e) {
			log.error("监控出错", e);
		}
		try {
			client.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return yarnApplicationState;
	}
}

调用如下:

		YarnMonitorComponent yarnMonitorComponent = new YarnMonitorComponent(
				sparkContext.applicationId());
		ExecutorService pool = Executors.newSingleThreadExecutor();
		pool.execute(yarnMonitorComponent);

但是这种实现方案有一个问题,就是spark运行失败,但是yarn日志仍然显示成功,这个也不知道到底什么原因,大概是因为只要yarn主程序流程走完就是成功状态。

于是找了半天,又发现了SparkListener。实现SparkListener接口,重写相关方法,代码如下:

@Slf4j
public class SparkAppListener extends SparkListener {

	public SparkAppListener() {
	}

	@Override
	public void onTaskEnd(SparkListenerTaskEnd taskEnd) {
		if (!taskEnd.reason().toString().equals("Success")) {
			log.info("task运行失败");
		} else {
			log.info("task运行成功");
		}
	
	}

	@Override
	public void onApplicationEnd(SparkListenerApplicationEnd applicationEnd) {

		log.info("应用运行完成");

	}
}

在sparkContext中注册这个监听器,这样当有task结束,或者应用结束就会调用相关方法。

sparkContext().addSparkListener(new SparkAppListener());

但是应用结束无法获取应用结束的原因或者状态,只知道应用结束,不知道应用结束的状态是成功还是失败,这真的是一个大遗憾……大概是分布式环境下这个工作不好做吗?task结束可以后可以获取task结束的原因,但是应用结束无法获取。

所以我现在就只能通过task来间接监控,只要有一个task失败,就认为整个应用失败。这对于监控整个应用来说不太合理。但是我也没发现其他的办法。

各位如果有好的方案可以私我,或者评论,大家一起讨论,如果我有好的方案也会及时补充的。

注意以上,均需要将yarn-site.xml拷贝到resource目录下。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值