spark-submit的使用shell时时灵活性较低,livy作为spark提交的一种工具,是使用接口或者java客户端的方式提交,可以集成到web应用中

1.客户端提交的方式

http://livy.incubator.apache.org/docs/latest/programmatic-api.html

核心代码

LivyClient client = new LivyClientBuilder()
.setURI(new URI(livyUrl))
.build(); try {
System.err.printf("Uploading %s to the Spark context...\n", piJar);
client.uploadJar(new File(piJar)).get(); System.err.printf("Running PiJob with %d samples...\n", samples);
double pi = client.submit(new PiJob(samples)).get(); System.out.println("Pi is roughly: " + pi);
} finally {
client.stop(true);
}

2.REST API

http://livy.incubator.apache.org/docs/latest/rest-api.html

1.以最常使用的batches接口作为例子,请求参数

rest 的http

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory; public class HttpUtils {
//post 请求
public String postAccess(String url, Map<String, String> headers, String data) { HttpPost post = new HttpPost(url);
if (headers != null && headers.size() > 0) {
headers.forEach((K, V) -> post.addHeader(K, V));
}
try {
StringEntity entity = new StringEntity(data);
entity.setContentEncoding("UTF-8");
entity.setContentType("application/json");
post.setEntity(entity);
HttpResponse response = httpClient.execute(post);
HttpEntity resultEntity = response.getEntity();
result = EntityUtils.toString(resultEntity);
return result;
} catch (Exception e) {
e.printStackTrace();
logger.error("postAccess执行有误" + e.getMessage());
}
return result;
}
}  

livy提交spark应用类,异步线程进行状态打印或者也可以状态监控返回web端

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.wanmi.sbc.dw.utils.GsonUtil;
import com.wanmi.sbc.dw.utils.HttpUtils;
import lombok.SneakyThrows;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Component; import java.io.IOException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List; /**
* @ClassName: com.spark.submit.impl.livy.LivyApp
* @Description: livy提交spark任务
* @Author: 小何
* @Time: 2020/12/15 10:46
* @Version: 1.0
*/
@Component
public class LivyServer {
private static final Logger logger = LoggerFactory.getLogger(LivyServer.class); private static final List<String> FAIl_STATUS_LIST = Arrays.asList("shutting_down", "error", "dead", "killed");
private final HashMap<String, String> headers; private HttpUtils httpUtils; public LivyServer() {
headers = new HashMap<>();
headers.put("Content-Type", "application/json");
headers.put("X-Requested-By", "admin");
} /**
* 提交参数
*
* @param livyParam
* @return
*/
@SneakyThrows
public String batchSubmit(LivyParam livyParam) {
this.httpUtils = new HttpUtils();
String livyUri = livyParam.getLivyUri();
LivyParam livyParamCopy = new LivyParam();
BeanUtils.copyProperties(livyParam, livyParamCopy);
livyParamCopy.setLivyUri(null);
String request = GsonUtil.toJsonString(livyParamCopy);
logger.info("任务提交信息{}", request);
String result = httpUtils.postAccess(livyUri + "/batches", headers, request);
if (!GsonUtil.isJson(result)) {
logger.info("任务提交错误:{}", result);
return "error:" + result;
}
if (result == null) {
return "error:" + "livy地址:" + livyUri + "错误,请检查";
}
logger.info("提交返回任务返回信息:{}", result);
JSONObject jsonObject = JSONObject.parseObject(result);
String state = jsonObject.getString("state");
String id = jsonObject.getString("id");
Thread thread = new Thread(() -> {
try {
queryState(livyParam.getLivyUri(), id, state);
} catch (InterruptedException | IOException e) {
logger.error("线程运行出错:{}", e.fillInStackTrace());
}
}, livyParam.getName() + System.currentTimeMillis());
thread.start();
return result;
} //提交任务执行状态验证
public void queryState(String livyUrl, String batchId, String responseState) throws InterruptedException, IOException {
if (responseState != null && !FAIl_STATUS_LIST.contains(responseState)) {
boolean isRunning = true;
while (isRunning) {
String url = livyUrl + "/batches/" + batchId;
String batchesInfo = httpUtils.getAccess(url, headers);
JSONObject info = JSON.parseObject(batchesInfo);
String id = info.getString("id");
String sta = info.getString("state");
String appId = info.getString("appId");
String appInfo = info.getString("appInfo");
logger.info("livy:sessionId:{},state:{}", id, sta);
if ("success".equals(sta)) {
logger.info("任务{}:执行完成", appId, appInfo);
httpUtils.close();
isRunning = false;
} else if (FAIl_STATUS_LIST.contains(sta) || sta == null) {
logger.error("任务{}执行有误,请检查后重新提交:\n", appId, batchesInfo);
httpUtils.close();
isRunning = false;
} else if ("running".equals(sta) || "idle".equals(sta) || "starting".equals(sta)) {
logger.info("查看任务{},运行状态:\n{}", appId, batchesInfo);
} else {
logger.info("任务{}状态:{},未知,退出任务查看", id, sta);
isRunning = false;
}
Thread.sleep(5000);
}
}
}
}

