大数据平台开发——使用Java和Python调用Shell脚本
背景
在大数据平台开发中,经常会遇到需要调用Shell脚本的场景,倒不是说只能用Shell,毕竟大数据开发到头来一定是个语言无关的事情:
从Hive源码解读大数据开发为什么可以脱离SQL、Java、Scala:https://lizhiyong.blog.csdn.net/article/details/129742904
Shell能干的事情,Java和Python当然是一定可以干。但是可以不代表是最优的方式。
例如这种常见的情况,看起来就很紊乱。
由于Java微服务集群和大数据集群不太可能部署在相同的node上,也就导致了环境其实有很大的差异。
多数情况下,隔离的好处是利大于弊。比如大数据集群除了Flink,其它组件大多是用JDK1.8。而Flink为了使用ZGC这种更先进的GC,可能要用JDK11或者JDK17。Java后端微服务正在向JDK11平稳过渡,还有少一半JDK1.8,以及部分实在太过古老以至于无人敢动的JDK1.7应用。。。有的机器可能为了用上Free IPA、Ranger,有的机器可能要跑PySpark或者PyTorch,Python版本大概率也不同。大数据的集群一般还是多个。。。这种情况下,物理隔离后各种组件和应用大多都可以比较和谐融洽。
但是这么多机器,如果人员分工是按照大数据组/后端组这么分的,那就很容易出现甩锅的问题了。。。很可能大数据组的运维给机器配置的host和后端组的运维配置的host文件不一样。。。
还有一种情况就是Jar包的依赖冲突,例如我们的Tomcat和HBase还有Log4j出现过严重的冲突【没错,就是那个RSGroup硬件级资源隔离技术调研时遇到的】,光是排除依赖就折腾了有一两周。。。那么这种情况下,写能跑起来的Shell要比写能跑起来的Java容易很大,显然调用Shell就是个比排除依赖冲突再去调用API更好的主意。。。
有时候是成本问题。。。为了让Java后端服务器也可以调用命令去操作大数据集群而部署一套Cloudera Manager和Client显然是不划算的,一个node大概1w美刀/年的租金也不便宜,但是手动安装Client运维也大抵是不愿意这么做的。部署的服务变多后node宕掉了锅也不容易甩。。。
所以做大数据平台开发,也就躲不开调用Shell脚本,Shell脚本再去调用别的机器的Shell脚本这种事情了。。。
案例
Java
package com.zhiyong;
/**
* @program: zhiyong_study
* @description: 测试远程调用Shell
* @author: zhiyong
* @create: 2023-04-02 22:26
**/
public class TestShellDemo {
public static void main(String[] args) {
TestShellDemo demo = new TestShellDemo();
String cmd = "";
cmd = args[0];
int exeShResult = demo.exeSh(cmd);
System.out.println("exeShResult = " + exeShResult);
}
private int exeSh(String shellCommand) {
int Result = 0;
Process pid = null;
System.out.println("执行Shell:" + shellCommand);
try {
String[] cmd = {"bin/sh", "-c", shellCommand};
pid = Runtime.getRuntime().exec(cmd);
int exitValue = 0;
System.out.println("pid的信息:" + pid.toString());
if (null!=pid){
System.out.println("等待shell执行完毕");
pid.waitFor();
System.out.println("shell执行完毕");
exitValue = pid.exitValue();
System.out.println("shell返回值:" + exitValue);
}
return exitValue;
} catch (Exception e) {
e.printStackTrace();
}
return -1;
}
}
可以使用这种比较简单的方式。把脚本放在本地服务器即可调用。我们使用这种方式去调用HBase shell,将输出重定向到log文件后再将log文件scp回来解析,从而获取到结果,和调用HBase的API效果是一致的。在Java后端组排除依赖的一两周时间里,让租户们提前体验了新功能。
Python
#!/usr/bin/env python
import paramiko
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(hostname='192.168.88.100',port=22,username="root",password="123456")
stdin,stdout,stderr = ssh.exec_command('echo "sh /root/shell/xxx.sh" | ssh -Tq root@192.168.88.50')
print(stdout.read().decode(encoding="utf-8"))
ssh.close()
可以调用paramiko
这个Python包,它可以远程调用别的机器的Shell。
这种方式我们最早用于集群任务迁移过程中的数据迁移及数据比对。由于领导阶级是Oracle数据库开发出身,对大数据一知半解,致使新老多套集群都叫nameservice1
,这么搞无论如何:
USDP使用笔记(四)打通双集群HDFS实现跨nameservice访问:https://lizhiyong.blog.csdn.net/article/details/123436503
都是没办法打通跨nameservice域了。只能通过namenode的IP和8020端口来互相访问。但是HA模式下Active的master又是会变化的。。。
当然还有Kerberos认证的天坑一时半会儿也不太容易填。。。
于是我们的Shell脚本就可以放置在边缘节点,先从CDH5.16的老集群get需要的parquet文件到老集群某机器的本地,然后scp
的方式传输到边缘节点,再从边缘节点scp给CDP7.1.5集群的某个节点,再执行put
操作上传到指定的路径。虽然这是一种笨办法,但是在保障进度的特殊历史时期发挥了巨大作用。
总结
,然后scp
的方式从边缘节点传输到边缘节点,再从边缘节点scp给CDP7.1.5集群的某个节点,再执行put
操作上传到指定的路径。虽然这是一种笨办法,但是在保障进度的特殊历史时期发挥了巨大作用。
总结
大数据平台开发,由于跨服务器、多环境等问题,直接API调用的理想方式有时候是行不通的或者代价很大,这种情况就不一定要死磕API,可以考虑shell的方式去吊起别的集群的shell来执行所需的事项。。。
转载请注明出处:https://lizhiyong.blog.csdn.net/article/details/129919408