简答
在主端
hadoop-daemons.sh
在$HADOOP_HOME/sbin/hadoop-daemons.sh(不是$HADOOP_HOME/sbin/hadoop-daemon.sh,文件名中有s)中,有一行调用$HADOOP_HOME/sbin/slaves.sh。在我的版本(Hadoop v2.7.7)中,它显示:
exec "$bin/slaves.sh" --config $HADOOP_CONF_DIR cd "$HADOOP_PREFIX" \; "$bin/hadoop-daemon.sh" --config $HADOOP_CONF_DIR "$@"
将其更改为以下行以使其尊重从端环境变量:
exec "$bin/slaves.sh" "source" ".bash_aliases" \; "hadoop-daemon.sh" "$@"
yarn-daemons.sh
同样,在$HADOOP_HOME/sbin/yarn-daemons.sh 中,换行:
exec "$bin/slaves.sh" --config $YARN_CONF_DIR cd "$HADOOP_YARN_HOME" \; "$bin/yarn-daemon.sh" --config $YARN_CONF_DIR "$@"
到
exec "$bin/slaves.sh" "source" ".bash_aliases" \; "yarn-daemon.sh" "$@"
在从属端
将所有与Hadoop相关的环境变量放入$HOME/.bash_aliases。
开始/停止
要启动 HDFS,只需在主端运行 start-dfs.sh。从端数据节点将启动,就好像hadoop-daemon.sh start datanode 从从端的交互式 shell 中执行一样。
要停止 HDFS,只需运行 stop-dfs.sh。
注意
以上更改已经完成。但是对于完美主义者,您可能还想修复sbin/hadoop-daemons.sh 的调用者,以便在转储它们时命令正确。在这种情况下,请在 Hadoop 脚本中找到所有出现的 hadoop-daemons.sh,并将 --script "$bin"/hdfs 替换为 --script hdfs(并将所有 --script "$bin"/something 替换为 --script something)。在我的例子中,所有的出现都是hdfs,并且由于从属端会在与hdfs相关时重写命令路径,因此无论是否有此修复,该命令都可以正常工作。
这是sbin/start-secure-dns.sh 中的修复示例。
变化:
"$HADOOP_PREFIX"/sbin/hadoop-daemons.sh --config $HADOOP_CONF_DIR --script "$bin"/hdfs start datanode $dataStartOpt
到
"$HADOOP_PREFIX"/sbin/hadoop-daemons.sh --config $HADOOP_CONF_DIR --script hdfs start datanode $dataStartOpt
在我的版本(Hadoop v2.7.7)中,需要修复以下文件:
-
sbin/start-secure-dns.sh(出现 1 次)
-
sbin/stop-secure-dns.sh(出现 1 次)
-
sbin/start-dfs.sh(出现 5 次)
-
sbin/stop-dfs.sh(出现 5 次)
说明
在sbin/slaves.sh 中,通过ssh 连接主设备和从设备的线路为:
ssh $HADOOP_SSH_OPTS $slave $"${@// /\\ }" \
2>&1 | sed "s/^/$slave: /" &
我在它之前添加了 3 行来转储变量:
printf 'XXX HADOOP_SSH_OPTS: %s\n' "$HADOOP_SSH_OPTS"
printf 'XXX slave: %s\n' "$slave"
printf 'XXX command: %s\n' $"${@// /\\ }"
在sbin/hadoop-daemons.sh 中,调用sbin/slaves.sh 的行读取(我将其分成两行以防止滚动):
exec "$bin/slaves.sh" --config $HADOOP_CONF_DIR cd "$HADOOP_PREFIX" \; \
"$bin/hadoop-daemon.sh" --config $HADOOP_CONF_DIR "$@"
sbin/start-dfs.sh 脚本调用sbin/hadoop-daemons.sh。这是执行sbin/start-dfs.sh 时的结果:
Starting namenodes on [master]
XXX HADOOP_SSH_OPTS:
XXX slave: master
XXX command: cd
XXX command: /home/hduser/hadoop-2.7.7
XXX command: ;
XXX command: /home/hduser/hadoop-2.7.7/sbin/hadoop-daemon.sh
XXX command: --config
XXX command: /home/hduser/hadoop-2.7.7/etc/hadoop
XXX command: --script
XXX command: /home/hduser/hadoop-2.7.7/sbin/hdfs
XXX command: start
XXX command: namenode
master: starting namenode, logging to /home/hduser/hadoop-2.7.7/logs/hadoop-hduser-namenode-akmacbook.out
XXX HADOOP_SSH_OPTS:
XXX slave: slave1
XXX command: cd
XXX command: /home/hduser/hadoop-2.7.7
XXX command: ;
XXX command: /home/hduser/hadoop-2.7.7/sbin/hadoop-daemon.sh
XXX command: --config
XXX command: /home/hduser/hadoop-2.7.7/etc/hadoop
XXX command: --script
XXX command: /home/hduser/hadoop-2.7.7/sbin/hdfs
XXX command: start
XXX command: datanode
slave1: bash: line 0: cd: /home/hduser/hadoop-2.7.7: Permission denied
slave1: bash: /home/hduser/hadoop-2.7.7/sbin/hadoop-daemon.sh: Permission denied
Starting secondary namenodes [master]
XXX HADOOP_SSH_OPTS:
XXX slave: master
XXX command: cd
XXX command: /home/hduser/hadoop-2.7.7
XXX command: ;
XXX command: /home/hduser/hadoop-2.7.7/sbin/hadoop-daemon.sh
XXX command: --config
XXX command: /home/hduser/hadoop-2.7.7/etc/hadoop
XXX command: --script
XXX command: /home/hduser/hadoop-2.7.7/sbin/hdfs
XXX command: start
XXX command: secondarynamenode
master: starting secondarynamenode, logging to /home/hduser/hadoop-2.7.7/logs/hadoop-hduser-secondarynamenode-akmacbook.out
从上面的结果可以看出,脚本不尊重从端.bashrc和etc/hadoop/hadoop-env.sh。
解决方案
从上面的结果,我们知道变量$HADOOP_CONF_DIR是在master端解析的。如果在slave端解决,问题就解决了。但是,由于ssh(附带命令)创建的shell 是非交互式shell,所以.bashrc 脚本不会在从端加载。因此,以下命令不会打印任何内容:
ssh slave1 'echo $HADOOP_HOME'
我们可以强制它加载.bashrc:
ssh slave1 'source .bashrc; echo $HADOOP_HOME'
但是,.bashrc(Ubuntu 18.04 中的默认值)中的以下块保护非交互式 shell:
# If not running interactively, don't do anything
case $- in
*i*) ;;
*) return;;
esac
此时,您可以从.bashrc 中删除上述块以尝试实现目标,但我认为这不是一个好主意。我没试过,但我认为守卫在那里是有原因的。
在我的平台 (Ubuntu 18.04) 上,当我以交互方式登录时(通过控制台或 ssh),.profile 加载 .bashrc,.bashrc 加载 .bash_aliases。因此,我习惯于保持所有.profile、.bashrc、.bash_logout 不变,并将任何自定义放入.bash_aliases。
如果您的平台上的.bash_aliases 未加载,请将以下代码附加到.bashrc:
if [ -f ~/.bash_aliases ]; then
. ~/.bash_aliases
fi
回到问题。因此我们可以加载.bash_aliases 而不是.bashrc。因此,下面的代码完成了这项工作,并打印了来自从站的$HADOOP_HOME:
ssh slave1 'source .bash_aliases; echo $HADOOP_HOME'
通过将这种技术应用于sbin/hadoop-daemons.sh 脚本,结果就是上面提到的Short Answer。