概述:为什么需要 CLVM?
在现代数据中心,高可用性(High Availability) 是关键需求。传统 LVM 只能在单个节点上管理存储,当应用需要跨多个节点访问共享存储时,就会面临数据一致性和并发访问问题。CLVM(Clustered LVM)应运而生,它是 LVM 的集群感知扩展,允许多个节点安全地共享和管理同一个物理存储池。
典型应用场景
- 数据库集群(如 Oracle RAC、MySQL Cluster)
- 虚拟化高可用(如 KVM 高可用集群)
- 共享文件系统(如 GFS2、OCFS2)的底层存储
- 企业级应用(如 SAP、ERP 系统)
第一章:CLVM 核心概念深度解析
1.1 CLVM 架构总览

1.2 CLVM vs LVM:关键差异
| 特性 |
传统 LVM |
CLVM(集群 LVM) |
| 架构模式 |
单节点访问 |
多节点并发访问 |
| 锁机制 |
本地文件锁 |
分布式锁(DLM) |
| 元数据更新 |
直接写入 |
通过 clvmd 协调 |
| 故障恢复 |
需要手动干预 |
自动故障转移 |
| 适用场景 |
单服务器 |
高可用集群 |
| 性能开销 |
低 |
中等(锁协调开销) |
| 复杂度 |
简单 |
复杂 |
1.3 核心组件详解
1.3.1 分布式锁管理器(DLM)
# DLM 在集群中的作用:
# 1. 资源锁管理
# 2. 防止脑裂(Split-brain)
# 3. 协调并发访问
# 查看 DLM 锁状态
dlm_tool ls
# 示例输出:
# name mode node gr rq empty master
# clvmd:ex:testvg EX 1 0 0 0 1
# testvg:ex:00 EX 1 0 0 0 1
1.3.2 集群 LVM 守护进程(clvmd)
# clvmd 是 CLVM 的核心进程,负责:
# 1. 处理 LVM 命令
# 2. 与 DLM 交互获取锁
# 3. 同步元数据更新
# 检查 clvmd 状态
ps aux | grep clvmd
systemctl status clvmd
# clvmd 日志位置
/var/log/cluster/clvmd.log
1.3.3 集群管理器(Corosync + Pacemaker)
# 现代集群通常使用 Corosync+Pacemaker
# 查看集群状态
pcs status
# 查看集群节点
corosync-cmapctl | grep members
# 检查仲裁状态
pcs quorum status
第二章:CLVM 工作原理深度剖析
2.1 锁机制详解
锁类型
// CLVM 使用的主要锁类型:
// 1. 排他锁(Exclusive Lock,EX)
// - 用于元数据更新(创建/删除/扩展 LV)
// - 同一时间只能有一个节点持有
// 2. 共享锁(Shared Lock,SH)
// - 用于读取操作(lvdisplay、vgdisplay)
// - 多个节点可以同时持有
// 3. 保护锁(Protected Lock,PW)
// - 用于防止并发写操作
// - 允许一个写操作,多个读操作
锁层次结构
卷组(VG)层级锁
├── 元数据更新锁(EX)
├── 激活/去激活锁(EX)
└── 逻辑卷(LV)层级锁
├── LV 创建锁(EX)
├── LV 扩展锁(EX)
└── LV 访问锁(SH/PW)
2.2 元数据同步流程

