找回密码
立即注册
搜索
热搜: Java Python Linux Go
发回帖 发新帖

1980

积分

0

好友

274

主题
发表于 昨天 00:16 | 查看: 2| 回复: 0

概述:为什么需要 CLVM?

在现代数据中心,高可用性(High Availability) 是关键需求。传统 LVM 只能在单个节点上管理存储,当应用需要跨多个节点访问共享存储时,就会面临数据一致性和并发访问问题。CLVM(Clustered LVM)应运而生,它是 LVM 的集群感知扩展,允许多个节点安全地共享和管理同一个物理存储池

典型应用场景

  • 数据库集群(如 Oracle RAC、MySQL Cluster)
  • 虚拟化高可用(如 KVM 高可用集群
  • 共享文件系统(如 GFS2、OCFS2)的底层存储
  • 企业级应用(如 SAP、ERP 系统)

第一章:CLVM 核心概念深度解析

1.1 CLVM 架构总览

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 元数据同步流程

CLVM创建逻辑卷的锁协调流程图

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 配置完成"

4.4 配置 Pacemaker 管理 CLVM 资源

#!/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 "多卷组配置完成"

5.3 备份与恢复配置

#!/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

    总结与后续步骤

    关键要点回顾

    1. CLVM 核心价值: 实现共享存储的高可用访问,防止数据损坏
    2. 关键组件: clvmd、DLM、Corosync/Pacemaker 协同工作
    3. 锁机制: 分布式锁确保数据一致性
    4. 配置层次: 从硬件准备到应用集成的完整链条

    生产部署检查清单

    - [ ] 硬件兼容性验证
    - [ ] 网络冗余配置
    - [ ] 存储多路径配置
    - [ ] 集群软件安装
    - [ ] SSH 互信设置
    - [ ] 集群基础配置
    - [ ] 隔离设备配置
    - [ ] CLVM 服务配置
    - [ ] 卷组和逻辑卷创建
    - [ ] Pacemaker 资源配置
    - [ ] 监控系统部署
    - [ ] 备份策略实施
    - [ ] 文档编写完成
    - [ ] 故障转移测试
    - [ ] 性能基准测试
    - [ ] 团队培训完成

    下一步建议

    1. 测试环境验证: 在实际部署前,在测试环境验证所有配置
    2. 渐进式部署: 先部署非关键业务,逐步迁移
    3. 监控建立: 部署完善的监控告警系统
    4. 文档完善: 持续更新运维文档,将经验分享到技术社区如 云栈社区 进行交流
    5. 定期演练: 定期进行故障转移演练

    获取帮助

    • 官方文档:
      • Red Hat Cluster Suite Documentation
      • Linux Cluster LVM Administration
    • 社区支持:
      • Linux Cluster邮件列表
      • Stack Overflow
    • 专业服务:
      • 考虑购买厂商支持服务
      • 聘请经验丰富的集群架构师

    通过本指南,您应该已经全面掌握了 CLVM 的概念、原理和配置方法。成功的集群部署不仅需要技术知识,还需要周密的规划、严格的测试和持续的维护。祝您部署顺利!




    上一篇:架构师面试:高性能、高并发、高可用的核心权衡与业务场景适配
    下一篇:LLM量化投资实战指南:基于LangChain与RAG的文本因子挖掘与避坑技巧
    您需要登录后才可以回帖 登录 | 立即注册

    手机版|小黑屋|网站地图|云栈社区 ( 苏ICP备2022046150号-2 )

    GMT+8, 2026-1-12 01:13 , Processed in 0.214622 second(s), 40 queries , Gzip On.

    Powered by Discuz! X3.5

    © 2025-2025 云栈社区.

    快速回复 返回顶部 返回列表