目录
针对集群运维
基础
脚本编写规范
①脚本文件后缀:通常以.sh结尾(并非强制,但便于识别)
②首行解释器:#!/bin/bash(固定写法,告诉系统用 bash 解释器执行脚本)
③注释规范
-
单行注释:# 注释内容(用于解释单行命令或变量含义)
-
多行注释:
方式1:多行单注释(适合少量多行)
这是一个大数据批量处理脚本
功能:同步原始数据并进行格式转换
方式2:利用here文档(适合大量多行注释)
: <<EOF
这是多行注释内容- 脚本作者:XXX
- 适用场景:Hadoop数据预处理
- 执行条件:需拥有bigdata目录读写权限
EOF
运行方式
①赋予执行权限:
# 方式1:给当前用户添加执行权限(推荐,最安全)
chmod u+x bigdata_task.sh
# 方式2:给所有用户添加执行权限(适合公共脚本)
chmod a+x bigdata_task.sh
# 方式3:给当前用户读+写+执行权限,其他用户读+执行权限(精细权限控制)
chmod 755 bigdata_task.sh
# 权限说明:数字对应r(读=4)、w(写=2)、x(执行=1),7=4+2+1,5=4+1
②运行脚本:
# 方式1:相对路径运行(推荐,需先赋予执行权限)
./bigdata_task.sh
# 适用:脚本在当前工作目录下
# 方式2:绝对路径运行(推荐,需先赋予执行权限)
/opt/bigdata/scripts/bigdata_task.sh
# 适用:脚本在固定目录,便于定时任务调用
# 方式3:通过解释器直接运行(无需赋予执行权限)
bash bigdata_task.sh
# 或
sh bigdata_task.sh
# 适用:临时运行脚本,无需修改权限
# 方式4:在当前shell环境中运行(用.或source)
. ./bigdata_task.sh
# 或
source ./bigdata_task.sh
# 适用:脚本中定义的变量需要在当前shell中生效(如配置环境变量的脚本)
语法
变量
①变量的定义:
-
变量名=值(等号前后无空格,不能包含特殊字符)
-
变量名只能包含字母、数字、下划线,不能以数字开头
-
变量值如果包含空格,需要用双引号包裹
#!/bin/bash
定义集群运维常用变量(贴合实际场景)
HADOOP_HOME="/opt/hadoop" # Hadoop安装目录(无空格,直接定义)
SPARK_HOME="/opt/spark-3.3.0" # Spark安装目录
CLUSTER_NODES="master slave1 slave2 slave3" # 集群节点列表(有空格,用双引号包裹也可以)
LOG_DIR="/bigdata/ops/logs" # 运维日志目录
DATA_DIR="/bigdata/data" # 数据存储目录
②变量的使用:
-
调用变量时,在变量名前加 ,推荐用 {变量名} 的格式,更规范。
#!/bin/bash
定义变量
HADOOP_HOME="/opt/hadoop"
LOG_DIR="/bigdata/ops/logs"使用变量
echo "Hadoop安装目录:HADOOP_HOME" # 简单调用 echo "运维日志目录:{LOG_DIR}" # 推荐格式,更规范
echo "HDFS启动脚本路径:${HADOOP_HOME}/sbin/start-dfs.sh" # 拼接路径(核心用法)
③特殊变量:
-
$0:脚本自身文件名
-
1、2...:接收脚本运行时传入的参数
#!/bin/bash
脚本名称:check_node.sh
运行方式:./check_node.sh slave1 20251221
echo "要检查的节点名称:1" # 接收第一个参数(slave1) echo "检查日期:2" # 接收第二个参数(20251221)
echo "脚本文件名:0" # 0 固定表示脚本本身的名字(check_node.sh) -
{n}:第 3\~9 个位置参数(超过 9 个需用{10}格式)
-
$#:位置参数的总个数(统计传入参数的数量)
-
$*:所有位置参数的集合,将所有参数视为一个整体(命令用双引号包裹时生效)
-
$@:所有位置参数的集合,将所有参数中每个参数视为独立个体(用双引号包裹时生效)
#!/bin/bash
示例:区分*和@
echo "===== 遍历$*(视为整体) ====="
for arg in "*"; do echo "参数:arg" # 仅输出1行:参数:a b c
doneecho "===== 遍历$@(视为独立个体,推荐) ====="
for arg in "@"; do echo "参数:arg" # 输出3行:参数:a;参数:b;参数:c
done -
?:获取上一条命令的执行结果,? 只有两个值:0 表示上一条命令执行成功,非0 表示执行失败,这是运维脚本中 "判断命令是否生效"的用法。
#!/bin/bash
尝试启动HDFS
/opt/hadoop/sbin/start-dfs.sh
判断启动是否成功
if [ $? -eq 0 ]; then
echo "HDFS启动成功!"
else
echo "HDFS启动失败!"
fi
条件判断
①语法格式:
# 格式1:test + 空格 + 条件表达式(空格不可省略,用于区分命令和表达式)
# Shell 内置的条件检测命令,无需依赖特殊解释器
test -f "$DATA_FILE"
# 格式2:[ + 空格 + 条件表达式 + 空格 + ](推荐,更直观,注意前后必须有空格)
[ -f "$DATA_FILE" ]
# 格式3:[[ + 条件表达式 + ]](bash专属,支持正则匹配、逻辑运算更简洁)
[[ "$DATA_DATE" =~ ^[0-9]{8}$ ]]
# 写法
if [ 条件表达式 ]; then
# 条件满足时,执行的命令(可以写多行)
命令1
命令2
else
# 条件不满足时,执行的命令(可以写多行)
命令3
命令4
fi
②常用判断条件:
| 判断类型 | 条件表达式 | 含义 |
|---|---|---|
| 文件判断 | [ -f "$file" ] | 判断是否为普通文件 |
| 文件判断 | [ -d "$dir" ] | 判断是否为目录 |
| 文件判断 | [ -e "$path" ] | 判断文件 / 目录是否存在 |
| 文件判断 | [ -r "$file" ] | 判断是否有读权限(读取数据文件时校验) |
| 文件判断 | [ -w "$file" ] | 判断是否有写权限(写入数据时校验) |
| 字符串判断 | [ "\(str1" = "\)str2" ] | 判断两个字符串相等(注意等号前后有空格) |
| 字符串判断 | [ "\(str1" != "\)str2" ] | 判断两个字符串不相等 |
| 字符串判断 | [ -n "$str" ] | 判断字符串非空(校验参数是否传入) |
| 字符串判断 | [ -z "$str" ] | 判断字符串为空 |
| 数字判断 | [ num1 -eq num2 ] | 等于(equal) |
| 数字判断 | [ num1 -ne num2 ] | 不等于(not equal) |
| 数字判断 | [ num1 -gt num2 ] | 大于(greater than) |
| 数字判断 | [ num1 -lt num2 ] | 小于(less than) |
| 数字判断 | [ num1 -ge num2 ] | 大于等于(greater or equal) |
| 数字判断 | [ num1 -le num2 ] | 小于等于(less or equal) |
| 逻辑运算 | [条件 1] && [ 条件 2 ] | 逻辑与(两个条件都成立) |
| 逻辑运算 | [条件 1] || [ 条件 2 ] | 逻辑或(两个条件有一个成立) |
| 逻辑运算 | [! 条件] | 逻辑非(条件不成立) |
#!/bin/bash
# 条件判断实战:集群环境前置检查
HADOOP_HOME="/opt/hadoop"
LOG_DIR="/bigdata/ops/logs"
DISK_USAGE=86 # 模拟磁盘使用率
# 1. 判断Hadoop目录是否存在
if [ -d "${HADOOP_HOME}" ]; then
echo "Hadoop目录存在:${HADOOP_HOME}"
else
echo "错误:Hadoop目录不存在!"
exit 1 # 退出脚本,不再执行后续内容
fi
# 2. 判断日志目录是否存在,不存在则创建
if [ ! -d "${LOG_DIR}" ]; then # ! 表示"非",即目录不存在时
echo "日志目录不存在,正在创建:${LOG_DIR}"
mkdir -p "${LOG_DIR}" # -p 递归创建目录
fi
# 3. 判断磁盘使用率是否超标(大于85%)
if [ ${DISK_USAGE} -gt 85 ]; then
echo "警告:磁盘使用率超标(${DISK_USAGE}%),请及时清理!"
else
echo "磁盘使用率正常(${DISK_USAGE}%)"
fi
循环
①for循环:
-
基础格式:
格式1:遍历固定列表(适合集群节点批量操作)
for 变量名 in 列表内容; do
# 循环执行的命令
命令
done格式2:数字循环(适合按序号遍历分区/任务)
for ((i=1; i<=5; i++)); do
# 循环执行的命令
命令
done#!/bin/bash
批量检查所有从节点的DataNode进程
定义节点列表
nodes=("slave1" "slave2" "slave3")
遍历节点列表
for node in "{nodes[@]}"; do # "{nodes[@]}" 表示遍历所有节点
echo "===== 正在检查节点:{node} =====" # 远程执行命令,检查DataNode进程 ssh root@{node} "jps | grep DataNode | grep -v grep"
# 判断进程是否存在
if [ ? -eq 0 ]; then echo "节点{node}:DataNode进程正常"
else
echo "节点${node}:DataNode进程缺失(异常)"
fi
done
②while循环:
-
基础格式
while [ 条件表达式 ]; do
# 条件满足时,循环执行的命令
命令
sleep 10 # 休眠10秒,避免循环过快占用资源
done特殊:无限循环(适合集群监控脚本)
while true; do
# 持续执行的命令(如监控进程状态)
命令
sleep 60 # 每分钟检查一次
done#!/bin/bash
监控NameNode进程,异常时打印告警
while true; do
# 检查NameNode进程
jps | grep NameNode | grep -v grep
if [ ? -ne 0 ]; then echo "[(date +'%Y-%m-%d %H:%M:%S')] 告警:NameNode进程异常退出!"
else
echo "[$(date +'%Y-%m-%d %H:%M:%S')] NameNode进程运行正常"
fi
sleep 60 # 每分钟检查一次
done
示例
免密登录配置
# 1. 在主节点生成RSA密钥对(一路回车,不设置密钥密码)
ssh-keygen -t rsa -b 4096 # -b 4096提升密钥安全性
# 2. 将公钥批量分发到所有集群节点(包括主节点自身)
# 定义节点列表(替换为你的集群节点)
nodes=("master" "slave1" "slave2" "slave3")
for node in "${nodes[@]}"; do
ssh-copy-id -i ~/.ssh/id_rsa.pub root@${node}
done
# 3. 验证免密登录(无需密码即可登录从节点)
ssh slave1
远程执行命令
# 场景1:批量检查所有从节点的DataNode进程
nodes=("slave1" "slave2" "slave3")
for node in "${nodes[@]}"; do
echo "===== 节点${node}进程状态 ====="
ssh root@${node} "jps | grep DataNode | grep -v grep"
done
# 场景2:批量在从节点创建数据目录
for node in "${nodes[@]}"; do
ssh root@${node} "mkdir -p /bigdata/data /bigdata/logs && chmod 755 /bigdata"
done
# 场景3:批量查看从节点磁盘使用率
for node in "${nodes[@]}"; do
echo "===== 节点${node}磁盘使用情况 ====="
ssh root@${node} "df -h | grep /bigdata"
done
批量同步配置文件
#!/bin/bash
# 批量同步Hadoop配置文件
SRC_DIR="/opt/hadoop/conf" # 主节点配置源目录
DST_DIR="/opt/hadoop/conf" # 从节点配置目标目录
nodes=("slave1" "slave2" "slave3") # 从节点列表
for node in "${nodes[@]}"; do
echo "===== 同步配置到节点${node} ====="
# 步骤1:备份从节点原有配置
BACKUP_DIR="${DST_DIR}_backup_$(date +%Y%m%d%H%M%S)"
ssh root@${node} "mkdir -p ${BACKUP_DIR} && cp -r ${DST_DIR}/* ${BACKUP_DIR}/"
# 步骤2:批量同步配置文件(-r 递归复制,-p 保留权限)
scp -rp "${SRC_DIR}"/* root@${node}:"${DST_DIR}/"
# 步骤3:验证配置一致性(对比MD5值)
SRC_MD5=$(md5sum "${SRC_DIR}/core-site.xml" | awk '{print $1}')
DST_MD5=$(ssh root@${node} "md5sum ${DST_DIR}/core-site.xml | awk '{print \$1}'")
if [ "${SRC_MD5}" = "${DST_MD5}" ]; then
echo "节点${node}配置同步成功,一致性验证通过"
else
echo "节点${node}配置同步失败,已自动回滚到${BACKUP_DIR}"
ssh root@${node} "cp -r ${BACKUP_DIR}/* ${DST_DIR}/"
fi
done
集群一键启动/停止脚本
#!/bin/bash
# 集群一键运维脚本:启动/停止Hadoop+Spark+HBase
# 用法:./cluster_start_stop.sh [start|stop]
# 全局配置
HADOOP_HOME="/opt/hadoop-3.3.4"
SPARK_HOME="/opt/spark-3.3.0"
HBASE_HOME="/opt/hbase-2.5.3"
SLAVE_NODES=("slave1" "slave2" "slave3")
OPS_LOG_DIR="/bigdata/ops/logs"
mkdir -p "${OPS_LOG_DIR}"
LOG_FILE="${OPS_LOG_DIR}/cluster_start_stop_$(date +%Y%m%d).log"
exec > "${LOG_FILE}" 2>&1
# 颜色输出函数
echo_info() { echo -e "\033[32m[INFO] $(date +'%Y-%m-%d %H:%M:%S') $1\033[0m"; }
echo_error() { echo -e "\033[31m[ERROR] $(date +'%Y-%m-%d %H:%M:%S') $1\033[0m"; }
# 集群启动函数
start_cluster() {
echo_info "===== 开始启动大数据集群 ====="
# 1. 启动Hadoop(HDFS+YARN)
echo_info "步骤1:启动Hadoop集群..."
${HADOOP_HOME}/sbin/start-dfs.sh
if [ $? -ne 0 ]; then
echo_error "HDFS启动失败,查看日志:${LOG_FILE}"
exit 1
fi
sleep 10 # 等待HDFS初始化完成
${HADOOP_HOME}/sbin/start-yarn.sh
if [ $? -ne 0 ]; then
echo_error "YARN启动失败,查看日志:${LOG_FILE}"
exit 1
fi
# 启动HistoryServer(便于查看任务历史)
${HADOOP_HOME}/sbin/mr-jobhistory-daemon.sh start historyserver
# 2. 启动Spark集群
echo_info "步骤2:启动Spark集群..."
${SPARK_HOME}/sbin/start-all.sh
if [ $? -ne 0 ]; then
echo_error "Spark启动失败,查看日志:${LOG_FILE}"
exit 1
fi
# 启动Spark HistoryServer
${SPARK_HOME}/sbin/start-history-server.sh
# 3. 启动HBase集群
echo_info "步骤3:启动HBase集群..."
${HBASE_HOME}/bin/start-hbase.sh
if [ $? -ne 0 ]; then
echo_error "HBase启动失败,查看日志:${LOG_FILE}"
exit 1
fi
# 4. 验证启动状态
echo_info "===== 集群启动完成,验证核心进程 ====="
jps | grep -E "NameNode|ResourceManager|Master|HMaster"
for node in "${SLAVE_NODES[@]}"; do
echo_info "节点${node}进程状态:"
ssh root@${node} "jps | grep -E 'DataNode|NodeManager|Worker|RegionServer'"
done
echo_info "集群启动日志已保存至:${LOG_FILE}"
}
# 集群停止函数
stop_cluster() {
echo_info "===== 开始停止大数据集群 ====="
# 1. 停止HBase集群
echo_info "步骤1:停止HBase集群..."
${HBASE_HOME}/bin/stop-hbase.sh
# 2. 停止Spark集群
echo_info "步骤2:停止Spark集群..."
${SPARK_HOME}/sbin/stop-history-server.sh
${SPARK_HOME}/sbin/stop-all.sh
# 3. 停止Hadoop集群
echo_info "步骤3:停止Hadoop集群..."
${HADOOP_HOME}/sbin/mr-jobhistory-daemon.sh stop historyserver
${HADOOP_HOME}/sbin/stop-yarn.sh
${HADOOP_HOME}/sbin/stop-dfs.sh
# 4. 验证停止状态
echo_info "===== 集群停止完成,验证进程是否清理 ====="
jps | grep -vE "Jps|${0##*/}"
for node in "${SLAVE_NODES[@]}"; do
echo_info "节点${node}剩余进程:"
ssh root@${node} "jps | grep -vE 'Jps'"
done
echo_info "集群停止日志已保存至:${LOG_FILE}"
}
# 主逻辑
if [ $# -ne 1 ]; then
echo "用法:$0 [start|stop]"
exit 1
fi
case $1 in
"start") start_cluster ;;
"stop") stop_cluster ;;
*) echo_error "无效参数,仅支持start/stop"; exit 1 ;;
esac
exit 0