2.3 故障处理机制
节点故障
# 当集群节点故障时:
# 1. 集群管理器检测到节点离线
# 2. DLM 释放该节点持有的所有锁
# 3. 剩余节点重新协商锁所有权
# 4. 故障节点的激活逻辑卷自动去激活
# 模拟节点故障后的恢复
pcs node standby node2 # 将 node2 设为备用
pcs cluster cleanup node2 # 清理故障节点
pcs cluster start node2 # 重新加入集群
脑裂预防
# CLVM 防止脑裂的策略:
# 1. 仲裁机制(Quorum)
# 2. 隔离(Fencing)
# 3. 锁超时机制
# 配置隔离设备
pcs stonith create myfence fence_scsi \
pcmk_host_list="node1 node2" \
devices="/dev/sdc" \
meta provides="unfencing"
# 检查仲裁状态
pcs quorum config
第三章:环境准备与先决条件
3.1 硬件和网络要求
存储配置
# 1. 共享存储配置示例(iSCSI)
# 所有集群节点都能访问的共享存储
# 在各节点发现 iSCSI 目标
iscsiadm -m discovery -t st -p 192.168.1.100
# 登录目标
iscsiadm -m node -T iqn.2021-01.com.example:storage -p 192.168.1.100 --login
# 确认所有节点看到相同的磁盘
# 节点1:
lsblk
# sdb 8:16 0 100G 0 disk
# 节点2:
lsblk
# sdb 8:16 0 100G 0 disk # 必须是相同的设备名
# 创建专用集群网络配置文件
cat > /etc/sysconfig/network-scripts/ifcfg-bond0 << 'EOF'
DEVICE=bond0
TYPE=Bond
NAME=bond0
BONDING_MASTER=yes
IPADDR=10.0.0.1
PREFIX=24
GATEWAY=10.0.0.254
DNS1=8.8.8.8
ONBOOT=yes
BOOTPROTO=none
BONDING_OPTS="mode=1 miimon=100"
EOF
# 集群节点 hosts 文件
cat >> /etc/hosts << 'EOF'
# Cluster Nodes
10.0.0.1 node1.cluster.lab node1
10.0.0.2 node2.cluster.lab node2
10.0.0.3 node3.cluster.lab node3
EOF
3.2 软件包安装
#!/bin/bash
# install-cluster-packages.sh
# 在所有集群节点上执行
# 定义节点列表
NODES=("node1" "node2" "node3")
# 要安装的软件包列表
PACKAGES=(
"lvm2-cluster" # CLVM 核心包
"corosync" # 集群通信
"pacemaker" # 集群资源管理器
"pcs" # Pacemaker 配置工具
"fence-agents-all" # 隔离代理
"dlm" # 分布式锁管理器
"cman" # 集群管理器(可选)
"gfs2-utils" # GFS2 文件系统工具
)
install_packages() {
local node=$1
echo "在节点 $node 上安装软件包..."
# SSH 到节点执行安装
ssh "root@$node" "
# 更新系统
dnf update -y
# 安装集群软件包
dnf install -y ${PACKAGES[@]}
# 验证安装
rpm -qa | grep -E 'lvm2-cluster|corosync|pacemaker|dlm'
# 启用服务
systemctl enable pcsd
systemctl start pcsd
"
}
# 在所有节点上执行安装
for node in "${NODES[@]}"; do
install_packages "$node"
done
echo "所有节点软件包安装完成"
3.3 配置 SSH 互信
#!/bin/bash
# setup-ssh-trust.sh
# 配置集群节点间的 SSH 免密访问
NODES=("node1" "node2" "node3")
CLUSTER_USER="hacluster"
CLUSTER_PASSWORD="YourSecurePassword123"
# 1. 生成 SSH 密钥(在所有节点执行)
for node in "${NODES[@]}"; do
ssh "root@$node" "
# 生成 SSH 密钥(如果不存在)
if [ ! -f ~/.ssh/id_rsa ]; then
ssh-keygen -t rsa -N '' -f ~/.ssh/id_rsa
fi
# 设置 hacluster 用户密码
echo '$CLUSTER_PASSWORD' | passwd --stdin $CLUSTER_USER
"
done
# 2. 收集所有公钥
ALL_KEYS=""
for node in "${NODES[@]}"; do
KEY=$(ssh "root@$node" "cat ~/.ssh/id_rsa.pub")
ALL_KEYS="$ALL_KEYS$KEY"
done
# 3. 分发 authorized_keys 到所有节点
for node in "${NODES[@]}"; do
ssh "root@$node" "
# 备份现有 authorized_keys
cp ~/.ssh/authorized_keys ~/.ssh/authorized_keys.bak 2>/dev/null || true
# 写入所有节点的公钥
echo '$ALL_KEYS' > ~/.ssh/authorized_keys
# 设置正确的权限
chmod 600 ~/.ssh/authorized_keys
chmod 700 ~/.ssh
# 为 hacluster 用户也设置
mkdir -p /home/$CLUSTER_USER/.ssh
echo '$ALL_KEYS' > /home/$CLUSTER_USER/.ssh/authorized_keys
chown -R $CLUSTER_USER:$CLUSTER_USER /home/$CLUSTER_USER/.ssh
chmod 600 /home/$CLUSTER_USER/.ssh/authorized_keys
"
done
# 4. 测试 SSH 连接
for source_node in "${NODES[@]}"; do
for target_node in "${NODES[@]}"; do
if [ "$source_node" != "$target_node" ]; then
echo "测试 $source_node -> $target_node ..."
ssh "root@$source_node" "ssh -o StrictHostKeyChecking=no root@$target_node 'hostname'"
fi
done
done
echo "SSH 互信配置完成"
第四章:CLVM 完整配置实战
4.1 集群基础配置
#!/bin/bash
# configure-cluster-basic.sh
# 定义集群参数
CLUSTER_NAME="mycluster"
NODES=("node1" "node2" "node3")
TRANSPORT="udpu" # 对于3节点以上使用 udpu,2节点使用 udp
# 1. 认证集群节点(在任一节点执行)
pcs host auth ${NODES[@]} -u hacluster -p YourSecurePassword123
# 2. 创建集群
pcs cluster setup $CLUSTER_NAME ${NODES[@]} \
--transport $TRANSPORT \
--totem token=30000 \
--ipv6
# 3. 配置集群属性
pcs property set \
stonith-enabled=true \
no-quorum-policy=freeze \
cluster-recheck-interval=2min \
default-resource-stickiness=100 \
symmetric-cluster=true \
maintenance-mode=false
# 4. 配置 Corosync 选项
pcs config update \
totem.token=30000 \
totem.join=60 \
totem.consensus=36000 \
totem.max_messages=20 \
totem.transport=$TRANSPORT
# 5. 启用并启动集群
pcs cluster enable --all
pcs cluster start --all
# 6. 检查集群状态
echo "=== 集群状态检查 ==="
pcs status
echo ""
corosync-cmapctl | grep -E "runtime|members"
echo ""
pcs quorum status
# 7. 配置隔离(STONITH)
# 根据硬件选择隔离代理,以下是 IPMI 示例
for node in "${NODES[@]}"; do
pcs stonith create fence-$node fence_ipmilan \
pcmk_host_list=$node \
ipaddr=192.168.1.$((100 + ${node:4:1})) \
login=admin \
passwd=password \
lanplus=true \
power_wait=5 \
op monitor interval=60s
done
# 8. 配置隔离级别
pcs stonith level add 1 node1 fence-node2,fence-node3
pcs stonith level add 1 node2 fence-node1,fence-node3
pcs stonith level add 1 node3 fence-node1,fence-node2
4.2 CLVM 服务配置
#!/bin/bash
# configure-clvmd-service.sh
# 1. 停止并禁用本地 lvm2-lvmetad
systemctl stop lvm2-lvmetad
systemctl disable lvm2-lvmetad
systemctl mask lvm2-lvmetad
# 2. 配置 lvm.conf 启用集群模式
cat > /etc/lvm/lvm.conf << 'EOF'
# 启用集群锁定
locking_type = 3
# 使用外部锁管理器
use_lvmetad = 0
# 等待锁的超时时间(毫秒)
locking_timeout = 30
# 回退到本地锁定(当集群不可用时)
fallback_to_local_locking = 1
# 集群范围过滤
filter = [ "a|/dev/sd.*|", "r|.*|" ]
global_filter = [ "a|/dev/sd.*|", "r|.*|" ]
# 启用共享卷组
volume_list = [ "clustervg" ]
# 设置系统ID(自动生成)
system_id_source = "uname"
EOF
# 3. 配置 clvmd
cat > /etc/lvm/lvmlocal.conf << 'EOF'
# clvmd 本地配置
locking_type=3
activation=1
# 锁管理器配置
locking_args="--systemid $(hostname -s)"
# 心跳间隔
heartbeat=5
EOF
# 4. 创建 clvmd systemd 服务配置
mkdir -p /etc/systemd/system/clvmd.service.d
cat > /etc/systemd/system/clvmd.service.d/override.conf << 'EOF'
[Service]
# 确保在集群服务之后启动
After=corosync.service pacemaker.service
Requires=corosync.service pacemaker.service
# 重启策略
Restart=always
RestartSec=10
# 安全上下文
ReadWritePaths=/var/lock/lvm /run/lvm /etc/lvm/archive /etc/lvm/backup /etc/lvm/cache
# 环境变量
Environment="CLVMD_OPTS=--pidfile /run/clvmd.pid"
EOF
# 5. 启动 clvmd 服务
systemctl daemon-reload
systemctl enable clvmd
systemctl start clvmd
# 6. 检查 clvmd 状态
echo "=== clvmd 状态检查 ==="
systemctl status clvmd
echo ""
clvmd -T
echo ""
lvmlockctl --dump
4.3 创建集群卷组和逻辑卷
#!/bin/bash
# create-clustered-lvm.sh
# 定义参数
SHARED_DISK="/dev/sdb" # 共享存储设备
VG_NAME="clustervg"
LV_NAME="clusterlv"
LV_SIZE="50G"
MOUNT_POINT="/shared"
# 1. 在所有节点上初始化物理卷
echo "在所有节点上初始化物理卷..."
for node in "${NODES[@]}"; do
ssh "root@$node" "
# 创建物理卷(只在第一个节点执行写操作)
if [ '$node' = 'node1' ]; then
pvcreate -y --metadatasize 128M $SHARED_DISK
fi
# 扫描物理卷
pvscan --cache $SHARED_DISK
"
done
# 2. 创建集群卷组(在一个节点执行)
echo "创建集群卷组..."
ssh root@node1 "
# 创建集群卷组
vgcreate --shared $VG_NAME $SHARED_DISK
# 设置卷组系统ID
vgs --noheadings -o vg_name,systemid
# 激活卷组
vgchange -ay $VG_NAME
# 检查卷组状态
vgdisplay $VG_NAME
"
# 3. 同步卷组元数据到所有节点
echo "同步卷组配置..."
for node in "${NODES[@]}"; do
if [ "$node" != "node1" ]; then
ssh "root@$node" "
# 扫描卷组
vgscan --cache
# 导入卷组
vgimport $VG_NAME
# 激活卷组
vgchange -ay $VG_NAME
# 验证卷组
vgs $VG_NAME
"
fi
done
# 4. 创建集群逻辑卷
echo "创建集群逻辑卷..."
ssh root@node1 "
# 创建逻辑卷
lvcreate -L $LV_SIZE -n $LV_NAME $VG_NAME
# 设置逻辑卷标签
lvchange --addtag 'cluster-shared' /dev/$VG_NAME/$LV_NAME
# 检查逻辑卷
lvdisplay /dev/$VG_NAME/$LV_NAME
# 查看锁状态
lvmlockctl -i $VG_NAME
"
# 5. 验证所有节点都能看到逻辑卷
echo "验证所有节点的访问..."
for node in "${NODES[@]}"; do
echo "节点 $node:"
ssh "root@$node" "
# 扫描逻辑卷
lvscan
# 检查逻辑卷信息
lvs /dev/$VG_NAME/$LV_NAME
# 检查锁状态
dlm_tool ls | grep $VG_NAME
"
done
# 6. 创建文件系统(只在第一个节点)
echo "创建文件系统..."
ssh root@node1 "
# 创建 XFS 文件系统(支持集群)
mkfs.xfs -f /dev/$VG_NAME/$LV_NAME
# 设置文件系统标签
xfs_admin -L 'cluster_data' /dev/$VG_NAME/$LV_NAME
# 显示文件系统信息
xfs_info /dev/$VG_NAME/$LV_NAME
"
# 7. 配置自动挂载(在所有节点)
echo "配置挂载点..."
for node in "${NODES[@]}"; do
ssh "root@$node" "
# 创建挂载点
mkdir -p $MOUNT_POINT
# 添加 fstab 条目(使用 _netdev 选项)
echo '/dev/$VG_NAME/$LV_NAME $MOUNT_POINT xfs defaults,_netdev,noauto 0 0' >> /etc/fstab
# 测试挂载
mount $MOUNT_POINT
df -h $MOUNT_POINT
umount $MOUNT_POINT
"
done
echo "集群 LVM 配置完成"
#!/bin/bash
# configure-pacemaker-clvm.sh
# 1. 创建集群 LVM 激活资源
pcs resource create clvmd-service systemd:clvmd \
op monitor interval="30s" timeout="30s" \
op start timeout="90s" interval="0s" \
op stop timeout="100s" interval="0s" \
meta target-role="Started"
# 2. 创建 DLM 资源
pcs resource create dlm ocf:pacemaker:controld \
op monitor interval="30s" timeout="30s" \
op start timeout="90s" interval="0s" \
op stop timeout="100s" interval="0s"
# 3. 创建卷组资源
pcs resource create clvmd-vg LVM \
volgrpname=clustervg \
exclusive=true \
op start timeout="30s" interval="0s" \
op stop timeout="30s" interval="0s" \
op monitor interval="10s" timeout="30s"
# 4. 创建文件系统资源
pcs resource create shared-fs Filesystem \
device="/dev/clustervg/clusterlv" \
directory="/shared" \
fstype="xfs" \
options="noatime,inode64" \
op monitor interval="20s" timeout="40s" \
op start timeout="60s" interval="0s" \
op stop timeout="60s" interval="0s"
# 5. 设置资源约束和顺序
# DLM 必须在 clvmd 之前启动
pcs constraint order start dlm then clvmd-service
pcs constraint colocation add clvmd-service with dlm
# clvmd 必须在卷组之前启动
pcs constraint order start clvmd-service then clvmd-vg
pcs constraint colocation add clvmd-vg with clvmd-service
# 卷组必须在文件系统之前激活
pcs constraint order start clvmd-vg then shared-fs
pcs constraint colocation add shared-fs with clvmd-vg
# 6. 配置资源粘性(防止不必要的迁移)
pcs resource meta clvmd-service resource-stickiness=100
pcs resource meta clvmd-vg resource-stickiness=100
pcs resource meta shared-fs resource-stickiness=100
# 7. 配置故障转移策略
pcs resource meta clvmd-service migration-threshold=3
pcs resource meta clvmd-vg migration-threshold=3
pcs resource meta shared-fs migration-threshold=3
# 设置故障后操作
pcs resource op defaults \
timeout=600s \
record-pending=true
# 8. 创建资源组(简化管理)
pcs resource group create cluster-storage \
dlm clvmd-service clvmd-vg shared-fs
# 9. 配置资源组约束
pcs constraint location cluster-storage prefers node1=100 node2=50 node3=0
# 10. 验证配置
echo "=== 资源配置验证 ==="
pcs status resources
echo ""
pcs constraint show
echo ""
pcs status --full
第五章:高级配置与优化
5.1 性能优化配置
#!/bin/bash
# optimize-clvm-performance.sh
# 1. LVM 缓存配置
cat > /etc/lvm/lvm-cache.conf << 'EOF'
# LVM 缓存配置
cache {
# 缓存模式:writethrough(安全)或 writeback(性能)
cache_mode = "writethrough"
# 缓存策略:smq(多队列)或 mq(多队列)
cache_policy = "smq"
# 元数据格式:2(更高效)
metadata_format = 2
# 区块大小(KB)
block_size = 128
# 迁移阈值(%)
migration_threshold = 80
}
# 物理卷读取优化
devices {
# 预读设置
read_ahead = "auto"
# I/O 调度器
scheduler = "deadline"
}
EOF
# 2. DLM 性能调优
cat > /etc/dlm/dlm.conf << 'EOF'
# DLM 性能配置
protocol = "tcp"
timewarn = 500
log_debug = 0
plock_ownership = 1
plock_rate_limit = 1000
plock_policy = 1
# 锁空间配置
lockspace clvmd {
name = clvmd
notify_quorum = 0
dead_time = 5
}
# 网络调优
tcp {
buffer_size = 32768
window_size = 65535
keepalive = 1
keepalive_time = 60
keepalive_probes = 3
keepalive_interval = 10
}
EOF
# 3. Corosync 网络优化
pcs config update \
totem.max_network_delay=50 \
totem.max_messages=100 \
totem.token_retransmits_before_loss_const=6 \
totem.hold=180 \
totem.retransmit_interval=1000
# 4. 内核参数优化
cat > /etc/sysctl.d/90-cluster.conf << 'EOF'
# 网络优化
net.core.rmem_max = 134217728
net.core.wmem_max = 134217728
net.ipv4.tcp_rmem = 4096 87380 134217728
net.ipv4.tcp_wmem = 4096 65536 134217728
net.ipv4.tcp_window_scaling = 1
net.ipv4.tcp_timestamps = 1
net.ipv4.tcp_sack = 1
# 内存和 I/O 优化
vm.swappiness = 10
vm.dirty_ratio = 10
vm.dirty_background_ratio = 5
vm.dirty_expire_centisecs = 3000
vm.dirty_writeback_centisecs = 500
# 文件系统缓存
vm.vfs_cache_pressure = 50
# 网络重传
net.ipv4.tcp_retries2 = 5
net.ipv4.tcp_syn_retries = 3
net.ipv4.tcp_synack_retries = 3
EOF
# 应用内核参数
sysctl -p /etc/sysctl.d/90-cluster.conf
# 5. I/O 调度器优化
for disk in /dev/sd[b-c]; do
echo "deadline" > /sys/block/$(basename $disk)/queue/scheduler
echo "1024" > /sys/block/$(basename $disk)/queue/nr_requests
echo "128" > /sys/block/$(basename $disk)/queue/read_ahead_kb
done
# 6. 监控配置
cat > /etc/cluster-monitoring.conf << 'EOF'
# 集群监控配置
[metrics]
# 收集间隔(秒)
interval = 30
# 监控项
monitor_locks = true
monitor_io = true
monitor_network = true
monitor_resources = true
# 阈值
lock_wait_threshold = 1000 # 毫秒
io_latency_threshold = 50 # 毫秒
network_latency_threshold = 10 # 毫秒
# 告警
alarm_email = "admin@example.com"
alarm_sms = "+1234567890"
EOF
echo "性能优化配置完成"
5.2 多卷组配置
#!/bin/bash
# configure-multiple-vgs.sh
# 定义多个卷组配置
declare -A VG_CONFIG=(
["oraclevg"]="/dev/sdc"
["datavg"]="/dev/sdd"
["logvg"]="/dev/sde"
)
# 1. 为每个卷组创建物理卷
for vg_name in "${!VG_CONFIG[@]}"; do
disk="${VG_CONFIG[$vg_name]}"
echo "创建卷组: $vg_name 使用磁盘 $disk"
# 创建物理卷(只在主节点)
ssh root@node1 "pvcreate -y $disk"
# 创建集群卷组
ssh root@node1 "vgcreate --shared $vg_name$disk"
# 激活卷组
ssh root@node1 "vgchange -ay $vg_name"
# 同步到其他节点
for node in node2 node3; do
ssh "root@$node" "
vgscan --cache
vgimport $vg_name
vgchange -ay $vg_name
"
done
# 在 Pacemaker 中创建资源
pcs resource create "vg-$vg_name" LVM \
volgrpname="$vg_name" \
exclusive=true \
op monitor interval="20s" timeout="30s"
done
# 2. 创建逻辑卷
# Oracle 数据卷
ssh root@node1 "
lvcreate -L 100G -n oradata oraclevg
lvcreate -L 50G -n oraarch oraclevg
"
# 数据卷
ssh root@node1 "
lvcreate -L 200G -n data01 datavg
lvcreate -L 200G -n data02 datavg
"
# 日志卷
ssh root@node1 "
lvcreate -L 50G -n logs01 logvg
"
# 3. 创建文件系统
for vg_name in "${!VG_CONFIG[@]}"; do
case $vg_name in
"oraclevg")
ssh root@node1 "
mkfs.xfs -f /dev/$vg_name/oradata
mkfs.xfs -f /dev/$vg_name/oraarch
"
;;
"datavg")
ssh root@node1 "
mkfs.ext4 /dev/$vg_name/data01
mkfs.ext4 /dev/$vg_name/data02
"
;;
"logvg")
ssh root@node1 "
mkfs.xfs -f /dev/$vg_name/logs01
"
;;
esac
done
# 4. 配置资源约束
# 设置启动顺序
pcs constraint order set vg-oraclevg vg-datavg vg-logvg sequential=true
# 设置共置约束
pcs constraint colocation add vg-datavg with vg-oraclevg INFINITY
pcs constraint colocation add vg-logvg with vg-datavg INFINITY
echo "多卷组配置完成"
#!/bin/bash
# clvm-backup-setup.sh
# 配置 CLVM 元数据备份和恢复
BACKUP_DIR="/backup/clvm"
LOG_DIR="/var/log/clvm-backup"
# 1. 创建目录结构
mkdir -p $BACKUP_DIR/{metadata,config,locks}
mkdir -p $LOG_DIR
mkdir -p /etc/lvm/{archive,backup}
# 2. 配置 LVM 自动备份
cat > /etc/lvm/lvm-autobackup.conf << 'EOF'
# LVM 自动备份配置
backup = 1
backup_dir = "/etc/lvm/archive"
# 保留策略
retain_days = 30
retain_min = 10
# 压缩备份
compress = "gzip"
# 详细日志
verbose = 1
EOF
# 3. 创建备份脚本
cat > /usr/local/bin/clvm-backup.sh << 'EOF'
#!/bin/bash
# CLVM 完整备份脚本
DATE=$(date +%Y%m%d_%H%M%S)
BACKUP_ROOT="/backup/clvm"
LOG_FILE="/var/log/clvm-backup/backup_${DATE}.log"
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a $LOG_FILE
}
# 1. 备份 LVM 配置
backup_lvm_config() {
log "备份 LVM 配置..."
tar -czf $BACKUP_ROOT/config/lvm_config_${DATE}.tar.gz \
/etc/lvm/lvm.conf \
/etc/lvm/lvmlocal.conf \
/etc/lvm/lvm-autobackup.conf \
/etc/lvm/archive/ \
/etc/lvm/backup/
}
# 2. 备份卷组元数据
backup_vg_metadata() {
log "备份卷组元数据..."
# 获取所有集群卷组
VGS=$(vgs --noheadings -o vg_name | grep -v '^$')
for vg in $VGS; do
log "备份卷组: $vg"
# 导出卷组配置
vgcfgbackup -f $BACKUP_ROOT/metadata/${vg}_${DATE}.vg $vg
# 备份物理卷信息
pvs --noheadings -o pv_name,vg_name | grep $vg > \
$BACKUP_ROOT/metadata/${vg}_pvs_${DATE}.txt
# 备份逻辑卷信息
lvs --noheadings -o lv_name,vg_name,lv_size | grep $vg > \
$BACKUP_ROOT/metadata/${vg}_lvs_${DATE}.txt
done
}
# 3. 备份锁状态
backup_lock_state() {
log "备份锁状态..."
# DLM 锁状态
dlm_tool ls > $BACKUP_ROOT/locks/dlm_state_${DATE}.txt
# LVM 锁状态
lvmlockctl --dump > $BACKUP_ROOT/locks/lvm_locks_${DATE}.txt
# 集群锁资源
if command -v pcs >/dev/null; then
pcs status > $BACKUP_ROOT/locks/pcs_status_${DATE}.txt
pcs constraint show > $BACKUP_ROOT/locks/pcs_constraints_${DATE}.txt
fi
}
# 4. 备份系统配置
backup_system_config() {
log "备份系统配置..."
# 集群配置文件
tar -czf $BACKUP_ROOT/config/cluster_config_${DATE}.tar.gz \
/etc/cluster/ \
/etc/corosync/ \
/etc/pacemaker/ \
/etc/dlm/ 2>/dev/null || true
# 系统服务配置
systemctl list-unit-files --type=service | grep -E 'lvm|cluster|corosync|pacemaker|dlm' > \
$BACKUP_ROOT/config/services_${DATE}.txt
}
# 5. 验证备份完整性
verify_backup() {
log "验证备份完整性..."
# 检查关键文件
CHECK_FILES=(
"$BACKUP_ROOT/metadata/*_${DATE}.vg"
"$BACKUP_ROOT/locks/dlm_state_${DATE}.txt"
"$BACKUP_ROOT/config/lvm_config_${DATE}.tar.gz"
)
for file in "${CHECK_FILES[@]}"; do
if ls $file >/dev/null 2>&1; then
log "✓ $file 备份成功"
else
log "✗ $file 备份失败"
fi
done
# 计算备份大小
BACKUP_SIZE=$(du -sh $BACKUP_ROOT | cut -f1)
log "备份总大小: $BACKUP_SIZE"
}
# 6. 清理旧备份
cleanup_old_backups() {
log "清理旧备份..."
# 保留最近30天的备份
find $BACKUP_ROOT/metadata -name "*.vg" -mtime +30 -delete
find $BACKUP_ROOT/config -name "*.tar.gz" -mtime +30 -delete
find $BACKUP_ROOT/locks -name "*.txt" -mtime +30 -delete
find $LOG_DIR -name "*.log" -mtime +30 -delete
log "旧备份清理完成"
}
# 主函数
main() {
log "开始 CLVM 备份流程"
# 执行备份步骤
backup_lvm_config
backup_vg_metadata
backup_lock_state
backup_system_config
verify_backup
cleanup_old_backups
log "CLVM 备份完成"
# 发送通知(可选)
# mail -s "CLVM Backup Report" admin@example.com < $LOG_FILE
}
# 执行
main
EOF
chmod +x /usr/local/bin/clvm-backup.sh
# 4. 创建恢复脚本
cat > /usr/local/bin/clvm-recovery.sh << 'EOF'
#!/bin/bash
# CLVM 灾难恢复脚本
BACKUP_DIR="/backup/clvm"
RECOVERY_LOG="/var/log/clvm-recovery/$(date +%Y%m%d_%H%M%S).log"
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a $RECOVERY_LOG
}
# 恢复卷组元数据
recover_vg_metadata() {
local vg_name=$1
local backup_date=$2
log "恢复卷组: $vg_name"
# 查找最新的备份
BACKUP_FILE=$(ls -t $BACKUP_DIR/metadata/${vg_name}_*.vg | head -1)
if [ -f "$BACKUP_FILE" ]; then
log "使用备份文件: $BACKUP_FILE"
# 停用卷组
vgchange -an $vg_name 2>/dev/null || true
# 恢复元数据
vgcfgrestore -f $BACKUP_FILE $vg_name
# 重新激活卷组
vgchange -ay $vg_name
log "卷组 $vg_name 恢复完成"
else
log "错误: 找不到 $vg_name 的备份文件"
return 1
fi
}
# 恢复完整配置
full_recovery() {
log "开始完整恢复流程"
# 1. 恢复 LVM 配置
if [ -f "$BACKUP_DIR/config/lvm_config_latest.tar.gz" ]; then
log "恢复 LVM 配置..."
tar -xzf $BACKUP_DIR/config/lvm_config_latest.tar.gz -C /
fi
# 2. 恢复所有卷组
for vg_file in $BACKUP_DIR/metadata/*.vg; do
if [ -f "$vg_file" ]; then
vg_name=$(basename $vg_file | cut -d_ -f1)
recover_vg_metadata "$vg_name" "$backup_date"
fi
done
# 3. 恢复集群配置
if [ -f "$BACKUP_DIR/config/cluster_config_latest.tar.gz" ]; then
log "恢复集群配置..."
tar -xzf $BACKUP_DIR/config/cluster_config_latest.tar.gz -C /
# 重启集群服务
systemctl restart corosync pacemaker
fi
log "完整恢复完成"
}
# 交互式恢复菜单
interactive_recovery() {
echo "选择恢复选项:"
echo "1. 恢复单个卷组"
echo "2. 恢复完整配置"
echo "3. 查看可用备份"
echo "4. 退出"
read -p "请输入选择 [1-4]: " choice
case $choice in
1)
echo "可用卷组备份:"
ls $BACKUP_DIR/metadata/*.vg | xargs -n1 basename | cut -d_ -f1 | sort -u
read -p "输入卷组名: " vg_name
read -p "输入备份日期 (YYYYMMDD): " backup_date
recover_vg_metadata "$vg_name" "$backup_date"
;;
2)
full_recovery
;;
3)
echo "可用备份:"
find $BACKUP_DIR -type f -name "*.vg" -o -name "*.tar.gz" | \
xargs -I {} sh -c 'echo "{} - $(stat -c %y {})"'
;;
4)
exit 0
;;
*)
echo "无效选择"
;;
esac
}
# 创建恢复软链接
ln -sf /usr/local/bin/clvm-recovery.sh /usr/local/bin/clvm-restore
echo "备份和恢复配置完成"
EOF
chmod +x /usr/local/bin/clvm-recovery.sh
# 5. 配置定时备份
cat > /etc/cron.d/clvm-backup << 'EOF'
# CLVM 定时备份
0 2 * * * root /usr/local/bin/clvm-backup.sh >> /var/log/clvm-backup/cron.log 2>&1
# 每周完整备份
0 3 * * 0 root /usr/local/bin/clvm-backup.sh --full >> /var/log/clvm-backup/full-backup.log 2>&1
EOF
# 6. 测试备份
echo "测试备份系统..."
/usr/local/bin/clvm-backup.sh
echo "备份和恢复系统配置完成"
第六章:监控与维护
6.1 监控配置
#!/bin/bash
# setup-clvm-monitoring.sh
# 配置 CLVM 监控系统
# 1. 安装监控工具
dnf install -y \
nagios-plugins-cluster \
collectd \
ganglia-gmond \
zabbix-agent
# 2. 配置 Nagios 检查
cat > /usr/lib64/nagios/plugins/check_clvm << 'EOF'
#!/bin/bash
# Nagios CLVM 检查插件
# 检查 clvmd 进程
check_clvmd() {
if pgrep -x clvmd >/dev/null; then
echo "OK: clvmd is running"
return 0
else
echo "CRITICAL: clvmd is not running"
return 2
fi
}
# 检查 DLM 锁
check_dlm_locks() {
LOCK_COUNT=$(dlm_tool ls | wc -l)
if [ $LOCK_COUNT -gt 0 ]; then
echo "OK: $LOCK_COUNT DLM locks found"
return 0
else
echo "WARNING: No DLM locks found"
return 1
fi
}
# 检查卷组状态
check_vg_status() {
VG_COUNT=$(vgs --noheadings | wc -l)
if [ $VG_COUNT -gt 0 ]; then
echo "OK: $VG_COUNT volume groups found"
return 0
else
echo "CRITICAL: No volume groups found"
return 2
fi
}
# 主检查函数
main() {
local status=0
local message=""
check_clvmd
status=$((status + $?))
check_dlm_locks
status=$((status + $?))
check_vg_status
status=$((status + $?))
# 根据状态码返回
case $status in
0) echo "OK: All CLVM checks passed"; exit 0 ;;
[1-3]) echo "WARNING: Some CLVM checks failed"; exit 1 ;;
*) echo "CRITICAL: Critical CLVM failures"; exit 2 ;;
esac
}
main "$@"
EOF
chmod +x /usr/lib64/nagios/plugins/check_clvm
# 3. 配置 Collectd
cat > /etc/collectd.d/clvm.conf << 'EOF'
# CLVM Collectd 配置
LoadPlugin exec
<Plugin exec>
Exec "nagios:clvmd" "/usr/local/bin/collect_clvm_metrics.sh"
</Plugin>
# 监控 LVM
LoadPlugin lvm
<Plugin lvm>
VolumeGroup "clustervg"
VolumeGroup "oraclevg"
VolumeGroup "datavg"
VolumeGroup "logvg"
IgnoreSelected false
</Plugin>
# 监控进程
LoadPlugin processes
<Plugin processes>
Process "clvmd"
Process "dlm"
Process "corosync"
Process "pacemaker"
</Plugin>
EOF
# 4. 创建自定义监控脚本
cat > /usr/local/bin/collect_clvm_metrics.sh << 'EOF'
#!/bin/bash
# 收集 CLVM 指标
METRICS_DIR="/var/lib/collectd/clvm"
mkdir -p $METRICS_DIR
while true; do
# 1. DLM 锁统计
LOCK_STATS=$(dlm_tool ls | wc -l)
echo "PUTVAL $(hostname)/clvm/dlm_locks interval=30 N:$LOCK_STATS" > $METRICS_DIR/dlm_stats.txt
# 2. clvmd 队列深度
if [ -f /proc/$(pgrep clvmd)/status ]; then
QUEUE_DEPTH=$(grep Threads /proc/$(pgrep clvmd)/status | awk '{print $2}')
echo "PUTVAL $(hostname)/clvm/clvmd_queue interval=30 N:$QUEUE_DEPTH" > $METRICS_DIR/clvmd_stats.txt
fi
# 3. LVM 操作延迟
START_TIME=$(date +%s%N)
vgs --noheadings > /dev/null
END_TIME=$(date +%s%N)
DELAY=$((($END_TIME - $START_TIME)/1000000))
echo "PUTVAL $(hostname)/clvm/lvm_latency interval=30 N:$DELAY" > $METRICS_DIR/lvm_latency.txt
# 4. 卷组使用率
VG_USAGE=$(vgs --noheadings -o vg_name,vg_free --units g | awk '{print $1":"$2}')
echo "PUTVAL $(hostname)/clvm/vg_free interval=30 N:$VG_USAGE" > $METRICS_DIR/vg_usage.txt
sleep 30
done
EOF
chmod +x /usr/local/bin/collect_clvm_metrics.sh
# 5. 配置 Zabbix 模板
cat > /etc/zabbix/zabbix_agentd.d/clvm.conf << 'EOF'
# Zabbix CLVM 监控
UserParameter=clvm.clvmd.status, systemctl is-active clvmd
UserParameter=clvm.dlm.locks.count, dlm_tool ls | wc -l
UserParameter=clvm.vg.count, vgs --noheadings | wc -l
UserParameter=clvm.vg., vgs --noheadings -o vg_free --units m $1 | awk '{print $$1}'
UserParameter=clvm.lv.count, lvs --noheadings | wc -l
UserParameter=clvm.lock.wait.time, /usr/local/bin/check_lock_wait.sh
EOF
# 6. 创建锁等待检查脚本
cat > /usr/local/bin/check_lock_wait.sh << 'EOF'
#!/bin/bash
# 检查锁等待时间
# 模拟锁请求并测量时间
START_TIME=$(date +%s%N)
lvdisplay /dev/clustervg/clusterlv > /dev/null 2>&1
END_TIME=$(date +%s%N)
WAIT_TIME=$((($END_TIME - $START_TIME)/1000000))
echo $WAIT_TIME
EOF
chmod +x /usr/local/bin/check_lock_wait.sh
# 7. 配置日志监控
cat > /etc/logrotate.d/clvm << 'EOF'
/var/log/cluster/clvmd.log {
daily
missingok
rotate 30
compress
delaycompress
notifempty
create 640 root root
postrotate
/usr/bin/systemctl reload rsyslog >/dev/null 2>&1 || true
endscript
}
/var/log/cluster/dlm.log {
daily
missingok
rotate 30
compress
delaycompress
notifempty
create 640 root root
}
EOF
# 8. 创建监控仪表板配置
cat > /usr/local/share/clvm-monitoring/dashboard.json << 'EOF'
{
"dashboard": {
"title": "CLVM Cluster Monitoring",
"panels": [
{
"title": "DLM Locks",
"type": "graph",
"metrics": ["clvm.dlm.locks.count"]
},
{
"title": "Volume Group Free Space",
"type": "graph",
"metrics": ["clvm.vg.clustervg", "clvm.vg.oraclevg"]
},
{
"title": "Service Status",
"type": "singlestat",
"metrics": ["clvm.clvmd.status"]
},
{
"title": "Lock Wait Time",
"type": "graph",
"metrics": ["clvm.lock.wait.time"]
}
],
"refresh": "30s"
}
}
EOF
echo "监控配置完成"
6.2 日常维护脚本
#!/bin/bash
# clvm-maintenance.sh
# CLVM 日常维护脚本
LOG_FILE="/var/log/clvm/maintenance_$(date +%Y%m%d).log"
ALERT_EMAIL="admin@example.com"
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a $LOG_FILE
}
send_alert() {
local subject=$1
local message=$2
echo "$message" | mail -s "$subject" $ALERT_EMAIL
log "警报已发送: $subject"
}
# 1. 健康检查
health_check() {
log "开始健康检查..."
# 检查服务状态
SERVICES=("clvmd" "corosync" "pacemaker" "dlm")
for service in "${SERVICES[@]}"; do
if systemctl is-active --quiet $service; then
log "✓ $service 服务运行正常"
else
log "✗ $service 服务异常"
send_alert "CLVM 服务异常" "$service 服务未运行"
systemctl restart $service
fi
done
# 检查集群状态
if pcs status >/dev/null 2>&1; then
log "✓ Pacemaker 集群运行正常"
else
log "✗ Pacemaker 集群异常"
send_alert "集群异常" "Pacemaker 集群状态异常"
fi
# 检查仲裁
QUORUM=$(pcs quorum status | grep -i quorate | awk '{print $NF}')
if [ "$QUORUM" = "quorate" ]; then
log "✓ 集群仲裁正常"
else
log "✗ 集群仲裁丢失"
send_alert "仲裁丢失" "集群失去仲裁"
fi
}
# 2. 锁状态检查
check_locks() {
log "检查锁状态..."
# 检查死锁
DEADLOCKS=$(lvmlockctl --dump | grep -i deadlock | wc -l)
if [ $DEADLOCKS -gt 0 ]; then
log "✗ 发现 $DEADLOCKS 个死锁"
send_alert "CLVM 死锁检测" "发现 $DEADLOCKS 个死锁"
lvmlockctl --kill
else
log "✓ 无死锁"
fi
# 检查锁等待时间
MAX_WAIT=1000 # 毫秒
for vg in $(vgs --noheadings -o vg_name); do
WAIT_TIME=$(/usr/local/bin/check_lock_wait.sh)
if [ $WAIT_TIME -gt $MAX_WAIT ]; then
log "⚠️ $vg 锁等待时间过长: ${WAIT_TIME}ms"
fi
done
}
# 3. 存储空间检查
check_storage() {
log "检查存储空间..."
# 检查卷组空间
vgs --units g --noheadings -o vg_name,vg_free | while read vg free; do
if [[ $free =~ ^[0-9]+(\.[0-9]+)?$ ]]; then
if (( $(echo "$free < 10" | bc -l) )); then
log "⚠️ $vg 空间不足: ${free}G 剩余"
send_alert "存储空间警告" "$vg 仅剩 ${free}G 空间"
fi
fi
done
# 检查逻辑卷使用率
lvs --units g --noheadings -o lv_name,vg_name,lv_size,data_percent | \
while read lv vg size percent; do
if [ -n "$percent" ] && [ "$percent" -gt 90 ]; then
log "⚠️ $vg/$lv 使用率过高: ${percent}%"
fi
done
}
# 4. 性能检查
check_performance() {
log "检查性能指标..."
# I/O 延迟检查
IODELAY=$(iostat -x 1 2 | grep -A1 avg-cpu | tail -1 | awk '{print $12}')
if (( $(echo "$IODELAY > 50" | bc -l) )); then
log "⚠️ I/O 延迟过高: ${IODELAY}ms"
fi
# 网络延迟检查
for node in node2 node3; do
PING_TIME=$(ping -c 3 $node | tail -1 | awk -F '/' '{print $5}')
if (( $(echo "$PING_TIME > 10" | bc -l) )); then
log "⚠️ 到 $node 的网络延迟过高: ${PING_TIME}ms"
fi
done
}
# 5. 备份状态检查
check_backups() {
log "检查备份状态..."
# 检查最近备份
LAST_BACKUP=$(find /backup/clvm/metadata -name "*.vg" -type f -mtime -1 | wc -l)
if [ $LAST_BACKUP -eq 0 ]; then
log "✗ 最近24小时无备份"
send_alert "备份失败" "CLVM 备份已超过24小时未执行"
else
log "✓ 备份正常"
fi
# 检查备份完整性
for backup in $(find /backup/clvm/metadata -name "*.vg" -mtime -7); do
if ! vgcfgrestore --test -f $backup 2>/dev/null; then
log "✗ 备份文件损坏: $backup"
send_alert "备份损坏" "备份文件 $backup 损坏"
fi
done
}
# 6. 日志清理
cleanup_logs() {
log "清理日志文件..."
# 清理旧日志
find /var/log/cluster -name "*.log" -mtime +30 -delete
find /var/log/clvm -name "*.log" -mtime +30 -delete
# 清理旧的 core 文件
find /var/lib/systemd/coredump -name "core.*" -mtime +7 -delete
log "日志清理完成"
}
# 7. 元数据一致性检查
check_metadata() {
log "检查元数据一致性..."
# 检查卷组元数据
for vg in $(vgs --noheadings -o vg_name 2>/dev/null); do
if vgck $vg 2>/dev/null; then
log "✓ $vg 元数据一致"
else
log "✗ $vg 元数据不一致"
send_alert "元数据不一致" "$vg 卷组元数据不一致"
vgck --updatemetadata $vg
fi
done
# 检查物理卷标签
pvs --noheadings | while read pv vg fmt size free; do
if [ "$vg" = "" ] && [ "$fmt" = "lvm2" ]; then
log "⚠️ 未使用的物理卷: $pv"
fi
done
}
# 主函数
main() {
log "开始 CLVM 日常维护"
# 执行维护任务
health_check
check_locks
check_storage
check_performance
check_backups
check_metadata
cleanup_logs
log "日常维护完成"
# 生成报告
REPORT="CLVM 维护报告 - $(date)
====================
检查时间: $(date)
日志文件: $LOG_FILE
服务状态: $(systemctl is-active clvmd)
集群状态: $(pcs status | grep -i online | wc -l) 节点在线
卷组数量: $(vgs --noheadings | wc -l)
逻辑卷数量: $(lvs --noheadings | wc -l)
锁数量: $(dlm_tool ls | wc -l)
详情请查看附件日志。"
# 发送报告(可选)
# echo "$REPORT" | mail -s "CLVM 维护报告 $(date +%Y%m%d)" $ALERT_EMAIL
}
# 执行
main
6.3 故障排除与调试
#!/bin/bash
# clvm-troubleshoot.sh
# CLVM 故障排除工具
DEBUG_LOG="/tmp/clvm-debug_$(date +%Y%m%d_%H%M%S).log"
REPORT_FILE="/tmp/clvm-report_$(date +%Y%m%d_%H%M%S).txt"
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a $DEBUG_LOG
}
collect_debug_info() {
log "收集调试信息..."
# 1. 系统信息
echo "=== 系统信息 ===" > $REPORT_FILE
uname -a >> $REPORT_FILE
cat /etc/os-release >> $REPORT_FILE
echo "" >> $REPORT_FILE
# 2. 服务状态
echo "=== 服务状态 ===" >> $REPORT_FILE
systemctl status clvmd --no-pager >> $REPORT_FILE
echo "" >> $REPORT_FILE
systemctl status corosync --no-pager >> $REPORT_FILE
echo "" >> $REPORT_FILE
systemctl status pacemaker --no-pager >> $REPORT_FILE
echo "" >> $REPORT_FILE
systemctl status dlm --no-pager >> $REPORT_FILE
echo "" >> $REPORT_FILE
# 3. 集群状态
echo "=== 集群状态 ===" >> $REPORT_FILE
pcs status --full >> $REPORT_FILE
echo "" >> $REPORT_FILE
# 4. 存储信息
echo "=== 存储信息 ===" >> $REPORT_FILE
lsblk >> $REPORT_FILE
echo "" >> $REPORT_FILE
multipath -ll >> $REPORT_FILE 2>/dev/null || true
echo "" >> $REPORT_FILE
# 5. LVM 信息
echo "=== LVM 信息 ===" >> $REPORT_FILE
pvs -v >> $REPORT_FILE
echo "" >> $REPORT_FILE
vgs -v >> $REPORT_FILE
echo "" >> $REPORT_FILE
lvs -v >> $REPORT_FILE
echo "" >> $REPORT_FILE
# 6. 锁信息
echo "=== 锁信息 ===" >> $REPORT_FILE
lvmlockctl --dump >> $REPORT_FILE
echo "" >> $REPORT_FILE
dlm_tool ls >> $REPORT_FILE
echo "" >> $REPORT_FILE
# 7. 网络信息
echo "=== 网络信息 ===" >> $REPORT_FILE
ip addr show >> $REPORT_FILE
echo "" >> $REPORT_FILE
ss -tulpn | grep -E ':67|:68|:21064|:5404|:5405' >> $REPORT_FILE
echo "" >> $REPORT_FILE
# 8. 日志信息
echo "=== 最近日志 ===" >> $REPORT_FILE
journalctl -u clvmd --since "1 hour ago" --no-pager >> $REPORT_FILE
echo "" >> $REPORT_FILE
journalctl -u corosync --since "1 hour ago" --no-pager >> $REPORT_FILE
echo "" >> $REPORT_FILE
tail -100 /var/log/cluster/clvmd.log >> $REPORT_FILE 2>/dev/null || true
log "调试信息收集完成: $REPORT_FILE"
}
check_common_issues() {
log "检查常见问题..."
# 1. 检查 clvmd 连接
if ! lvscan >/dev/null 2>&1; then
log "问题: clvmd 连接失败"
log "尝试解决方案: 重启 clvmd 服务"
systemctl restart clvmd
sleep 5
fi
# 2. 检查 DLM 锁
if ! dlm_tool ls >/dev/null 2>&1; then
log "问题: DLM 不可用"
log "尝试解决方案: 重启 dlm 服务"
systemctl restart dlm
sleep 5
fi
# 3. 检查卷组激活
for vg in $(vgs --noheadings -o vg_name 2>/dev/null); do
if ! vgchange -ay $vg >/dev/null 2>&1; then
log "问题: 卷组 $vg 激活失败"
log "尝试解决方案: 强制激活"
vgchange -aay $vg
fi
done
# 4. 检查脑裂状态
if [ $(pcs status | grep -c "UNCLEAN") -gt 0 ]; then
log "问题: 检测到脑裂状态"
log "尝试解决方案: 清理集群状态"
pcs cluster cleanup --all
fi
# 5. 检查仲裁
if ! pcs quorum status | grep -q "quorate"; then
log "问题: 集群失去仲裁"
log "尝试解决方案: 检查网络连接"
for node in node2 node3; do
if ! ping -c 2 $node >/dev/null 2>&1; then
log "节点 $node 不可达"
fi
done
fi
}
perform_recovery() {
local issue=$1
case $issue in
"metadata_corruption")
log "执行元数据恢复..."
# 从备份恢复
latest_backup=$(ls -t /backup/clvm/metadata/*.vg | head -1)
if [ -f "$latest_backup" ]; then
vgcfgrestore -f $latest_backup
vgchange -ay
fi
;;
"lock_conflict")
log "解决锁冲突..."
# 释放所有锁并重新获取
lvmlockctl --kill
systemctl restart clvmd
sleep 10
;;
"network_split")
log "处理网络分区..."
# 停止受影响的服务
pcs cluster stop --all
# 清理状态
pcs cluster cleanup --all
# 重新启动
pcs cluster start --all
;;
*)
log "未知问题: $issue"
;;
esac
}
interactive_troubleshoot() {
echo "CLVM 故障排除菜单"
echo "=================="
echo "1. 收集调试信息"
echo "2. 检查常见问题"
echo "3. 执行自动修复"
echo "4. 查看日志"
echo "5. 重启集群服务"
echo "6. 恢复元数据"
echo "7. 退出"
read -p "请选择操作 [1-7]: " choice
case $choice in
1)
collect_debug_info
echo "调试信息已保存到: $REPORT_FILE"
;;
2)
check_common_issues
;;
3)
read -p "输入问题类型 (metadata_corruption/lock_conflict/network_split): " issue
perform_recovery "$issue"
;;
4)
echo "选择日志文件:"
echo "1. clvmd 日志"
echo "2. corosync 日志"
echo "3. pacemaker 日志"
echo "4. 系统日志"
read -p "选择: " log_choice
case $log_choice in
1) journalctl -u clvmd -f ;;
2) journalctl -u corosync -f ;;
3) journalctl -u pacemaker -f ;;
4) tail -f /var/log/messages ;;
*) echo "无效选择" ;;
esac
;;
5)
echo "重启集群服务..."
systemctl restart corosync pacemaker clvmd dlm
;;
6)
echo "从备份恢复元数据..."
/usr/local/bin/clvm-recovery.sh
;;
7)
exit 0
;;
*)
echo "无效选择"
;;
esac
}
# 非交互模式
if [ "$1" = "auto" ]; then
collect_debug_info
check_common_issues
else
interactive_troubleshoot
fi
echo "故障排除完成"
第七章:最佳实践与建议
7.1 设计原则
# CLVM 部署最佳实践
## 1. 硬件规划
- **存储**: 使用企业级 SAN 或支持 SCSI-3 PR 的存储
- **网络**: 专用冗余网络用于集群通信
- **主机**: 相似的硬件配置,相同 CPU/内存架构
## 2. 网络设计
- 专用集群网络(1GbE 或更高)
- 与存储网络分离
- 使用绑定(bonding)增加可靠性
- 启用巨帧(jumbo frames)提高性能
## 3. 存储设计
- 每个卷组使用独立的物理卷
- 避免跨存储阵列的卷组
- 为元数据预留足够空间(通常 128MB-1GB)
- 使用适当的条带大小(通常 64KB-1MB)
## 4. 集群设计
- 最小 3 节点以避免脑裂
- 配置正确的仲裁策略
- 实施隔离(STONITH)防止数据损坏
- 定期测试故障转移
## 5. 性能优化
- 匹配 I/O 调度器与工作负载
- 适当调整缓存大小
- 监控锁争用情况
- 避免过小的逻辑卷
## 6. 安全考虑
- 使用专用集群用户
- 限制管理访问
- 加密集群通信
- 定期审计配置更改
## 7. 监控策略
- 实时监控锁状态
- 预警磁盘空间不足
- 跟踪性能指标
- 记录所有管理操作
## 8. 备份策略
- 定期备份 LVM 元数据
- 测试恢复流程
- 异地备份关键配置
- 文档化恢复步骤
## 9. 文档要求
- 网络拓扑图
- 存储布局图
- 集群配置详情
- 应急操作手册
- 联系人列表
7.2 性能调优指南
#!/bin/bash
# clvm-performance-tuning.sh
# CLVM 性能调优检查清单
echo "CLVM 性能调优指南"
echo "================="
# 1. 检查当前配置
echo "1. 当前系统配置:"
echo " CPU 核心数: $(nproc)"
echo " 内存总量: $(free -h | grep Mem | awk '{print $2}')"
echo " 存储类型: $(lsblk -d -o rota | tail -1 | awk '{print $1=="0"?"SSD":"HDD"}')"
# 2. 建议的优化参数
cat > /tmp/clvm-tuning-suggestions.txt << 'EOF'
## 基于工作负载的优化建议
### 高并发 OLTP 数据库
1. DLM 配置:
- lock_timeout = 5000
- plock_rate_limit = 5000
- protocol = "tcp"
2. LVM 配置:
- cache_mode = "writethrough"
- cache_policy = "mq"
- read_ahead = 1024
3. 内核参数:
- vm.dirty_ratio = 20
- vm.dirty_background_ratio = 10
- vm.swappiness = 5
### 大文件顺序读写
1. DLM 配置:
- lock_timeout = 10000
- plock_rate_limit = 1000
2. LVM 配置:
- stripe_size = 1024
- read_ahead = 4096
3. 内核参数:
- vm.dirty_ratio = 40
- vm.dirty_background_ratio = 20
- vm.vfs_cache_pressure = 100
### 虚拟化环境
1. DLM 配置:
- lock_timeout = 3000
- plock_ownership = 0
2. LVM 配置:
- cache_mode = "writeback"
- thin_pool_metadata_size = 2G
3. 内核参数:
- vm.dirty_ratio = 30
- vm.dirty_background_ratio = 5
- vm.swappiness = 30
### 通用优化
1. 网络:
- MTU = 9000 (如果支持)
- 使用 deadline 或 noop 调度器
- 启用 TCP 窗口缩放
2. 存储:
- 对齐分区
- 适当的条带大小
- 定期碎片整理
3. 监控:
- 跟踪锁等待时间
- 监控 I/O 延迟
- 记录错误率
EOF
echo "优化建议已保存到: /tmp/clvm-tuning-suggestions.txt"
echo ""
echo "应用建议前请:"
echo "1. 在测试环境验证"
echo "2. 备份当前配置"
echo "3. 监控变更影响"
echo "4. 记录所有修改"
7.3 容量规划
#!/bin/bash
# clvm-capacity-planning.sh
# CLVM 容量规划工具
calculate_capacity() {
local total_disk_gb=$1
local growth_rate=$2 # 每月增长率(百分比)
local months=$3
echo "容量规划计算"
echo "============="
echo "当前总容量: ${total_disk_gb}GB"
echo "月增长率: ${growth_rate}%"
echo "规划周期: ${months}个月"
echo ""
# 计算需求
current=$total_disk_gb
echo "月份 | 所需容量(GB) | 建议扩容至(GB)"
echo "----------------------------------"
for ((i=1; i<=months; i++)); do
needed=$(echo "$current * (1 + $growth_rate/100)" | bc -l)
recommended=$(echo "$needed * 1.2" | bc -l) # 20% 缓冲
printf " %2d | %12.1f | %15.1f\n" $i $needed $recommended
current=$needed
done
echo ""
echo "建议:"
echo "1. 每月监控使用率"
echo "2. 保持至少 20% 空闲空间"
echo "3. 提前规划采购周期"
echo "4. 考虑数据增长趋势"
}
# 交互式容量规划
interactive_planning() {
read -p "当前总存储容量 (GB): " total_gb
read -p "预计月增长率 (%): " growth
read -p "规划周期 (月): " months
calculate_capacity $total_gb $growth $months
}
# 显示示例
echo "示例: 1TB 存储,月增长 5%,12 个月规划"
calculate_capacity 1024 5 12
echo ""
echo "是否进行自定义计算? (y/n)"
read -p "选择: " choice
if [ "$choice" = "y" ]; then
interactive_planning
fi
总结与后续步骤
关键要点回顾
- CLVM 核心价值: 实现共享存储的高可用访问,防止数据损坏
- 关键组件: clvmd、DLM、Corosync/Pacemaker 协同工作
- 锁机制: 分布式锁确保数据一致性
- 配置层次: 从硬件准备到应用集成的完整链条
生产部署检查清单
- [ ] 硬件兼容性验证
- [ ] 网络冗余配置
- [ ] 存储多路径配置
- [ ] 集群软件安装
- [ ] SSH 互信设置
- [ ] 集群基础配置
- [ ] 隔离设备配置
- [ ] CLVM 服务配置
- [ ] 卷组和逻辑卷创建
- [ ] Pacemaker 资源配置
- [ ] 监控系统部署
- [ ] 备份策略实施
- [ ] 文档编写完成
- [ ] 故障转移测试
- [ ] 性能基准测试
- [ ] 团队培训完成
下一步建议
- 测试环境验证: 在实际部署前,在测试环境验证所有配置
- 渐进式部署: 先部署非关键业务,逐步迁移
- 监控建立: 部署完善的监控告警系统
- 文档完善: 持续更新运维文档,将经验分享到技术社区如 云栈社区 进行交流
- 定期演练: 定期进行故障转移演练
获取帮助
- 官方文档:
- Red Hat Cluster Suite Documentation
- Linux Cluster LVM Administration
- 社区支持:
- Linux Cluster邮件列表
- Stack Overflow
- 专业服务:
通过本指南,您应该已经全面掌握了 CLVM 的概念、原理和配置方法。成功的集群部署不仅需要技术知识,还需要周密的规划、严格的测试和持续的维护。祝您部署顺利!