0
0
0
0
博客/.../

自动化生成topology.yml文件

 Frank_飞  发表于  2026-08-22
原创

#!/bin/bash

全局严格模式

set -euo pipefail

#颜色定义 RED="\033[31m" GREEN="\033[32m" YELLOW="\033[33m" BLUE="\033[34m" BOLD="\033[1m" RESET="\033[0m" # 取消颜色

=========== 错误捕捉打印函数 ============

error_exit() { local LINE_NUM="$1" local FAILED_CMD="$2" local EXIT_CODE="$3" echo -e "${BOLD}${RED}" echo "" echo -e "############################ 脚本异常终止 ############################" echo -e "❌ 出错行号: ${LINE_NUM}" echo -e "❌ 失败命令内容: ${FAILED_CMD}" echo -e "❌ 命令退出码: ${EXIT_CODE}" echo -e "####################################################################" echo -e "${RESET}" } trap 'error_exit $LINENO "$BASH_COMMAND" $?' ERR

打印头部信息

echo -e "${BOLD}${GREEN}" echo "============================================================" echo "脚本名称:TiDB 密钥与拓扑配置自动生成脚本" echo "功能描述:单节点/3节点混部/6节点分离部署/9节点分离部署/自定义角色" echo "功能特性:自动按 TiKV 节点物理内存 50% 计算 block-cache" echo "适配系统:CentOS 7.x/9.X" echo "执行用户:root" echo "编写作者:Frank 飞" echo "编写时间:2026年08月10日" echo "版本信息:V1.0" echo "执行方式:sh gen_tidb_topology.sh" echo "============================================================" echo -e "${RESET}"

========== 自定义配置区域,请按需修改 ===========

TOPO_FILE="topology.yaml" INSTALL_DIR="/tidb-deploy" DATA_DIR="/tidb-deploy/tidb-data" SSH_USER="root" RUN_USER="tidb" RUN_GROUP="tidb" SSH_PWD="passwd" SSH_PORT=22 SSH_CONNECT_TIMEOUT=5

=======================================

================ 工具函数 =================

按逗号分割字符串为数组

split_comma() { local str="$1" IFS=',' read -ra arr <<< "$str" echo "${arr[@]}" }

获取远程主机总物理内存(单位:GB)

入参:目标主机IP;返回:内存GB数,获取失败返回空

get_remote_total_mem_gb() { local target_ip="$1" # 关闭主机密钥检查,避免首次连接交互;超时时间防止脚本卡住 local mem_kb mem_kb=$(ssh -p "${SSH_PWD}" -o ConnectTimeout="${SSH_CONNECT_TIMEOUT}" -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null "${SSH_USER}@${target_ip}" "cat /proc/meminfo | grep MemTotal | awk '{print $2}'" 2>/dev/null)

if [[ -z "$mem_kb" || ! "$mem_kb" =~ ^[0-9]+$ ]]; then
    echo ""
    return 1
fi

# KB转GB,四舍五入:(kb + 0.5GB对应的KB) / 1GB的KB数
local round_offset=$(( 512 * 1024 ))   # 0.5GB = 524288 KB
local one_gb_kb=$(( 1024 * 1024 ))     # 1GB = 1048576 KB
local mem_gb=$(( (mem_kb + round_offset) / one_gb_kb ))
echo "$mem_gb"
return 0

}

打印帮助信息

print_help() { cat << EOF 用法: $0 [选项]

必选参数: -i, --ips <ip列表> 所有服务器IP,逗号分隔,例如: 192.168.1.1,192.168.1.2

可选参数: --pd-ips <ip列表> 手动指定PD节点IP,逗号分隔(不指定则自动分配) --tikv-ips <ip列表> 手动指定TiKV节点IP,逗号分隔(不指定则自动分配) --tidb-ips <ip列表> 手动指定TiDB节点IP,逗号分隔(不指定则自动分配) --monitor-ip 手动指定监控/Grafana/Alertmanager节点IP(不指定默认首台PD) --block-cache <大小> 手动指定TiKV block-cache大小,如 16GB(不指定则自动按内存50%计算) --ssh-user <用户名> SSH登录用户名,默认与运行用户一致: ${SSH_USER} -o, --output <文件路径> 输出YAML文件路径,默认: topology.yaml -h, --help 显示帮助信息

自动分配规则: 1个IP : 单节点全组件部署 (1PD + 1TiKV + 1TiDB + 监控) 3个IP : 三节点全混部 (3PD + 3TiKV + 3TiDB + 监控) 6个IP : 前3台PD/TiDB、后3台TiKV、首台PD兼监控 9个IP : 前3台PD、中3台TiKV、后3台TiDB、首台PD兼监控

使用示例:

示例1: 6节点标准部署(自动计算block-cache)

$0 -i "192.168.1.1,192.168.1.2,192.168.1.3,192.168.1.4,192.168.1.5,192.168.1.6"

示例2: 3节点混合部署,手动指定block-cache

$0 -i "192.168.1.1,192.168.1.2,192.168.1.3" --block-cache 8GB

示例3: 单节点测试部署

$0 -i "192.168.1.1"

自定义角色分配

$0 --pd-ips "10.0.0.1,10.0.0.2,10.0.0.3" --tikv-ips "10.0.0.4,10.0.0.5,10.0.0.6" --tidb-ips "10.0.0.7,10.0.0.8" -o custom-topology.yaml EOF exit 0 }

