上篇咱们聊了一个特别邪门的case——NFS环境下装数据库,报了一堆乱七八糟的错,什么权限不足啊、文件只读啊,反正看着就让人头皮发麻。结果你猜怎么着?最后发现就是Shell环境变量没加载,一行source .bashrc就搞定了,真的,就一行代码的事儿。
说实话,这种问题最容易让人钻牛角尖。我跟你说,我以前遇到这情况,恨不得把服务器都重装了,眼睛一闭chmod -R 777,能想到的办法全试一遍。最后发现是环境变量的问题,当时心态直接崩了。
所以今天咱们来点实在的,聊聊怎么在NFS环境下顺顺利利把数据库给部署上去,以及万一出了问题怎么有条不紊地去排查。我把我踩过的坑、走过的弯路都总结了一下,你们可得好好看看,下次遇到这事儿心里就有底了。
安装之前,这些检查不做你就等着哭吧
老铁们,我先说一句,安装前检查这事儿真的太重要了。你要是嫌麻烦跳过这些步骤,后面出问题的时候有你哭的。我当年就是吃了这个亏,折腾了三天三夜,最后发现就是个很傻的问题。
先看看你现在是哪个用户
这事儿看着简单,但真的是最容易出错的地方。你是kingbase用户还是root?是在自己家目录还是跑到别人地盘去了?
whoami
id
# 看看自己是谁,UID多少,属于哪个组
echo $HOME
# 这个很关键,有时候变量指向的目录根本不是你以为的那个
# 重点来了,环境变量没加载的话啥都白搭
source ~/.bashrc
source ~/.bash_profile
我跟你说,有个项目我记得特别清楚,当时凌晨三点被叫起来,说数据库怎么都装不上。我远程登上去一看,whoami显示是root,但HOME变量指向的是/home/kingbase,我直接在根目录瞎搞,肯定出问题啊。后来切到正确的用户,环境变量一加载,啪,搞定了。你说这事儿整的。
万一你的.bashrc文件不知道咋的被删了或者损坏了,可以从系统模板恢复:
# 从系统模板复制一份
cp /etc/skel/.bashrc ~/
cp /etc/skel/.bash_profile ~/
# 加载一下
source ~/.bashrc
Shell解释器这玩意儿也得看看
数据库安装脚本跑的时候依赖sh和bash这些解释器,你得确认它们能用,而且版本别太老。
sh --version
bash --version # 建议4.0以上,版本太老可能有兼容性问题
which sh
which bash # 看看路径对不对,一般是/bin/sh /bin/bash这样
# 快速测试一下解释器正不正常
echo 'echo "test"' | sh
echo 'echo "test"' | bash
我记得有个客户那边,sh指向的是一个很老的版本,安装脚本跑着跑着就报错了,各种奇奇怪怪的符号解析错误。一开始还以为是脚本代码问题,查了半天发现是解释器版本太旧,换成bash就好了。
目录权限这事儿马虎不得
安装目录和家目录的权限都得检查清楚了。
# 看家目录
ls -ld ~
# 看安装目录,你改成自己的实际路径
ls -ld /opt/kingbase
# 写个测试文件试试能不能写进去
touch ~/test_write_$$ && rm ~/test_write_$$
touch /opt/kingbase/test_write_$$ && rm /opt/kingbase/test_write_$$
要是写入失败,别急着chmod,先看看NFS挂载参数有没有问题。
NFS挂载参数!这个是重点中的重点
好了好了,敲黑板了,这个地方踩坑的人最多。
我跟你讲,NFS挂载参数要是没配对,你啥都别想装上去。我见过最离谱的一个情况是,服务端给配置成了noexec,就是禁止执行脚本,那还玩啥呀,数据库安装程序压根跑不起来。
# 先看看当前NFS挂载情况
mount | grep nfs
# 看看有没有rw和exec这两个参数
mount | grep nfs | grep -E "rw|exec"
# 如果啥输出都没有,完蛋,挂载有问题
# 完整的挂载参数
cat /proc/mounts | grep nfs
# 看看有没有noexec或者ro这种坑爹的参数
cat /proc/mounts | grep nfs | grep -E "noexec|ro"
# 要是有输出,你今天就别想装上去了
标准情况下,挂载参数应该是这样的:
# 正确的参数,这些得有
rw # 可读写,不然装到哪去
exec # 可执行,脚本得能跑
suid # 允许SUID,有些程序需要这个
no_root_squash # 这个看情况,数据库场景建议加上
# 错误的参数,这些要是出现了你就等着哭吧
noexec # 禁止执行 - 脚本全废
ro # 只读模式 - 装个寂寞
nosuid # 禁止SUID - 某些程序直接GG
发现了问题咋整?重新挂载呗:
# 先卸掉
umount /home/test
# 重新挂上,这次带上正确参数
mount -t nfs 192.168.1.100:/nfs_share /home/test \
-o rw,exec,suid,no_root_squash
# 想永久生效就写进fstab
# 格式:服务端IP:共享目录 本地挂载目录 nfs 参数 0 0
192.168.1.100:/nfs_share /home/test nfs rw,exec,suid,no_root_squash 0 0
SELinux和防火墙有时候也会搞事情
安全策略这玩意儿吧,有时候真的挺烦人的,明明啥都配置好了,它就是不让你过。
getenforce
# 如果显示Enforcing,可能得临时关掉试试
# 临时关闭
setenforce 0
# 永久关闭的话改配置文件然后重启
sed -i 's/SELINUX=enforcing/SELINUX=disabled/' /etc/selinux/config
# 看看防火墙
systemctl status firewalld
systemctl status iptables
# 临时关掉试试
systemctl stop firewalld
我跟你说,之前有个项目,NFS服务端和客户端都配得好好的,但就是连不上。查了半天,发现是防火墙把111端口给封了,RPC服务压根通信不了。你说这找谁说理去。
系统依赖包得装齐全了
数据库跑起来需要一些基础包,这些没装的话会出现各种奇怪的报错。
# RHEL/CentOS的话
yum install -y libaio-devel gcc make glibc
# Debian/Ubuntu的话
apt install -y libaio-dev gcc make
# 看看装上了没
rpm -qa | grep libaio # 红帽系
dpkg -l | grep libaio # Debian系
系统资源限制别忘了调
数据库这玩意儿挺吃资源的,信号量、文件句柄、最大进程数都得够用才行。
ipcs -l # 看信号量
ulimit -a # 看各种限制
# 临时调大点
ulimit -n 65535 # 文件句柄
ulimit -u 65535 # 最大进程数
# 永久生效的话改这个配置文件
cat >> /etc/security/limits.conf << EOF
kingbase soft nofile 65535
kingbase hard nofile 65535
kingbase soft nproc 65535
kingbase hard nproc 65535
EOF
内核参数也得看看:
sysctl -a | grep -E "shm|sem|file-max"
# 加到配置文件里
cat >> /etc/sysctl.conf << EOF
kernel.shmmax = 68719476736
kernel.shmall = 4294967296
kernel.shmmni = 4096
kernel.sem = 250 256000 100 1024
file-max = 65536
EOF
sysctl -p # 让配置生效
网络相关的也得确认清楚
集群环境的话,主机名和hosts配置特别重要,还有网络得通。
hostname
hostname -f
cat /etc/hosts
# 确保所有节点都在里面,格式是 IP 主机名
# 网络得通才行
ping -c 3 192.168.1.100 # NFS服务器
ping -c 3 其他节点IP
语言环境设置好
echo $LANG
# 建议设成UTF-8
export LANG=en_US.UTF-8
# 或者
export LANG=zh_CN.UTF-8
# 永久生效
echo "export LANG=en_US.UTF-8" >> ~/.bashrc
source ~/.bashrc
磁盘空间和inode得够
df -h # 看空间
df -i # 看inode,有时候空间够但inode用完了也白搭
# NFS目录的话还跟网络延迟有关系
df -h /home/test
系统日志是救命稻草
出了问题第一时间去看日志,这个我后面还会重点讲。
dmesg | grep -i nfs # 内核日志
tail -100 /var/log/messages # 系统日志
cat /var/log/nfsd # NFS服务端日志,需要服务端权限
rpcinfo -p # RPC服务状态
写了个一键检查脚本,你要不要试试
每次装之前都得跑一遍这些检查,说实话挺烦的。我就写了个脚本,一次性全跑完,出问题的环节一目了然:
#!/bin/bash
# pre_install_check.sh
RED='\033[0;31m'
GREEN='\033[0;32m'
NC='\033[0m'
echo "=========================================="
echo " 数据库安装前环境检查"
echo "=========================================="
echo ""
check_result() {
if [ $? -eq 0 ]; then
echo -e "${GREEN}[PASS]${NC} $1"
else
echo -e "${RED}[FAIL]${NC} $1"
fi
}
# 1. 用户身份
echo "1. 用户身份检查"
whoami
id
echo ""
# 2. 环境变量
echo "2. 环境变量检查"
source ~/.bashrc 2>/dev/null
echo "PATH=$PATH"
echo ""
# 3. Shell解释器
echo "3. Shell解释器检查"
which sh
which bash
sh --version | head -1
echo ""
# 4. NFS挂载
echo "4. NFS挂载检查"
mount | grep nfs
mount | grep nfs | grep -q rw && echo " 读写模式: OK" || echo " 读写模式: FAIL"
mount | grep nfs | grep -q exec && echo " 执行权限: OK" || echo " 执行权限: FAIL"
echo ""
# 5. 写入测试
echo "5. 目录写入测试"
touch ~/nfs_test_$$ 2>/dev/null && rm ~/nfs_test_$$ && echo " 家目录: OK" || echo " 家目录: FAIL"
touch /tmp/nfs_test_$$ 2>/dev/null && rm /tmp/nfs_test_$$ && echo " 临时目录: OK" || echo " 临时目录: FAIL"
echo ""
# 6. 资源限制
echo "6. 资源限制检查"
ulimit -n
ulimit -u
echo ""
# 7. 依赖包
echo "7. 依赖包检查"
rpm -qa | grep -E "libaio|gcc" | head -5
echo ""
echo "=========================================="
echo " 检查完成"
echo "=========================================="
NFS环境下部署数据库的一些经验
服务端配置是基础
服务端/etc/exports配置不对,后面全是白搭。
# /etc/exports大概长这样
/nfs_share 192.168.1.0/24(rw,sync,no_root_squash,no_subtree_check)
# rw是读写,sync是同步写入数据更安全但性能略差
# async的话性能好但可能丢数据,看你取舍
# no_root_squash数据库场景建议加上
# no_subtree_check关掉能减少延迟
提醒一句啊,no_root_squash安全风险是有的,你要是跑在内网环境问题不大,但要是啥不可信的网络,你得掂量掂量。
客户端挂载参数得完整
# 推荐这么挂
mount -t nfs 192.168.1.100:/nfs_share /home/test \
-o rw,exec,suid,hard,intr,rsize=32768,wsize=32768,tcp,vers=3
# rw,exec,suid基础权限不用说了
# hard是硬挂载,服务端挂了会等着
# intr允许中断等待
# rsize和wsize调大点能提升性能
# tcp比udp稳定多了
# vers=3兼容性最好
网络质量得盯紧
NFS这玩意儿对网络依赖挺大的,你网络要是经常抽风,那数据库也别想稳。
ping -c 10 192.168.1.100 # 看看延迟稳不稳
time ls /home/test # NFS响应时间
nfsstat # 统计信息
不同的部署场景怎么搞
场景一:单机装在NFS上
这个最简单,数据库软件和数据目录都扔NFS上。
# 目录结构大概这样
/export/nfs_share/
├── kingbase/
│ └── KingbaseES/
└── data/
└── KES/
# ~/.bashrc里配环境变量
export KINGBASE_HOME=/export/nfs_share/kingbase/KingbaseES
export PATH=$KINGBASE_HOME/bin:$PATH
export LD_LIBRARY_PATH=$KINGBASE_HOME/lib:$LD_LIBRARY_PATH
场景二:主备集群共用存储
主备架构下,所有节点都访问同一个数据目录,NFS是必须的。
# 节点A挂载
mount -t nfs 192.168.1.100:/nfs_share /home/kingbase/data \
-o rw,exec,suid,hard,intr,tcp,vers=3
# 节点B也得挂上同样的目录
mount -t nfs 192.168.1.100:/nfs_share /home/kingbase/data \
-o rw,exec,suid,hard,intr,tcp,vers=3
# 重点:各节点的用户UID必须一致
useradd -u 1001 -g kingbase -d /home/kingbase -s /bin/bash kingbase
场景三:NFS加本地盘混合部署
性能敏感的数据放本地SSD,普通数据扔NFS。
# 目录规划
/export/nfs_share/ # NFS共享存储
/home/kingbase/
├── data/ # NFS: 主数据目录
├── xlog/ # NFS: WAL日志
└── tablespace/ # NFS: 表空间
/ssd/local_data/ # 本地SSD
└── hot_data/ # 本地: 热数据
NFS版本和操作系统兼容性问题
操作系统兼容性
cat /etc/redhat-release
cat /etc/os-release
uname -r
ldd --version | head -1
这些信息得跟数据库版本要求对得上,不然装上了也跑不稳。
NFSv3还是v4?
cat /proc/fs/nfsd/versions
# v3的好处是兼容性杠杠的,调试也简单,老系统用它准没错
# v4性能好一点,还支持Kerberos认证,新系统可以考虑
# 遇到兼容性问题可以强制用v3
mount -t nfs -o vers=3 192.168.1.100:/nfs_share /mnt
调试脚本的几板斧
遇到问题不可怕,可怕的是不知道怎么找问题。下面几招我常用。
环境变量怎么查
env # 所有环境变量都列出来
echo $PATH
echo $LD_LIBRARY_PATH
# 脚本里开启调试
#!/bin/bash
set -x # 打印每条命令和参数
set -v # 打印输入行
set -e # 命令失败就退出
set -u # 未定义变量报错
脚本调试
bash -x setup.sh # 一步步看执行过程
# 只要错误输出的话
bash -x setup.sh 2>&1 | grep -E "^\\+|error|warning"
# strace跟踪系统调用,超级详细
strace -f -o /tmp/strace.log ./setup.sh
grep -E "open|read|write" /tmp/strace.log | head -50
NFS调试
mount -t nfs -o remount,debug /home/test # 开启debug
rpcinfo -p # RPC状态
cat /proc/mounts # 挂载详情
# 服务端的话需要权限
showmount -e localhost
exportfs -v
日志怎么看
tail -f /var/log/messages # 实时看日志
grep -i nfs /var/log/messages # 搜索NFS相关内容
grep -i error /var/log/messages | tail -20 # 错误日志
# 实时监控NFS日志
tail -f /var/log/messages | grep -i nfs
实战案例分享
批量部署怎么搞
生产环境不可能一台台机器手动去装,写个脚本批量跑:
#!/bin/bash
# deploy_to_all_nodes.sh
NODES=(
"192.168.1.101"
"192.168.1.102"
"192.168.1.103"
)
PACKAGE="/nfs_share/packages/KingbaseES_V009R004C002B0024_Lin64_install.tar.gz"
for node in "${NODES[@]}"; do
echo "========================================"
echo "部署到节点: $node"
echo "========================================"
echo "[1/5] 复制安装包..."
scp -q $PACKAGE root@$node:/tmp/ || {
echo "复制失败,跳过 $node"
continue
}
echo "[2/5] 执行环境检查..."
ssh root@$node "bash < /dev/stdin" << 'CHECK'
source ~/.bashrc
echo "PATH: $PATH"
mount | grep nfs | grep -q rw && echo "NFS: OK" || echo "NFS: FAIL"
df -h /home/kingbase
CHECK
echo "[3/5] 解压安装包..."
ssh root@$node "cd /tmp && tar -xzf KingbaseES*.tar.gz"
echo "[4/5] 执行安装..."
ssh root@$node "cd /tmp/KingbaseES && ./setup.sh -y"
echo "[5/5] 验证安装..."
ssh root@$node "source ~/.bashrc && sys_ver"
echo "节点 $node 部署完成"
echo ""
done
echo "========================================"
echo "批量部署完成"
echo "========================================"
自动修复脚本
环境变量没加载的问题,我写了个自动修复的脚本,遇到这种情况直接跑一遍:
#!/bin/bash
# fix_env.sh
echo "开始修复Shell环境..."
# .bashrc不存在就创建一个
if [ ! -f ~/.bashrc ]; then
echo "[1/5] 创建 .bashrc..."
if [ -f /etc/skel/.bashrc ]; then
cp /etc/skel/.bashrc ~/
else
cat > ~/.bashrc << 'EOF'
# .bashrc
export PATH=/usr/local/bin:/usr/bin:/bin
export HOME=/root
EOF
fi
else
echo "[1/5] .bashrc 已存在"
fi
# .bash_profile不存在或者没调用.bashrc的话补上
if [ ! -f ~/.bash_profile ]; then
echo "[2/5] 创建 .bash_profile..."
cat > ~/.bash_profile << 'EOF'
# .bash_profile
if [ -f ~/.bashrc ]; then
source ~/.bashrc
fi
EOF
else
echo "[2/5] .bash_profile 已存在"
grep -q "\.bashrc" ~/.bash_profile || {
echo "[2/5] 添加 .bashrc 调用..."
echo 'if [ -f ~/.bashrc ]; then' >> ~/.bash_profile
echo ' source ~/.bashrc' >> ~/.bash_profile
echo 'fi' >> ~/.bash_profile
}
fi
echo "[3/5] 重新加载环境..."
source ~/.bashrc
source ~/.bash_profile
echo "[4/5] 验证环境..."
echo "PATH: $PATH"
which sh
which bash
echo "[5/5] 环境修复完成"
echo ""
echo "请重新登录Shell或执行: exec bash"
if [ -n "$SSH_CONNECTION" ]; then
exec bash
fi
安装完了怎么验证
装完之后跑一下这个脚本,看看是不是真的装好了:
#!/bin/bash
# verify_install.sh
set -e
echo "=========================================="
echo " 数据库安装验证"
echo "=========================================="
echo ""
echo "1. 检查环境变量..."
source ~/.bashrc
echo " KINGBASE_HOME=$KINGBASE_HOME"
echo " PATH包含bin目录: $(echo $PATH | grep -q bin && echo 'YES' || echo 'NO')"
echo "2. 检查数据库服务..."
if systemctl is-active kingbase.service >/dev/null 2>&1; then
echo " 服务状态: 运行中"
elif pgrep -f "sys_master" >/dev/null; then
echo " 服务状态: 运行中(进程存在)"
else
echo " 服务状态: 未运行"
fi
echo "3. 检查数据库连接..."
$KINGBASE_HOME/bin/ksql -U system -d postgres -c "SELECT version();" >/dev/null 2>&1
if [ $? -eq 0 ]; then
echo " 数据库连接: 正常"
else
echo " 数据库连接: 失败"
fi
echo "4. 检查数据目录..."
ls -ld $KINGBASE_DATA 2>/dev/null && echo " 数据目录: 存在" || echo " 数据目录: 不存在"
echo "5. 检查NFS挂载..."
mount | grep nfs | grep -q "$KINGBASE_DATA" && echo " 数据目录在NFS: 是" || echo " 数据目录在NFS: 否"
echo ""
echo "=========================================="
echo " 验证完成"
echo "=========================================="
我踩过的那些坑,你们可别再踩了
坑一:SSH远程执行环境丢了
通过SSH跑命令的时候,环境变量不生效。这问题我遇到过好几次了。
# 错误的写法
ssh test@host "source ~/.bashrc && ./setup.sh"
# 正确的写法
ssh test@host '
source ~/.bashrc
./setup.sh
'
# 或者用bash -l强制走登录Shell
ssh -t test@host "bash -l -c './setup.sh'"
坑二:su切换用户后环境不对
su过去之后命令找不到了,这种事儿太常见了。
# 错误
su kingbase
# 正确
su - kingbase
# 或者显式加载环境
su -c "source ~/.bashrc && your_command" kingbase
坑三:fstab改了但重启不生效
改了/etc/fstab但挂载没生效,这种情况我见过不少。
cat /etc/fstab # 检查格式
mount -a # 测试语法,不实际挂载
dmesg | tail -20 # 看挂载错误
journalctl -xe | tail -50
坑四:装了但启动不了
数据库装好了,但systemctl start就是起不来。
vim /usr/lib/systemd/system/kingbase.service
# 在[Service]段落加这个
EnvironmentFile=/home/kingbase/.bashrc
# 或者在ExecStart前加
ExecStartPre=/bin/bash -c 'source /home/kingbase/.bashrc'
systemctl daemon-reload
坑五:权限看着对但就是写不进去
ls -la显示权限没问题,但touch文件就是报权限拒绝。
# 服务端看看
cat /etc/exports
# 看看有没有no_root_squash,或者anonuid配置对不对
# 客户端看看
id
# 确认UID和用户名映射关系对不对
最后叨叨几句
好了,写了这么多,也不知道你看完感觉咋样。
NFS环境下装数据库,说来说去就那么几件事:Shell环境变量得加载对、NFS挂载参数得配对、用户权限得到位。遇到问题别慌,先source一下.bashrc试试,实在不行就跑一遍检查清单,十分钟的检查能省下后面好几个小时的折腾。
日志这东西真的是救命稻草,学会看日志、分析日志,问题定位起来就快多了。
说真的,技术这东西没有万能药。NFS有NFS的好,本地盘有本地盘的妙,看你具体啥需求,别盲目的跟风选什么"最佳实践",适合自己的才是最好的。