最近有个需求,就是SpringBoot提供一个web接口给业务方,业务方传入参数调接口,接口去执行hive离线计算,一般可能是说直接用jdbc去连hive执行hive操作,但是这种方案,对于单个任务可能还是可以的,如果对于10个维度的数据统计,那这个代码写起来就坑了。。所以还是想着,把所有hive脚本都放一个shell脚本里,java调接口的时候直接去执行这个脚本,而且不需要等待结果,所以我采取这种方案。
但是,想法是好的,现实很残酷。
问题抛出:java无法调hive脚本无法执行。
这个问题卡了一天了,期间也问了一些朋友,都没遇到过这种需求,所以没有办法,只能自己来搞。卡的原因在哪里呢?如果直接在java代码里调hive脚本执行的话,会出现如下问题:
百度、谷歌也搜了,都没搜到我要的答案。真是坑。期间我也想过是不是权限的问题、或者是不是没找到hadoop路径之类的问题,都配置上去了,不起作用。。
所执行的test.sh脚本中,只放了一个清空hive表的语句
搞了一天,不行,该试的方法都试过了,咋办呢?甚至连直接通过java代码去执行hive语句,但是因为生产环境中是一个离线统计的脚本,脚本语句就大几百行,如果转成java去调用,这工作量可想而知。。而且,脚本中不单单是hive语句的脚本,还有hadoop的脚本,比如删除hdfs某个文件夹、执行某个已经写好的mapreduce任务……等等这些,反正就是通过java好干难(方言:艰难的意思),所以我心想,不行,得解决这个问题。所以我又重新梳理了一下问题,报:“Unable to determine Hadoop version information”,这个错误是在hive启动脚本中的,所以问题还是回到了原来的思路:是不是直接通过java调这个脚本,可能无法加载hadoop环境,既然不能直接调,那间接的是否可以呢?
问题解决:间接法
解决思路:
① Java先调一个脚本,在这个脚本中专门接收参数,并将参数写入指定文件中;
② 然后再写一个shell脚本来实时监控这个参数文件的变化,如果文件内容有变化,则直接调用真正的hive脚本取执行
代码如下:
第一步:创建一个接收参数的脚本acceptParam.sh:
rm -rf /root/single_prod/data/single.txt
echo $1 >> /root/single_prod/data/single.txt
第二步:通过java代码去调用,看看能否将参数写入指定的文件中
第三步:最重要的一步,写一个实时监控脚本monitor.sh:
#!/bin/bash
# $param1 需要监测的文件
# $param2 存放文件md5值,用于判断文件是否更改
param1='/root/single_prod/data/single.txt'
param2='/root/single_prod/data/single.txt.md5'
if [ ! $param1 ] || [ ! $param2 ] || [ ! -e $param1 ] ; then
echo "\$1 or \$2 is file"
exit
fi
# 生成md5验证文件
function creatMd5file()
{
md5sum -b $param1 > $param2
}
# 判断文件是否存在
if [ ! -e $param2 ] ; then
creatMd5file $param1 $param2
fi
while(true) ; do
# 检测文件是否修改,$?返回1 表示修改, 0表示未修改
md5sum -c $param2 --status
if [ $? -gt 0 ] ; then
echo "执行吧"
for line in $(cat $param1)
do
echo "读取文件内容为:"$line
sh /root/single_prod/test.sh $line >> /root/single_prod/logs/test.log
done
creatMd5file $param1 $param2
fi
# 每过3秒检测一次
sleep 3
done
第四步:验证
[root@master1 single_prod]# nohup sh monitor.sh >> monitor.log &
终于大功告成了,真是不容易,搞了一天半。。。