livy请求参数

@Data
public class LivyParam {
/**
* livy的地址
*/
private String livyUri; /**
* 要运行的jar包路径
*/
private String file;
/**
* 运行的代理名
*/
private String proxyUser;
/**
* 运行主类
*/
private String className;
/**
* 主类的参数
*/
private List<String> args;
/**
* 需要运行的jar包
*/
private String thirdJarPath;
private List<String> jars;
private List<String> pyFiles;
private List<String> files;
private String driverMemory;
private Integer driverCores;
private String executorMemory;
private Integer executorCores;
private Integer numExecutors;
private List<String> archives;
/**
* 队列
*/
private String queue;
/**
* appName
*/
private String name;
/**
* 其他配置
*/
private Map<String, String> conf; }

测试

      构建参数
new livyParam = new LivyParam();
livyParam.setLivyUri(sparkSubmitParam.getLivyUri());
livyParam.setClassName(sparkSubmitParam.getClassName());
livyParam.setArgs(sparkSubmitParam.getArgs());
livyParam.setConf(sparkSubmitParam.getConf());
livyParam.setDriverCores(sparkSubmitParam.getDriverCores());
livyParam.setDriverMemory(sparkSubmitParam.getDriverMemory());
livyParam.setArchives(sparkSubmitParam.getArchives());
livyParam.setExecutorCores(sparkSubmitParam.getExecutorCores());
livyParam.setExecutorMemory(sparkSubmitParam.getExecutorMemory());
livyParam.setJars(sparkSubmitParam.getJars());
livyParam.setFile(sparkSubmitParam.getFile());
livyParam.setName(sparkSubmitParam.getName());
livyParam.setQueue(sparkSubmitParam.getQueue());
livyParam.setProxyUser(sparkSubmitParam.getProxyUser()); //发送请求
String result = liveServer.batchSubmit(livyParam);

  

