• [技术干货] openGauss存储过程创建及应用
    一、引言openGauss 是一款开源关系型数据库管理系统,广泛应用于企业级应用中。随着数据量的增长和业务逻辑的复杂化,数据库管理和操作的自动化需求越来越高。存储过程(Stored Procedures)作为数据库中重要的编程工具,能够极大地简化复杂操作,提高系统的性能和安全性。本文将详细介绍 openGauss 的存储过程,并提供具体的代码和案例,以帮助读者更好地理解和应用这些工具。二、存储过程1. 什么是存储过程存储过程是一组预先编写好的 SQL 语句集合,存储在数据库中,可以通过调用存储过程来执行一系列操作。存储过程能够简化复杂的数据库操作,减少代码重复,提高效率。此外,存储过程运行在数据库服务器端,这意味着可以减少客户端和服务器之间的通信开销,提高执行效率。存储过程的特点包括:封装性:将一系列操作封装在一个过程里,简化调用。重用性:定义一次,可以在多个地方调用,减少代码重复。安全性:通过存储过程可以控制访问权限,提高数据安全性。性能:减少客户端和服务器之间的通信,执行效率高。2. 创建和使用存储过程在 openGauss 中,创建存储过程使用 CREATE PROCEDURE 语句。一个存储过程可以包含多个输入参数、输出参数,甚至没有参数。下面是一个详细的例子,演示如何创建和调用存储过程。创建员工表-- 创建员工表CREATE TABLE employees ( id INT PRIMARY KEY, name VARCHAR(100), salary NUMERIC(15, 2), department VARCHAR(100) );创建存储过程-- 创建插入员工的存储过程CREATE OR REPLACE PROCEDURE add_employee( emp_id INT, emp_name VARCHAR, emp_salary NUMERIC, emp_department VARCHAR )LANGUAGE plpgsql AS $$ BEGIN INSERT INTO employees (id, name, salary, department) VALUES (emp_id, emp_name, emp_salary, emp_department); END; $$;-- 创建更新触发器函数-- 创建更新员工的存储过程CREATE OR REPLACE PROCEDURE update_employee( emp_id INT, emp_name VARCHAR, emp_salary NUMERIC, emp_department VARCHAR ) LANGUAGE plpgsql AS $$ BEGIN UPDATE employees SET name = emp_name, salary = emp_salary, department = emp_department WHERE id = emp_id; END;$$;-- 创建删除员工的存储过程CREATE OR REPLACE PROCEDURE delete_employee(emp_id INT) LANGUAGE plpgsql AS $$ BEGIN DELETE FROM employees WHERE id = emp_id; END;$$;-- 创建查询员工的存储过程CREATE OR REPLACE PROCEDURE get_employee(emp_id INT) LANGUAGE plpgsql AS $$ BEGIN PERFORM * FROM employees WHERE id = emp_id; END; $$;调用存储过程-- 调用存储过程插入员工CALL add_employee(1, 'John Doe', 50000, 'Engineering');-- 调用存储过程更新员工CALL update_employee(1, 'John Doe', 55000, 'Marketing');-- 调用存储过程删除员工CALL delete_employee(1);-- 调用存储过程查询员工CALL get_employee(1);3. 存储过程的高级应用存储过程不仅可以简化常见的增删改查操作,还可以用于更复杂的业务逻辑处理。以下是一些存储过程的高级应用场景:批量数据处理在实际业务中,经常需要对大量数据进行批量处理,如批量插入、批量更新等。使用存储过程可以极大地简化这些操作,并提高执行效率。-- 定义员工记录的复合类型CREATE TYPE emp_record AS ( id INT, name VARCHAR(100), salary NUMERIC(15, 2), department VARCHAR(100) );-- 创建批量插入员工的存储过程CREATE OR REPLACE PROCEDURE batch_insert_employees(emp_records emp_record[]) LANGUAGE plpgsql AS $$ DECLARE rec emp_record; BEGIN FOREACH rec IN ARRAY emp_records LOOP INSERT INTO employees (id, name, salary, department) VALUES (rec.id, rec.name, rec.salary, rec.department); END LOOP; END; $$;-- 调用批量插入存储过程CALL batch_insert_employees(ARRAY[ ROW(2, 'Jane Doe', 60000, 'HR')::emp_record, ROW(3, 'Alice', 70000, 'Finance')::emp_record, ROW(4, 'Bob', 80000, 'IT')::emp_record ]);数据校验和清洗在存储过程中可以添加数据校验和清洗的逻辑,确保插入数据库的数据的完整性和准确性。例如,可以在插入员工数据前,检查数据是否符合业务规则。CREATE OR REPLACE PROCEDURE add_employee_with_validation( emp_id INT, emp_name VARCHAR, emp_salary NUMERIC, emp_department VARCHAR ) LANGUAGE plpgsql AS $$ BEGIN IF emp_salary < 0 THEN RAISE EXCEPTION 'Salary cannot be negative'; END IF; IF emp_department IS NULL THEN RAISE EXCEPTION 'Department cannot be null'; END IF; INSERT INTO employees (id, name, salary, department) VALUES (emp_id, emp_name, emp_salary, emp_department); END; $$;-- 调用存储过程插入员工CALL add_employee_with_validation(5, 'Charlie', 5000, 'Sales');自动化任务存储过程可以用于自动化任务,如定时任务、数据备份等。可以结合数据库调度器(如 cron 表达式)来实现定时调用存储过程,完成自动化管理。-- 定时任务:每天凌晨2点备份员工表CREATE OR REPLACE PROCEDURE backup_employees() LANGUAGE plpgsql AS $$ BEGIN EXECUTE 'COPY employees TO ''/path/to/backup/employees_' || to_char(current_date, 'YYYYMMDD') || '.csv'' WITH CSV HEADER'; END; $$;
  • [技术干货] openGauss 6.0安装过程解除对root用户依赖之gs_preinstall
    在给客户部署业务系统时,由于openGauss数据库的预安装过程需要用到root用户执行,总会被挑战root用户权限太大,若有风险谁负责,只能怯怯的说我们仅安装一个数据库,很快用完了就释放。而openGauss 6.0版本和5.0版本相比,数据库安装流程中的预安装命令(gs_preinstall)以及校验操作系统命令,同时扩容命令可以用非root命令执行了。用非root命令执行预命令,在安全和易用性等方面都有很大的改进(当然还有一些前提条件需要root用户执行,期待后续版本的继续优化),可以减少用户执行过程的用户切换,也可以控制root用户权限控制。一定程度减少了用户误操作对整个系统的影响范围。除了gs_preinstall外,做了类似改进的还有扩容(gs_checkos)和校验(gs_checkos),本文仅介绍gs_preinstall。(其余命令待后文整理)。1.执行前提条件本文由于是单机版安装所以未执行gs_sshexkey -f host,直接执行设置os参数这步,需要注意的是,前提条件的操作,仍然需要以root用户执行。详情参考官网资料,点击文末阅读原文。1.1设置OS参数:注意直接按照官网资料执行会报错Invalid argument,如下:该问题为已知资料问题,执行时需去掉双引号,即可成功。echo 'kernel.sem=250 6400000 1000 25600' >> /etc/sysctl.conf1.2定时任务权限赋予普通用户执行定时任务的权限echo "xxx" >> /etc/cron.allow重启定时任务使生效。systemctl restart crond1.3 修改最大文件描述符2.切换至omm用户,执行preinstall[omm@ecs-oe-2203 script]$ ./gs_preinstall -U omm -G dbgrp -X /opt/software/opengauss/clusterconfig.xml3.source环境变量preinstall成功后,用omm用户执行gs_install,报错:因是环境变量问题,因此回退至root用户,先source环境变量,再执行gs_install命令,就可以成功。[root@ecs-oe-2203 script]# source /home/omm/.bashrc[root@ecs-oe-2203 script]# su omm4.执行gs_install切换至omm用户,继续执行gs_install,安装成功,登录默认数据库并查询。Gs_checkos和gs_expansion的会在后续发出,敬请关注。本文作者本文内容来自于数据库领域资深技术专家赵锋老师,希望我们的文章正好能解决你的问题。
  • [问题求助] TPOPS什么都不显示,是什么问题?
    tpops什么都不显示添加了主机  安装包
  • [问题求助] TPOPS上进行数据库实例备份失败
    TPOPS上新建了一个备份计划,执行到64%后失败了。2024-08-13 20:31:562024-08-13 21:24:20/data/backupNAS全量手动--64%失败页面报错日志如下:[2024-08-13 20:31:59.324]The task is running[2024-08-13 21:24:20.116]{"detailmsg":"Backup retry failed 3 times.Backup failed. [GAUSS-60202]:Result exception error : Roach task is abnormal or roach action is not executed right now still.","retcode":1}[2024-08-13 21:24:20.284]jobPostProcess starting...[2024-08-13 21:24:20.285]queryProcessBackupJob execute failed. Reason: SYS_EXCEPTION:OP_STATUS_FAILURE备份计划配置参数如下-存储方式:NASNAS服务器部署模式:单服务器备份类型:全量备份方式:手动备份存储容量告警阈值(%):80备份根路径 :/data/backup分布式gaussdb库的数据库实例挂载的nas如下:[root@localhost omm]# df -Th Filesystem                          Type      Size  Used Avail Use% Mounted on devtmpfs                            devtmpfs   64G     0   64G   0% /dev tmpfs                               tmpfs      64G  256K   64G   1% /dev/shm tmpfs                               tmpfs      64G  4.1G   60G   7% /run tmpfs                               tmpfs      64G     0   64G   0% /sys/fs/cgroup /dev/mapper/klas-root               xfs       3.0T  486G  2.6T  16% / tmpfs                               tmpfs      64G     0   64G   0% /tmp /dev/mapper/klas-cluster_data_data1 ext4      492G   73M  467G   1% /cluster/data/data1 /dev/mapper/klas-cluster_data_etcd  ext4       63G  428M   59G   1% /cluster/data/etcd /dev/sda2                           xfs       482M  212M  271M  44% /boot /dev/sda1                           vfat      100M  6.4M   94M   7% /boot/efi tmpfs                               tmpfs      13G     0   13G   0% /run/user/1000 tmpfs                               tmpfs      13G     0   13G   0% /run/user/0 tmpfs                               tmpfs      13G     0   13G   0% /run/user/993 tmpfs                               tmpfs      13G     0   13G   0% /run/user/1001 10.56.24.47:/nasDir                 nfs4      1.0T  13G 1021G   2% /data/backup/nas/data 计划开始执行时,一直有写入,查看nas写入大小13G左右后,又回退到初始值了,然后TPOPS页面显示报错了。请专家帮忙看看,分析下原因。
  • GaussDB关键技术原理|高可用:两地三中心跨Region容灾
    接上篇GaussDB关键技术原理|高可用:逻辑复制。从逻辑复制方面对GaussDB的高可用能力进行了介绍,本篇将从两地三中心跨Region容灾方面继续解读GaussDB高可用技术。4 两地三中心跨Region容灾4.1 概述两地三中心,顾名思义,两地指的是两座城市,即同城和异地,三中心指的是生产中心,同城容灾中心以及异地容灾中心。近年来,国内外频繁出现自然灾害,以同城双中心加异地灾备中心的“两地三中心”的灾备模式也随之出现,这一方案兼具高可用性和灾难备份的能力。同城双中心是指在同城或邻近城市建立两个可独立承担关键系统运行的数据中心,双中心具备基本等同的业务处理能力并通过高速链路实时同步数据,日常情况下可同时分担业务及管理系统的运行,并可切换运行;灾难情况下可在基本不丢失数据的情况下进行灾备应急切换,保持业务连续运行。异地灾备中心是指在异地的城市建立一个备份的灾备中心,用于双中心的数据备份,当双中心出现自然灾害等原因而发生故障时,异地灾备中心可以用备份数据进行业务的恢复。数据库实例之间借助存储介质或者不借助存储介质直接实现数据的全量和增量同步。当主数据库实例(即生产数据库实例)出现地域性故障,数据完全无法恢复时,可考虑启用将灾备数据库实例升主,以接管业务。GaussDB当前提供基于流式复制的异地容灾解决方案。目前需要通过om_agent的https REST API来操控数据库实例实现异地容灾。4.2 异地容灾部署示例集中式主集群是同城跨AZ的单集群,5台服务器,4副本,CMS-4副本,ETCD-5副本。Server5可以看做是仲裁副本,为上海2机房脑裂时,提供仲裁能力。分布式:分布式示例主集群是同城跨AZ的单集群,33台服务器,32C32D-4副本,GTM-4副本,CMS-4副本,ETCD-5副本。server33可以看做是仲裁副本,为北京2机房脑裂时,提供仲裁能力。容灾集群为16台服务器,16C32D-2副本,需要开启最大可用模式,1个副本故障时任何对外提供服务,GTM-4副本,CMS-4副本,ETCD-3副本。由于机器数量有限,需要支持单服务器上部署2个主DN的部署方式。特别说明:图中展示的是合肥地域集群为正常集群时的组网,该集群成为灾备集群后,不会再有主DN,变为首备与级联备。4.3 总体设计集中式部署场景:主实例和灾备实例副本数可不同,灾备集群最少为1副本。图 两地三中心异地容灾方案集中式部署场景分布式部署场景:支持灾备集群的CN个数和主集群CN个数不对等。主集群和灾备集群DN分片数要求相同,DN分片内副本数可不同,灾备集群最少为1副本。图 两地三中心异地容灾方案分布式部署场景容灾方案提供如下操作流程:容灾搭建:两个正常集群成为容灾状态下的主集群和灾备集群。图 两地三中心异地容灾方案集中式部署容灾搭建集群变化1. 主备集群副本数可不同。2. 灾备集群有首备+级联备概念,只有首备从主集群主DN拷贝全量数据并建立异地流式复制关系。3. 灾备集群内级联备从首备拷贝数据,并与首备建立流式复制关系。灾备集群升主failover:无论主集群是否异常,灾备集群都可以通过升主成为正常集群对外提供服务,并脱离容灾。演练特性-主备集群switchover:主备集群在都是正常的情况下进行倒换,主集群降为备机,备机升为主机。图 两地三中心异地容灾方案集中式部署failover与switchover集群变化主集群容灾解除:用于在灾备集群升主后,主集群删除容灾信息,脱离容灾。容灾状态查询:容灾状态日常监测,上报集群容灾状态、容灾搭建进度、failover进度、switchover进度,集群RTO,RPO实时数值。上报项含义hadr_cluster_stat (主备集群都可查到)参与容灾的集群状态hadr_establish_stat容灾搭建过程中主备集群搭建进度查询,显示进度百分比。hadr_failover_stat (备集群可查到)灾备集群升主过程进度,hadr_cluster_stat = promote时hadr_failover_stat中的值有效,显示进度百分比。hadr_switchover_stat (主备集群都可查到)计划内switchover过程进度,hadr_cluster_stat = switchover时hadr_switchover_stat中的值有效,显示进度百分比。RTO(主集群可查到)集群容灾RTO(所有分片的最大值)RPO(主集群可查到)集群容灾RPO(所有分片的最大值)容灾状态下支持如下功能:流控:通过GUC参数设置目标值,对主集群的日志产生速度进行控制,以保证RPO,RTO。压缩:主备集群间日志传输可打开压缩,节约带宽,压缩比70%。4.4 容灾搭建容灾搭建总体流程图 流式容灾集群搭建流程图图 灾备集群搭建build备集群实例流程图容灾流程图说明灾备集群搭建主流程:1. 管控A下发搭建新集群A,管控B下发搭建新集群B。2. 管控A,B同时对集群下发灾备集群搭建指令,假设A为主集群,B为灾备集群。B集群中各实例配置A集群中对应节点实例的IP、PORT信息,A集群同样添加B集群中主备的IP、PORT信息。3. 选择B集群中首备实例。向B集群主备实例下发全量重建指令。4. 待B集群主备重建完成,建立A集群和B集群中主备的流复制,并下发B集群重建级联备指令。5. 待B集群所有实例重建成功,且B集群主备实例和A集群对应备机(分布式下对应分片的备机)建立流复制,其他B集群备机(分布式下同分片内)和首备建立连接成功后,返回灾备搭建成功。容灾集群流式日志复制图 流式容灾灾备集群流复制复制消息序列图1. 在开启容灾阶段:在主集群每个副本上,配置replconninfo、hadr_recovery_time_target、hadr_recovery_point_target GUC参数,配置pg_hba.conf;在灾备集群的每个副本上,配置replconninfo参数。2. CM仲裁选举灾备集群中的首备。3. 灾备集群首备轮询主集群中所有的副本,直到找到主DN。4. 灾备首备发起日志复制请求,包括:版本校验、对端状态校验、系统一致性校验、日志一致性校验;灾备首备创建和继续流复制槽,流复制槽名称采用application_name + _hadr方式拼接,以便和主集群同名副本进行区分。5. 主集群主DN遍历所有主集群walsender,获取多数派副本已经同步的日志LSN位置的最小值,并将首备请求LSN位置到该LSN位置之间的日志发送给首备。6. 灾备集群首备接受到日志之后,由walreceiver writer下盘。7. 灾备集群其他副本对首备发起级联复制请求,首备将上述请求LSN位置到本地下盘日志LSN位置之间的日志,级联发送到各个级联副本。8. 级联副本接受到日志之后,将本地的日志下盘位置和日志回放位置反馈给首备。9. 首备将灾备集群中所有副本中日志下盘的多数派LSN位置和日志回放的多数派LSN位置反馈给主集群的主DN。10. 主集群主DN将首备反馈的灾备集群多数派日志下盘位置,作为日志回收以及灾备RPO流控的判断条件(之一)。11. 主集群主DN将首备反馈的灾备集群多数派回放下盘位置,作为灾备RTO流控的判断条件(之一)。容灾集群流式日志复制的高可用主集群少数派副本故障图 主集群发生少数派副本消息序列图1. 主集群CM发起锁分片和重新选主。2. 灾备集群首备的复制链接中断,wal receiver线程退出,重新开始轮询主集群各个副本。3. 主集群新主选主成功。4. 灾备集群轮询到新主,再次开始流式日志复制。5. 由于发送给灾备集群首备的日志都是在主集群已经达成多数派的,因此不会发生日志分叉的问题。灾备集群少数派故障:图 灾备集群发生少数派副本消息序列图1. 灾备首备故障,跨region复制中断。2. 灾备CMS发起首备重新选举,类似主集群选主:首先锁分片,然后从剩余备副本中找到本地日志term最大、日志最大的那个副本,选为首备,最后再给剩余级联备副本下发连接新首备的命名。3. 先首备轮询主集群各个副本,请求跨region日志复制,流程同上。4. 灾备集群中,其他副本在从新首备请求日志复制时,可能会出现本地日志大于新首备的情况(故障再加回场景),由于日志不会发生分叉,因此在这种情况下,该日志较多的级联备只需要在日志一致性校验阶段等待新首备的日志超过本地日志即可。CN支持流复制机制根据上述分布式容灾搭建的对应关系,备集群CN需要和主集群的CN建立一对一的流式容灾关系以保证日志的持续拷贝和回放。该设计的基本思路同集群内的主备关系,但是不要求CN间复制是强同步的,所以修改CN的synchronous_commit = off,不阻塞主集群CN的提交。在备集群的CN和备机一样,以standby模式启动,当本地日志回放结束后0启动walreceiver线程通过解析replconninfo参数建立和主集群CN walsender的连接。由主集群CN walsender开始持续发送xlog日志,再由备集群CN本地回放日志使数据和主集群CN保证一致。故障处理和原集群内主备一致。当备CN未连接主CN时,备CN标记为disconnected状态;当日志crc校验不一致时备集群CN将自己的build reason标记为wal segments removed状态;当主备断连时标记为connecting状态。主要交互流程如图所示。图 灾备集群搭建备集群CN实例build流程图同时对于新增的CN流复制应考虑日志回收的逻辑。日志回收总体方案和原DN主备逻辑一致,先参考本地日志是否大于wal_keep_segments参数,若大于则主集群CN参考对应流复制槽,(目前只有备CN的槽位)日志落盘位置,保证正向场景下备CN所需日志不会被主CN回收。考虑到异常的备CN断连场景,主CN的日志回收应参考最大日志保留量max_size_for_xlog_prune参数,保证在不影响主集群CN可用性下,为备CN保留最多的日志,减少全量build的可能。灾备集群的CN个数和主集群CN个数不对等场景下建立容灾关系图中主备集群CN对应关系的处理说明:受限于replconninfo配置个数的上限,集群达到一定规模后不可能将对端所有的节点链接信息都配上,所以OM在主备集群搭建容灾关系时CN依据如下计算方式进行对应。当前使用CN instance id从小到大排序后的normal CN id list进行主备集群CN配对,比如主集群有M个normal CN,灾备集群有N的normal CN,对M,N中较小的值取模对应。可能出现的情况分析如下:图  主集群CN多于灾备集群CN容灾搭建示例(1)、如果主集群的CN多(上图M=5),灾备集群的CN少(上图N=3),以灾备集群的CN数量为准, 一对一进行build之后建立replication;主集群多出来的CN没有灾备CN对应,配置有容灾信息replconninfo,但不发生作用。灾备集群的CN会配置多条容灾使用的replconninfo,比如主集群的CN1挂了,灾备CN1可以连到CN4上触发build。图 主集群CN少于灾备集群CN容灾搭建示例(2)、如果灾备集群的CN多(上图N=5),主集群的CN少(上图M=3)(主要出现场景为计划内switchover、灾备集群升主后反向搭建容灾关系),此时灾备集群会有多个灾备CN同时和主集群相同CN建立流式复制的关系,比如上图上CN1和CN4都是与主集群的CN1建立容灾关系。容灾过程中灾备故障CN的处理1. 主集群CN故障导致灾备CN故障的处理机制主集群处于容灾的CN发生剔除,或者主备集群间网络断链导致灾备CN处于故障状态,CN采用Need_repair(<build_reason>)上报机制,灾备CM对这一状态的CN不做剔除处理。主集群处于容灾的CN发生剔除或者网络断链状态,灾备集群对应的CN感知到断连,将上报Need_repair(Disconnected)状态,并由CM显示。主集群CN因为修复等操作发生build,灾备CN试图同步的日志和本地xlog日志不一致,灾备CN需要上报Need_repair(wal segment removed)等状态,灾备CMS感知后,会通知CN所在CMA下发CN全量build(从主集群对应cn build,build完成后自动拉起),build完成后CN恢复Normal状态。相关命令gs_ctl build -b cross_cluster_full -Z coordinator -D <dir_path> -M standby。灾备CN build期间,显示building状态,不参与barrier推进,也不参与备机只读的接入。灾备集群的CN会将当前连接成功的生产集群CN的序号持久化到文件里边,重启后会从文件读取最近一次的CN序号,优先连接最近一次连接的成功的对端CN。在尝试连接失败次数达到一个阈值(当前阈值设定为3000次)时候,才会尝试连接下一个replication info里边的CN。2. 灾备集群CN故障的处理机制灾备的CN故障同主集群有所不同:灾备集群的CN是按standby起的,不会和其他CN/DN联系,满足条件(CN心跳超时25s、CN反复重启)会被剔除,置Deleted状态。Deleted状态的CN不参与barrier推进,也不参与备机只读的接入。被剔除CN由CMA检测满足自动加回条件后进行自动修复,或手动进行CN修复。修复期间会触发全量build。修复完成后CN恢复Normal状态。要保证最后一个非超前状态的CN不触发build,否则会出现容灾集群无CN可用的暂态。3. 灾备集群CN故障的告警在容灾状态下,灾备集群CN如果出现Need_repair(Disconnected),上报容灾实例断连告警,并在Detail信息中体现本端实例id与对端实例id的容灾关联性。该告警信息上报管控。详见《3.3.8系统外部接口(和其他产品)》4. 灾备集群CN状态转化汇总图 灾备集群CN状态转换约束对应集群只要有一个CN还活着,就能提供服务:容灾状态的集群同样保证最后一个CN不做剔除。灾备集群需要始终保持至少一个CN不处于waiting或者deleted状态。异地容灾集群间日志传输需要支持日志压缩受客户场景跨集群间的网络带宽限制,将跨集群的xlog日志在发送端压缩,接收端解压,以提高传输效率。1. 功能实现:添加控制xlog压缩启停的guc参数enable_wal_shipping_compression,描述如下:enable_wal_shipping_compression参数说明:在流式容灾模式下设置启动跨集群日志压缩功能。该参数属于SIGHUP类型参数。取值范围:布尔型该参数仅作用于跨集群传输的一对walsender与walreceiver中,作用于主集群DN。默认值:false添加日志类型type ’C’用于表示被压缩的wal类型,在处理前会执行解压操作。采用了已在Gauss库中的lz4无损压缩算法进行日志压缩,使用默认压缩级别LZ4_compress_default(),具体实现如下:日志发送方的Walsender.cpp:XLogSendPhysical()中,在XLogRead()函数将数据传入t_thrd.walsender_cxt.output_xlog_message前先进行压缩,并更改类型表示为’C’,之后将压缩后的数据传入output_xlog_message,同时更改pq_putmessage_noblock中数据长度为压缩后的大小。日志接收方的walreceiver.cpp:XLogWalRcvProcessMsg()中,type=’C’时,将buf中的数据先进行解压,用解压后的decompressBuf继续之后的逻辑。为了减少cpu在压缩/解压上的性能损失,仅对异地容灾的流式复制开启压缩功能,集群内的流式复制不开启压缩功能。2. 压缩率在流式容灾集中式场景开发环境自测中,使用8核虚拟机tpcc 50仓 64并发进行tpcc测试,带宽充足场景下,tpcc执行中测得xlog压缩率平均在64.8%左右。异地容灾的流控机制流式容灾在集中式场景已经添加了流控参数,描述如下:hadr_recovery_time_target参数说明:在流式容灾模式下设置hadr_recovery_time_target能够让备集群完成日志写入和回放。该参数属于SIGHUP类型参数。取值范围:整型,0~3600 (秒)0是指不开启日志流控,1~3600是指备机能够在hadr_recovery_time_target时间内完成日志的写入和回放,可以保证主集群与备集群切换时能够在hadr_recovery_time_target秒完成日志写入和回放,保证备集群能够快速升主。hadr_recovery_time_target设置时间过小会影响主机的性能,设置过大会失去流控效果。默认值:0hadr_recovery_point_target参数说明:在流式容灾模式下设置hadr_recovery_point_target能够让备集群完成日志刷盘的rpo时间。该参数属于SIGHUP类型参数。取值范围:整型,0~3600 (秒)0是指不开启日志流控,1~3600是指备机能够在hadr_recovery_point_target时间内完成日志的刷盘,可以保证主集群与备集群切换时日志差距能够在hadr_recovery_point_target秒内,保障备集群升主日志量。hadr_recovery_point_target设置时间过小会影响主机的性能,设置过大会失去流控效果。默认值:0这两个参数在客户对于异地容灾RPO,RTO有强烈需求的情况下,可以进行配置用于保证在任何时刻RPO,RTO都能达到客户要求。在分布式部署场景下,打开流控,流控机制会在分片级别上生效。比如RPO目标是10s,hadr_recovery_point_target可配置为10s,超过这个值的时候,流控生效,会对主集群日志写入速率进行反压,降低业务性能来保证RPO达标。比如RTO目标是10min,hadr_recovery_time_target可以配置60s,超过这个值的时候,流控生效,会对日志写入速率进行反压,降低业务性能来保证RTO达标。这里hadr_recovery_time_target控制灾备升主期间日志回放的耗时,是整个灾备集群升主流程耗时的一部分。针对异地容灾的RPO需求,新增了RPO流控与原有的RTO流控共同作用,对应修改了系统视图global_streaming_hadr_rto_and_rpo_stat与gs_hadr_local_rto_and_rpo_stat中的current_sleep_time列为rto_sleep_time和rpo_sleep_time。global_streaming_hadr_rto_and_rpo_stat参数说明:参数类型描述hadr_sender_node_nametext节点的名称,包含主集群和备集群首备。hadr_receiver_node_nametext备集群首备名称。current_rtoint流控的信息,当前主备集群的日志rto时间(单位:秒)。target_rtoint流控的信息,目标主备集群间的rto时间(单位:秒)。current_rpoint流控的信息,当前主备集群的日志rpo时间(单位:秒)。target_rpoint流控的信息,目标主备集群间的rpo时间(单位:秒)。rto_sleep_timeintRTO流控信息,为了达到target_rto这一预期,主机日志发送所需要的睡眠时间(单位:微秒)rpo_sleep_timeintRPO流控信息,为了达到target_rpo这一预期,主机日志生成所需要的睡眠时间(单位:微秒)gs_hadr_local_rto_and_rpo_stat参数说明:参数类型描述hadr_sender_node_nametext节点的名称,包含主集群和备集群首备。hadr_receiver_node_nametext备集群首备名称。source_iptext主集群主DN IP地址。source_portint主集群主DN通信端口。dest_iptext备集群首备DN IP地址。dest_portint备集群首备DN通信端口。current_rtoint流控的信息,当前主备集群的日志rto时间(单位:秒)。target_rtoint流控的信息,目标主备集群间的rto时间(单位:秒)。current_rpoint流控的信息,当前主备集群的日志rpo时间(单位:秒)。target_rpoint流控的信息,目标主备集群间的rpo时间(单位:秒)。rto_sleep_timeintRTO流控信息,为了达到target_rto这一预期,主机日志发送所需要的睡眠时间(单位:微秒)rpo_sleep_timeintRPO流控信息,为了达到target_rpo这一预期,主机日志生成所需要的睡眠时间(单位:微秒)集中式场景流控逻辑rto计算逻辑是:通过备机每次返回的最新落盘、回放lsn,计算备机日志落盘和回放的速度,估算当前备机所有已接收日志全部完成落盘、回放需要的时间,作为RTO。rpo计算逻辑是:通过主机新生成日志的速度,结合主备落盘日志量差值,估算当前主备日志差相当于主机多少秒的新增,作为RPO。分布式场景流控逻辑在分布式流式容灾中,为了保证分布式一致性采用全局一致性打点,对备机回放做了限制,即每个节点回放到全局targetBarrier点后会停止回放,等待下一个targetBarrier更新。而灾备集群升主时,targetBarrier后的日志会被丢弃,因此不能与普通集群一样按flush点计算RTO/RPORTO新增逻辑是:在集中式逻辑的基础上,因为灾备集群升主时,targetBarrier后的日志会被丢弃,所以当节点日志回放到targetBarrier后即可视为回放完成,RTO=0。灾备集群各节点会将当前是否回放到targetBarrier点,返回给对应的主集群节点,标记此时rto=0。RPO计算逻辑是:由于targetBarrier后的日志灾备升主时会被丢弃,所以应该以备机targetBarrier点与主机最新日志计算RPO。barrierId的最后13位为其生成时的时间信息,RPO算法利用这个时间戳,由灾备返回targetBarrierID,与主机最新生成的currentBarrierID比较,时间差即是灾备升主时丢失日志的时间长度。周期性全局一致性打点与推进图 barrier处理消息序列图消息序列图说明如上图所示是一个barrier点从生成到删除的整个过程,大致可以分为四个部分:barrier生成、barrier解析存储、barrier推进、barrier删除。其中barrier推进是最重要的一环,有它来确定各备节点恢复的位置来达到一致性要求。详细设计Barrier生成Barrier生成是Barrier一致性的前提。Barrier点任一CN都可以发起,但由第一个CN负责生成。若发起barrier生成的CN不是第一个CN,则通知第一个CN进行生成。生成后CN与DN将其落到xlog日志中。负责打点的CN会启动barrier_crearor线程从GTM获取CSN,来生成barrier,格式如下:生成的CSN类型barrier信息格式为 ”csn_%021lu_%013ld”,头部信息固定为csn_,中间21位为得到的csn号,最后13位为时间信息,当前仅用于RPO计算。Barrier解析存储Barrier解析存储是Barrier一致性的基础,备集群上对应的备节点通过walreciever收到xlog日志后,将日志落盘。通过新添加barrier解析线程对新落盘的日志进行预解析,并将解析到的barrier存储在hash table中,并保存当前收到的最大barrier。Hash table在创建日志解析线程前进行创建,在集群卸载时进行释放。Hash table中储存着解析出来的barrier,这些barrier将在回放xlog日志时进行删除。Barrier推进Barrier解析存储是Barrier一致性的关键,这部分稍微复杂一些,需要CN、DN、CMA、CMS、ETCD相互配合进行。barrier一致性点的推进需要五步:CMA通过sql函数查询CN、DN的barrier最大值上报至CMS。此处的barrier为预解析结果,日志实际还未回放;CMS通过收齐各个实例上报的barrier,将其中的最小值作为query barrier;CMA从CMS获取到query barrier,调用sql函数对CN、DN进行查询,确认是否存在该barrier点,将结果上报给CMS。CMS收齐后判断,若该query barrier已达到多数派条件,则作为target barrier点,否则舍弃;CMA读取CMS里存放的target barrier,更新CMA本地的target barrier;CMA通过sql函数设置CN,DN实例的recovery barrier设置为targer barrier。在一次上报中,CMA需要查询执行barrier最大值的上报、本地查询querybarrier是否存在,更新targetbarrier这三步;CMS需要执行querybarrier的更新和targetbarrier的更新。其他说明:Querybarrier达到多数派成为target barrier的条件。单一DN分片内多数派已上报该barrier。所有DN分片都已上报该barrier。CN多数派已经上报该barrier。CN多数派数目动态调整策略:由于主集群允许cn剔除到只有一个cn,所以在故障场景下cn多数派的数目要随时调整,策略为:CN多数派初始值为n_cn=init_cn_number/2 +1。当发现barrier在1分钟内因为达不成cn多数派无法推进,n_cn--;极限值n_cn>=1。当发现barrier可以有大于 n_cn个数的cn参与推进barrier,n_cn++;极限值n_cn<=init_cn_number/2 +1。灾备集群CN不同状态参与barrier推进的情况容灾过程中灾备集群中被Deleted,building的CN对CM的barrier查询请求不会有响应。由于灾备集群CN发生build导致barrier超前推进,它处于等待其他CN的waiting状态,或者容灾过程中灾备集群中处于need repair态的CN是有可能查到CM请求的barrier的,会参与barrier推进。灾备集群CN处于waiting状态的条件改造基于OBS异地容灾方案中增加的sql函数gs_get_local_barrier_status()查询得到当前CN实例redo的barrier。CM通过该函数获得CN实例当前redo的localbarrier,与targetbarrier进行比较,localbarrier>targetbarrier时,该CN置为waiting状态。该状态与CN其他状态的转化参见《3.3.6.3容灾过程中灾备故障CN的处理》。Barrier删除Barrier删除是barrier一致性的终点,Barrier删除发生在xlog日志回放中,在日志回放时,回放到barrier会对回放位置recoverybarrier进行更新,并在hash table将该barrier点删除,完成barrier从生成到删除的全过程。
  • [技术干货] GaussDB关键技术原理:高弹性(一)
    GaussDB关键技术原理:高可用篇,从GaussDB数据库DCF、双集群容灾、逻辑复制及两地三中心跨Region容灾方面对GaussDB高可用能力进行了解读。本篇将分享GaussDB高弹性方面的相关知识,从CBI索引方面对hashbucket展开介绍。1 前言  GaussDB支持hash分布表,hash分布表的数据行根据hash分布列进行hash计算,计算出的hash值被打散到各个DN。随着业务增长数据规模变大,DN的承载能力会逐渐不够,这样就需要对DN节点数量进行扩充。节点数量扩充后,存储于原DN节点的数据就需要进行数据重新分布。目前GaussDB采用的是share-nothing的本地盘架构,各个DN节点独立维护各自的数据,这种架构下数据重分布的难度很大。如下图所示,在线扩容从时间轴上看主要由两部分组成:图1  在线扩容示意图集群加节点阶段:对新加入的DN节点进行元信息的同步,然后更新集群拓扑,启动新节点。设置包含新节点的Installation NodeGroup信息,将老集群的NodeGroup设置为待重分布的状态。数据重分布阶段:对分布在老集群的用户表通过数据重分布搬迁至新集群,在新加节点完成业务上线。数据重分布主要有两种方式,一种逻辑搬迁方式,主要通过SQL接口进行,另一种是物理搬迁的方式,直接通过文件拷贝和日志多流追增进行。本节主要介绍逻辑数据重分布的过程。    由此可见,在线数据重分布是在线扩容的关键步骤。目前已经支持了以表为粒度的逻辑数据重分布,其核心思想是采用SQL接口将原表的数据导入到一个按照新分布方式存储的新表上,然后进行两个表的元数据切换。处理在线业务的核心思想是:将DML操作的UPDATE拆分成INSERT和DELETE,所有INSERT都采用追增写入的模式,写入原表的尾部,通过CTID确定每轮处理数据的范围,使用“{节点ID}+{元组ID}”表示删除的元组位置,原表的数据直接删除,新表的数据追增删除,直至原表和新表数据收敛追平,详细步骤如下图。图2  重分布过程中在线业务处理过程P1:将原表设置为追增模式,创建新表(新增两列表示元组ID和节点ID)、delete_delta表记录删除原组的位置信息,并将新表索引失效,提升基线数据批量插入的效率。P2_1:采用“insert into 新表select * from 原表”的方式完成基线数据的插入。此时用户业务采用追加写的方式写在原表的后面,删除的数据直接进行删除并且将原组ID和节点ID记录在delete_delta表中。P2_2:重建新表的索引,此阶段引入了并行建索引来提升重建索引的效率。P3:采用多轮追增(推进CTID、DELETE、INSERT)的方式完成新表和元数据的数据追平。    P4:拿原表的8级锁,完成元数据切换,保留原表的元信息和新表的数据文件信息。逻辑数据重分布的方式比较类似于VACUUM FULL的运行机制,存在很多约束和限制。首先新老表同时存在,会占用双份磁盘空间影响磁盘的利用率。其次,如果要支持在线的数据重分布,采用SQL接口的方式挑战会比较大,例如表锁冲突,shared-buffer资源争抢等问题。如果两个具有相同分布规则的表需要进行JOIN操作,重分布期间可能存在一个表完成数据重分布,另一个表没有完成,这个阶段两个表就可能存在跨节点的分布式JOIN,与原有的本地JOIN相比性能会下降十分严重。为了解决逻辑扩容在有复杂业务查询场景在线业务的性能劣化问题,我们引入了基于hashbucket表的物理在线扩容方案,不仅可以很好地解决带有JOIN关系业务性能下降的问题,还可以解除预留磁盘空间的约束,同时引入物理扩容的概念,大大提升了在线扩容本身的性能。2 hashbucket介绍  2.1简介  hashbucket表在DN上的数据按照hash值进行聚簇存储,具有相同hash值的数据会统一管理在一个bucket中。从分布式集群的角度看,hashbucket表将用户表拆分为多个分片的形式存储——每个表切分为N个分片,每个DN存储N/DNnum个分片。拆分使用的规则与hash分布规则一致,使用相同的分布列计算hash值。图3显示的是插入一行数据,在CN上根据分布列计算hash值并取模bucket桶长度BUCKETLEN(图中是6)计算出具体的DN节点,在DN节点上对不同的hash值再进行分片拆分。    图3  hashbucket表插入数据逻辑示意图存储的组织方式如下图4所示,假设用户表是hash分布表,在CN上有6个hash bucket桶,其中1~3对应DN1的数据分片,4~6对应DN2的数据分片。CN上存储一个映射关系表示每个DN分片上有哪些bucket桶,用户存入一条数据时将根据分布列的值计算属于哪个bucket桶,再根据CN上的映射关系路由到对应DN分片进行数据存储。图4  存储组织方式示意图如果每张hash分布的表都进行文件拆分,将会导致小文件非常多,给文件系统造成比较大的压力,因此hashbucket采用段页式的存储方式,即所有表都采用一组文件进行存储,后续段页式章节会进行详细介绍。从DN存储节点的角度上看,hashbucket表和普通页式表主要区别在于数据文件管理,事务管理和元数据管理三个方面:    图5  数据管理示意图数据文件: 按照bucket对段页式文件组进行库级别分片存储。事务管理: 按照bucket对CLOG进行实例级分片存储。后文会做详细介绍。元数据管理: pg_class增加库级分片标识、pg_hashbucket增加库级别分片信息。为了能够在CN和DN区分hashbucket表,在pg_class系统表中增加一列relbucket,CN上存储1,DN上存储3,表示将进行分片存储。另外新增一个库级系统表pg_hashbucket,存储hashbucket相关的信息,定义如下表1所示。表1  系统表pg_hashbucket 属性名数据类型注释bucketidoidCN上为PG_HASHBUCKET系统表所在DATABASE绑定的NodeGroup的OID。DN上此列为空。bucketcntintergerCN上不使用此参数,DN上为当前DN所拥有的bucket数量。bucketvectoroidvector_extendCN上不使用此参数,DN上为当前DN所拥有的bucket列表。bucketmaptext用来存储逻辑bucket到物理bucket的映射关系,即16384到1024的映射关系。bucketversionoidvector_extend记录后续hashbucket扩容过程中发生改变的信息版本号。bucketcsntexthashbucket重分布前源节点每个bucket对应的最大CSN,用于新节点可见性判断。bucketxidtexthashbucket扩容,新节点上线设置的next_xid,用于校验是否在阈值范围内。因此,创建库的时候会生成pg_hashbucket中bucket分片的分布信息,hashbucket表拥有库级的特点,即一个库的所有hashbucket表一定具有相同的分布方式。所有hash分布的用户表都可以采用hashbucket分片存储的方式,用户在创建表时通过指定参数来实现,如下:    CREATE TABLE t1 (a int, b text) WITH (hashbucket=on);hashbucket表在扩容的时候通过物理文件搬迁完成,因此每个库以bucket文件为粒度在新节点上线业务,同时原子性地刷新pg_hashbucket系统表。业务会在DN上访问pg_hashbucket系统表过滤bucket list来找到正确的数据。由于hashbucket表对数据文件进行了切片,如果直接创建BTree索引,索引也需要进行切片才能访问到正确的数据,如果计划可以直接剪枝则性能不受影响,如果计划不能剪枝则需要遍历1024/DN分片数棵BTree树,会严重影响性能,因此引入一种新的索引——CBI索引,跨bucket索引,所有bucket一棵BTree,索引中增加bucketid信息,来提升性能,下一章节将会详细介绍。2.2 CBI索引  GaussDB针对hashbucket表有两种索引,bucket全局索引(跨bucket索引,cross-bucket index,CBI)和bucket本地索引(local-bucket index,LBI)。跨bucket索引为hashbucket聚簇存储提供一种跨bucket的索引能力,即在创建索引时,一个索引文件可以对应表级或分区级的所有bucket文件。该索引可以为指定粒度的表提供跨bucket的索引扫描,避免顺序扫描当前表下的大量bucket文件才能查到目标元组,提升查询性能。通过在创建索引时指定“crossbucket=on”可以创建跨bucket索引。图6  创建CBI索引示意图hashbucket表跨bucket索引如下图7所示,只有一个跨bucket索引文件,在扫描该索引时能获取目标元组完备的位置信息(元组所在bucket分片等),读取指定的bucket分片就能获取目标元组。图7  CBI索引结构示意图需要注意的是,在当前版本中跨bucket索引只面向分布式GaussDB,CBI创建的前提是hashbucket聚簇存储开启,仅支持BTree索引,不支持部分索引以及其他类型索引,GLOBAL和LOCAL索引不允许建在同一列,仅支持行存表,GLOBAL CROSSBUCKET索引支持最大列数为30;LOCAL CROSSBUCKET索引支持最大列数为31。2.2.1 CBI索引元组索引元组是一种用于建立索引的数据结构,CBI索引元组的结构如下图所示,包含索引键值、bucket分片id、数据元组信息。当需要访问数据时,通过bucketid找到数据元组所在的bucket分片,然后按数据行id找到对应的数据元组。图8  CBI索引元组结构2.2.2 CBI索引的实现CBI索引创建跨bucket索引创建流程如下:解析SQL语句确定要创建的索引是CBI,进入创建索引流程;创建跨bucket索引关系,进入索引构建流程;索引构建流程中判断索引为跨bucket索引时,遍历每个bucket扫描堆表查找要加到索引中的元组,进入BTree构建流程;BTree构建流程中使用堆表关系和索引关系创建BTree索引,保存扫描到的数据元组数和创建的索引元组数。CBI索引扫描基本思路是,对父表构建索引,索引元组记录所在分片的bucketid,这两个属性作为INCLUDE参数被加入到索引列,封装进索引元组。索引扫描时,先通过BTree遍历找到满足索引键条件的索引元组,然后读取该元组中记录的bucketid,获取目标元组所在的分区和bucket分片,再根据这些信息缩小查找范围获取最终的目标元组。CBI索引插入删除分布式全局索引插入流程与普通索引插入流程基本一致,需要注意的是唯一性检测流程的适配。当插入的数据不允许重复,会触发唯一性检测,也就需要将当前即将插入的数据与已存在数据进行比较,这就需要对特定范围的数据进行扫描。对于跨Bucket索引,这个特定范围需要根据当前索引元组中存储的bucketid来锁定,实现载入相应的目标表。CBI索引清理索引清理对于hashbucket表的处理是通过遍历数据表以及对应的索引分片,分别清理各个分片。引入CBI后检查数据表相关的索引是否为CBI,同时收集当前bucket的bucketid和bucket中dead的数据元组进入BTree清理页面流程。在BTree清理页面流程中,如果索引为CBI,则从索引元组中获取目标元组所在的bucketid,清理目标元组对应的索引元组。    2.2.3 CBI元数据跨bucket索引的元数据可通过系统视图pg_indexes、系统表pg_class查看。系统视图pg_indexes提供对数据库中每个索引的有用信息的访问,包含的关键字段如下表2所示。表2  系统视图pg_indexes部分字段名称类型描述tablenamename索引所服务的表的名称。indexnamename索引名称。tablespacename包含索引的表空间名称。indexdeftext索引定义。系统表pg_class存储数据库对象及其之间的关系。与CBI索引相关的字段如下表3,可以查到跨bucket索引的表空间、访问方法等信息。表3  系统表pg_class部分字段名称类型描述relnamename包含这个关系的名称空间的oidreloptionstext[]表或索引的访问方法,使用"keyword=value"格式的字符串。relbucketOid当前表是否包含hashbucket分片。有效的oid指向 pg_hashbucket表中记录的具体分片信息。NULL表示不包含hash bucket分片。以上内容从CBI索引方面对hashbucket进行了解读,下篇将从优化器剪枝、执行器方面继续介绍GaussDB高弹性技术,敬请期待!
  • [开发应用] jdbc连不上gaussdb库,报错返回:invalid value for parameter "TimeZone":"GMT-08:00"
    一.环境差异:研发环境gaussdb内核版本是gaussdb (GaussDB Kernel 503.1.0.SPC1100 build cd73e43e) compiled at 2023-06-09 05:25:27 commit 5630 last mr 11583 release,现场环境gaussdb内核版本是GaussDB Kernel 503.1.0.SPC1700。去连接gaussdb库的应用程序代码和jdbc驱动都是一样的。二.问题现象:研发环境能正常连接gaussdb库,现场环境不能连接gaussdb库,返回报错如下:invalid value for parameter "TimeZone":"GMT-08:00"按官方给的说明:JDBC向GaussDB发起连接请求,会默认添加以下配置参数,params = {{ "user", user },{ "database", database },{ "client_encoding", "UTF8" },{ "DateStyle", "ISO" },{ "extra_float_digits", "3" },{ "TimeZone", createPostgresTimeZone() },};然后createPostgresTimeZone方法拿到了GMT-08:00的值,由于数据库实例、数据库主机、应用程序主机三者时区不一致,所以返回错误。我的疑问是,为啥研发环境时区不一致,能连上gaussdb,没有返回报错?是不是研发环境的503.1.0.SPC1100版本没有时区校验。有没有大佬知道原因,帮忙分析一下。
  • [问题求助] gs_dump数据库备份报错
    环境服务端:opengauss 3.1.0gsql客户端:dws_client_8.1.x_redhat_x64.zip在数据库服务器上使用omm能够成功导出,但是在其他服务器环境下gs_dump命令报错。gs_dump: [port='30100'] [macbs_db] [archiver (db)] [2024-08-10 17:37:37] query failed: ERROR: relation "pg_catalog.pg_redaction_policy" does not exist on gaussdb LINE 1: ..._expr(p.expression, p.object_oid) AS polexpr FROM pg_catalog... ^ gs_dump: [port='30100'] [macbs_db] [archiver (db)] [2024-08-10 17:37:37] query was: SELECT p.tableoid, p.oid, p.policy_name, p.enable, pg_catalog.pg_get_expr(p.expression, p.object_oid) AS polexpr FROM pg_catalog.pg_redaction_policy p WHERE p.object_oid = '17039'::pg_catalog.oid
  • [运维管理] GaussDB轻量化管理平台安装故障问题案例指导
    问题1:分发包之后action文件夹下被清空问题现象报错提示:sh /data/docker-service/action/mainAction/precheck.sh: No such file or directoryinit manifest failed!修复方案首先检查/data/docker-service/config/user_edit_file.conf配置文件中配置的ip是否正确是否可以通过ifconfig命令查到若配置的ip有误,请修正ip,并删除/data/docker-service/config/json/deploy_render.json文件。再次重新下发安装即可。问题2:安装的常驻进程crontab_file.sh is killed abnormally或者init manifest任务卡住问题现象错误提示:install failed. The install process [crontab_file.sh] is killed abnormally!安装任务执行到Start to init manifest... 时不往下执行。修复方案执行source /etc/profile命令,查看是否有异常或者报错输出。若存在异常输出,说明/etc/profile中有错误语法,需要将/etc/profile中的错误语法修正后,再进行安装。问题3:加载基础镜像失败问题现象错误提示:Load docker base image error: load /data/docker-service/xxxxx/base_image_aarch64.tar error.修复方案执行以下命令重启dockersystemctl restart docker.service重启完成后,重试安装流程即可。问题4:管理面节点间时间差别过大导致前置检查失败问题现象错误提示:The time diff between ip1 and ip2 is xxs, the requirement is less than 60s, please check.修复方案报错中提示的两个几点之间的时间差距过大(超过60秒),需要通过date -s命令将环境之间的时间修改为一致问题5:/etc/profile、/etc/password、/etc/group只读,导致用户创建失败,sftp和元库安装失败问题现象/etc/profile、/etc/password、/etc/group文件只读,导致管理面安装失败修复方案执行以下命令,lsattr /etc/profilelsattr /etc/passwordlsattr /etc/group若文件存在i属性,说明文件是只读的,需要执行命令chattr -i /etc/profile,去除文件的只读属性。修改完成之后,重试安装即可。问题6:sftp启动超时问题现象sftp安装过程中,sftp启动超时。手动执行 systemctl start sftpd 命令,仍然超时。修复方案编辑sftpd服务的systemd单元文件的配置,删除Type=notify这一行vim /etc/systemd/system/sftpd.service删除后再次执行命令systemctl start sftpd命令,启动sftp服务,回显sftp服务的状态为running为正常。随后重试安装即可。问题7:初始化manifest失败,提示文件不存在问题现象安装过程,报错precheck文件不存在。错误提示:sh: /data/docker-service/action/mainAction/precheck.sh: No such file or directory修复方案检查配置文件(/data/docker-service/config/user_edit_file.conf)中配置的ip是否正确且可以通过ifconfig命令查到。如果配置的ip不正确或者不可以通过ifconfig查到说明配置的ip有问题,需要正确配置,且配置的ip可以通过ifconfig命令查到。问题8:kafka安装失败/kafka起不来/kafka的server.log中报证书解密失败的问题问题现象安装过程,Kafka组件安装失败。登录Kafka容器,查看Kafka服务日志。docker exec -it "`docker ps | grep kafka | awk '{print $1}'`" bashvim /opt/cloud/kafka/logs/server.log日志报错提示证书加解密失败:Get key failed: Given final block not properly padded. Such issues can arise if a bad key is used during decryption.修复方案执行命令查询java版本:java -version,回显的openjdk版本如果不是1.8*的话,说明是java版本的问题,需要用1.8*版本的openjdk生成的kafka证书才可以被kafka识别。问题9:GaussDB元库安装失败常见问题处理问题现象gaussdb安装失败。日志查看路径:gaussdb安装日志路径:/tmp/install_cluster.loggaussdb内核安装日志路径:预安装日志:/opt/gaussdb/logs/gaussdb/dbadmin/om/gs_preinstall-xxx.log安装日志:/opt/gaussdb/logs/gaussdb/dbadmin/om/gs_install-xxx.log修复方案gaussdb轻量化管理平台也是用GaussDBInstaller安装的元库,常见的问题可以参考持续完善中....
  • [运维管理] 分布式gaussdb库磁盘io达到100%
    分布式gaussdb库磁盘io达到100%,而且io读写时延也比较高,如下图:avg-cpu:  %user   %nice %system %iowait  %steal   %idle            4.85    0.00    1.81   10.02    0.00   83.32  Device            r/s     rMB/s   rrqm/s  %rrqm r_await rareq-sz     w/s     wMB/s   wrqm/s  %wrqm w_await wareq-sz     d/s     dMB/s   drqm/s  %drqm d_await dareq-sz  aqu-sz  %util dm-0            41.50      3.55     0.00   0.00   60.48    87.52  584.50     32.43     0.00   0.00   67.73    56.81    0.00      0.00     0.00   0.00    0.00     0.00   42.10 100.50 dm-1             0.00      0.00     0.00   0.00    0.00     0.00    0.00      0.00     0.00   0.00    0.00     0.00    0.00      0.00     0.00   0.00    0.00     0.00    0.00   0.00 dm-2             0.00      0.00     0.00   0.00    0.00     0.00   12.50      0.63     0.00   0.00   64.80    52.00    0.00      0.00     0.00   0.00    0.00     0.00    0.81  53.00 dm-3             0.00      0.00     0.00   0.00    0.00     0.00    0.00      0.00     0.00   0.00    0.00     0.00    0.00      0.00     0.00   0.00    0.00     0.00    0.00   0.00 sda             41.00      3.52     0.00   0.00   60.83    87.80  610.00     31.43    16.00   2.56   54.97    52.76    0.00      0.00     0.00   0.00    0.00     0.00   33.16 102.50 然后查看io占比最高的线程是pagewriter,如下:PRIO  USER     DISK READ  DISK WRITE  SWAPIN     IO>    COMMAND 1600438 be/4 omm         0.00 B/s    0.00 B/s  0.00 % 99.99 % gaussdb --datanode -D /cluster/data/dn/dn_6005 -M pending [pagewriter] 1600429 be/4 omm         0.00 B/s    0.00 B/s  0.00 % 99.99 % gaussdb --datanode -D /cluster/data/dn/dn_6009 -M pending [pagewriter] 1600437 be/4 omm         0.00 B/s    0.00 B/s  0.00 % 99.99 % gaussdb --datanode -D /cluster/data/dn/dn_6005 -M pending [pagewriter] 1600426 be/4 omm         0.00 B/s    0.00 B/s  0.00 % 99.99 % gaussdb --datanode -D /cluster/data/dn/dn_6009 -M pending [pagewriter] 2500889 be/4 root        0.00 B/s    0.00 B/s  0.00 % 99.99 % [kworker/u130:1+flush-252:0] 1600428 be/4 omm         0.00 B/s    0.00 B/s  0.00 % 99.43 % gaussdb --datanode -D /cluster/data/dn/dn_6009 -M pending [pagewriter]     896 be/4 root        0.00 B/s    0.00 B/s  0.00 % 99.08 % [xfsaild/dm-0] 1600439 be/4 omm         0.00 B/s    0.00 B/s  0.00 % 97.21 % gaussdb --datanode -D /cluster/data/dn/dn_6005 -M pending [pagewriter] 1600452 be/4 omm         0.00 B/s    0.00 B/s  0.00 % 96.85 % gaussdb --datanode -D /cluster/data/dn/dn_6001 -M pending [pagewriter] 1600441 be/4 omm         0.00 B/s    0.00 B/s  0.00 % 96.20 % gaussdb --datanode -D /cluster/data/dn/dn_6005 -M pending [pagewriter] 1600449 be/4 omm         0.00 B/s    0.00 B/s  0.00 % 96.10 % gaussdb --datanode -D /cluster/data/dn/dn_6001 -M pending [pagewriter] 1600451 be/4 omm         0.00 B/s    0.00 B/s  0.00 % 95.57 % gaussdb --datanode -D /cluster/data/dn/dn_6001 -M pending [pagewriter] 1600448 be/4 omm         0.00 B/s    0.00 B/s  0.00 % 95.24 % gaussdb --datanode -D /cluster/data/dn/dn_6001 -M pending [pagewriter] 1600450 be/4 omm         0.00 B/s    0.00 B/s  0.00 % 94.86 % gaussdb --datanode -D /cluster/data/dn/dn_6001 请教一下,这个问题是什么原因导致的?如何解决?
  • [性能调优] gaussdb分布式数据库批量插入数据很慢
    gaussdb分布式数据库,写了一个存储过程用于加压性能数据,发现批量插入数据很慢。遍历时每500条数据提交事务批量插入1次,依次轮询插入31张按天分表中。平均下来1s入库300条。然后,同样的存储过程在gaussdb主备库上跑,发现1s可以入库1700+条数据。这种入库慢问题要怎么分析啊?需要看哪些日志或者查询哪些指标,请大佬指点一下。存储过程大致如下:CREATE OR REPLACE FUNCTION "oss_nms"."inspect_video_quality_his_day"("task_code_param" varchar)   RETURNS "pg_catalog"."void"   LANGUAGE plpgsql VOLATILE   COST 100 AS $BODY$ DECLARE     RECORD_ID VARCHAR;     EXE_TYPE INT4;   -- 执行方式1-自动,2-手动     CHECK_TIME INT8;  -- 巡检时间     VIDEO_TYPE INT4 := 1;    --视频类型1-实时流,2-录像     EXE_METHOD INT4  := 2;    --执行方式   2-VQRS     RESULT_STATUS INT4;     ABNORMAL_CAUSE VARCHAR;     FAILURE_CODE VARCHAR;     NORMAL_ITEM VARCHAR;     DAY_FLAG INT4 := 1;     DAY_NUM INT4;      -- 执行的日期  1-31     channel_codes TEXT[];     insert_sql TEXT := 'INSERT INTO oss_nms.inspect_video_quality_his_${day} (record_id,channel_code,video_type,exe_type,exe_method,check_time,result_status,abnormal_cause,failure_code,normal_item,task_code,create_time,day_flag) VALUES ';     value_sql TEXT := '';     batch_size INT := 500;   current_batch_size INT := 0;     rand_num INT :=0;     start_date DATE;     end_date DATE;     excute_sql TEXT := ''; BEGIN     -- 设置事务的自动提交   SET autocommit = ON;     SELECT ARRAY_AGG(t.channel_code) INTO channel_codes FROM (select channel_code FROM "oss_nms"."eam_channel_base" WHERE "unit_type" = '1' LIMIT 300000) as t;      -- 打压数据=通道数*3*31       -- 定义开始和结束日期     -- 按需修改'90 days'值   start_date = CURRENT_DATE - INTERVAL '93 days';   end_date = CURRENT_DATE;     -- 结果状态、异常原因、失败码、视频截图URL或文件中心ID     rand_num := ROUND(RANDOM() * 2);     EXE_TYPE := ROUND(RANDOM()) + 1;     -- 正常     IF rand_num=0 THEN                 RESULT_STATUS := 4;                 ABNORMAL_CAUSE := NULL;                 FAILURE_CODE := NULL;                 NORMAL_ITEM := '4,6,2,5,1,10,9,8,11,12,7,13,14,15,17,20,18,19';     -- 异常             ELSEIF rand_num=1 THEN                 RESULT_STATUS := 3;                 ABNORMAL_CAUSE := '17,7,10,9,8,5,15,12,6';                 FAILURE_CODE := NULL;                 NORMAL_ITEM := '4,2,1,11,13,14,20,18,19';     -- 失败     ELSE                  RESULT_STATUS := 2;                 ABNORMAL_CAUSE := NULL;                 FAILURE_CODE := 4;                 NORMAL_ITEM := NULL;             END IF;     -- 循环处理日期范围内的数据   WHILE start_date <= end_date LOOP                  --根据巡检时间计算出哪一天,用来找分表                 DAY_NUM := EXTRACT(DAY FROM start_date);                 CHECK_TIME := EXTRACT ( EPOCH FROM to_char(start_date, 'YYYY-MM-DD 00:00:00' ) :: TIMESTAMP) * 1;                 FOR i IN 1..array_length(channel_codes, 1) LOOP                         -- 检测记录编码                          RECORD_ID := md5( random( ) :: VARCHAR );                         value_sql := CONCAT(value_sql, '('  ,quote_literal(RECORD_ID), ','  , quote_literal(channel_codes[i]), ',',VIDEO_TYPE,',',EXE_TYPE,',',EXE_METHOD,',',CHECK_TIME,',',RESULT_STATUS,',',quote_literal(COALESCE(ABNORMAL_CAUSE, '')),',',quote_literal(COALESCE(FAILURE_CODE, '')),',',quote_literal(COALESCE(NORMAL_ITEM, '')),',',quote_literal(TASK_CODE_PARAM),',',CHECK_TIME,',',DAY_FLAG,')',',');                         current_batch_size := current_batch_size + 1;                         -- 当达到指定批大小或循环结束时,执行插入操作                         IF current_batch_size = batch_size OR i = array_length(channel_codes, 1) THEN                             excute_sql := CONCAT(REPLACE(insert_sql,'${day}',DAY_NUM) , value_sql);                             excute_sql := substring(excute_sql, 1, length(excute_sql)-1) || ';';                             EXECUTE excute_sql;                             COMMIT;                             current_batch_size := 0;                             value_sql := '';                         END IF;                 END LOOP;                                     -- 更新开始日期为下一个日期         start_date = start_date + INTERVAL '1 day';     END LOOP;     -- 更新执行表中的updateTime     update inspect_task_execution set update_time = EXTRACT ( EPOCH FROM to_char(end_date, 'YYYY-MM-DD 00:00:00' ) :: TIMESTAMP) * 1000 where task_code = quote_literal(TASK_CODE_PARAM); END $BODY$ 
  • [技术解读] GaussDB行级访问控制
    CREATE ROW LEVEL SECURITY POLICY当对表创建了行访问控制策略,只有打开该表的行访问控制开关(ALTER TABLE ... ENABLE ROW LEVEL SECURITY),策略才能生效。否则不生效。当前行访问控制影响数据表的读取操作(SELECT、UPDATE、DELETE),暂不影响数据表的写入操作(INSERT、MERGE INTO)。表所有者或系统管理员可以在USING子句中创建表达式,在客户端执行数据表读取操作时,数据库后台在查询重写阶段会将满足条件的表达式拼接并应用到执行计划中。针对数据表的每一条元组,当USING表达式返回TRUE时,元组对当前用户可见,当USING表达式返回FALSE或NULL时,元组对当前用户不可见。行访问控制策略名称是针对表的,同一个数据表上不能有同名的行访问控制策略;对不同的数据表,可以有同名的行访问控制策略。行访问控制策略可以应用到指定的操作(SELECT、UPDATE、DELETE、ALL),ALL表示会影响SELECT、UPDATE、DELETE三种操作;定义行访问控制策略时,若未指定受影响的相关操作,默认为ALL。行访问控制策略可以应用到指定的用户(角色),也可应用到全部用户(PUBLIC);定义行访问控制策略时,若未指定受影响的用户,默认为PUBLIC。
  • [技术解读] GaussDB管理事务
    事务是用户定义的一个数据库操作序列,这些操作要么全做要么全不做,是一个不可分割的工作单位。数据库支持的事务控制命令有启动、设置、提交、回滚。数据库支持的事务隔离级别有READ COMMITTED、READ UNCOMMITTED、REPEATABLE READ和SERIALIZABLE,不推荐使用READ UNCOMMITTED,SERIALIZABLE等价于REPEATABLE READ。事务控制以下是数据库支持的事务命令:启动事务用户可以使用START TRANSACTION或者BEGIN语法启动事务,详细操作请参考START TRANSACTION和BEGIN。设置事务用户可以使用SET TRANSACTION或者SET LOCAL TRANSACTION语法设置事务,详细操作请参考SET TRANSACTION。提交事务用户可以使用COMMIT或者END可完成提交事务的功能,即提交事务的所有操作,详细操作请参考COMMIT | END。回滚事务回滚是在事务运行的过程中发生了某种故障,事务不能继续执行,系统将事务中对数据库的所有已完成的操作全部撤销,详细操作请参考ROLLBACK。事务隔离级别事务隔离级别,它决定多个事务并发操作同一个对象时的处理方式。READ UNCOMMITTED:读未提交隔离级别。不推荐使用,可能产生数据不一致现象。在协调节点故障无法恢复时或应急时可考虑使用,越过GTM与不一致时的阻塞,但建议若写事务不要使用,以免产生数据不一致,读事务可应急使用。READ COMMITTED:读已提交隔离级别,事务只能读到已提交的数据而不会读到未提交的数据,这是缺省值。实际上,SELECT查询会查看到在查询开始运行的瞬间该数据库的一个快照。不过,SELECT能查看到其自身所在事务中先前更新的执行结果。即使先前更新尚未提交。请注意,在同一个事务里两个相邻的SELECT命令可能会查看到不同的快照,因为其它事务会在第一个SELECT执行期间提交。因为在读已提交模式里,每个新的命令都是从一个新的快照开始的,而这个快照包含所有到该时刻为止已提交的事务,因此同一事务中后面的命令将看到任何已提交的其它事务的效果。这里关心的问题是在单个命令里是否看到数据库里完全一致的视图。读已提交模式提供的部分事务隔离对于许多应用而言是足够的,并且这个模式速度快,使用简单。不过,对于做复杂查询和更新的应用,可能需要保证数据库有比读已提交模式更加严格的一致性视图。REPEATABLE READ:事务可重复读隔离级别,事务只能读到事务开始之前已提交的数据,不能读到未提交的数据以及事务执行期间其它并发事务提交的修改(但是,查询能查看到自身所在事务中先前更新的执行结果,即使先前更新尚未提交)。这个级别和读已提交是不一样的,因为可重复读事务中的查询看到的是事务开始时的快照,不是该事务内部当前查询开始时的快照,就是说,单个事务内部的select命令总是查看到同样的数据,查看不到自身事务开始之后其他并发事务修改后提交的数据。使用该级别的应用必须准备好重试事务,因为可能会发生串行化失败。SERIALIZABLE:目前功能上不支持此隔离级别,等价于REPEATABLE READ。
  • [技术干货] GaussDB常用概念
    实例实例的最小管理单元是实例,一个实例代表了一个独立运行的数据库。用户可以在控制台创建和管理实例。实例的状态、规格、存储类型、版本,请参考实例说明。实例版本该版本支持版本。实例类型支持和实例。分布式形态能够支撑较大的数据量,且提供了横向扩展的能力,可以通过扩容的方式提高实例的数据容量和并发能力。适用于数据量较小,且长期来看数据不会大幅度增长,但是对数据的可靠性,以及业务的可用性有一定诉求的场景。实例规格数据库实例各种规格(vCPU个数、内存(GB))请参考数据库实例规格。CNCoordinator Node,负责数据库系统元数据存储、查询任务的分解和部分执行,以及将DN中查询结果汇聚在一起。DNData Node,和CN对应的概念。负责实际执行表数据的存储、查询操作。自动备份创建实例时,服务默认开启策略,实例创建成功后,您可对其进行修改,服务会根据您的配置,自动创建数据库实例的备份。手动备份手动备份是由用户启动的数据库实例的全量备份,它会一直保存,直到用户手动删除。区域和可用区区域和可用区用来描述数据中心的位置,您可以在特定的区域、可用区创建资源。区域(Region)指物理的数据中心。每个区域完全独立,这样可以实现最大限度的容错能力和稳定性。资源创建成功后不能更换区域。可用区(AZ,Availability Zone)是同一区域内,电力和网络互相隔离的物理区域,一个可用区不受其他可用区故障的影响。一个区域内可以有多个可用区,不同可用区之间物理隔离,但内网互通,既保障了可用区的独立性,又提供了低价、低时延的网络连接。
  • [技术干货] 在使用物化视图时,有哪些常见的性能优化技巧?
    在使用物化视图进行性能优化时,可以采用以下一些技巧来提高效率和效果:定期刷新:根据数据变化的频率和查询需求,合理安排物化视图的刷新时间。可以选择在数据变化较少的时段进行刷新,以减少对性能的影响。增量刷新:如果可能,使用增量刷新而不是完全刷新。增量刷新只更新自上次刷新以来发生变化的数据,这可以显著减少计算和I/O成本。索引优化:为物化视图及其底层表创建适当的索引,可以加快查询速度和刷新效率。查询优化:优化物化视图定义中的SQL查询,避免复杂的连接、子查询和不必要的数据转换。数据分区:如果物化视图的数据量很大,考虑使用分区技术来管理数据,这有助于提高查询和刷新的性能。并行处理:利用数据库的并行处理能力,尤其是在刷新物化视图时,可以显著提高性能。使用合适的聚合:在物化视图中使用聚合函数时,确保它们是必要的,并且正确使用,以避免不必要的计算。限制数据量:在物化视图的定义中使用WHERE子句来限制数据量,减少存储和处理的数据量。避免过度使用物化视图:物化视图虽然可以提高查询性能,但它们也需要存储空间和维护成本。评估是否真的需要物化视图,以及是否可以用其他方式达到相同的效果。监控和分析:使用数据库的监控工具来跟踪物化视图的性能,分析其使用情况,并根据分析结果进行调整。使用物化视图的替代方案:在某些情况下,可以考虑使用临时表或存储过程来替代物化视图,尤其是在物化视图的维护成本过高时。考虑数据一致性:确保物化视图的刷新策略不会导致数据一致性问题,特别是在高并发的环境下。合理配置资源:根据系统资源和负载情况,合理配置物化视图的刷新频率和并发级别。使用数据库提供的优化工具:利用数据库管理系统提供的各种优化工具和建议,如查询分析器、性能顾问等。通过这些技巧,可以有效地提高物化视图的性能,减少维护成本,并确保数据的及时性和准确性。然而,每种技巧的适用性可能会根据具体的数据库环境和业务需求而有所不同,因此在应用这些技巧时需要进行适当的调整和测试。
总条数:1672 到第 页
上滑加载中