一、Azkaban概述
1.1 Azkaban简介
Azkaban是由Linkedin公司推出的一个批量工作流任务调度器,主要用于在一个工作流内以一个特定的顺序运行一组工作和流程;它的配置是通过简单的key:value对的方式,通过配置中的Dependencies来设置依赖关系。Azkaban使用job配置文件建立任务之间的依赖关系,并提供一个易于使用web用户界面维护和跟踪你的工作流。
1.2 为什么需要工作流调度系统
-
一个完整的数据分析系统通常都是由大量任务单元组成;
Shell脚本程序,Java程序,MapReduce程序,Hive脚本等
-
各任务单元之间存在时间先后或前后依赖关系;
-
为了更好的组织起这样的复杂执行计划,需要一个工作流调度系统来调度执行。
1.3 常见的工作流调度系统
-
简单的任务调度
直接使用crontab实现
-
复杂的任务调度
开发调度平台或使用现成的开源调度系统(如Ooize,Azkaban等)
1.4 Azkaban特点
- 兼容任何版本的hadoop;
- 易于使用的web用户界面;
- 简单的工作流的上传;
- 方便设置任务之间的关系;
- 调度工作流;
- 认证/授权(权限的工作);
- 模块化和可插拔的插件机制;
- 能够杀死并重新启动工作流;
- 有关失败和成功的电子邮件提醒。
1.5 Azkaban的架构
Azkaban由三个关键组件构成:
- Web Server:是整个Azkaban工作流系统的主要管理者;它用于用户登录、负责project管理、定时执行工作流、跟踪工作流执行进度等一系列任务;
- Executor Server:负责具体的工作流的提交、执行,它们通过mysql数据库来协调任务的执行;
- MySQL:存储大部分执行流状态,Web Server和Executor Server都需要访问数据库。
二、源码构建(azkaban-3.90.0.zip)
Gradle和maven是竞争对手,在home目录(root用户/root)有一个.gradle的目录(隐藏),相当于maven本地仓库。
-
安装zip和unzip命令
yum -y install zip unzip
-
解压、重命名
-
构建javac,要把.java文件变成.class文件
./gradlew build
-
安装git
yum -y install git
-
打包
./gradlew installDist
-
把class文件删除,重新编译
./gradlew clean
三、单机(azkaban-solo-server)
-
修改配置文件(start-solo.sh)
添加环境变量:HDAOOP_HOME
-
启动服务器
bin/start-solo.sh
-
访问网页
node7-2:8081
-
用户名和密码配置文件
conf/zakaban-users.xml
四、多机
4.1 配置前部署
-
时间统一修改为东八区
修改配置文件azkaban-exec-server/conf/azkaban.properties
default.timezone.id=Asia/Shanghai
-
数据库(创建azkaban数据库)
添加配置文件my.ini到mysql本地安装目录,之后重启mysql
[mysqld] log-bin-trust-function-creators=true max_allowed_packet=1024M
-
导入脚本
azkaban-sou/azkaban-db/build/distributions/.tar或.zip都可以/create-all-sql-0.1.0-SNAPSHOT.sql
-
部署
node7-1 node7-2 node7-3 node7-4 Web Server √ Executor Server √ √
4.2 部署Executor Server
-
替换mysql最新驱动包
mysql-connect-java-5.1.49.jar
-
修改配置文件(conf/azkaban.properties)
# mysql相关信息 azkaban.webserver.url=http://node7-2:8081 database.type=mysql mysql.port=3306 mysql.host=192.168.56.1 mysql.database=azkaban mysql.user=root mysql.password=123456 mysql.numconnections=100
-
修改配置文件(bin/start-exec.sh)
添加环境变量:HADOOP_HOME
-
启动服务器
bin/start-exec.sh
-
停止服务器
bin/shutdown-exec.sh
-
激活executor(每次重启一定要激活)
curl -G "/localhost:$(<./executor.port)/executor?action=activate" && echo
4.3 部署Web Server
-
修改配置文件(conf/azkaban.properties和bin/start-web.sh)
-
替换mysql最新驱动包
mysql-connect-java-5.1.49.jar
-
启动服务器
bin/start-web.sh
4.4 网页使用
-
创建两个文件
flow20.project
azkaban-flow-version:2.0
basic.flow(不能用tab键)(相互依赖)
nodes: -name:jobC type:noop # jobC depends on jobA and jobB dependsOn: -jobA -jobB -name:jobA type:command config: command:echo "This is an echoed text." -name:jobB type:command config: command:pwd
-
把这两个文件打一个zip包(不要使用中文命名)
五、JavaSE编程连接api
ApiUtil.java
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import java.util.HashMap;
import java.util.Map;
/**
* azkaban的api工具类
*/
public class ApiUtil {
private String serverUrl = "http://node7-2:8081/";
/**
* 登录
* @param user 用户名
* @param password 密码
* @return 将服务器返回的字符串解析为JSON
*/
public JSONObject login(String user, String password) {
System.out.println("--ApiUtil--login--");
String requestUrl = serverUrl;
HttpUtil httpUtil = new HttpUtil();
Map<String, String> headerMap = new HashMap<String, String>();
// 加一个请求头
headerMap.put("Content-Type", "application/x-www-form-urlencoded");
Map<String, String> requestMap = new HashMap<String, String>();
requestMap.put("username", user);
requestMap.put("password", password);
requestMap.put("action", "login");
Map<String, String> responseMap = new HashMap<String, String>();
// 请求网页
// String response = httpUtil.methodGet(requestUrl, headerMap, requestMap, responseMap);
String response = httpUtil.methodPost(requestUrl,headerMap, requestMap, responseMap);
System.out.println("--headerMap--" + headerMap);
System.out.println("--requestMap--" + requestMap);
System.out.println("--responseMap--" + responseMap);
System.out.println("--返回结果--" + response);
return (JSONObject) JSON.parse(response);
}
/**
* 登录
* @param sessionId 用户名
* @param name 密码
* @param description 描述
* @return 将服务器返回的字符串解析为JSON
*/
public JSONObject create(String sessionId, String name, String description) {
System.out.println("--ApiUtil--create--");
String requestUrl = serverUrl + "manager";
HttpUtil httpUtil = new HttpUtil();
Map<String, String> headerMap = new HashMap<String, String>();
// 加一个请求头
headerMap.put("Content-Type", "application/x-www-form-urlencoded");
Map<String, String> requestMap = new HashMap<String, String>();
requestMap.put("name", name);
requestMap.put("description", description);
requestMap.put("action", "login");
Map<String, String> responseMap = new HashMap<String, String>();
// 请求网页
String response = httpUtil.methodPost(requestUrl,headerMap, requestMap, responseMap);
System.out.println("--headerMap--" + headerMap);
System.out.println("--requestMap--" + requestMap);
System.out.println("--responseMap--" + responseMap);
System.out.println("--返回结果--" + response);
return (JSONObject) JSON.parse(response);
}
}
ClientMain.java
import com.alibaba.fastjson.JSONObject;
public class ClientMain {
public static void main(String[] args) {
ApiUtil apiUtil = new ApiUtil();
String user = "azkaban";
String password = "azkaban";
JSONObject resultJSON = apiUtil.login(user, password);
System.out.println("--返回--" + resultJSON.toJSONString());
System.out.println("--响应码--" + resultJSON.get("session.id"));
if ("success".equalsIgnoreCase(resultJSON.getString("status"))) {
// 登录成功
System.out.println("--登录成功--");
String sessionId = resultJSON.get("session.id") + "";
String name = "code_aaa";
String describe = "code_bbb";
resultJSON = apiUtil.create(sessionId, name, describe);
System.out.println("--返回--" + resultJSON.toJSONString());
}
}
}
HttpUtil.java
import java.io.*;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
/**
* 封装整个http的网络请求
* 它像一个浏览器
*/
public class HttpUtil {
/**
* get请求
* @param requestUrl 请求的网址
* @param headerMap 请求头
* @param requestMap 请求体
* @return 响应体
*/
public String methodGet(String requestUrl, Map<String, String> headerMap, Map<String, String> requestMap, Map<String, String> responseMap) {
System.out.println("--HttpUtil--methodGet--");
try {
/*
信的内容的格式是:a=1&b=2&c=3&d=4
=左边的叫键
=右边的叫值
*/
StringBuffer requestSb = new StringBuffer();
for (Iterator iterator = requestMap.entrySet().iterator(); iterator.hasNext(); ) {
Map.Entry me = (Map.Entry) iterator.next();
String key = me.getKey() + "";
String value = me.getValue() + "";
// 设置信封的内容
requestSb.append(key + "=" + value + "&");
}
System.out.println("--请求体--" + requestSb);
if (requestUrl.indexOf("?") != -1) {
requestUrl = requestUrl + "&" + requestSb.toString();
} else {
requestUrl = requestUrl + "?" + requestSb.toString();
}
System.out.println("--requestUrl--" + requestUrl);
// 准备写信,收件人
URL url = new URL(requestUrl);
// 邮递员
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
// 写信封
for (Iterator iterator = headerMap.entrySet().iterator(); iterator.hasNext(); ) {
Map.Entry me = (Map.Entry) iterator.next();
String key = me.getKey() + "";
String value = me.getValue() + "";
// 设置信封的内容
connection.setRequestProperty(key, value);
}
// 默认是get请求
connection.setRequestMethod("GET");
// 写信的内容:得写到信封上
StringBuffer sb = new StringBuffer();
InputStream is = connection.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is, "UTF-8"));
String line = "";
while ((line = br.readLine()) != null) {
sb.append(line);
}
// 关闭BufferedReader
br.close();
// 设置回信的信封
Map<String, List<String>> responseHeader = connection.getHeaderFields();
// 写信封
for (Iterator iterator = responseHeader.entrySet().iterator(); iterator.hasNext(); ) {
Map.Entry me = (Map.Entry) iterator.next();
String key = me.getKey() + "";
String value = me.getValue() + "";
// 设置信封的内容
requestMap.put(key, value.toString());
}
return sb.toString();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return "";
}
/**
* get请求
* @param requestUrl 请求的网址
* @param headerMap 请求头
* @param requestMap 请求体
* @param responseMap 响应头
* @return 响应体
*/
public String methodPost(String requestUrl, Map<String, String> headerMap, Map<String, String> requestMap, Map<String, String> responseMap) {
System.out.println("--HttpUtil--methodPost--" + requestUrl);
try {
// 准备写信,收件人
URL url = new URL(requestUrl);
// 邮递员
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
// 写信封
for (Iterator iterator = headerMap.entrySet().iterator(); iterator.hasNext(); ) {
Map.Entry me = (Map.Entry) iterator.next();
String key = me.getKey() + "";
String value = me.getValue() + "";
// 设置信封的内容
connection.setRequestProperty(key, value);
}
// 默认是get请求
connection.setRequestMethod("POST");
// 输入,输出,都是允许
connection.setDoInput(true);
connection.setDoOutput(true);
// 加一个信封的内容
OutputStream os = connection.getOutputStream();
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(os, "UTF-8"));
StringBuffer requestSb = new StringBuffer();
for (Iterator iterator = requestMap.entrySet().iterator(); iterator.hasNext(); ) {
Map.Entry me = (Map.Entry) iterator.next();
String key = me.getKey() + "";
String value = me.getValue() + "";
// 设置信封的内容
requestSb.append(key + "=" + value + "&");
}
requestSb.delete(requestSb.lastIndexOf("&"), requestSb.length());
System.out.println("--请求体--" + requestSb);
// 写东西
bw.write(requestSb.toString());
bw.close();
// 写信的内容:得写道信封上
StringBuffer sb = new StringBuffer();
InputStream is = connection.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is, "UTF-8"));
String line = "";
while ((line = br.readLine()) != null) {
sb.append(line);
}
// 关闭BufferedReader
br.close();
// 设置回信得信封
Map<String, List<String>> responseHeader = connection.getHeaderFields();
// 写信封
for (Iterator iterator = responseHeader.entrySet().iterator();iterator.hasNext(); ) {
Map.Entry me = (Map.Entry) iterator.next();
String key = me.getKey() + "";
String value = me.getValue() + "";
// 设置信封的内容
requestMap.put(key, value.toString());
}
return sb.toString();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return "";
}
public static void main(String[] args) {
String requestUrl = "https://www.baidu.com";
HttpUtil httpUtil = new HttpUtil();
Map<String, String> headerMap = new HashMap<String, String>();
Map<String, String> requestMap = new HashMap<String, String>();
Map<String, String> responseMap = new HashMap<String, String>();
// 请求网页
String response = httpUtil.methodGet(requestUrl, headerMap, requestMap, responseMap);
// String response = httpUtil.methodPost(requestUrl, headerMap, requestMap, responseMap);
System.out.println("--headerMap--" + headerMap);
System.out.println("--requestMap--" + requestMap);
System.out.println("--responseMap--" + responseMap);
System.out.println("--返回结果--" + response);
}
}