【实施分享】Gaussdb华为云实施分享发表时间:2024-08-15 16:44 目录 第1章、 Gaussdb实施技术分享 1.1、 解决DRS无法发起全量+模式任务的问题 1.2、 使用DRS迁移后表数量不一致的问题 1.3、 数据源如何适配方案 1.4、 dbever工具连接gaussdb案例分享 1.5、 获取密钥并解密RDSAdmin密获案例分享 1.6、 drs-meta库因为cgroup无法启动案例分享 1.7、 GaussDB应用磁盘IO类故障在线诊断 1.8、 Redis应用网络时延类故障在线诊断 1.9、 一场由fork引发的超时,让我们重新探讨了Redis的抖动 1.10、 DRS (Database Replication System) 连接Oracle数据库出现网络连接异常的问题 15 1.11、 drs-FATAL terminating connection due to administrator command 1.12、 ugo迁移注意事项 1.13、 Drs使用过程中遇到问题案例 1.14、 使用 psycopg2 连接高斯数据库报错 failed: none of the server‘s SASL Gaussdb实施技术分享解决DRS无法发起全量+模式任务的问题问题背景: 在使用华为云DRS(Data Replication Service)进行Oracle到GaussDB的数据库迁移时,遇到了无法发起全量+模式任务的问题。本文将详细描述问题现象、分析过程及解决方案。 问题分析: 1.问题现象 DRS版本:2.23.07.263 源端:Oracle 19c 目标端:GaussDB分布式8.3.1 无法发起全量+模式的迁移任务。 2.问题分析 进入drs-node服务器。查看具体drs任务日志 /drs/run/{job-id}/log/relay.info.log 3.查看任务日志 进入DRS节点服务器,查看具体的DRS任务日志: /drs/run/{job-id}/log/relay.info.log 4.日志分析 在日志中观察到thread2的获取对应SCN号的日志一直失败。最初怀疑是由于归档被清理导致的问题,但即使注释了清理归档的任务后,问题依然存在。 5.特殊环境分析 经过进一步调查,发现客户的Oracle环境是从RAC改造出的单机数据库,thread2处于启用状态,但对应的thread2日志已经被删除。是问题的关键所在。 使用DRS迁移后表数量不一致的问题问题背景: 在使用华为云DRS(Data Replication Service)进行Oracle到GaussDB的数据库迁移时,遇到了源库和目标库表数量不一致的问题。本文将详细描述问题现象、原因分析及解决方案。 问题现象: 源库schema下共有3858张表。 其中12张表因为保留字、中文表名问题不迁移;1张表因为表定义超长,在目标端服务器上创建。 故在目标端,理论上应该有3846张表。 但是使用\d命令发现只有3845张表。 查询pg_tables则显示有3846张表。 问题分析: 在目标端使用\d命令时,发现无法匹配到plan_table表,仅在全词匹配下,才能发现该表。 原因分析: \d命令在默认情况下是进行模糊匹配的,它可能不会列出所有表,尤其是那些名称包含特殊字符或不常见单词的表。plan_table表可能因为名称特殊或与\d命令的默认匹配规则不兼容,因此在\d命令下未被列出。 解决方案: 1.忽略plan_table表即可。 2.使用更精确的查询方法,如pg_tables,来验证表的数量。 数据源如何适配方案:集中式连接 对于集中式的GaussDB集群,可以使用如下JAVA JDBC URL格式进行连接: Jdbc:postgresql://IP1:port1, IP2:port2, IP3:port3/appdb?targetServerType=master&socketTimeout=5&connectTimeout=5&loginTimeout=3defaultRowFetchSize=1000 参数解释: targetServerType:指定连接的目标服务器类型,可以选择 socketTimeout:套接字超时时间(秒),用于读取数据。 oconnectTimeout:连接超时时间(秒),用于建立连接。 ologinTimeout:登录超时时间(秒),用于认证过程。 defaultRowFetchSize:每次从结果集中获取的行数,默认为0表示一次性获取所有行,可能引起内存溢出(OOM)。 分布式连接 对于分布式GaussDB集群,可以使用如下JAVA JDBC URL格式进行连接: Jdbc:postgresql://IP1:port1, IP2:port2, IP3:port3/appdb?autoBalance=true&socketTimeout=5 &connectTimeout=5&loginTimeout=3defaultRowFetchSize=1000 参数解释: autoBalance:是否启用自动平衡连接,可以选择 true:轮询模式。 priorityN:前N个为主优先级,如果这些不可用,则使用其他节点。 shuffle:随机选择。 false:关闭自动平衡功能。 orefreshCNIpListTime:定义JDBC客户端刷新协调节点列表的时间间隔,默认为10秒。 Python 连接华为云GaussDB方案 示例代码: vi test_gaussdb.py ## psycopg2安装方式见:https://support.huaweicloud.com/distributed-devg-v8-gaussdb/gaussdb-12-0154.html # -*- coding: utf-8 -*- import psycopg2 import os # 从环境变量中获取用户名和密码 user = "root" password = "ATT@2022" # 创建连接对象 conn=psycopg2.connect(database="postgres", user=user, password=password, host="192.168.1.23", port=8000) cur=conn.cursor() #创建指针对象 # 创建表 cur.execute("CREATE TABLE student(id integer,name varchar,sex varchar);") # 批量插入数据 stus = ((4,'John','M'),(5,'Alice','F'),(6,'Peter','M')) cur.executemany("INSERT INTO student(id,name,sex) VALUES(%s,%s,%s)",stus) # 获取结果 cur.execute('SELECT * FROM student') results=cur.fetchall() print (results) # 提交操作 conn.commit() # 插入一条数据 cur.execute("INSERT INTO student(id,name,sex) VALUES(%s,%s,%s)",(7,'Lucy','F')) # 回退操作 conn.rollback() # 关闭连接 cur.close() conn.close() 注意事项: 其他注意 1、当密码中包含@等特殊符号,密码无法被识别问题 使用unicode编码规避密码特殊字符,例如 @ 为 \%40 2、Pycopg2非Gaussdb原生导致出现SASL 原生Pycopg2密码校验默认是md5,而高斯使用sha256。需要使用高斯的原生pycopg2,注意全部替换相关lib dbever工具连接gaussdb案例分享Dbever是一款基于Java的通用型数据库客户端工具,支持多种数据库类型。为了确保最佳的兼容性和性能,建议使用与您的数据库版本相匹配的Java版本和专用的数据源驱动。例如,Dbever 24.1.2版本需要Java Development Kit (JDK) 17,而从24.1.4版本开始,Dbever内置了专用的GaussDB数据源驱动。配置方法如下:打开Dbever工具后,选择“数据库”菜单下的“驱动管理器”。对于Dbever 24.1.4及更高版本,可以直接使用内置的GaussDB专用驱动。
下载专用的gsjdbc4库。请访问以下链接下载gsjdbc4-1.0.jar文件,链接:https://repo.huaweicloud.com/repository/maven/huaweicloudsdk/gsjdbc4/gsjdbc4/1.0/gsjdbc4-1.0.jar
配置驱动
使用数据源
获取密钥并解密RDSAdmin密获案例分享首先登录服务器 sqlite3 /home/Ruby/agnet_sqlite.db select * from instance_tb;
为了获取RDSAdmin的密码,您需要执行解密操作。首先,确保您已经在数据库服务器上准备好了解密脚本decry.py。此脚本本身只有833字节大小,不包含任何密钥信息,这意味着您需要在数据库服务器上执行此脚本,并提供正确的密钥作为输入。执行解密命令 import sys import os import psutil sys.path.append("/dbs/agent") from base.utils.logical_sql import LogicalSql def get_pid(cmd_name, part_of_cmd_line): pid_list = psutil.pids() for pid in pid_list: try: p = psutil.Process(pid) if p.name() == cmd_name: if part_of_cmd_line: if part_of_cmd_line in " ".join(p.cmdline()): return pid else: return pid except psutil.NoSuchProcess: continue return 0 if __name__ == "__main__": dbmanager_pid = get_pid("python", "dbs/agent/base/cmd/dbmanager.py") os.environ['fpr1nt'] = "" os.environ['fpr1nt'] = os.environ['fpr1nt'] + "@" + str(dbmanager_pid) pwd = sys.argv[1] ret = LogicalSql.decryptPassword(pwd) print("pwd:%s" % ret) drs-meta库因为cgroup无法启动案例分享问题现象如下: 1.DRS版本:2.23.07.263 2.RS Web页面无法显示。 通过命令ps -ef | grep drs检查DRS进程的日志,发现DRS无法连接到数据库。进一步使用ps -ef | grep gaussdb命令检查,发现GaussDB数据库没有启动。 问题分析显示,GaussDB数据库实例的状态为down。 通过上述描述,您可以清楚地了解到DRS Web页面无法显示的原因在于DRS无法连接到数据库,而数据库本身也没有启动。接下来可以进一步排查数据库未启动的原因,并尝试手动启动数据库来解决问题。
手工拉起实例 Gs_ctl start -D /data/cluster/data/dn/dn_6001 -M primary GaussDB应用磁盘IO类故障在线诊断该案例通过对Gaussdb应用注入磁盘IO故障来模拟。 1. 故障注入前 应用实时拓扑关系如下图所示,gaussdb应用包含1个master(进程id:1548)和1个slaver(进程id:1739),运行在虚拟机vm02上,gaussdb master有5个客户端TCP连接。 此时,gaussdb的应用性能平均600 TPS。 2. 注入故障 在gaussdb的数据目录注入磁盘读写故障,命令如下:blade create disk burn --read --write --path /data --timeout 120
3. 应用性能诊断 此时应用性能出现劣化,从大概600 TPS → 60 TPS,下降了近10倍,如下图所示:
故障发现与定位结果如下图所示,可以看出已产生应用性能劣化事件,原因是磁盘读写响应异常。 具体的故障传播关系如下图所示,可见应用性能劣化是因为磁盘写响应异常以及block层request时延异常,进一步的磁盘类异常是由于故障注入工具chaos(进程id:3941335)导致。 Redis应用网络时延类故障在线诊断1. 注入故障 通过故障注入工具ChaosBlade注入2分钟网络时延故障,具体命令:blade create network delay --time 50 --offset 50 --interface ens1 --local-port 3742 --timeout 120 故障注入期间redis sli指标出现明显劣化,大概从10ms → 80ms 2. 应用性能诊断 故障发现与定位,在节点上可以看出已产生应用性能劣化事件,原因是网络时延异常。 一场由fork引发的超时,让我们重新探讨了Redis的抖动问题现象: 某客户业务接入GaussDB(for Redis)压测发现,每5分钟系统出现一次规律性的时延抖动: 1)正常情况消息时延在1-3ms,抖动时刻时延达到300ms左右。 2)通常是压测一段时间后开始出现抖动;抖动一旦出现后就非常规律的保持在每5分钟1次;每次抖动的持续时长在10ms以内。 下图是从系统慢日志中捕获到的发生抖动的消息样例(对敏感信息进行了遮掩) 1.排查抖动源: 1)由于故障的时间分布非常规律,首先排除定时任务的影响,主要包括: lagent:和管控对接的周期性统计信息上报任务 l内核:执行引擎(Redis协议解析)和存储引擎(rocksdb)的周期性操作(包括rocskdb统计,wal清理等) 屏蔽上述2类定时任务后,抖动依然存在。 2)排除法未果后,决定回到正向定位的路上来。通过对数据访问路径增加分段耗时统计,最终发现抖动时刻内存操作(包括allocate、memcpy等)的耗时显著变长;基本上长出来的时延,都是阻塞在了内存操作上。 既然定位到是系统级操作的抖动,那么下一步的思路就是捕获抖动时刻系统是否有异常。我们采取的方法是,通过脚本定时抓取top信息,分析系统变化。运气比较好,脚本部署后一下就抓到了一个关键信息:每次在抖动的时刻,系统中会出现一个frm-timer进程;该进程为GaussDB(for Redis)进程的子进程,且为瞬时进程,持续1-2s后退出。 确定引发抖动的代码: 1)分析frm-timer的来历是下一步的关键。因为这个标识符不在我们的代码中,所以就需要拉通给我们提供类库的兄弟部门联合分析了。经过大家联合排查,确认frm-timer是日志库liblog中的一个定时器处理线程。如果这个线程fork了一个匿名的子进程,就会复用父进程的线程名,表现为Redis进程创建出1个名为frm-timer的子进程的现象。 2)由于frm-timer负责处理liblog中所有模块的定时器任务,究竟是哪个模块触发了上述fork?这里我们采取了一个比较巧妙的方法,我们在定时器处理逻辑中增加了一段代码:如果处理耗时超过30ms,则调用std:: abort()退出,以生成core栈。 3)通过分析core栈,并结合代码排查,最终确认引发抖动的代码如下:
解决方法 1.修改日志库liblog中的周期性归档逻辑,不再fork子进程。 2.系统排查并整改GaussDB(for Redis)代码(包括使用的类库代码)中的fork调用。 3.最终排查结果,实际只有本次的这个问题点涉及fork。当前修改后即可确保GaussDB(for Redis)的时延保持稳定,不再受fork性能影响。 注:GaussDB(for Redis)由华为云基于存算分离架构自主开发,因此不存在原生Redis的fork调用的场景。 总结 本文通过分析GaussDB(for Redis)的一次由fork引发的时延抖动问题,探究了fork这个系统调用的性能影响。最新的GaussDB(for Redis)版本已解决了这个抖动问题,并清零了内部的fork使用,与原生Redis相比,彻底解决了fork的性能隐患。希望通过这个问题的分析,能够带给大家一些启发,方便大家更好的选型。 DRS (Database Replication System) 连接Oracle数据库出现网络连接异常的问题案例背景: 假设我们在使用DRS进行Oracle数据库迁移的过程中遇到了连接异常问题,具体错误为“connection reset by peer”。我们需要解决这个问题以便让数据迁移能够顺利进行。 案例描述: 环境:源Oracle数据库位于服务器A上,DRS服务器位于服务器B上。 现象:DRS服务器B在尝试连接服务器A上的Oracle数据库时出现了连接被重置的错误。 日志位置:DRS服务器的日志文件位于/opt/drs/logs/;DRS节点的日志文件位于/drs/run/job-id。 已知检查:使用了curl -kv 21.96.16.153:1521命令进行初步测试,返回了“connection reset by peer”的错误。 排查步骤: 1. SELinux配置检查 原因:SELinux可能会阻止某些网络连接。 操作: Bash # 查看SELinux状态 sestatus # 如果SELinux启用,尝试临时关闭它 sudo setenforce 0 验证:再次尝试使用DRS连接Oracle数据库,查看是否仍然出现同样的错误。 2. Firewall配置检查 原因:防火墙可能阻止了必要的端口访问。 操作: bash # 查看防火墙状态 sudo systemctl status firewalld # 如果防火墙启用,添加1521端口到允许列表 sudo firewall-cmd --permanent --add-port=1521/tcp sudo firewall-cmd --reload 验证:再次尝试使用DRS连接Oracle数据库,查看是否仍然出现同样的错误。 3. Oracle白名单配置检查 原因:Oracle的SQLNET.ORA文件可能限制了IP地址。 操作:登录到Oracle数据库服务器。 Bash # 查找SQLNET.ORA文件 find / -name sqlnet.ora # 允许所有IP地址 SQLNET.AUTHENTICATION_SERVICES=(NONE) # 或者指定DRS服务器的IP地址 SQLNET.ALLOWED_LOGON_VERSION_SERVER = 12 SQLNET.SSL_SERVER_DN_MATCH = YES SQLNET.ENCRYPT_SERVER = REQUIRED SQLNET.FEATURE_ENABLE = 1 SQLNET.ALLOWED_CLIENTS = 192.168.1.100 # DRS服务器的IP地址 综合验证: 再次尝试使用DRS连接Oracle数据库,查看问题是否得到解决 drs-FATAL terminating connection due to administrator command问题现象: 故障报错 drs版本:2.23.07.263 drs报错如下,应该是drs的meta库出现连接问题
其他现象:在第一次发生后(超过8H),后面多次重试基本1h内会发生中断 原因分析 Session_timeout参数默认为1800 分析是生成某些逻辑的session等待时间超过1800,导致连接中断。分析是前期的动作频繁,到了中期动作较少,出现了某些关键session超时 解决办法 设置参数到0,即不超时,可以设置为database级 alter database drs set session_timeout to 0; alter database drs reset configuration ; ugo迁移注意事项用于oralce迁移至gaussdb分布式 迁移对象类型,可以选择迁移对象类型,为了最快迁移大量数据,不要对目标表创建索引。故而选择最小的drs数据迁移所需要的对象
转换配置处选择最大兼容性,可以处理掉诸多转换问题,如 logging关键字,float型大于53。
唯一索引不存在分布列键 如果目标端是分布式环境,唯一键必须是分布键的一部分。转换报错如下:
可以做在转换配置处配置分布式环境选项处理
表空间默认需要映射,也可以使用配置中的参数,将所有表放在默认表空间下,即注释掉表空间字句(这里迁移时没有超级用户,无法创建表空间,故采取此方法)。
Drs使用过程中遇到问题案例:Java heap space空间问题:
Jvm空间不足导致异常退出。多次重启任务仍然如此,报错可能会在unknow error 设置drs参数,jvm使用20g sync.tunstenEnv.OPS_FULL_INCRE_MAX=20480 设置drs参数,数据源超时时间 *.datamove.source.urlOptions=&oracle.jdbc.ReadTimeout=300000 卡在某个分片,长时间没有进展 首先尝试暂停-续传任务 如果仍没有效果,使用以下sql在drs的库中查看进程的状态
大批量分片失败处理 进入drs库中,是用sql处理
唯一约束(主键约束)导致分片失败
出现过诡异的部分表数据量正好double的情况,可以用insert模式处理冲突。Drs设置参数,将传输模式改为insert sync.datamove.replicator.optimizeMode=false 建议完成后做数据比对,然后将不一致的表全部truncate,Not-null约束导致数据无法同步。
由于oracle源库是后生效型not null,数据的完整性不足。导致not null约束在迁移时不满足。 alter table TAB_NAME alter COL_NAME drop not null; alter table bancs.bocnet_mgr_elect_card alter name drop not null; 然后将所有失败分片之为waiting重传 update drs_full.shared_info set status=’waiting’ where schema_name=’’ and table_name=’’ and job_id=’’; Invalid bytes sequence 设置以下参数为true sync.datamove.replicator.standardizeStringType 续传任务 Don’t support COPY FROM table with insert tigger 将drs的传输模式改为insert Drs设置参数,将传输模式改为insert sync.datamove.replicator.optimizeMode=false Column “upddat” does not exists Position:20 where referenced column
对照源库目标库表结构,结构为一致,查询数据目标端为0行truncate该表仍无法传输,删除新建该表解决。 使用 psycopg2 连接高斯数据库报错 failed: none of the server‘s SASL authentication mechanisms are supported1.使用 命令安装 安装 psycopg2 pip3 install psycopg2 编写python文件 test2.py,连接数据库。 import psycopg2 #创建连接对象 conn=psycopg2.connect(dbname="db_tpcc",user="tpcc_user",password="password",host="10.201.65.207",port=30100) cur=conn.cursor() #创建指针对象 #创建连接对象(SSl连接) #conn = psycopg2.connect(dbname="db_tpcc", user="tpcc_user", password="password", host="10.201.65.207", port=30100,sslmode="verify-ca", sslcert="client.crt",sslkey="client.key.unsecure",sslrootcert="ca.pem") cur=conn.cursor() #创建指针对象 # 创建表 cur.execute("CREATE TABLE student(id integer,name varchar,sex varchar);") #插入数据 cur.execute("INSERT INTO student(id,name,sex) VALUES(%s,%s,%s)",(1,'Aspirin','M')) cur.execute("INSERT INTO student(id,name,sex) VALUES(%s,%s,%s)",(2,'Taxol','F')) cur.execute("INSERT INTO student(id,name,sex) VALUES(%s,%s,%s)",(3,'Dixheral','M')) # 获取结果 cur.execute('SELECT * FROM student') results=cur.fetchall() print (results) # 关闭连接 conn.commit() cur.close() conn.close() 运行test2.py 报错 conn = _connect(dsn, connection_factory=connection_factory, **kwasync) psycopg2.OperationalError: connection to server at "10.201.65.207", port 30100 failed: none of the server's SASL authentication mechanisms are supported 解决方法如下: A.执行命令修改加密参数 gs_guc reload -N all -I all -c "password_encryption_type=1"; B.修改数据库每台机器的pg_hba.conf文件 切换到你们那边的gaussdb用户,在所有DN节点都要修改如下内容 cd /data/cluster/data/dn/dn_6001(目录改成你那边的) vi pg_hba.conf ,将下图标注的sha256改为md5
前台报错cgroup does not exists,通过/data/cluster/data/dn/dn_6001下的postgresql.conf找到log_directory,查看log日志如下
错误是无法fork进程的warning,与cgroup关联性很大 查看cgroup的情况
总结: 尽管cgroup查询的值都是正确的,但仍旧报错提示gaussdb:omm组不存在。这一问题出现在尝试启动GaussDB数据库实例时。 解决办法: Cgroup在系统层是在以下两个路径会创建出相应的文件夹 /sys/fs/cgroup/cpuset /sys/fs/cgroup/cpu 例子如:
尽管cgroup查询的值都是正确的,但仍旧报错提示gaussdb:omm组不存在。这一问题出现在尝试启动GaussDB数据库实例时。此时将目录改为mv gaussdb: gaussdb:omm进行测试。
故障解决,drs实例启动,web页面恢复 |