GBase 8a
运维管理
文章
南大通用GBase 8a集群配置参数批量持久化实现
发表于2026-04-23 17:50:08313次浏览4个评论
背景
GBase 8a MPP 是一款国产大规模并行处理分析型数据库,在实际生产环境中通常部署在数十甚至上百个节点上。
由于数据库自身没有提供参数固化的管理命令(类似于 Oracle 的 ALTER SYSTEM SET ... SCOPE=SPFILE,或者mysql8的 SET PERSIST 参数名=参数值),所有配置调整都需要运维人员登录每个节点手动修改对应的 .cnf文件。当集群规模较大时,这种操作不仅效率低下,而且极易因疏忽导致节点间配置不一致,进而引发执行计划异常或集群不稳定。本文介绍一种基于 Python 2.7 的自动化脚本方案,通过主机互信批量修改 GBase 8a 集群层(gcluster)与节点层(gnode)的配置参数,将集群的参数持久化操作简化为一条命令。
脚本代码
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
GBase 8a 集群参数批量配置工具
用法:python persist_args.py "参数名 = 值" n/c node.list
Author: Bryan
"""
from __future__ import print_function
import sys
import os
import subprocess
# SSH 连接超时设置(秒)
SSH_TIMEOUT = 10
def run_remote_cmd(host, cmd, suppress_error=False):
"""
通过 SSH 执行远程命令,返回 (stdout, stderr, returncode)
"""
ssh_cmd = [
'ssh',
'-o', 'ConnectTimeout=%d' % SSH_TIMEOUT,
'-o', 'BatchMode=yes',
'-o', 'StrictHostKeyChecking=no',
host,
cmd
]
try:
proc = subprocess.Popen(ssh_cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
out, err = proc.communicate()
return out.strip(), err.strip(), proc.returncode
except Exception as e:
return '', str(e), 1
def main():
if len(sys.argv) != 4:
print("用法: %s \"参数名 = 值\" n/c node.list" % sys.argv[0])
sys.exit(1)
param_line = sys.argv[1].strip()
layer = sys.argv[2].strip().lower()
node_list_file = sys.argv[3].strip()
# 检查参数行是否包含 '='
if '=' not in param_line:
print("错误:参数行必须包含 '=',格式如 \"param_name = value\"")
sys.exit(1)
# 提取参数名(等号左侧,去除首尾空格)
param_name = param_line.split('=', 1)[0].strip()
if not param_name:
print("错误:参数名不能为空")
sys.exit(1)
# 检查层次参数
if layer not in ('c', 'n'):
print("错误:第二个参数必须为 'c' (集群层) 或 'n' (节点层)")
sys.exit(1)
# 确定环境变量和配置文件名
if layer == 'c':
env_var = 'GCLUSTER_BASE'
conf_filename = 'gbase_8a_gcluster.cnf'
else: # layer == 'n'
env_var = 'GBASE_BASE'
conf_filename = 'gbase_8a_gbase.cnf'
# 读取节点列表
if not os.path.isfile(node_list_file):
print("错误:节点列表文件 %s 不存在" % node_list_file)
sys.exit(1)
with open(node_list_file, 'r') as f:
nodes = [line.strip() for line in f if line.strip()]
if not nodes:
print("警告:节点列表为空")
sys.exit(0)
print("准备将参数 '%s' 添加到 %s 配置文件中..." % (param_name, conf_filename))
print("目标节点数量: %d\n" % len(nodes))
success_count = 0
fail_count = 0
for host in nodes:
print("处理节点: %s" % host)
# 1. 获取环境变量值
get_env_cmd = 'echo $%s' % env_var
out, err, rc = run_remote_cmd(host, get_env_cmd)
if rc != 0 or not out:
print(" [错误] 无法获取环境变量 $%s,请确认该变量已在节点 %s 上定义" % (env_var, host))
if err:
print(" 远程错误: %s" % err)
fail_count += 1
continue
base_dir = out.rstrip('/')
conf_dir = base_dir + '/config'
conf_file = conf_dir + '/' + conf_filename
# 2. 检查配置文件是否存在
check_file_cmd = 'test -f "%s" && echo "EXISTS" || echo "NOT_EXISTS"' % conf_file
out, err, rc = run_remote_cmd(host, check_file_cmd)
if out != 'EXISTS':
print(" [错误] 配置文件不存在: %s" % conf_file)
fail_count += 1
continue
# 3. 检查参数是否已存在
# 使用 grep 匹配行首的参数名(忽略值),允许等号前后有空格
grep_cmd = 'grep -q "^[[:space:]]*%s[[:space:]]*=" "%s" && echo "EXISTS" || echo "NOT_EXISTS"' % (param_name, conf_file)
out, err, rc = run_remote_cmd(host, grep_cmd)
if out == 'EXISTS':
print(" [错误] 节点 %s 的配置文件 %s 中已存在参数 '%s'" % (host, conf_file, param_name))
fail_count += 1
continue
# 4. 检查是否存在 [gbasedump] 标签
check_section_cmd = 'grep -q "^\[gbasedump\]" "%s" && echo "EXISTS" || echo "NOT_EXISTS"' % conf_file
out, err, rc = run_remote_cmd(host, check_section_cmd)
if out != 'EXISTS':
print(" [错误] 配置文件 %s 中未找到 [gbasedump] 标签,无法定位插入位置" % conf_file)
fail_count += 1
continue
# 5. 执行插入操作
# 使用 sed 在第一个 [gbasedump] 之前插入新行
# 注意:需要对参数行中的特殊字符进行转义,但通常参数行只含字母数字下划线和等号空格,无需额外转义
# 使用单引号包裹 sed 命令,内部的双引号需要处理,这里用双引号包裹整个表达式,变量直接替换
insert_cmd = 'sed -i "/^\[gbasedump\]/i %s" "%s"' % (param_line, conf_file)
out, err, rc = run_remote_cmd(host, insert_cmd)
if rc != 0:
print(" [错误] 执行 sed 插入命令失败")
if err:
print(" 远程错误: %s" % err)
fail_count += 1
continue
# 6. 验证插入是否成功
verify_cmd = 'grep -q "^[[:space:]]*%s[[:space:]]*=" "%s" && echo "EXISTS" || echo "NOT_EXISTS"' % (param_name, conf_file)
out, err, rc = run_remote_cmd(host, verify_cmd)
if out != 'EXISTS':
print(" [错误] 插入后验证失败,参数可能未成功写入")
fail_count += 1
continue
print(" [成功] 参数已添加到 %s" % conf_file)
success_count += 1
print("\n处理完成:成功 %d 个节点,失败 %d 个节点" % (success_count, fail_count))
if __name__ == '__main__':
main()
参数说明
参数1:要添加的配置,格式 "参数名 = 值"(含等号)。
参数2:c 改集群层($GCLUSTER_BASE/.../gbase_8a_gcluster.cnf),n 改节点层($GBASE_BASE/.../gbase_8a_gbase.cnf)。
参数3:节点 IP 列表文件,一行一个 IP。
逻辑验证
添加一个自造的参数到集群层配置文件
[gbase@data1 persist_args]$ python persist_args.py "some_args = 123" c node.list
准备将参数 'some_args' 添加到 gbase_8a_gcluster.cnf 配置文件中...
目标节点数量: 2
处理节点: 192.168.56.101
[成功] 参数已添加到 /opt/192.168.56.101/gcluster/config/gbase_8a_gcluster.cnf
处理节点: 192.168.56.102
[成功] 参数已添加到 /opt/192.168.56.102/gcluster/config/gbase_8a_gcluster.cnf
处理完成:成功 2 个节点,失败 0 个节点
[gbase@data1 persist_args]$
[gbase@data1 persist_args]$
[gbase@data1 persist_args]$
添加一个自造的参数到节点层配置文件
[gbase@data1 persist_args]$ python persist_args.py "some_args = 123" n node.list
准备将参数 'some_args' 添加到 gbase_8a_gbase.cnf 配置文件中...
目标节点数量: 2
处理节点: 192.168.56.101
[成功] 参数已添加到 /opt/192.168.56.101/gnode/config/gbase_8a_gbase.cnf
处理节点: 192.168.56.102
[成功] 参数已添加到 /opt/192.168.56.102/gnode/config/gbase_8a_gbase.cnf
处理完成:成功 2 个节点,失败 0 个节点
添加已存在的参数,报错
[gbase@data1 persist_args]$ python persist_args.py "some_args = 456" n node.list
准备将参数 'some_args' 添加到 gbase_8a_gbase.cnf 配置文件中...
目标节点数量: 2
处理节点: 192.168.56.101
[错误] 节点 192.168.56.101 的配置文件 /opt/192.168.56.101/gnode/config/gbase_8a_gbase.cnf 中已存在参数 'some_args'
处理节点: 192.168.56.102
[错误] 节点 192.168.56.102 的配置文件 /opt/192.168.56.102/gnode/config/gbase_8a_gbase.cnf 中已存在参数 'some_args'
处理完成:成功 0 个节点,失败 2 个节点
[gbase@data1 persist_args]$ python persist_args.py "some_args = 456" c node.list
准备将参数 'some_args' 添加到 gbase_8a_gcluster.cnf 配置文件中...
目标节点数量: 2
处理节点: 192.168.56.101
[错误] 节点 192.168.56.101 的配置文件 /opt/192.168.56.101/gcluster/config/gbase_8a_gcluster.cnf 中已存在参数 'some_args'
处理节点: 192.168.56.102
[错误] 节点 192.168.56.102 的配置文件 /opt/192.168.56.102/gcluster/config/gbase_8a_gcluster.cnf 中已存在参数 'some_args'
处理完成:成功 0 个节点,失败 2 个节点
配置文件修改情况(添加正常)
....
#const express can calculated before query
gcluster_prepare_const_express = 0
#gbase_jvm_options = -Xms1G;Xmx2G;-XX:NewRatio=2;-XX:+UseG1GC
#gbase_jvm_path = /usr/lib/jvm/java-1.6.0/jre/lib/amd64/server/libjvm.so
#udf_jar_files
gbase_dblink_gateway_ip = 192.168.56.101
gbase_dblink_gateway_port = 8989
some_args = 123
[gbasedump]
max_allowed_packet = 64M
[gbase]
no_auto_rehash
评论
登录后才可以发表评论
热门帖子
- 12025-12-01浏览数:182759
- 22023-05-09浏览数:25044
- 42023-09-25浏览数:18519
- 52020-05-11浏览数:17526