livy提交spark应用的更多相关文章

  1. Spark On Yarn:提交Spark应用程序到Yarn

    转载自:http://lxw1234.com/archives/2015/07/416.htm 关键字:Spark On Yarn.Spark Yarn Cluster.Spark Yarn Clie ...

  2. 如何在Java应用中提交Spark任务?

    最近看到有几个Github友关注了Streaming的监控工程--Teddy,所以思来想去还是优化下代码,不能让别人看笑话,是不.于是就想改在一下之前最丑陋的一个地方--任务提交 本博客内容基于Spa ...

  3. 利用SparkLauncher 类以JAVA API 编程的方式提交Spark job

    一.环境说明和使用软件的版本说明: hadoop-version:hadoop-2.9.0.tar.gz spark-version:spark-2.2.0-bin-hadoop2.7.tgz jav ...

  4. 【Spark】提交Spark任务-ClassNotFoundException-错误处理

    提交Spark任务-ClassNotFoundException-错误处理 Overview - Spark 2.2.0 Documentation Spark Streaming - Spark 2 ...

  5. Spark2.x(五十九):yarn-cluster模式提交Spark任务,如何关闭client进程?

    问题: 最近现场反馈采用yarn-cluster方式提交spark application后,在提交节点机上依然会存在一个yarn的client进程不关闭,又由于spark application都是 ...

  6. Idea里面远程提交spark任务到yarn集群

    Idea里面远程提交spark任务到yarn集群 1.本地idea远程提交到yarn集群 2.运行过程中可能会遇到的问题 2.1首先需要把yarn-site.xml,core-site.xml,hdf ...

  7. spark-submit提交spark任务的具体参数配置说明

    spark-submit提交spark任务的具体参数配置说明 1.spark提交任务常见的两种模式 2.提交任务时的几个重要参数 3.参数说明 3.1 executor_cores*num_execu ...

  8. 提交Spark作业遇到的NoSuchMethodError问题总结

    测试应用说明 测试的Spark应用实现了同步hive表到kafka的功能.具体处理流程: 从 ETCD 获取 SQL 语句和 Kafka 配置信息 使用 SparkSQL 读取 Hive 数据表 把 ...

  9. 基于Livy的Spark提交平台搭建与开发

    为了方便使用Spark的同学提交任务以及加强任务管理等原因,经调研采用Livy比较靠谱,下图大致罗列一下几种提交平台的差别. 本文会以基于mac的单机环境搭建一套Spark+Livy+Hadoop来展 ...

随机推荐

  1. PyQt(Python+Qt)学习随笔:QTableView的sortingEnabled属性

    老猿Python博文目录 老猿Python博客地址 sortingEnabled属性用于控制是企业视图按列排序功能,如果此属性为True,则对tableView视图中的数据启用排序,如果此属性为Fal ...

  2. 第15.14节 PyQt(Python+Qt)入门学习:Designer的Buttons按钮详解

    一.引言 Qt Designer中的Buttons部件包括Push Button(常规按钮.一般称按钮).Tool Button(工具按钮).Radio Button(单选按钮).Check Box( ...

  3. Android的intent

    title: Android基础01 date: 2020-02-15 17:17:04 tags: 1.Intent Intent可以让活动进行跳转.使用方式有两种,一种是显式,另一种是隐式. 1. ...

  4. dm8数据库的安装 for linux

    目录 dm8数据库的安装 for linux 1.创建用户 2.修改limit的文件 3.解压文件安装包 4.挂载iso镜像 5.对于安装介质和目录进行权限授予 6.切换用户安装数据库软件 7.dm数 ...

  5. Scrum 冲刺第一天

    一.团队信息 1.团队名称 挑战极限队 2.团队成员 张博愉(3118005074) 张润柏(3118005075) 郑堉涵(3118005077) 周伟建(3118005079) 林梓琦(31180 ...

  6. Springboot mini - Solon详解(一)- 快速入门

    一.Springboot min -Solon 最近号称 Springboot mini 的 Solon框架,得空搞了一把,发觉Solon确实好用,小巧而快速.那Solon到底是什么,又是怎么好用呢? ...

  7. 【题解】P6329 【模板】点分树 | 震波

    题外话 (其实模板题没必要在这里水题解的--主要是想说这个qwq) 小常数的快乐.jpg 我也不知道我为啥常数特别小跑得飞快--不加快读就能在 luogu 的最优解上跑到 rank5 ( 说不定深夜提 ...

  8. P1654 OSU! 题解

    \(x\) 为该位置有 \(1\) 的期望. 统计两个值 : \(suma\) 和 \(sumb\). \(suma\) 表示连续 \(X\) 个 \(1\) , \(X\) 的平方的期望, \(su ...

  9. uni-app中封装统一请求函数

    封装统一请求函数有利于项目的维护 整体功能简单实用,但小编遇到一个巨坑,项目中在vue文件使用跳转方法,url参数输入 "/" 后工具提示的路径为 "/pages/log ...

  10. 前端面试题CSS-div宽度设置为100%,设置属性margin-left和margin-right时出现的问题

    前端面试题CSS-div宽度设置为100%,设置属性margin-left和margin-right时出现的问题 div格式如下 <div class="a"> < ...