================ 参数解析 =================

ALL_IPS="" PD_IPS_INPUT="" TIKV_IPS_INPUT="" TIDB_IPS_INPUT="" MONITOR_IP_INPUT="" BLOCK_CACHE_INPUT=""

while [[ $# -gt 0 ]]; do case "$1" in -i|--ips) ALL_IPS="$2" shift 2 ;; --pd-ips) PD_IPS_INPUT="$2" shift 2 ;; --tikv-ips) TIKV_IPS_INPUT="$2" shift 2 ;; --tidb-ips) TIDB_IPS_INPUT="$2" shift 2 ;; --monitor-ip) MONITOR_IP_INPUT="$2" shift 2 ;; --block-cache) BLOCK_CACHE_INPUT="$2" shift 2 ;; --ssh-user) SSH_USER="$2" shift 2 ;; -o|--output) TOPO_FILE="$2" shift 2 ;; -h|--help) print_help ;; *) echo "错误: 未知参数 $1" print_help exit 1 ;; esac done

=============== 参数校验 ==================

if [[ -z "$ALL_IPS" && -z "$PD_IPS_INPUT" ]]; then echo "错误: 必须通过 -i 指定服务器IP列表" print_help exit 1 fi

============== 角色分配逻辑 ================

if [[ -n "$ALL_IPS" ]]; then all_ips_arr=($(split_comma "$ALL_IPS")) total_ip=${#all_ips_arr[@]} fi

echo "===================== 检测到服务器总数量:${total_ip} 台 ====================="

自动分配模式:用户未手动指定角色IP

if [[ -z "$PD_IPS_INPUT" && -z "$TIKV_IPS_INPUT" && -z "$TIDB_IPS_INPUT" ]]; then if [[ $total_ip -eq 1 ]]; then pd_ips=("${all_ips_arr[@]}") tikv_ips=("${all_ips_arr[@]}") tidb_ips=("${all_ips_arr[@]}") monitor_ip="${all_ips_arr[0]}" elif [[ $total_ip -eq 3 ]]; then pd_ips=("${all_ips_arr[@]}") tikv_ips=("${all_ips_arr[@]}") tidb_ips=("${all_ips_arr[@]}") monitor_ip="${all_ips_arr[0]}" elif [[ $total_ip -eq 6 ]]; then pd_ips=("${all_ips_arr[0]}" "${all_ips_arr[1]}" "${all_ips_arr[2]}") tikv_ips=("${all_ips_arr[3]}" "${all_ips_arr[4]}" "${all_ips_arr[5]}") tidb_ips=("${pd_ips[0]}" "${pd_ips[1]}" "${pd_ips[2]}") monitor_ip="${pd_ips[0]}" elif [[ $total_ip -eq 9 ]]; then pd_ips=("${all_ips_arr[0]}" "${all_ips_arr[1]}" "${all_ips_arr[2]}") tikv_ips=("${all_ips_arr[@]:3:3}") tidb_ips=("${all_ips_arr[@]:6}") monitor_ip="${pd_ips[0]}" fi else # 手动指定角色模式 if [[ -z "$PD_IPS_INPUT" || -z "$TIKV_IPS_INPUT" || -z "$TIDB_IPS_INPUT" ]]; then echo "错误:手动指定角色时,必须同时指定 --pd-ips、--tikv-ips、--tidb-ips" exit 1 fi pd_ips=($(split_comma "$PD_IPS_INPUT")) tikv_ips=($(split_comma "$TIKV_IPS_INPUT")) tidb_ips=($(split_comma "$TIDB_IPS_INPUT")) monitor_ip="${MONITOR_IP_INPUT:-${pd_ips[0]}}" fi

计算合理的副本数(奇数原则,不超过TiKV节点数)

tikv_count=${#tikv_ips[@]} if [[ $tikv_count -ge 3 ]]; then max_replicas=3 elif [[ $tikv_count -eq 2 ]]; then max_replicas=1 else max_replicas=1 fi

pd_count=${#pd_ips[@]} tidb_count=${#tidb_ips[@]}

============= 动态计算 block-cache ===========

first_tikv_ip="${tikv_ips[0]}"

if [[ -n "$BLOCK_CACHE_INPUT" ]]; then # 优先级1:用户手动指定 BLOCK_CACHE_SIZE="$BLOCK_CACHE_INPUT" echo "ℹ️ 使用手动指定的 block-cache 大小: ${BLOCK_CACHE_SIZE}" else # 优先级2:自动探测节点内存,按 50% 计算 total_mem_gb=$(get_remote_total_mem_gb "$first_tikv_ip")

if [[ -n "$total_mem_gb" && $total_mem_gb -gt 0 ]]; then
    # 取总内存 50%,向下取整,最小保底 1GB
    cache_gb=$(( total_mem_gb / 2 ))
    if [[ $cache_gb -lt 1 ]]; then
        cache_gb=1
    fi
    BLOCK_CACHE_SIZE="${cache_gb}GB"
    echo "ℹ️  自动探测TiKV节点(${first_tikv_ip})总内存: ${total_mem_gb}GB"
    echo "   按50%比例设置 block-cache: ${BLOCK_CACHE_SIZE}"
else
    # 优先级3:探测失败,兜底默认值并提示
    BLOCK_CACHE_SIZE="5GB"
    echo "⚠️  无法连接TiKV节点(${first_tikv_ip})获取内存信息,使用默认兜底值: ${BLOCK_CACHE_SIZE}"
    echo "   请确认SSH免密登录已配置,或通过 --block-cache 参数手动指定大小"
fi

fi

=============== 生成 YAML 文件 =============

cat > "$TOPO_FILE" << EOF

TiDB 集群拓扑配置文件

自动生成于 $(date '+%Y-%m-%d %H:%M:%S')

global: user: "${RUN_USER}" group: "${RUN_GROUP}" ssh_port: ${SSH_PORT} deploy_dir: "${INSTALL_DIR}" data_dir: "${DATA_DIR}" os: "linux" arch: "amd64" monitored: node_exporter_port: 9100 blackbox_exporter_port: 9115

PD节点配置 ${pd_count}节点高可用

pd_servers: EOF

生成PD节点列表

idx=1 for ip in "${pd_ips[@]}"; do cat >> "$TOPO_FILE" << EOF

  • host: ${ip} name: pd-${idx} client_port: 2379 peer_port: 2380 EOF idx=$((idx + 1)) done

cat >> "$TOPO_FILE" << EOF

TiKV节点配置 ${tikv_count}节点多副本

tikv_servers: EOF

生成TiKV节点列表

for ip in "${tikv_ips[@]}"; do cat >> "$TOPO_FILE" << EOF

  • host: ${ip} port: 20160 status_port: 20180 config: server.labels: host: ${ip} EOF done

cat >> "$TOPO_FILE" << EOF

TiDB Server ${tidb_count}节点负载均衡

tidb_servers: EOF

生成TiDB节点列表

for ip in "${tidb_ips[@]}"; do cat >> "$TOPO_FILE" << EOF

  • host: ${ip} port: 4000 status_port: 10080 EOF done

cat >> "$TOPO_FILE" << EOF

监控节点配置

monitoring_servers:

  • host: ${monitor_ip} grafana_servers:
  • host: ${monitor_ip} alertmanager_servers:
  • host: ${monitor_ip}

组件个性化参数

server_configs: tidb: log.slow-threshold: 300 tikv: readpool.storage.use-unified-pool: false readpool.coprocessor.use-unified-pool: true storage.block-cache.capacity: "${BLOCK_CACHE_SIZE}" pd: replication.location-labels: ["host"] replication.max-replicas: ${max_replicas} EOF

echo "" echo "✅ 拓扑文件已生成: $TOPO_FILE" echo " PD节点数: ${pd_count} | TiKV节点数: ${tikv_count} | TiDB节点数: ${tidb_count} | 副本数: ${max_replicas}"

0
0
0
0

版权声明:本文为 TiDB 社区用户原创文章,遵循 CC BY-NC-SA 4.0 版权协议,转载请附上原文出处链接和本声明。

评论
暂无评论