1. 背景2. 问题
2.1 问题描述2.2 问题原因 3. 解决方案4. 参考文献
1. 背景在使用腾讯云的EMR-3.2.1时,客户有个需求,需要每周定时执行balance。
balance的脚本内容如下:
#!/bin/bash
# It does not allow to run more than 1 Balancer process at the same time on a same hdfs-cluster.
count=0
log_file=/opt/balancer/logs/balancer-out.log
err_outfile=/opt/balancer/logs/balancer-debug.log
function my_balancer(){
if [ ! -f ${log_file} ]; then
touch ${log_file}
elif [ ! -f ${err_outfile} ]; then
touch ${err_outfile}
fi
jps | grep Balancer # if no Balancer running, then "$?" is 1. then good to start "hdfs balancer"
if [ $? -ne 0 ]; then
echo "No other Balancer process, go on to run this balancer job"
nohup hdfs balancer -Ddfs.balancer.movedWinWidth=5400000 -Ddfs.balancer.moverThreads=1000 -Ddfs.balancer.dispatcherThreads=200 -Ddfs.datanode.balance.bandwidthPerSec=20971520 -Ddfs.balancer.max-size-to-move=10737418240 -threshold 5 1>${log_file} 2>${err_outfile} &
if [ $? -eq 0 ]; then
echo "successfully started running balancer as Daemon at" `date +'%Y-%m-%d_%H:%M:%S'`
#count=$((${count}+1)) # TODO: to run next balancer loop, need to clean corresponding log then re-run.
else
echo "failed started balancer at" `date +'%Y-%m-%d_%H:%M:%S'`
fi
fi
}
# run the Balancer
my_balancer
测试定时任务时使用的crontab 如下:
*/1 * * * * sh /home/hadoop/auto_balance.sh2. 问题 2.1 问题描述
在测试时发现定时任务没有正常执行,因为在上述脚本中的日志文件中没有得到正常的输出,且报错内容也看不到。
修改该crontab 如下,以便查看定时任务在执行时有何报错:
*/1 * * * * sh /home/hadoop/auto_balance.sh > /home/hadoop/1.log 2>/home/hadoop/2.log
然后在/home/hadoop/2.log中看到了报错如下:
nohup: failed to run command ‘hdfs’: No such file or directory2.2 问题原因
从/home/hadoop/2.log中的报错,可以确定是crontab的环境变量问题。crontab没有获取到正确的环境变量。这是因为crontab有自己的环境变量,在/etc/crontab中。
SHELL=/bin/bash PATH=/sbin:/bin:/usr/sbin:/usr/bin MAILTO=root HOME=/ # For details see man 4 crontabs # Example of job definition: # .---------------- minute (0 - 59) # | .------------- hour (0 - 23) # | | .---------- day of month (1 - 31) # | | | .------- month (1 - 12) OR jan,feb,mar,apr ... # | | | | .---- day of week (0 - 6) (Sunday=0 or 7) OR sun,mon,tue,wed,thu,fri,sat # | | | | | # * * * * * user-name command to be executed
配置解释:
前四行是用来配置crond任务运行的环境变量
第一行SHELL变量指定了系统要使用哪个shell,这里是bash;
第二行PATH变量指定了系统执行命令的路径;
第三行MAILTO变量指定了crond的任务执行信息将通过电子邮件发送给root用户,如果MAILTO变量的值为空,则表示不发送任务执行信息给用户;
第四行的HOME变量指定了在执行命令或者脚本时使用的主目录。
手动执行的执行环境是当前账户的配置文件~/.bash_profile
注意:手动执行成功的命令/脚本,放到crontab中不一定能够正常执行。
3. 解决方案有两种解决方案:
- 非系统自带的命令,使用绝对路径,如hdfs命令改为/usr/local/service/hadoop/bin/hdfs。在balance脚本中#!/bin/bash下加上一行source /etc/profile 或 . /etc/profile,这样crontab就能获取到正确的环境变量了。或者直接通过绝对路径来使用非系统自带的命令。在/etc/crontab中添加环境变量
即可在PATH属性后面添加,也可以在执行对应的命令之前,加入一条命令,使得环境变量生效,例如:
0 * * * * . /etc/profile;/bin/sh /var/www/java/audit_no_count/bin/restart_audit.sh注意:在corntab 中执行多条语句时,用分号;隔开。故以上例子就是先执行. /etc/profile;这条命令,然后再运行sh脚本。
这样,crontab在执行脚本的时候,就能够读到用户的环境变量参数
[1] Crontab内环境变量与Shell环境变量的关系及解决问题的办法
[2] Linux中crontab的坑爹环境变量问题



