参考资料
一、前言
在Hadoop完全分布式集群环境下,里面的各个节点都是通过 SSH免密登陆 连接的,比如现有三台集群节点,分别是 hadoop101、hadoop102、hadoo103。
hadoop101节点可以通过 ssh命令连接到hadoop102,即:
ssh hadoop102
那么,除了远程登陆以外,还有其他的作用吗?
当然有的,比如远程传输文件:scp命令参考资料
如果要将hadoop101节点的hadoop配置文件传输到hadoop102,那么可以尝试:
scp -r /opt/module/hadoop/etc/hadoop/*.xml root@hadoop102:/opt/module/hadoop/etc/hadoop
但是如果每次都这样使用scp命令去传输,会比较浪费时间,因为这两个集群节点的hadoop目录都是相同的,只是配置文件的内容不同,接下来将根据参考的资料进行描述,如何使用一些命令来简化集群之间的文件传输。
二、rsync 远程同步工具
rsync 主要用于 备份 和 镜像。它具有速度快、避免复制相同内容和支持符号链接的优点。
rsync 和 scp的区别: 用 rsync 做文件复制要比scp的速度快,rsync只对差异文件做更新,scp是复制所有的文件。
基本语法
rsync -av $pdir/$fname $user@host:$pdir/$fname
# 命令 选项参数 要拷贝的文件路径/名称 目的地用户@主机名:目的地路径/名称
选项参数的说明:
-a ——归档拷贝 -v —— 显示复制过程
三、使用 shell 编写分发脚本
需求:循环复制文件到所有节点的相同目录下
需求分析:
由于rsync命令速度比scp命令快,所以脚本使用rsync命令实现
在文件复制时候,后者的路径少一级,比如在前言部分中,复制hadoop的配置文件,前者需指定/*.xml参数,后者则不需要指定这个/*.xml
脚本在任何路径都能使用,故shell脚本需方在声明了全局环境变量的路径比如:~/bin
具体实现:
cd ~/bin
sudo vim xsync
脚本内容:(参考视频资料)
#!/bin/bash
#1. 判断参数个数
if [ $# -lt 1 ]
then
echo 请输入合理的一个参数:[要拷贝的文件/目录]
exit;
fi
#2. 遍历集群所有机器
for host in hadoop101 hadoop102 hadoop103
do
echo '==================== 集群节点$host的操作 ===================='
#3. 遍历所有目录,逐个
for file in $@
do
#4. 判断文件是否存在
if [ -e $file ]
then
#5. 获取父目录
pdir=$(cd -P $(dirname $file); pwd)
#6. 获取当前文件的名称
fname=$(basename $file)
ssh $host "mkdir -p $pdir"
rsync -av $pdir/$fname $host:$pdir
else
echo '$file 文件不存在!'
fi
done
done
创建脚本后需要对其赋予可执行权限:
sudo chmod +x xsync
接下来结合视频讲解还有自己的理解对这个脚本进行解读
在分发文件时有两种情况,第一种分发一个具体文件,第二种分发整个文件夹,由此产生了几个问题:
脚本是同步到哪几个节点?
如果接收文件节点的目录不存在怎么办?
如果一次性分发多个文件或者目录怎么办?
首先脚本的定位就是分发到所有的集群节点,这一点可以确认,所以就需for循环遍历所有的节点,
其次,为防止接收文件的位置目录不存在,需在接收文件的节点里创建这个文件的目录,同时获取文件的目录,并且要获取文件的具体名称,将这二者区分开则可以解决接收文件节点不存在的问题。
一次性分发多个文件,使用shell脚本的#@ 以个体的形式获取所有的输入参数,然后使用 for in 进行循环遍历即可。
如果对 shell 脚本不够熟悉,可以参考这两篇文章,里面有写参考的资料,查看参考资料会更加清晰明了:
Linux | Shell 学习笔记(二)Shell 流程控制 if、case、for、while| read读取输入 | 函数的使用 | cut、sed、awk、sort命令 +Demo
我认为上面的分发脚本,比较难理解的就是这一部分:
pdir=$(cd -P $(dirname $file); pwd)
fname=$(basename $file)
ssh $host "mkdir -p $pdir"
rsync -av $pdir/$fname $host:$pdir
我最疑惑的就是,cd -P 的意义是什么? 于是在Linux系统里输入了 help cd 查看cd命令的帮助文档,返回的结果如下:
[s0125@hadoop ~]$ help cd
cd: cd [-L|[-P [-e]]] [dir]
Change the shell working directory.
Change the current directory to DIR. The default DIR is the value of the
HOME shell variable.
The variable CDPATH defines the search path for the directory containing
DIR. Alternative directory names in CDPATH are separated by a colon (:).
A null directory name is the same as the current directory. If DIR begins
with a slash (/), then CDPATH is not used.
If the directory is not found, and the shell option `cdable_vars' is set,
the word is assumed to be a variable name. If that variable has a value,
its value is used for DIR.
Options:
-L force symbolic links to be followed
-P use the physical directory structure without following symbolic
links
-e if the -P option is supplied, and the current working directory
cannot be determined successfully, exit with a non-zero status
The default is to follow symbolic links, as if `-L' were specified.
Exit Status:
Returns 0 if the directory is changed, and if $PWD is set successfully when
-P is used; non-zero otherwise.
其中比较关键的信息:
原先:
-P use the physical directory structure without following symbolic
links
机翻:
-P 使用物理目录结构而不使用以下符号链接
总之就是理解为找到真实的地址吧
除此之外还用到了 dirname命令,脚本的内容:
pdir=$(cd -P $(dirname $file); pwd)
dirname命令的作用就是取文件相对于当前的位置目录,比如:
dirname /opt/module/love.txt
执行结果就是 /opt/module,它并不能判断文件是否存在,只是相当于一种字符串处理的操作,提取文件所在目录仅此而已。
而 pwd 就是取当前的目录,脚本的这句就是先切换目录到传输文件的所在目录(dirname获取到的),然后再将当前的文件目录复制给pdir变量,用于表示要拷贝的文件的目录。
接下来的第二行
fname=$(basename $file)
basename同样是一种字符串处理的操作,作用是将路径的文件名提取出来,比如:
basename /opt/module/love.txt
返回的结果是字符串形式的:love.txt
通过以上两行就获取到了拷贝文件的目录位置和文件的名称,接下来就是先创建好目录,防止目录不存在的情况,mkdir -p可以在文件存在时忽略报错,然后ssh命令则可以将后面的命令发送到远程的节点。
ssh $host "mkdir -p $pdir"
rsync -av $pdir/$fname $host:$pdir
四、总结
hadoop集群节点的脚本分发主要是通过ssh免密码登陆、rsync工具,rsync只拷贝有差异的文件,这样可以提高效率,另外还需要熟悉一下shell脚本的for循环遍历,以及条件判断等知识点,大概思路就是先循环遍历所有的集群节点,然后在循环里通过#@遍历每一个输入的参数,即需同步/拷贝的文件,对于每个参数,先提取目录,再提取文件名,提取完毕后先使用ssh $host “mkdir -p…” 远程将节点的目录创建好,以免报错,最后再使用rsync命令去拷贝文件。