• [存储] 数仓GaussDB(DWS)GTM总结
    1 GTM概述:    GTM全称为全局事务管理器,是系统中的常驻进程,主要作用是分发xid(事务ID)、snapshot(快照)、sequence(序列)等信息。为了保证事务标识的一致性和全局唯一性,在集群中只有一个主GTM提供服务,并采用了主备方式,从而实现了高可用。在连接方面,GTM是被动连接的,它不关心连接方的节点类型(是CN还是DN),只会根据接收到的报文信息,进行相应处理,并返回消息。一般情况下,CN会在事务执行阶段连接GTM获取XID和snapshot,DN在AutoVaccumWork时获取XID,CM在仲裁GTM时获取状态信息。GTM在架构中的关系如图1所示。图1 GTM在架构中的关系图 注:        a)        Coordination:名为协调者,是所有客户端(gsql,jdbc,odbc)的入口,执行解析器、优化器、分布式事务等。        b)        CM:名为集群管理,保障各个组件自动化协同工作。        c)        DN:名为数据节点,是数据存储引擎,支持行存和列存、HDFS存储、向量化引擎和HA等。        d)       xid:事务ID,具有全局一致性。        e)        snapshot: 快照,用来判断给定的事务是否还在运行,如果一个事务在快照之中,那么即使该事务已经结束了也会被认为是正在运行        f)         Sequence:序列,是用来产生唯一整数的数据库对象。序列的值是按照一定规则单挑自增的整数。因为自增所以不重复,因此sequence具有唯一性,常用于做主键。              二 GTM工具和文件简述2.1 GTM工具GTM二进制常用工具有两个:gtm_ctl和gtm_initgtm。该类工具都是单线程执行,不存在多线程并发。gtm_ctl通过信号控制GTM的进程,包括GTM的启停和升主降备,GTM的switchover和failover,以及GTM的状态查询和同步设置等命令。例如GTM启动命令:gtm_ctl -Z gtm -D ../gtm start。gs_initgtm主要在集群安装时用于生产GTM配置文件。例如gtm.control,gtm.conf等文件。2.2 GTM文件       gtm.conf是GTM的配置文件,GTM启动时会解析该文件的参数,具体参数含义如表1。 表1 gtm.conf参数表gtm.control:是GTM控制文件,用来存放xid、timeline,文件格式如下:     xid     timeline     transaction_num (默认是1)gtm.sequence:存放GTM的uuid和sequence文件,数据行数不定,文件格式如下:    uuid    seq1 info (包括sequence的基本属性值)    seq2 info     。。。。gtm.pid:存储GTM的进程号和数据目录等。gtm.opts:存储GTM启动arguments参数。三GTM的HA机制  3.1 GTM的状态       在GTM的HA机制,我们将GTM分为三种类型的状态,分别为主机状态、连接状态和同步状态,下面简要介绍三种类型的状态。GTM 主机状态有四种:    1:Pending:初始启动状态,GTM待仲裁状态。    2:Priamry:主GTM状态表示。    3:Standby:备GTM状态表示。    4:Unknow:GTM进程不在的状态。GTM连接状态,表示主GTM与备GTM或ETCD的连接状态。    1:Connection ok:主备连接正常或与ETCD连接正常。    2:Connetion bad:主备连接异常。GTM同步状态,表示GTM的同步逻辑。    1:Most available:最大可用模式。当无ETCD,且主备GTM连接异常时,主GTM的同步状态为该状态。    2:Sync:同步状态。3.2 GTM的状态切换流程简述GTM的状态切换流程如图2所示。CM拉起的GTM状态初始都是Pending状态,然后通过比较xid决定主备,xid大的为主GTM,xid小的为备GTM。当主备连接异常且无ETCD时,主GTM的同步状态会变为most_available。当主GTM出现问题时,CM会仲裁备GTM,通过failover升主GTM,如果无ETCD,那么同步状态变为most available。也可以通过switchover进行主备GTM转换,此时同步状态不会变化。图2 GTM状态切换流程图3.3 GTM同步机制       GTM的同步需要满足相应的同步条件并处于对应的同步模式才可以进行。例如xid的同步需要满足curval(当前值)>=backupVak(备份值)且GTM_SyncGXIDFlag为true时才可进行同步。Sequence的同步也要满足curval(当前值)>=backupVak(备份值)的条件,sequence创建时会默认同步一次。此外还需要处于相应的同步模式下才可以,有三种同步模式:        a)        sync auto:异步同步模式。GTM以pending模式启动后,所呈现的初始同步模式。        b)       sync on:强同步模式。当GTM主备启动后,CM_Server接收到CM_Agent上报的主备GTM连接正常的消息时,会将GTM主备的同步状态从sync auto置为sync on。        c)        sync off:GTM主备不同步并且主GTM也不与ETCD同步。Sync off默认不使用。    注:        1 在主备从无ETCD集群中,如果主备连接异常,主GTM的同步状态会变为most available。而在有ETCD的集群中,无论主备是否连接异常或挂掉,ETCD是否挂掉,都不会切换最大可用模式。        2 只有GTM处于sync on模式下,failover和switchover操作才可进行。原文链接:https://bbs.huaweicloud.com/blogs/198243【推荐阅读】【最新活动汇总】DWS活动火热进行中,互动好礼送不停(持续更新中)  HOT  【博文汇总】GaussDB(DWS)博文汇总1,欢迎大家交流探讨~(持续更新中)【维护宝典汇总】GaussDB(DWS)维护宝典汇总贴1,欢迎大家交流探讨(持续更新中)【项目实践汇总】GaussDB(DWS)项目实践汇总贴,欢迎大家交流探讨(持续更新中)【DevRun直播汇总】GaussDB(DWS)黑科技直播汇总,欢迎大家交流学习(持续更新中)【培训视频汇总】GaussDB(DWS) 培训视频汇总,欢迎大家交流学习(持续更新中)扫码关注我哦,我在这里↓↓↓
  • [存储] GaussDB(DWS)对接NBU备份环境配置指南
    【摘要】 本文主要介绍将GaussDB数据库集群备份到NBU服务器,以及用NBU服务器上的备份集来恢复GaussDB数据库集群时,配置NBU环境的一些注意事项。当前主要使用场景是线下环境,而针对线上环境GaussDB正在开发相应的特性使得也能够无缝对接NBU,所以对于GaussDB相关的NBU环境配置方法是相通的。概述       业界一种主流的备份存储管理软件是NetBackup(本文简称NBU),其优势是可以将备份文件存储到磁带介质上。       目前NetBackup软件提供了两种备份方式: 1)  从NetBackup软件界面进行操作,选择要备份或恢复的文件,或者使用其对应的命令行工具bpbackup; 2)  以GaussDB为代表的数据库,采用NetBackup软件提供的libxbsa64.so动态库(实现了标准的XBSA系列接口),将本地数据传送到NBU服务器,然后由NBU服务器负责落盘到磁带介质上。GaussDB的专用备份工具Roach,负责调用libxbsa64.so库将本地数据库文件备份到远端NBU服务器。  本文简要描述了华为GaussDB数据库和NetBackup对接进行备份、恢复的配置方法与注意事项。1. GaussDB备份到NBU的部署介绍1.1 NBU备份GaussDB的部署架构        GaussDB数据库提供了专门的备份恢复工具Roach,该工具与NBU交互,完成GaussDB数据库文件备份到NBU的过程。线下场景下,整个备份恢复流程由Roach工具或FusionInsight等封装了Roach命令行调用的界面软件及脚本发起。后续线上场景下将从DWS管控面发起,目前从管控面仅支持了OBS备份,正在集成NBU备份功能。         图1-1 NBU备份GaussDB的部署图        如上图所示,数据库集群中每个节点的Roach进程读取本节点GaussDB数据库文件,通过XBSA接口发送给NBU服务器,NBU Master Server控制各个NBU Client收发数据,数据最终到达NBU Media Server指定的磁盘或磁带存储介质。集群恢复时亦然,只不过数据流向与上图相反。        本图示例了最典型的NBU部署方式。实际使用中,NBU Master Server和NBU Media Server可能合布在同一台机器,NBU Server和其中一个NBU Client也可能合布在同一台机器。NBU Master Server和NBU Media Server可能有多台,分组管理部分NBU Client。也可能多个Server组成Clustered Master Server(高版本NetBackup支持)来增强NBU服务器侧的高可用性。1.2 与NetBackup软件的配套情况        因Roach工具只是调用NetBackup提供的XBSA标准接口库,与NetBackup软件并无耦合,因此从原理上讲,GaussDB数据库可以通过Roach工具无缝对接到任何版本的NetBackup,只需正确配置NBU相关环境。        目前业界常用的NetBackup软件版本有:  l  NetBackup 7.5  l  NetBackup 7.6  l  NetBackup 7.7  l  NetBackup 8.1  l  NetBackup 8.2  当前GaussDB和NetBackup可同时支持的操作系统平台情况如下(具体能支持的OS小版本号以GaussDB产品文档为准):  l  Suse11~Suse12  l  Redhat7/CentOS x86  l  不支持ARM和Euler系统,因NetBackup尚无对应安装包本文将以NetBackup 7.5版本为例,来介绍GaussDB备份恢复相关的NBU配置。2. NBU环境配置流程与注意事项2.1 安装NBU Server软件       NetBackup软件的安装请详细参考NetBackup官方文档,不在本文描述范围内。为了示例方便,本文仅简要说明这个过程。       本文意在说明NBU配置注意事项,因此仅采用最简单的配置部署方式作为示例,并简要描述这种部署方式下的NBU安装过程。       本文中,假设GaussDB数据库集群共有3个机器,hostname分别为plat1、plat2、plat3,采用单一的NBU Master Server和NBU Media Server,且Mater Server与Media Server合布在一台机器,选择plat3部署NBU Server,即该节点既做为NBU Server又做为NBU Client。本文只演示NBU存储介质为磁盘的方式,磁带没有特殊的区别,只要按NBU官方文档正确配置即可。       整个安装过程都要使用root用户。具体步骤如下:       步骤 1      用root登录待安装NBU Master Server的机器,本文为plat3。                       解压NBU Server安装包后,切换到安装目录,以root用户执行解压后的install脚本:./install                                                图2-1 安装NBU Server                        安装NBU Server的机器应选择具有X11图形化环境的机器,否则安装后无法启动java界面从而无法配置NBU环境。        步骤 2      按向导完成整个NBU Server的安装过程。                        安装过程中,有多个交互式选择的地方,可参考如下输入:1)Do you   wish to continue? (y/n) (y) (回车默认)2)Participate   in the NetBackup Product Improvement Program? (y/n) (y) (回车默认)3)Do you   want to install NetBackup and Media Manager files? [y,n] (y) (回车默认)4)Is it OK   to install in /usr/openv? [y,n] (y) (回车默认)5)Enter   license key: 输入软件许可证编号6)Do you   want to add additional license keys now? [y,n] (y) n7)Would you   like to use "plat3" as the configured NetBackup server name of this   machine? [y,n] (y) (回车默认)8)Is plat3   the master server? [y,n] (y) (回车默认)9)Do you   want to add any media servers now? [y,n] (n) (回车默认)10)Enter the   Enterprise Media Manager server (default: plat3):(回车默认)11)Do you   want to start the job-related NetBackup daemons so backups and restores can   be initiated? [y,n] (y) (回车默认)12)Enter the   OpsCenter server (default: NONE):(回车默认)注:如上斜体的plat3为Master Serve节点的hostname。                        至此,plat3上就安装了NBU Master Server和NBU Media Server,同时默认安装了NBU Client。                        其它节点上尚未安装NBU Client,稍后的章节会单独进行安装。        步骤 3      查看bp.conf文件。                        查看NBU生成的/usr/openv/netbackup/bp.conf配置文件,里面CLIENT_NAME字段取值初始值应该为本机hostname。                        该文件截图前半部分如下:                                      图2-2 NBU Server端的bp.conf文件                         ----结束2.2 配置NBU备份环境        本节描述NBU备份策略、存储、界面勾选项、配置文件修改相关事宜。  步骤 1      登录NBU Master Server机器,在/etc/hosts中配置IP/hostname映射信息。                  需要在Master Server的/etc/hosts中配置Media Server以及所有NBU Client的IP/hostname映射信息。  步骤 2      登录NBU Media Server机器,在/etc/hosts中配置IP/hostname映射信息。                  同理,需要在Media Server的/etc/hosts中配置Master Server以及所有NBU Client的IP/hostname映射信息。  步骤 3      登录每个NBU Client机器,在/etc/hosts中配置IP/hostname映射信息。                  需要在每个NBU Client的/etc/hosts中配置所有Master Server以及Media Server的IP/hostname映射信息。                  以上几步如果遗漏,会导致NBU备份出现通信问题。每次新增NBU Client或Server,都要重新执行如上三步。  步骤 4      登录NBU Master Server机器,启动NBU管理界面。                  用root登录NBU Master Server,执行如下命令:cd /usr/openv/java/./jnbSA                        在弹出的java界面上,输入Master Server的root密码并点击登录,就可以进入NBU配置管理界面。                                                图2-3 启动NBU管理界面                       NBU Client机器也可以启动NBU界面,只要X11环境OK的话。        步骤 5      配置存储单元(Storage Unit)。                       本节仅描述存储介质为磁盘的方式。                       选择左侧Storage菜单,并点击New Storage Unit按钮,新建一个存储单元。                                              图2-4 新建存储单元                       在弹出的新建页面,填写存储单元名字,并在Absolute pathname to directory填写备份文件在服务器的哪个磁盘路径下存储。                       本文配置的是单一NBU Server,且是单一存储单元,因此GaussDB集群中所有节点的备份文件都会集中存储到plat3这台Media Server的该路径下。                       如果配置的是Storage Unit Group,则可以分组存储在该服务器的多个路径下。                       此处我们的存储介质是Disk,存储类型应选择BasicDisk。                                              图2-5 配置存储单元                                            在上图中,应调大Maximum concurrent jobs的取值,建议至少高于数据库集群中节点个数,否则其它节点就会排队等待。                      理想情况下,该取值为集群中节点数乘以单个节点的主DN数,或者更高一些(考虑到CN和从备DN也需要占用并发资源)。                      如果上图中指定的存储单元路径位于系统盘上,则必须勾选图中的复选框,否则备份第一个对象时就会创建对象失败。                      This directory can exist on the root file system or system disk是说允许备份文件存放到根文件系统或系统盘上。                      例如,本文中指定了/opt下面的子目录作为存储目录,属于系统盘路径,所以必须勾选该复选框。步骤 6      配置NBU策略(NBU Policy)。                选择左侧Policies菜单,点击Add new policy按钮,新建一个NBU策略。                                图2-6 新建NBU策略             在弹出的对话框中输入NBU Policy的名字,比如nbu_policy。                      在新的NBU策略配置页面中,Policy类型选择为DataStore,Policy存储选择为上一步新建的Storage Unit名称。                      另外,右侧Active Go into effect at的时间应早于第一次备份发起时间。通常来说,默认是新建该Policy的时间且该复选框处于勾选状态,                      因此都是满足条件的。                                      图2-7 配置NBU策略         如果存储介质是磁带,则上图Policy storage需要选择为我们自己的磁带库名称,比如xxx-robot-tld-0。                同时,Policy volume pool选择为已安装磁带库的Volume pool,后者可以从NBU配置主界面左侧的Media->Volume Pools列表中查到。                上图中Policy storage需要选择为我们自己新建的存储单元或磁带库名称,如果不选择会导致备份失败。步骤 7      配置NBU客户端。               需要将所有NBU Client机器都加入到如下NBU客户端列表中。               选择左侧Policies菜单,双击我们自己的NBU Policy名称nbu_policy,                             图2-8 更改NBU策略配置                            进入NBU策略配置界面(与上一步界面相同),点击Clients标签页,点击标签页下方的New按钮,在弹出的Add Client对话框中逐个添加所有的NBU Client。对话框中Client name输入各个NBU Client的hostname,操作系统下拉框中选择最接近的系统选项,注意不要选错,否则客户端安装会失败,或安装后功能不正确。                          图2-9 添加NBU客户端                   注意:NBU客户端清单中的Client name非常重要,填写为hostname还是IP效果都不一样,可能导致备份或恢复失败。             ----结束2.3 安装NBU Client软件        NetBackup提供了专门的工具脚本install_client_files,用于批量化安装NBU Client。所有的操作都只需在NBU Server上执行。        该脚本有两种常用方法:  1)      安装单个NBU Client:           install_client_files ssh hostname           后面斜体的参数是待安装Client机器的hostname。           NBU Server节点不需要单独安装NBU Client,安装Server时就自动安装过了。       2)      安装所有NBU Client:                 install_client_files ssh ALL                 此处ALL必须是大写。                 步骤 1      登录NBU Master Server命令行,安装所有NBU Client。                                 用root执行如下命令,可以一次性远程安装好所有机器的NBU Client软件。                                 cd /usr/openv/netbackup/bin                                   ./install_client_files  ssh ALL                  步骤 2      登录各个NBU Client机器,检查各客户端的bp.conf文件。                                如果上述两种方法都无法成功安装,可尝试将NBU Client安装包拷贝到对应的客户端机器,解压后执行其中的install脚本单独安装。                                                          图2-10 NBU Client端的bp.conf文件                          此处bp.conf里面的CLIENT_NAME比较关键,应该与NBU Policy界面的NBU Client列表中的Client Name相同。                ----结束2.4 调整NBU配置          为了取得较佳的性能效果,需要配置合适的NBU参数。最常见的是NBU Server端的最大并发数和最大超时时间。          特别是客户端个数上百时就很有必要,本文只有3个客户端,因此取值相对较小。    步骤 1      调整Master Server端最大并发数。                    选择左侧Host Properties -> Master Servers,鼠标右键点击Master Server的hostname,点击Properties菜单项。                                        图2-11 配置Master Server的属性               在弹出的Master Server属性页面中,切换到Global Attributes标签页,将Maximum jobs per client调整为6。                         该取值决定了每个NBU Client上可以并发执行的任务数,最小应高于集群中单个节点的主DN个数,过小可能导致排队现象。                         根据NBU官方文档说明,每个Master Server上,每1秒只能发起一个NBU job,其余job只能排队。                         同时,每个NBU Client上,每1秒也只能发起一个NBU job。                         从NetBackup 8.2开始,Master Server取消了这个限制,每1秒可以并发发起多个不同NBU Client对应的job,                        这对于节点数很多且数据量很大的数据库集群可以大幅提升性能;但NBU Client的限制仍然存在。                        该限制主要作用于XBSA接口的BSACreateObject(),每调用一次该接口就需耗费1s(但同一个对象的分片不会再次建连)。                                          图2-12 调整Server端并发任务数 步骤 2      调整Master Server端最大超时时间。                  在Master Server的属性页,切换到Timeouts标签页,将Client connect timeout、Client read timeout、Media server connect timeout都调整到300s以上。                                    图2-13 配置Master Server的最大超时时间     步骤 3      调整Media Server端最大超时时间。                       同Master Server一样,在左侧Host Properties菜单下,选择Media Servers,并打开其属性页面。                                        图2-14 配置Media Server的属性          在Media Server的属性页,切换到Timeouts标签页,同样调整Client connect timeout、Client read timeout、Media server connect timeout到300s以上。                                  图2-15 配置Media Server的最大超时时间       ----结束3. NBU配置导致的常见备份问题3.1 问题排查手段         本节列出一些NBU备份恢复失败相关的常用排查方法,用于辅助NetBackup官方文档和网站提供的定位方法。   步骤 1      查看NBU管理界面的Activity Monitor。                   登录NBU Master Server,打开NBU管理界面,点击左侧Activity Monitor,在备份和恢复过程中就可以看到每个job的详细进展。                                      图3-1 NBU的Activity Monitor界面                        出现问题时,双击右侧失败的job,可以查看详细的执行信息,从中获取失败的原因。                        该方法是最直接的NBU交互问题定位手段。                                          图3-2 查看NBU job的详细执行信息                  根据上面报出的错误码和错误信息,结合NBU官网和产品文档,就可以大致判断出问题方向。   步骤 2      查看NBU日志。                  默认情况下,NBU日志是关闭的,需要根据错误信息,打开对应的NBU组件的debug级别日志,重新复现问题,结合NBU官方文档分析日志。                  左侧Host Properties下面可以分别设置Master Servers/Media Servers/NBU Clients的日志级别。                  其中NBU客户端的日志选择比较简单,从0改为5就可以打印最详细的日志。                                    图3-3 NBU Client的日志级别设置                        对于NBU Server来说,建议选择相干的NBU组件即可。                        比如bpbrm是NBU备份恢复管理模块(NetBackup backup and restore manager),                        而bptm是NBU磁带管理模块(NetBackup tape manager)。                                                图3-4 Media Server的日志级别设置        步骤 3      查看GaussDB备份恢复日志。                        可以结合GaussDB备份恢复工具Roach的日志进行分析,日志位于$GAUSSLOG/roach下面。  步骤 4      使用虚拟磁带库VTL模拟磁带问题。                  因磁带机比较昂贵,遇到磁带特有的问题,可以采用虚拟磁带库来模拟复现。                  VTL(Virtual Tape Library)可以模拟各种磁带类型,配置和安装方法在此不做描述。需要配合专门的硬件(HBA卡)使用。  步骤 5      从后台命令行执行备份恢复,或验证NBU单表备份恢复。                  可以用集群管理员用户从后台命令行登录集群节点,用GaussDB的GaussRoach.py脚本发起备份恢复操作,来对比验证问题。                  具体使用方法参见GaussDB产品手册,此处不再描述。                  同时,还可以减少数据量,尝试单表粒度的备份恢复,来快速排查NBU环境配置问题。进行NBU单表备份恢复的优点是对用户影响较小、耗时较短。  步骤 6      排查常见的配置文件问题。                 主要包括Master Server、Media Server、NBU Client上的/etc/hosts及/usr/openv/netbackup/bp.conf文件。  步骤 7      排查常见的网络配置问题。                 主要包括NBU管理界面的Master Server和Media Server各种超时时间,以及防火墙设置。  步骤 8      结合XBSA常见错误码列表进行分析。                  如果是XBSA接口访问报错,Roach日志和NBU日志中通常都会打印相应错误码。                                    图3-5 XBSA常见错误码参考                        详细可参考:                        http://www.iiug.org/onbar/debug.html#xbsarc3.2 找不到客户端hostname导致NBU备份恢复失败        【主要现象】从NBU Activity Monitor失败任务的详细信息界面,以及NBU日志文件/usr/openv/netbackup/logs/user_ops/dbext/logs下的日志中有“client hostname could not be found (48)”报错语句。        【原因分析】可能是NBU Master Server和Media Server的/etc/hosts中没有全部加入所有NBU Client的IP/hostname映射。参考:https://www.veritas.com/content/support/en_US/article.100016804http://systemmanager.ru/nbadmin.en/nbu_48.htm3.3 正确配置/etc/hosts后磁盘成功而磁带失败        【主要现象】出现找不到客户端hostname报错后,正确配置了Master Server和Media Server的/etc/hosts,但执行NBU备份磁盘可以成功,而磁带高概率失败。        【原因分析】可能是NBU host缓存导致,每次修改/etc/hosts后,建议立即清理缓存。原因是NBU缓存了hostname到IP地址的映射,以便最大程度减少DNS查询,虽然修改了/etc/hosts等IP/hostname映射相关的配置,但NBU host缓存可能1小时以上才会刷新,未能立即生效。        清理方法是:用root登录NBU Media Server,执行如下命令:cd /usr/openv/netbackup/bin./bpclntcmd   -clear_host_cache3.4 新添加的NBU Client备份报错        【主要现象】在数据库集群中新增几个节点并安装NBU Client后,集群备份报错。查看Roach工具日志,只有新添加的NBU节点才报错,其余节点都是由这几个节点报错导致出错。        【原因分析】可能是新增NBU Client机器后,没有在NBU Master Server和Media Server的/etc/hosts中添加所有NBU Client的IP/hostname映射关系。3.5 新添加的NBU Client恢复报错        【主要现象】在数据库集群中新增几个节点并安装NBU Client后,正确配置了NBU Server中的/etc/hosts,集群备份成功,但恢复报错。查看Roach工具日志和NBU日志,提示在NBU服务器上找不到待恢复的文件,XBSA接口BSAQueryObject()失败,错误码0x11,即BSA_RC_NO_MATCH。        【原因分析】备份文件在NBU Server上存储时是以Client Name(通常是hostname)作为文件名前缀的,如果备份时使用的Client Name与恢复时不一致,就可能导致无法从服务器上匹配到对应的备份文件。此时应检查新添加的NBU Client上的bp.conf文件,其中的CLIENT_NAME取值应当与NBU管理界面上Policy页面Clients清单中的客户端Client Name相同。bp.conf的默认值来自安装NBU客户端时指定的名字,有可能新添加的NBU Client在安装时指定了IP作为客户端名称,造成不匹配。通常建议安装NBU Client时输入的Client Name,与bp.conf中的CLIENT_NAME字段,以及新建Policy时Clients清单中每个客户端的Client Name,以及Host Properties->Client->Client Properties->Client Name均保持一致,全都取hostname。如果不一致,bp.conf和Policy中的Client Name都可以手动修改。                图3-6 备份文件在Media Server上的存储形式    其中客户端属性页中的Client Name位置如下,其余的Client Name在前面章节都已说明:          图3-7 客户端属性页的Client Name3.6 备份失败提示无法创建对象      【主要现象】集群备份失败,从Roach日志看到备份第一个对象就失败了,XBSA接口BSACreateObject()返回错误,无法在NBU服务器上创建备份对象。      【原因分析】可能是NBU存储单元相关配置错误。常见的两种情形:一是NBU Policy配置中的Policy storage未正确选择;          图3-8 Policy storage选择 另一种是使用系统盘作为存储路径,但Storage Unit中未勾选”This directory can exist on the root file system or system disk.”复选框。    图3-9 Storage Unit复选框勾选3.7 恢复到新集群失败      【主要现象】使用Roach工具可以将NBU上的备份集恢复到一个与原集群完全同构的新集群上。如果条件都满足,且备份集的metadata都已就绪,恢复仍然失败,提示找不到hostname等相关错误。      【原因分析】可能是没有正确配置虚拟客户端名称。首先,恢复时使用的NBU Policy名称需要与备份时使用的保持一致。最后,需要在NBU Master Server上手动创建文件:/usr/openv/netbackup/db/a**ames/No.Restrictions,从而NBU就可以知道是恢复到新的集群,自动完成虚拟客户端映射。原文链接:https://bbs.huaweicloud.com/blogs/177406【推荐阅读】【最新活动汇总】DWS活动火热进行中,互动好礼送不停(持续更新中)  HOT  【博文汇总】GaussDB(DWS)博文汇总1,欢迎大家交流探讨~(持续更新中)【维护宝典汇总】GaussDB(DWS)维护宝典汇总贴1,欢迎大家交流探讨(持续更新中)【项目实践汇总】GaussDB(DWS)项目实践汇总贴,欢迎大家交流探讨(持续更新中)【DevRun直播汇总】GaussDB(DWS)黑科技直播汇总,欢迎大家交流学习(持续更新中)【培训视频汇总】GaussDB(DWS) 培训视频汇总,欢迎大家交流学习(持续更新中)扫码关注我哦,我在这里↓↓↓
  • [存储] GaussDB(DWS)高可用之CN&GTM;组件高可用介绍
    前言本文主要内容分两块内容,1. 高可用的演进路线 2. 简单介绍各个内核组件的高可用方案GaussDB(DWS) 的内核侧组件为DN, CN, GTM,内核侧组件是通过集群管理组件CM server、CM agent 来进行管理的。内核组件和集群管理组件共同组成了GaussDB(DWS)集群。组件的逻辑关系如下图:演进路线GaussDB(DWS)源于Gauss 200, 经过若干版本的演进,形成当前高可用能力,从最初pgxc组件间没有任何高可用能力,到现在完整的高可用能力。后续高可用的能力还是围绕单点故障快速恢复,业务不中断进行构筑。内核高可用DN 高可用DN 的高可用是基于主备从的架构进行构筑,详细的原理请参见之前技术博文,本文不展开描述。GaussDB(DWS)高可用之数据复制GaussDB(DWS)高可用之主备从HA技术GaussDB(DWS)高可用之备机重建DN 高可用后续会增加  switchover/failover/catchup原理及的介绍。CN 高可用        在 DWS 集群中通常会部署多个CN,每个CN都可读写。如果一个CN故障,那么客户端可以使用其它CN。由于CN只存储元信息数据(即每张用户表数据分布在哪几个DN),因此只有DDL操作时才涉及到CN存储数据,DML时CN并不需要写数据。CN 的数据同步        在DDL操作时,接收业务的CN会把该SQL发送到所有其他CN与所有DN,通过两阶段提交来保证各个CN的数据一致性。这里也有一个场景:即当一个CN故障时,那么集群便无法操作DDL,此时CM已经提供了CN的自动剔除和加回功能,可以方便的处理CN的故障。 CN 重建方式        CN 的修复是通过使用一个正常的CN重建故障CN, 具体技术是用CN build 的方式使用其它CN重建出CN, 这个也是充分利用CN间互为多写互为备机的机制。在较老版本中使用gs_dump工具来实现 CN 的重建。CN 的状态转换       CN的状态分为 4 种如下图:Normal: 是正常提供服务,Starting: 实例启动过程,Down: 停止,Deleted: 被剔除状态。 在集群中CN的操作都是由CM agent来完成的,基本上不需要人工介入。GTM 高可用        在DWS集群中,GTM的作用是产生全局唯一的事务号及sequence id, 在DWS集群中GTM主备两个实例,主GTM提供服务和给备GTM同步信息,备GTM负责在主GTM故障时,升主继续提供服务。主备GTM的数据都需要在本地落盘,其中主GTM在达到阈值后写本地数据并同时保证在备GTM中也落盘,这样保证备GTM升主后不会分配重复的数据。GTM 数据同步        主 GTM  在xid、sequence 达到阈值时刷新本地和备GTM的数据,在上一次阈值是写入数据后的第一次分配的xid、sequence 的xid的基础上 + 一个值(20w) 作为一个阈值,在 xid、sequnce分配到这个点时,触发写本地和同步备GTM,此时备GTM接收到消息后创建一个服务线程,并将事务xid写入本地文件,回复消息,主机的一次同步便完成。GTM在内存中xid每加20w时会向备机同步一次。如果GTM主机永久故障,GTM备机升主后,只需要重新初始化一个GTM实例出来然后和主机同步xid即可。 GTM 状态转换GTM 的角色与 DN 类似,也是有primary, standby, pending 三种,并且通过外部命令switchover/failover/notify进行角色间的转换。当然这种转换是由cm层自动完成,基本上不需要人工介入原文链接:https://bbs.huaweicloud.com/blogs/177361【推荐阅读】【最新活动汇总】DWS活动火热进行中,互动好礼送不停(持续更新中)  HOT  【博文汇总】GaussDB(DWS)博文汇总1,欢迎大家交流探讨~(持续更新中)【维护宝典汇总】GaussDB(DWS)维护宝典汇总贴1,欢迎大家交流探讨(持续更新中)【项目实践汇总】GaussDB(DWS)项目实践汇总贴,欢迎大家交流探讨(持续更新中)【DevRun直播汇总】GaussDB(DWS)黑科技直播汇总,欢迎大家交流学习(持续更新中)【培训视频汇总】GaussDB(DWS) 培训视频汇总,欢迎大家交流学习(持续更新中)扫码关注我哦,我在这里↓↓↓
  • [存储] GaussDB(DWS)高可用之备机重建
    DWS的多实例在主机故障时,会发生failover,但对于主备机这种分布式架构,必然会有数据同步的时延,这种时延就会产生如下主备机日志分叉的问题(可以参考该贴日志分叉部分https://bbs.huaweicloud.com/forum/thread-60315-1-1.html):对于支持UNDO的数据库来说,可以通过UNDO日志将原主机分叉的部分回退到分叉前的一条wal日志,然后接上新主继续从不分叉的地方开始做wal日志同步,但是对于PG这类不支持UNDO的系统来说,这部分数据需要通过特殊的方式来处理,这种操作叫做增量重建(思路类似于社区的pg_rewind,但略有不同)。增量重建的基本的原理如下:分为以下几类数据:part1、从分叉点开始,原主机自己生成的wal日志对应的数据,这部分通过反解wal日志,记录下wal对应的数据页,并从新主机同步part2、原主机的数据文件和新主机的数据文件的列表做差异化比较 ,“拉齐”和新主机的数据以上数据部分同步后,相当于将原主对齐到新主机的一个时间点,并将原主机wal日志重新拉回到同一条wal日志线上。最后关键的一步,就是原主机作为备角色启动后,需要继续追赶在重建过程中的delta数据(整个重建过程中,新主机仍然在做业务),确保最终的一致性。再来解答一下之前有个同学咨询的关于拉齐的原则,这里实际是按照物理文件来处理的,处理的方式是基于size,对于size不一样的文件,会做不同的处理,一般原则如下:(以local作为本地要做build的节点,而remote代表要从远端同步数据的节点为例)1)对于local_file_size < remote_file_size时,说明对应的表有新增的数据,此时需要将local_file做copy_tail的动作2)对于local_file_size > remote_file_size时,由于有mvcc的机制,说明远端的表可能做过vacuum,因此对于tuple的位置均发生的变化,此时,需要先将本地的文件全部truncate掉,然后从远端copy完整文件到本地3)对于从分叉点解析的本地做过modify的页,则单独标记出来,按照页copy的方式,从remote侧进行页copy。原文链接:https://bbs.huaweicloud.com/blogs/177216【推荐阅读】【最新活动汇总】DWS活动火热进行中,互动好礼送不停(持续更新中)  HOT  【博文汇总】GaussDB(DWS)博文汇总1,欢迎大家交流探讨~(持续更新中)【维护宝典汇总】GaussDB(DWS)维护宝典汇总贴1,欢迎大家交流探讨(持续更新中)【项目实践汇总】GaussDB(DWS)项目实践汇总贴,欢迎大家交流探讨(持续更新中)【DevRun直播汇总】GaussDB(DWS)黑科技直播汇总,欢迎大家交流学习(持续更新中)【培训视频汇总】GaussDB(DWS) 培训视频汇总,欢迎大家交流学习(持续更新中)扫码关注我哦,我在这里↓↓↓
  • [实践系列] GaussDB(DWS)字符集浅谈
    1. 基本概念字符集(Character set):是一个系统支持的所有抽象字符的集合。字符是各种文字和符号的总称,包括各国家文字、标点符号、图形符号、数字等。常见的字符集有ASCII、ZHS16GBK 、ZHT16BIG5、 ZHS32GB18030字符集、Unicode字符集等。字符编码(Character Encoding):是一套法则,使用该法则能够对自然语言的字符的一个集合(如字母表或音节表),与其它的一个集合(如电脑编码)进行配对。即在符号集合与数字系统之间建立对应关系。与字符集相对应,常见的字符编码有:ASCii,ZHS16GBK,ZHT16BIG5,ZHS32GB18030等。字符集的定义其实就是字符的集合,而字符编码则是指怎么将这些字符变成字节用于保存、读取和传输。2. 字符集的前世今生1) 通用字符集UCS通用字符集(Universal Character Set,UCS)是由ISO制定的ISO 10646(或称ISO/IEC 10646)标准所定义的字符编码方式,采用4字节编码。又称Universal Multiple-Octet Coded Character Set,大陆译为通用多八位编码字符集,台湾译为广用多八位元编码字元集。通用字符集是所有包括了其他字符集。它保证了与其他字符集的双向兼容,即,如果你将任何文本字符串翻译到UCS格式,然后再翻译回原编码,你不会丢失任何信息。UCS包含了已知语言的所有字符。除了拉丁语、希腊语、斯拉夫语、希伯来语、阿拉伯语、亚美尼亚语、乔治亚语,还包括中文、日文、韩文这样的象形文字,UCS还包括大量的图形、印刷、数学、科学符号。通用字符集是与UNICODE同类的组织,UCS-2和UNICODE兼容。2) Unicode编码Unicode(统一码、万国码、单一码)是一种在计算机上使用的字符编码。包含了几乎人类所有可用的字符,每年还在不断的增加,可以看作是一种通用的字符集。Unicode定义了大到足以代表人类所有可读字符的字符集。Java语言就用到了Unicode编码,从而实现了该语言的国际通用性。Unicode 是基于通用字符集(Universal Character Set)的标准来发展, 用数字0-0x10FFFF来映射这些字符,或者说有1114112个码位(码位就是可以分配给字符的数字)。对可以用ASCII表示的字符使用UNICODE并不高效,因为UNICODE比ASCII占用大一倍的空间,而对ASCII来说高字节的0对他毫无用处。为了解决这个问题,有人发明了一种针对UNICODE的变换规则,把UNICODE字符串中的0去除. 注意这个变换规则不是通过查表实现的,而只要用一些位移操作就可以实现. 这就是UTF,他们被称为通用转换格式,即UTF(UCS Transformation Format)。常见的UTF格式有:UTF-32编码:固定使用4个字节来表示一个字符,这种编码存在空间利用效率的问题。UTF-16编码:对相对常用的60000余个字符使用两个字节进行编码,其余的使用4字节。UTF-8编码: 兼容ASCII编码;拉丁文、希腊文等使用两个字节;包括汉字在内的其它常用字符使用三个字节;剩下的极少使用的字符使用四个字节。下面重点介绍下UTF-8编码:UTF-8以字节为单位对Unicode进行编码。从Unicode到UTF-8的编码方式为:将Unicode二进制从低位往高位取出二进制数字,每次取6位,如上述的二进制就可以分别取出为如下示例所示的格式,前面按格式填补,不足8位用0填补。Unicode编码(16进制) UTF-8 字节流(二进制)000000 - 00007F 0xxxxxxx000080 - 0007FF 110xxxxx   10xxxxxx000800 - 00FFFF 1110xxxx   10xxxxxx 10xxxxxx010000 - 10FFFF 11110xxx   10xxxxxx 10xxxxxx 10xxxxxxUTF-8的特点是对不同范围的字符使用不同长度的编码。对于0x00-0x7F之间的字符,UTF-8编码与ASCII编码完全相同。UTF-8编码的最大长度是4个字节。从上表可以看出,4字节模板有21个x,即可以容纳21位二进制数字。Unicode的最大码位0x10FFFF也只有21位。例1:“汉”字的Unicode编码是0x6C49。0x6C49在0x0800-0xFFFF之间,使用3字节模板了:1110xxxx 10xxxxxx 10xxxxxx。将0x6C49写成二进制是:0110 1100 0100 1001, 用这个比特流依次代替模板中的x,得到:11100110 10110001 10001001,即E6 B1 89。例2:Unicode编码0x20C30在0x010000-0x10FFFF之间,使用用4字节模板了:11110xxx 10xxxxxx 10xxxxxx 10xxxxxx。将0x20C30写成21位二进制数字(不足21位就在前面补0):0 0010 0000 1100 0011 0000,用这个比特流依次代替模板中的x,得到:11110000 10100000 10110000 10110000,即F0 A0 B0 B0。3) ASCIIASCII(American Standard Code for Information Interchange,美国信息互换标准代码)是ANSI(American National Standards Institute)美国国家标准学会的规范标准,世界上所有的计算机都用同样的ASCII方案来保存英文文字。因为ASCII没有可以利用的字节状态来表示汉字,中国人在ASCII的基础上,通过组合的方式,组合除了大约7000多个简体汉字,把这种方案叫GB2312, GB2312是对ASCII 的中文扩展。4) GB2312中文文字数目大,而且还分为简体中文和繁体中文两种不同书写规则的文字,而计算机最初是按英语单字节字符设计的,因此,对中文字符进行编码,是中文信息交流的技术基础。我国国家标准总局1980年发布《信息交换用汉字编码字符集》,标准号是GB 2312—1980,它是计算机可以识别的编码,适用于汉字处理、汉字通信等系统之间的信息交换。基本集共收入汉字6763个和非汉字图形字符682个。GB2312的出现,基本满足了汉字的计算机处理需要,它所收录的汉字已经覆盖中国大陆99.75%的使用频率。1995年国家标准总局又颁布了《汉字编码扩展规范》(GBK)。GBK与GB 2312—1980国家标准所对应的内码标准兼容。对于人名、古汉语等方面出现的罕用字,GB2312不能处理,这导致了后来GBK及GB18030汉字字符集的出现。注意:UTF8 只是 UNICODE内码在存储/传输时的状态. 而从GB2312编码转换到UNICODE编码需要查表. UTF8 和 UNICODE 的关系 与 GB2312 和 UNICODE的关系有本质的不同. UTF8 和 UNICODE 是一个人的两个面孔, GB2312 和 UNICODE 是两个人. 所以,要实现UTF8编码到GB2312编码的转换必须先把 UTF8编码还原为UNICODE编码,再通过查表的方式,把UNICODE编码转化为GB2312编码。5)  Latin1Latin1是ISO-8859-1的别名,有些环境下写作Latin1,是单字节编码,向下兼容ASCII。3.  Linux字符集提到linux字符集就不得不说locale。locale 是国际化与本土化过程中的一个非常重要的概念,对于中文用户来说,通常会涉及到的国际化或者本土化,大致包含两个方面:看中文,写中文, locale的设定与看中文关系不大,但是与写中文有很密切的关系。locale这个单词中文翻译成地区或者地域,其实这个单词包含的意义要宽泛很多。Locale是根据计算机用户所使用的语言,所在国家或者地区,以及当地的文化传统所定义的一个软件运行时的语言环境。这个用户环境可以按照所涉及到的文化传统的各个方面分成几个大类,通常包括用户所使用的语言符号及其分类(LC_CTYPE),数字 (LC_NUMERIC),比较和排序习惯(LC_COLLATE),时间显示格式(LC_TIME),货币单位(LC_MONETARY),信息主要是提示信息,错误信息, 状态信息, 标题, 标签, 按钮和菜单等(LC_MESSAGES),姓名书写方式(LC_NAME),地址书写方式(LC_ADDRESS),电话号码书写方式 (LC_TELEPHONE),度量衡表达方式(LC_MEASUREMENT),默认纸张尺寸大小(LC_PAPER)和locale对自身包含信息的概述(LC_IDENTIFICATION)。例如:上面均说明LC_CTYPE(语言符号及其分类)表示这个系统的系统现在使用的字符集是en_US.UTF-8,LC_NUMERIC(数字)等其它与语言相关的变量。通常如果其它的语言变量都未设定,仅设定LANG这个变量就可以缺省代替所有其它变量了。Locale实际就是某一个地域内的人们的语言习惯和文化传统和生活习惯。一个地区的locale就是根据这几大类的习惯定义的,这些locale定义文件放在/usr/share/i18n/locales目录下面:4. GaussDB(DWS) 字符集GaussDB(DWS)默认使用sql_ascii作为默认字符集,ASCII存储的是单字节流,并且没有能力判断多字节字符的有效性, 所以会一股脑存储进去,换句话说你可能在SQL_ASCII中存储了utf8编码的字符, 也存储了gbk编码的字符, 还存储了其他编码的字符. 那么要将sql_ascii转换成UTF8就不是一件易事了, 会遇到多种字符的转换工作。如果数据库的编码为SQL_ASCII(可以通过“show server_encoding”命令查看当前数据库存储编码),则在创建数据库对象时,如果对象名中含有多字节字符(例如中文),超过数据库对象名长度限制(63字节)的时候,数据库将会将最后一个字节(而不是字符)截断,可能造成出现半个字符的情况。针对这种情况,请遵循以下条件:保证数据对象的名称不超过限定长度。使用例如utf-8编码集做为数据库的默认存储编码集(server_encoding)。不要使用多字节字符做为对象名。 结合以上情况,在GaussDB(DWS)初始化创建数据库时需要根据业务场景设置字符集。GaussDB(DWS)支持的字符集(编码格式): GBK、UTF-8和Latin1编码格式,多个数据库可以设置为不同的字符集。字符集规划原则设置方法GBK如果数据库只需要支持中文,数据量很大,性能要求也很高,那就应该选择双字节定长编码的中文字符集。对GaussDB(DWS)来说,目前只能选择GBK 。在安装数据库时指定初始化参数-E。通过SQL语句创建数据库时指定ENCODING参数。UTF-8如果应用程序要处理各种各样的文字,或者将处理结果发布到使用不同语言的国家或地区,就应该选择Unicode字符集。对GaussDB   for dws来说,目前只能选择UTF-8 。Latin1如果数据库只需要支持ASCII收录的字符、西欧语言、希腊语、泰语、阿拉伯语、希伯来语对应的文字符号,则可以选择Latin1。在使用GaussDB(DWS)过程中,服务端和客户端都可以设置字符集。由于服务端与客户端可以设置为不同的字符集,所以两者字符集中单个字符的长度也会不同,所以产生的最终结果可能会与预期不一致。如果服务端与客户端设置为不同的字符集,则客户端输入的字符串会以服务端字符集的格式进行处理,很有可能产生与预期不一致的结果。操作过程服务端和客户端编码一致服务端和客户端编码不一致存入和取出过程中没有对字符串进行操作输出预期结果输出预期结果(输入与显示的客户端编码必须一致)。存入取出过程对字符串有做一定的操作(如字符串函数操作)输出预期结果根据对字符串具体操作可能产生非预期结果。存入过程中对超长字符串有截断处理输出预期结果字符集中字符编码长度是否一致,如果不一致可能会产生非预期的结果。客户端及服务端字符集设置方法:client_encoding: 客户端的字符编码类型, 根据前端业务的情况确定。尽量客户端编码和服务器端编码一致,提高效率。参数类型:USERSET(普通用户参数,可被任何用户在任何时刻设置。)取值范围:兼容PostgreSQL所有的字符编码类型。其中UTF8表示使用数据库的字符编码类型。说明:使用命令locale -a查看当前系统支持的区域和相应的编码格式,并可以选择进行设置。默认情况下,gs_initdb会根据当前的系统环境初始化此参数,通过locale命令可以查看当前的配置环境。参数建议保持默认值,不建议通过gs_guc工具或其他方式直接在postgresql.conf文件中设置client_encoding参数,即使设置也不会生效,以保证集群内部通信编码格式一致。参数设置方法:gs_guc reload -Z coordinator -Z datanode -N all -I all -c " client_encoding =utf8"SET client_encoding TO utf8;server_encoding参数说明:报告当前数据库的服务端编码字符集。该参数属于INTERNAL类型参数,为固定参数,用户无法修改此参数,只能查看。 5. 常见问题乱码及报错简单的说乱码的出现是因为:编码和解码时用了不同或者不兼容的字符集。在计算机科学中,一个用UTF-8编码后的字符,用GBK去解码。由于两个字符集的字库表不一样,同一个汉字在两个字符表的位置也不同,最终就会出现乱码。因client_encoding与server_encoding设置不一致,导致报错或者乱码。示例:测试数据:创建数据库,字符集为gbk,导入数据CREATE DATABASE gbkdb ENCODING 'GBK' template =   template0;创建测试表create table t_gbk(id int,name varchar);导入数据copy t_gbk from '/home/omm/encode/test.csv'   with(format 'csv',encoding 'gbk');查询表数据报错select * from t_gbk;问题定位:查看server_encoding及client_encoding         因为数据是按照GBK存储的,使用utf-8查看,在转码时发生错误。解决方案:设置client_encoding=’GBK’查询不再报错,但是显示仍是乱码设置crt工具字符集查询数据:问题解决。 
  • [存储] GaussDB(DWS) 高可用之数据复制
    【摘要】 本文介绍了GaussDBDB(DWS)的数据复制高可用设计。1      前言   数据库中高可用普遍使用的是Log Shipping方式,即将WAL日志采用streaming方式传输给备实例,备实例通过重放该日志得到主实例的数据。对于行存储方式使用Log Shipping方式效率较高,但是对于列式存储,通常都是批量导入,如果同样将数据记录到日志中,会使数据写两遍IO,难以发挥列存储优势,因此通常采用数据复制方式(即数据从主实例的内存中直接通过网络传输给备实例,然后备实例写盘)更为合理。在行存的批量导入中,使用数据复制不仅可以提升传输效率(直接从内存中读取数据,无需通过磁盘读取日志),还可提升备实例恢复效率(直接从内存中恢复,无需将日志先写盘,再读取恢复)。GaussDBDB(DWS)的复制方式采用日志和数据混合方式,对于行存单条insert/update/delete,然后使用日志复制方式,对于行存批量导入(copy/insert into select from)默认采用数据复制方式;对于列存默认采用数据复制方式。下面主要介绍下GaussDBDB(DWS)中数据复制的主要设计。2      数据复制总体设计   在GaussDBDB(DWS)中,数据复制默认打开,分别在行存批量导入和列存导入时使用。整体设计如下图所示:           在数据导入过程中,每个业务线程Backend将收到的数据组成一个block(列存为一个CU)放到Datasend线程的数据队列(DataSenderQueue)里,Datasend线程将数据队列数据发送给Datareceive线程,Datareceive线程将接收的数据写入到数据队列(DataWriterQueue)中,Datarcvwrite线程从数据队列(DataWriterQueue)中取出数据按block分别写入到磁盘,实现主备复制高可用。2.1       Dataqueue设计Dataqueue是一块共享内存,用于实现DataSenderQueue和DataWriterQueue,其算法核心是循环使用共享内存,如下图所示:   首先tail1,head2,tail2初始化为0,每个变量为两个uint32位,第一个uint32 queueid表示数据队列使用了第几次,第二个uint32 queue offset表示当前数据队列的offset。数据导入后,首先tail2向后递增,各个导入通过锁控制实现并发,Datasend发送数据后将head2向后移动,当tail2到达末尾时,新导入数据将移动tail1指针,当tail1与head2接近时,表明没有缓存空间了,因此需要等待Datasend发送数据后将head2向后移动腾出空间。整体算法是一个循环利用实例制,数据的offset是一个单调递增的过程,类似WAL日志的LSN。2.2.2       同步提交设计在GaussDBDB(DWS)中,数据冗余使用的是同步提交,即数据写完两份后事务提交。WAL日志中通过比较LSN非常简单的实现了同步提交。类似WAL日志,数据复制由于Dataqueue中offset也是有序递增的,因此也很容易实现同步提交。其过程是Datarcvwrite将数据单元写入磁盘后,刷新写盘offset,Datareceive线程通过心跳信息将写盘offset发送给Datasend,各业务线程在事务提交前check本次导入最后一段数据备实例端已经写盘后即可提交。2.2.3       BCM与Catchup设计由于GaussDBDB(DWS)设计之初考虑到RAID5数据冗余存储,因此上层只存储两副本,由于分布式环境下各个数据节点采用异步提交时可能会导致全局数据不一致,因此各个数据节点必须使用同步提交。那么系统中如果坏了一个任何一个数据节点的主实例或者备实例系统便不可进行写事务操作。然而在大型分布式系统中这是往往不能接受的,必须要支持单节点故障。GaussDBDB(DWS)使用了缓存接收数据(从备)来实现同步提交下的单节点故障。那么就是备实例挂了后,数据将发往从备,等备实例修复后,备实例可以从主实例同步数据,如何区分哪些数据未同步便显得尤为重要。这里使用BCM(bit change map)文件来实现哪些block需要在追赶时发送给备实例,哪些不用发送。具体设计如下:当数据导入时,每个block对应BCM页面中两个bit(第一个bit用于标记是否同步,第二个保留),放入发送队列后将BCM页面中两个bit第一个标记为未同步,当数据已经写入到备实例端后,将对应block的BCM页面bit标记为已经同步。当备实例挂掉时,数据发送给从备后,BCM页面对应bit将不再清理未同步标记,任然为未同步。当备实例起来后,连接主实例,主实例启动catchup线程先获取从备上增量数据列表,然后扫描本地所有未同步数据发送给备实例,实现主备同步。2.2.4       数据复制与日志复制并发控制数据复制和日志复制是并发运行的,当数据复制正在写入数据时,日志复制无法恢复删除表与truncate表等操作,两者通过锁控制。同样当数据复制时要写入的database与表空间还未恢复时,同样需要等待日志复制恢复完成,这里通过循环检测等待实现。3    数据复制相比日志复制 当IO负载较高时,批量导入场景数据复制的性能优于日志复制30%左右,因此在大数据量入库时,使用数据复制性能更佳。然而对于行存来说触发数据复制时每次会获取新页面,因此对于insert into t1 values v1,v2,v3这种值较少的场景下会导致大量的空页面,不适用于数据复制,可以手动关闭数据复制开关。原文链接:https://bbs.huaweicloud.com/blogs/175234【推荐阅读】【最新活动汇总】DWS活动火热进行中,互动好礼送不停(持续更新中)  HOT  【博文汇总】GaussDB(DWS)博文汇总1,欢迎大家交流探讨~(持续更新中)【维护宝典汇总】GaussDB(DWS)维护宝典汇总贴1,欢迎大家交流探讨(持续更新中)【项目实践汇总】GaussDB(DWS)项目实践汇总贴,欢迎大家交流探讨(持续更新中)【DevRun直播汇总】GaussDB(DWS)黑科技直播汇总,欢迎大家交流学习(持续更新中)【培训视频汇总】GaussDB(DWS) 培训视频汇总,欢迎大家交流学习(持续更新中)扫码关注我哦,我在这里↓↓↓
  • [存储] EXT4文件系统损坏导致的实例无法启动的排查与修复
    【摘要】 DN实例由于无法申请到内存而无法做checkpoint导致crash,且无法启动,最终发现是EXT4文件系统损坏导致。文件系统损坏,但是对用户的报错信息是内存问题。这个路径也是很奇怪的。本文讲述了排查思路和最后的修复方法。现象某现网局点进行POC时,发现某DN core掉,且一直无法启动。core文件堆栈和dn的pg_log日志中的堆栈信息一致。堆栈中显示 checkpoint 时进行 buffer 落盘时导致corelog中报错信息为:could not flush dirty data: Cannot allocate memory排查再看操作系统内存,发现还有100G以上空闲,不存在内存不足的可能性。基本排除是因为内存导致的问题。通过代码排查发现是调用系统函数:sync_file_range ()。但是刷盘函数一般也不会导致无法申请内存。PS:此函数是Linux 2.6.17之后提供的用于提高IO性能的刷盘函数,作用类似于fsync等。既然翻车在文件操作函数,可以合理怀疑文件是不是有问题。翻一下操作系统日志 /var/log/messages,发现疑点:网上查询错误信息,基本上确认为EXT4文件系统损坏,需要对文件系统进行修复修复EXT4文件系统修复EXT4文件系统需要使用fsck.ext4命令,与windows的chkdsk命令一样,fsck命令是linux下必不可少的文件系统修复工具。一般都会默认安装的。使用root用户登录系统把要修复的磁盘umount掉。使用fsck修复文件系统一定要先把对应的磁盘卸载,否则是非常危险的(这是不如windows的地方)。首先检查是否有其他进程使用磁盘(也可以使用 lsof /dev/sdh1 查看占用情况)fuser -mv /dev/sdh1杀死占用的进程,并确保没有进程占用磁盘(也可以使用 kill 杀掉对应进程)fuser -kv /dev/sdh1 fuser -mv /dev/sdh1卸载磁盘umount /dev/sdh1使用fsck工具修复系统运行命令并确认fsck.ext4  /dev/sdh1            运行过程中会提示 inode 的一些信息,确认即可。            如果不想要点很多次的确认信息,可以加上 -a 参数。            修复完成后,会得到如下提示,表示fs已经修复完成。                通过reboot重启系统,修复工作结束。附:fsck命令常用选项及注意事项fsck.ext4的manpage直接跳转到e2fsck,因为他直接调用的e2fsck命令,可以阅读描述:常用选项和注意事项原文链接:https://bbs.huaweicloud.com/blogs/174945【推荐阅读】【最新活动汇总】DWS活动火热进行中,互动好礼送不停(持续更新中)  HOT  【博文汇总】GaussDB(DWS)博文汇总1,欢迎大家交流探讨~(持续更新中)【维护宝典汇总】GaussDB(DWS)维护宝典汇总贴1,欢迎大家交流探讨(持续更新中)【项目实践汇总】GaussDB(DWS)项目实践汇总贴,欢迎大家交流探讨(持续更新中)【DevRun直播汇总】GaussDB(DWS)黑科技直播汇总,欢迎大家交流学习(持续更新中)【培训视频汇总】GaussDB(DWS) 培训视频汇总,欢迎大家交流学习(持续更新中)扫码关注我哦,我在这里↓↓↓
  • [SQL] GaussDB(DWS)性能调优系列实战篇二:十八般武艺之坏味道SQL识别
    【摘要】 GaussDB在执行SQL语句时,会对其性能表现进行分析和记录,通过视图和函数等手段呈现给用户。本文将简要介绍如何利用GaussDB提供的这些“第一手”数据,分析和定位SQL语句中存在的性能问题,识别和消除SQL中的“坏味道”。SQL语言是关系型数据库(RDB)的标准语言,其作用是将使用者的意图翻译成数据库能够理解的语言来执行。人类之间进行交流时,同样的意思用不同的措辞会产生不同的效果。类似地,人类与数据库交流信息时,同样的操作用不同的SQL语句来表达,也会导致不同的效率。而有时同样的SQL语句,数据库采用不同的方式来执行,效率也会不同。那些会导致执行效率低下的SQL语句及其执行方式,我们称之为SQL中的“坏味道”。         下面这个简单的例子,可以说明什么是SQL中的坏味道。图1-a 用union合并集合         在上面的查询语句中,由于使用了union来合并两个结果集,在合并后需要排序和去重,增加了开销。实际上符合dept_id = 1和dept_id > 2的结果间不会有重叠,所以完全可以用union all来合并,如下图所示。图1-b 用union all合并集合         而更高效的做法是用or条件,在扫描的时候直接过滤出所需的结果,不但节省了运算,也节省了保存中间结果所需的内存开销,如下图所示。图1-c 用or条件来过滤结果         可见完成同样的操作,用不同的SQL语句,效率却大相径庭。前两条SQL语句都不同程度地存在着“坏味道”。         对于这种简单的例子,用户可以很容易发现问题并选出最佳方案。但对于一些复杂的SQL语句,其性能缺陷可能很隐蔽,需要深入分析才有可能挖掘出来。这对数据库的使用者提出了很高的要求。即便是资深的数据库专家,有时也很难找出性能劣化的原因。         GaussDB在执行SQL语句时,会对其性能表现进行分析和记录,通过视图和函数等手段呈现给用户。本文将简要介绍如何利用GaussDB提供的这些“第一手”数据,分析和定位SQL语句中存在的性能问题,识别和消除SQL中的“坏味道”。◆ 识别SQL坏味道之自诊断视图         GaussDB在执行SQL时,会对执行计划以及执行过程中的资源消耗进行记录和分析,如果发现异常情况还会记录告警信息,用于对原因进行“自诊断”。用户可以通过下面的视图查询这些信息:•       gs_wlm_session_info•       pgxc_wlm_session_info•       gs_wlm_session_history•       pgxc_wlm_session_history         其中gs_wlm_session_info是基本表,其余3个都是视图。gs_开头的用于查看当前CN节点上收集的信息,pgxc_开头的则包含集群中所有CN收集的信息。各表格和视图的定义基本相同,如下表所示。表1 自诊断表格&函数字段定义名称类型描述datidoid连接后端的数据库OID。dbnametext连接后端的数据库名称。schemanametext模式的名字。nodenametext语句执行的CN名称。usernametext连接到后端的用户名。application_nametext连接到后端的应用名。client_addrinet连接到后端的客户端的IP地址。 如果此字段是null,它表明通过服务器机器上UNIX套接字连接客户端或者这是内部进程,如autovacuum。client_hostnametext客户端的主机名,这个字段是通过client_addr的反向DNS查找得到。这个字段只有在启动log_hostname且使用IP连接时才非空。client_portinteger客户端用于与后端通讯的TCP端口号,如果使用Unix套接字,则为-1。query_bandtext用于标示作业类型,可通过GUC参数query_band进行设置,默认为空字符串。block_timebigint语句执行前的阻塞时间,包含语句解析和优化时间,单位ms。start_timetimestamp with time zone语句执行的开始时间。finish_timetimestamp with time zone语句执行的结束时间。durationbigint语句实际执行的时间,单位ms。estimate_total_timebigint语句预估执行时间,单位ms。statustext语句执行结束状态:正常为finished,异常为aborted。abort_infotext语句执行结束状态为aborted时显示异常信息。resource_pooltext用户使用的资源池。control_grouptext语句所使用的Cgroup。min_peak_memoryinteger语句在所有DN上的最小内存峰值,单位MB。max_peak_memoryinteger语句在所有DN上的最大内存峰值,单位MB。average_peak_memoryinteger语句执行过程中的内存使用平均值,单位MB。memory_skew_percentinteger语句各DN间的内存使用倾斜率。spill_infotext语句在所有DN上的下盘信息:None:所有DN均未下盘。All: 所有DN均下盘。[a:b]: 数量为b个DN中有a个DN下盘。min_spill_sizeinteger若发生下盘,所有DN上下盘的最小数据量,单位MB,默认为0。max_spill_sizeinteger若发生下盘,所有DN上下盘的最大数据量,单位MB,默认为0。average_spill_sizeinteger若发生下盘,所有DN上下盘的平均数据量,单位MB,默认为0。spill_skew_percentinteger若发生下盘,DN间下盘倾斜率。min_dn_timebigint语句在所有DN上的最小执行时间,单位ms。max_dn_timebigint语句在所有DN上的最大执行时间,单位ms。average_dn_timebigint语句在所有DN上的平均执行时间,单位ms。dntime_skew_percentinteger语句在各DN间的执行时间倾斜率。min_cpu_timebigint语句在所有DN上的最小CPU时间,单位ms。max_cpu_timebigint语句在所有DN上的最大CPU时间,单位ms。total_cpu_timebigint语句在所有DN上的CPU总时间,单位ms。cpu_skew_percentinteger语句在DN间的CPU时间倾斜率。min_peak_iopsinteger语句在所有DN上的每秒最小IO峰值(列存单位是次/s,行存单位是万次/s)。max_peak_iopsinteger语句在所有DN上的每秒最大IO峰值(列存单位是次/s,行存单位是万次/s)。average_peak_iopsinteger语句在所有DN上的每秒平均IO峰值(列存单位是次/s,行存单位是万次/s)。iops_skew_percentinteger语句在DN间的IO倾斜率。warningtext显示告警信息。queryidbigint语句执行使用的内部query   id。querytext执行的语句。query_plantext语句的执行计划。node_grouptext语句所属用户对应的逻辑集群。         其中的query字段就是执行的SQL语句。通过分析每个query对应的各字段,例如执行时间,内存,IO,下盘量和倾斜率等等,可以发现疑似有问题的SQL语句,然后结合query_plan(执行计划)字段,进一步地加以分析。特别地,对于一些在执行过程中发现的异常情况,warning字段还会以human-readable的形式给出告警信息。目前能够提供的自诊断信息如下:◇多列/单列统计信息未收集         优化器依赖于表的统计信息来生成合理的执行计划。如果没有及时对表中各列收集统计信息,可能会影响优化器的判断,从而生成较差的执行计划。如果生成计划时发现某个表的单列或多列统计信息未收集,warning字段会给出如下告警信息:Statistic Not Collect:schemaname.tablename(column name list)         此外,如果表格的统计信息已收集过(执行过analyze),但是距离上次analyze时间较远,表格内容发生了很大变化,可能使优化器依赖的统计信息不准,无法生成最优的查询计划。针对这种情况,可以用pg_total_autovac_tuples系统函数查询表格中自从上次分析以来发生变化的元组的数量。如果数量较大,最好执行一下analyze以使优化器获得最新的统计信息。◇SQL未下推         执行计划中的算子,如果能下推到DN节点执行,则只能在CN上执行。因为CN的数量远小于DN,大量操作堆积在CN上执行,会影响整体性能。如果遇到不能下推的函数或语法,warning字段会给出如下告警信息:SQL is not plan-shipping, reason : %s◇Hash连接大表做内表         如果发现在进行Hash连接时使用了大表作为内表,会给出如下告警信息:PlanNode[%d] Large Table is INNER in HashJoin \"%s\"目前“大表”的标准是平均每个DN上的行数大于100,000,并且内表行数是外表行数的10倍以上。◇大表等值连接使用NestLoop         如果发现对大表做等值连接时使用了NestLoop方式,会给出如下告警信息:PlanNode[%d] Large Table with Equal-Condition use Nestloop\"%s\"目前大表等值连接的判断标准是内表和外表中行数最大者大于DN的数量乘以100,000。◇数据倾斜         数据在DN之间分布不均匀,可导致数据较多的节点成为性能瓶颈。如果发现数据倾斜严重,会给出如下告警信息:PlanNode[%d] DataSkew:\"%s\", min_dn_tuples:%.0f, max_dn_tuples:%.0f目前数据倾斜的判断标准是DN中行数最多者是最少者的10倍以上,且最多者大于100,000。◇代价估算不准确         GaussDB在执行SQL语句过程中会统计实际付出的代价,并与之前估计的代价比较。如果优化器对代价的估算与实际的偏差很大,则很可能生成一个非最优化的计划。如果发现代价估计不准确,会给出如下告警信息:"PlanNode[%d] Inaccurate Estimation-Rows: \"%s\" A-Rows:%.0f, E-Rows:%.0f目前的代价由计划节点返回行数来衡量,如果平均每个DN上实际/估计返回行数大于100,000,并且二者相差10倍以上,则认定为代价估算不准。◇Broadcast量过大         Broadcast主要适合小表。对于大表来说,通常采用Hash+重分布(Redistribute)的方式效率更高。如果发现计划中有大表被广播的环节,会给出如下告警信息:PlanNode[%d] Large Table in Broadcast \"%s\"目前对大表广播的认定标准为平均广播到每个DN上的数据行数大于100,000。◇索引设置不合理  如果对索引的使用不合理,比如应该采用索引扫描的地方却采用了顺序扫描,或者应该采用顺序扫描的地方却采用了索引扫描,可能会导致性能低下。索引扫描的价值在于减少数据读取量,因此认为索引扫描过滤掉的行数越多越好。如果采用索引扫描,但输出行数/扫描总行数>1/1000,并且输出行数>10000(对于行存表)或>100(对于列存表),则会给出如下告警信息:PlanNode[%d] Indexscan is not properly used:\"%s\", output:%.0f, filtered:%.0f, rate:%.5f顺序扫描适用于过滤的行数占总行数比例不大的情形。如果采用顺序扫描,但输出行数/扫描总行数<=1/1000,并且输出行数<=10000(对于行存表)或<=100(对于列存表),则会给出如下告警信息:PlanNode[%d] Indexscan is ought to be used:\"%s\", output:%.0f, filtered:%.0f, rate:%.5f◇下盘量过大或过早下盘         SQL语句执行过程中,因为内存不足等原因,可能需要将中间结果的全部或一部分转储的磁盘上。下盘可能导致性能低下,应该尽量避免。如果监测到下盘量过大或过早下盘等情况,会给出如下告警信息:•       Spill file size large than 256MB•       Broadcast size large than 100MB•       Early spill•       Spill times is greater than 3•       Spill on memory adaptive•       Hash table conflict         下盘可能是因为缓冲区设置得过小,也可能是因为表的连接顺序或连接方式不合理等原因,要结合具体的SQL进行分析。可以通过改写SQL语句,或者HINT指定连接方式等手段来解决。         使用自诊断视图功能,需要将以下变量设成合适的值:▲ use_workload_manager(设成on,默认为on)▲ enable_resource_check(设成on,默认为on)▲ resource_track_level(如果设成query,则收集query级别的信息,如果设成operator,则收集所有信息,如果设成none,则以用户默认的log级别为准)▲ resource_track_cost(设成合适的正整数。为了不影响性能,只有执行代价大于resource_track_cost语句才会被收集。该值越大,收集的语句越少,对性能影响越小;反之越小,收集的语句越多,对性能的影响越大。)         执行完一条代价大于resource_track_cost后,诊断信息会存放在内存hash表中,可通过pgxc_wlm_session_history或gs_wlm_session_history视图查看。         视图中记录的有效期是3分钟,过期的记录会被系统清理。如果设置enable_resource_record=on,视图中的记录每隔3分钟会被转储到gs_wlm_session_info表中,因此3分钟之前的历史记录可以通过gs_wlm_session_info表或pgxc_wlm_session_info视图查看。◆ 发现正在运行的SQL的坏味道         上一节提到的自诊断视图可以显示已完成SQL的信息。如果要查看正在运行的SQL的情况,可以使用下面的视图:•       gs_wlm_session_statistics•       pgxc_wlm_session_statistics         类似地,gs_开头的用于查看当前CN节点上收集的信息,pgxc_开头的则包含集群中所有CN收集的信息。两个视图的定义与上一节的自诊断视图基本相同,使用方法也基本一致。 通过观察其中的字段,可以发现正在运行的SQL中存在的性能问题。         例如,通过“select queryid, duration from gs_wlm_session_statistics order by duration desc limit 10;”可以查询当前运行的SQL中,已经执行时间最长的10个SQL。如果时间过长,可能有必要分析一下原因。图2-a 通过gs_wlm_session_statistics视图发现可能hang住SQL         查到queryid后,可以通过query_plan字段查看该SQL的执行计划,分析其中可能存在的性能瓶颈和异常点。图2-b 通过gs_wlm_session_statistics视图查看当前SQL的执行计划         再下一步,可以结合等待视图等其他手段定位性能劣化的原因。图2-c 通过gs_wlm_session_statistics视图结合等待视图定位性能问题         另外,活动视图pg_stat_activity也能提供一些当前执行SQL的信息。◆ Top SQL——利用统计信息发现SQL坏味道         除了针对逐条SQL进行分析,还可以利用统计信息发现SQL中的坏味道。另一篇文章“Unique SQL特性原理与应用”中提到的Unique SQL特性,能够针对执行计划相同的一类SQL进行了性能统计。与自诊断视图不同的是,如果同一个SQL被多次执行,或者多个SQL语句的结构相同,只有条件中的常量值不同。这些SQL在Unique SQL视图中会合并为一条记录。因此使用Unique SQL视图能更容易看出那些类型的SQL语句存在性能问题。         利用这一特性,可以找出某一指标或者某一资源占用量最高/最差的那些SQL类型。这样的SQL被称为“Top SQL”。         例如,查找占用CPU时间最长的SQL语句,可以用如下SQL:select unique_sql_id,query,cpu_time from pgxc_instr_unique_sql order by cpu_time desc limit 10。         Unique SQL的使用方式详见https://bbs.huaweicloud.com/blogs/197299。◆ 结论         发现SQL中的坏味道是性能调优的前提。GaussDB对数据库的运行状况进行了SQL级别的监控和记录。这些打点记录的数据可以帮助用户发现可能存在的异常情况,“嗅”出潜在的坏味道。从这些数据和提示信息出发,结合其他视图和工具,可以定位出坏味道的来源,进而有针对性地进行优化。原文链接:https://bbs.huaweicloud.com/blogs/197413【推荐阅读】【最新活动汇总】DWS活动火热进行中,互动好礼送不停(持续更新中)  HOT  【博文汇总】GaussDB(DWS)博文汇总1,欢迎大家交流探讨~(持续更新中)【维护宝典汇总】GaussDB(DWS)维护宝典汇总贴1,欢迎大家交流探讨(持续更新中)【项目实践汇总】GaussDB(DWS)项目实践汇总贴,欢迎大家交流探讨(持续更新中)【DevRun直播汇总】GaussDB(DWS)黑科技直播汇总,欢迎大家交流学习(持续更新中)【培训视频汇总】GaussDB(DWS) 培训视频汇总,欢迎大家交流学习(持续更新中)扫码关注我哦,我在这里↓↓↓
  • [SQL] GaussDB(DWS) TD和Oracle兼容模式的差异
    【摘要】 GaussDB(DWS) TD和Oracle两种兼容模式的差异,以及对每种差异做了举例说明。GaussDB(DWS)支持两种兼容模式,即TD(Teradata)兼容模式、ORA(Oracle)兼容模式。可以在CREATE DATABASE时通过指定选项DBCOMPATIBILITY进行选择。语法如下:--创建兼容TD的数据库 postgres=# CREATE DATABASE td_compatible_db DBCOMPATIBILITY 'TD';CREATE DATABASE--创建兼容ORA的数据库 postgres=# CREATE DATABASE ora_compatible_db DBCOMPATIBILITY 'ORA';CREATE DATABASEpostgres=# SELECT datname,datcompatibility FROM PG_DATABASE WHERE datname LIKE '%compatible_db';       datname      | datcompatibility  -------------------+------------------  td_compatible_db  | TD  ora_compatible_db | ORA(2 rows)两种兼容模式的注意差异对比如下表格所示:下面对每一个兼容性进行举例说明:-- 切到TD兼容的库下,创建表并插入数据 postgres=# \c td_compatible_db td_compatible_db=# CREATE TABLE td_table(a INT,b VARCHAR(5),c date);NOTICE:  The 'DISTRIBUTE BY' clause is not specified. Using 'a' as the distribution column by default.HINT:  Please use 'DISTRIBUTE BY' clause to specify suitable data distribution column.CREATE TABLEtd_compatible_db=# INSERT INTO td_table VALUES(1,null,CURRENT_DATE);   INSERT 0 1td_compatible_db=# INSERT INTO td_table VALUES(2,'',CURRENT_DATE);  INSERT 0 1-- 区分空串和NULL,date类型只显示年月日td_compatible_db=# SELECT a, b, b IS NULL AS null, c FROM td_table;  a | b | null |     c       ---+---+------+------------  1 |   | t    | 2020-06-19  2 |   | f    | 2020-06-19(2 rows)td_compatible_db=# SELECT CURRENT_DATE;     date     ------------  2020-06-19(1 row)-- 空串转int,转为0。TD数据库不同于Oracle,Oracle将空串当做NULL进行处理,TD在将空串转换为数值类型的时候,默认将空串转换为0进行处理,因此查询空串会查询到数值为0的数据。同样地,在TD兼容模式下,字符串转换数值的过程中,也会将空串默认转换为相应数值类型的0值进行处理。除此之外,' - '、' + '、' '这些字符串也都会在TD兼容模式下默认转换为0进行处理,但是小数点字符串' . '会报错td_compatible_db=# SELECT b::int FROM td_table WHERE b = '';     b  --- 0(1 row)--超长字符自动截断。当连接到TD兼容的数据库时,td_compatible_truncation参数设置为on时,将启用超长字符串自动截断功能,在后续的insert语句中(不包含外表的场景下),对目标表中char和varchar类型的列上插入超长字符串时,系统会自动按照目标表中相应列定义的最大长度对超长字符串进行截断。td_compatible_db=# SHOW td_compatible_truncation;  td_compatible_truncation  -------------------------- on(1 row)td_compatible_db=# INSERT INTO td_table VALUES(3,'12345678',CURRENT_DATE);INSERT 0 1td_compatible_db=# SELECT * FROM td_table WHERE a = 3;                      a |   b   |     c       ---+-------+------------  3 | 12345 | 2020-06-19(1 row)--varchar   + int运算,转为numeric + numeric计算td_compatible_db=# EXPLAIN VERBOSE SELECT b + a FROM td_table WHERE a = 3;                                           QUERY PLAN                                           ----------------------------------------------------------------------------------------------- Data Node Scan  (cost=0.00..0.00 rows=0 width=0)    Output: (((td_table.b)::numeric + (td_table.a)::numeric))    Node/s: datanode7    Remote query: SELECT b::numeric + a::numeric AS "?column?" FROM public.td_table WHERE a = 3(4 rows)-- case和coalesce表达式。对于case 和coalesce,在TD 兼容模式下的处理● 如果所有输入都是相同的类型,并且不是unknown类型,那么解析成这种类型。● 如果所有输入都是unknown类型则解析成text类型。● 如果输入字符串(包括unknown,unknown当text来处理)和数字类型,那么解析成字符串类型,如果是其他不同的类型范畴,则报错。● 如果输入类型是同一个类型范畴,则选择该类型的优先级较高的类型。● 把所有输入转换为所选的类型。如果从给定的输入到所选的类型没有隐式转换则失败。示例1:Union中的待定类型解析。这里,unknown类型文本'b'将被解析成text类型。td_compatible_db=# SELECT text 'a' AS "text" UNION SELECT 'b';text------ab(2 rows)示例2:简单Union中的类型解析。文本1.2的类型为numeric,而且integer类型的1可以隐含地转换为numeric,因此使用这个类型。td_compatible_db=# SELECT 1.2 AS "numeric" UNION SELECT 1;numeric---------11.2(2 rows)示例3:转置Union中的类型解析。这里,因为类型real不能被隐含转换成integer,但是integer可以隐含转换成real,那么联合的结果类型将是real。td_compatible_db=# SELECT 1 AS "real" UNION SELECT CAST('2.2' AS REAL);real------12.2(2 rows)示例4:TD模式下,coalesce参数输入int和varchar类型,那么解析成varchar类型。ORA模式下会报错。查看coalesce参数输入int和varchar类型的查询语句的执行计划如下td_compatible_db=# EXPLAIN VERBOSE select coalesce(a, b) FROM td_table;                                          QUERY PLAN                                          --------------------------------------------------------------------------------------------- Data Node Scan  (cost=0.00..0.00 rows=0 width=0)    Output: (COALESCE((td_table.a)::character varying, td_table.b))    Node/s: All datanodes    Remote query: SELECT COALESCE(a::character varying, b) AS "coalesce" FROM public.td_table(4 rows)原文链接:https://bbs.huaweicloud.com/blogs/176361【推荐阅读】【最新活动汇总】DWS活动火热进行中,互动好礼送不停(持续更新中)  HOT  【博文汇总】GaussDB(DWS)博文汇总1,欢迎大家交流探讨~(持续更新中)【维护宝典汇总】GaussDB(DWS)维护宝典汇总贴1,欢迎大家交流探讨(持续更新中)【项目实践汇总】GaussDB(DWS)项目实践汇总贴,欢迎大家交流探讨(持续更新中)【DevRun直播汇总】GaussDB(DWS)黑科技直播汇总,欢迎大家交流学习(持续更新中)【培训视频汇总】GaussDB(DWS) 培训视频汇总,欢迎大家交流学习(持续更新中)扫码关注我哦,我在这里↓↓↓
  • [SQL] 拿走磁盘也甭想读数据——透明加密保安全
    【摘要】 简要介绍了数据库透明加密的基本概念,分析了加密粒度和优缺点,介绍了GaussDB(DWS)和其他系统的实现。透明加密是什么?透明加密(Transparent Data Encrytion,TDE)是用来加密数据库文件的技术。TDE在数据库文件级别提供加密,在磁盘和备份介质上加密数据库,解决了静态数据保护问题。TDE不会保护传输阶段的数据(比如客户端与服务端传输的数据)和使用中的数据(在非持久化介质中的数据,比如在内存、CPU cache,CPU寄存器中的数据)。为什么需要透明加密?当文件系统访问控制受到威胁时,TDE可以防止数据泄露:恶意用户会窃取存储设备并直接读取数据库文件。恶意备份操作员进行备份。解决合规性问题,比如PCI DSS(支付卡行业数据标准)。透明加密的粒度分析加密对象的粒度数据库集群数据库表空间表列表的集合比如schema集群范围加密好处架构简单密钥管理简单适用于所有加密需求(用户表、系统表、索引等对象)不足加密所有数据库对象带来的性能开销单个密钥加密整个集群,单个密钥加密的数量大。密钥更新需要重建整个集群细粒度加密好处减少性能开销减少单个密钥加密的数据量(使密码分析更困难,即使幸运拿到了密钥,较少的数据风险)重新加密或者密钥更新不需要重建整个数据库集群不足密钥管理比较复杂通过查找加密表的密钥引入了新的性能开销GaussDB(DWS)的实现三层密钥结构,集群级加密。在创建集群时启用加密。当选择KMS(密钥管理服务)对DWS进行密钥管理时,加密密钥层次结构有三层。按层次结构顺序排列,这些密钥为主密钥(CMK)、集群加密密钥 (CEK)、数据库加密密钥 (DEK)。主密钥用于给CEK加密,保存在KMS中。CEK用于加密DEK,CEK明文保存在DWS集群内存中,密文保存在DWS服务中。DEK用于加密数据库中的数据,DEK明文保存在DWS集群内存中,密文保存在DWS服务中。密钥更新通过更新CEK来实现,不更新数据加密密钥DEK,避免重建数据库的性能开销。其他系统中的TDEPG社区的实现(预计在2021年的PG14)集群范围的加密内部密钥管理系统(KMS),将密钥存储在数据库中加密所有持久化数据,不加密内存中的共享缓冲区数据MySQL(InnoDB)支持表空间级TDE。在MySQL中,表空间是指可以保持一个或多个表以及与表关联的索引的数据的文件。支持两层密钥结构,为每个表空间使用一个密钥,该密钥位于表空间文件的头部。主密钥用于保护表空间密钥,通过插件从外部系统获取。支持redo和undo日志加密和系统表加密。使用专有密钥而不是表空间密钥对每一页的redo和undo日志加密。日志加密密钥以加密状态存储在第一个redo/undo日志文件的头部。OracleOracle支持列级和表空间级TDE。使用两层秘钥结构。主加密秘钥(MEK)存储在外部密钥存储中,用于保护列级和表空间级密钥。列级TDE为每个表使用一个密钥,表空间级为每个表空间使用一个密钥。支持3DES和AES(128,192、256)加密算法。列级别TDE默认为AES192,表空间级别TDE默认为AES128。SQL Server支持三层密钥结构的数据库级TDE。服务主密钥(SMK)在安装过程中自动生成的(如postgres中的initdb)。数据库主密钥(DMK)是在master数据库(如postgres默认数据库)中创建,并由SMK加密。DMK用于生成实际用于数据加密密钥(DEK)的证书。DEK是每个数据库的秘钥,用户加密数据和日志文件。原文链接:https://bbs.huaweicloud.com/blogs/194924【推荐阅读】【最新活动汇总】DWS活动火热进行中,互动好礼送不停(持续更新中)  HOT  【博文汇总】GaussDB(DWS)博文汇总1,欢迎大家交流探讨~(持续更新中)【维护宝典汇总】GaussDB(DWS)维护宝典汇总贴1,欢迎大家交流探讨(持续更新中)【项目实践汇总】GaussDB(DWS)项目实践汇总贴,欢迎大家交流探讨(持续更新中)【DevRun直播汇总】GaussDB(DWS)黑科技直播汇总,欢迎大家交流学习(持续更新中)【培训视频汇总】GaussDB(DWS) 培训视频汇总,欢迎大家交流学习(持续更新中)扫码关注我哦,我在这里↓↓↓
  • [SQL] GaussDB(DWS)的explain performance详解
    在SQL调优过程中,经常使用explain performance,查看某个执行比较慢的SQL语句的实际执行信息和估算信息,通过对比实际执行与优化器的估算之间的差别,找到执行中的瓶颈点,来为优化提供依据。Explain performance的结果包括七部分,分别为:以表格形式显示的计划Predicate Information (identified by plan id)Memory Information (identified by plan id)Targetlist Information (identified by plan id)DataNode Information (identified by plan id)User Define Profiling====== Query Summary =====下面,以8个DN,数据量为1TB的GaussDB中执行tpcds的Q67为例,对这7部分分别进行详细介绍。具体的SQL语句及查询计划参考附件Q67.txt。以表格形式显示的计划表格字段解读:id:执行算子节点编号。该编号只是为了唯一标识每个算子,不代表算子的执行顺序。operation:具体的执行节点算子名称。常用的算子参见下面的常用算子介绍章节。A-time:当前算子执行完成时间,一般DN上执行的算子的A-time是由[]括起来的两个值,分别表示此算子在所有DN上完成的最短时间和最长时间。一般,算子的A-time中包含其下子节点的执行时间。比如:  Id为20号的Vector Sort算子的A-time中的第二个值,其A-time = 该算子本身的执行时间 + 21号算子的A-time,由此可以计算出来,20号算子的执行时间 = 28201.498 – 4097.214 ≈ 24000,单位为ms。  通过这种方式,就可以帮我们找到执行时间较长的算子,即瓶颈点,分析该算子是否可以优化。比如下图示例计划中从id为16到21之间部分,如下图所示。rollup函数使用sort耗时长,总耗时达到50s(即17号-20号算子的总耗时),(并行度32的情况下),20号算子Vector sort达24s,19号算子Vector Sore Aggregate达9s,18号算子做重分布达10s,17号算子hashagg达到8s。因此需要考虑对rollup类的分析函数考虑使用其它方式进行优化,比如用hashagg替代sortagg,避免大数据量排序性能降低。另外,A-time中有两个值,第一个是所有DN中执行该算子用时最短的时间,第二个是所有DN中执行该算子用时最长的时间。当这两个值相差较大时,说明存在计算倾斜。这两个值偏差越大,表明此算子的计算倾斜(在不同DN上执行时间差异)越大,人工干预调优的必要性越大。  导致计算倾斜的原因,可能是数据在各DN上分布存在倾斜(可通过select * from table_distribution(‘schema_name’, ‘table_name’);查看表在各DN上的数据分布情况),也可能是DN之间的资源配置有差异,也可能是分布列设置不合理等。对于stream算子来说,它的A-time比较特殊,stream算子主要是接收子节点的数据。它的子节点是在计划开始执行时,就启动多线程并发执行,而不是等着父节点向其请求数据时才触发执行。所以在stream的父节点向stream节点请求数据时,它的子节点如果已经准好了数据,那么stream节点的实际执行时间就是接收数据的时间,因此有时可以看到stream算子的A-time比其子节点的A-time小,如上图中的12号算子。A-rows:表示当前算子实际输出的全局元组数,即所有DN输出的元组数之和。如果是复制表,则此列的值=表中总行数*DN数。当要多次读取某个算子的执行结果,比如,nestloop中,外表中的每条数据都要扫描一遍内表的数据,即内表数据要被多次rescan,此时,A-rows显示的是多次loop之后的行数。E-rows:每个算子估算的输出行数。A-row和E-row的差异体现了优化器估算和实际执行的偏差度。一般来说,偏差越大,越可以认为优化器生成的计划越不可信,人工干预调优的必要性越大。如果估算不准,可能会导致如下的几种问题:采取不正确的连接方式。比如把内表数据估计太小,可能会导致使用性能不好的nestloop方式进行连接搞反内外表。如果估计的内表数量较小,外表数量较大,但实际内表数量大,外表数量小,就会导致数据量大的表作为了内表,数量小的表作为了外表。导致连接性能不好。采用不正确的重分布方式。如果要被分布的数据被估计的太小,会使得计划采用boardcast方式对数据进行重分布,当实际数据很大时,会导致数据在DN之间传输耗时较多。连接中选取数量大的表做重分布。下图就是一个错误选择大表做重分布的例子。E-distinct:表示单DN上hashjoin算子的distinct估计值。这一列有两个值,第一个值代表外表的distinct值,第二个值代表内表的distinct值。将来会将这两个值分别显示在内表和外表对应的行数,便于理解。Peak Memory:此算子在每个DN上执行时使用的内存峰值。当在SMP场景中,该列是单线程的数据。这点需要改进一下,应该显示单DN上所有线程peak memory的和比较合理,便于调优时合理设置内存。SMP的介绍参考SMP特性章节。E-memory:DN上每个算子估算的内存使用量,只有DN上执行的算子会显示。某些场景会在估算的内存使用量后使用括号显示该算子在内存资源充足下可以自动扩展的内存上限。A-width:表示当前算子每行元组的实际宽度,仅对于重内存使用算子会显示,包括:(Vec)HashJoin、(Vec)HashAgg、(Vec) HashSetOp、(Vec)Sort、(Vec)Materialize算子等,其中(Vec)HashJoin计算的宽度是其右子树算子的宽度,会显示在其右子树上。使用括号显示该算子输出元组中的最小和最大宽度。E-width:每个算子输出元组的估算宽度。E-costs:每个算子估算的执行代价。Predicate Information (identified by plan id)  这部分主要显示的是谓词信息,即在整个计划执行过程中不会变的信息,主要是一些join条件和一些filter信息。  下图中,对这部分进行了说明。Memory Information (identified by plan id)  这一部分显示的是整个计划中会将内存的使用情况打印出来的算子的内存使用信息,主要是Hash、Sort算子,包括:算子峰值内存(peak memory)DataNode Query Peak Memory显示每个DN节点在整个查询过程中使用的内存峰值。它们中的最大值经常用来估算SQL语句耗费的内存,也被用来作为SQL语句调优时运行态内存参数设置的重要依据。算子内的peak memory显示算子内每个DN节点使用的内存峰值。控制内存(control memory)一般出现在hash join、hash agg算子中,用于创建hash表和hash探测所使用的内存估算的内存使用(estimate memory)执行时实际宽度(width)内存使用自动扩展次数(auto spread times)是否提前下盘(early spilled),及下盘信息,包括重复下盘次数(spill Time(s)),内外表下盘分区数(inner/outer partition spill num),下盘文件数(temp file num),下盘数据量及最小和最大分区的下盘数据量(written disk IO [min, max] )。提前下盘是指还有可用内存,但不足以支撑接下来的操作。主要在以下情况会发生:当hash表中剩余的内存小于要插入数据申请的内存根据当前操作的内存使用判断该操作是一个非常耗内存操作时。比如大数据量的sort操作。此时就要看一下当前配置的work_mem是否太小。Targetlist Information (identified by plan id)这部分显示的是每一个算子输出的目标列。格式如下:输出的目标列一般是:查询中显示指定的输出列分组、排序、过滤条件、连接条件中出现的列。这些非显示指定的输出列,在查询的最后不会输出,但是在执行的中间过程中被输出给其它算子用于以上操作。比如下图中的store_sales.ss_sold_date_sk列就是只用于连接条件。  对于输出列信息中还有一点需要说明的是,某些需要经过计算的表达式列,比如下图19号算子中的sum表达式列,在19号算子中每个DN计算了这个表达式的结果,在上层18号streaming算子中只是引用19号算子的结果进行重分布数据,不对其进行计算,所以在18号算子中在该sum表达式两边加了一对圆括号,表示是对下层节点中该表达式结果的引用,不再重复计算。DataNode Information (identified by plan id)  这部分会将各个算子的执行时间、CPU、buffer的使用情况全部打印出来。  如果算子采用了SMP执行,则会详细列出DN上每个线程的情况,如下图:  Buffer有三种类型,分别为:Shared buffer:用于普通表数据Temp buffer:用于临时文件中的数据Local buffer:用于临时表数据  Buffer的使用情况包括read(从外存读入buffer数)、written(从buffer写出到外存数)、hit(数据被读入buffer后,再次被访问次数)、dirtied(buffer中内容被修改的buffer数)。其中temp buffer只会统计read和written情况。如下是一个对buffer使用情况的说明。User Define Profiling  这部分显示的是CN和DN、DN和DN建连的时间,以及存储层的一些执行信息。这里涉及到很多名词,此处做个简单介绍:建连(build connection)是指,不同节点间(CN和DN、DN和DN)需要传输数据,而建立的连接。这一般只有stream算子才会有。CU(Compression Unit),压缩单元。列存表的最小存储单位。Vector batch,向量批。存放参与向量计算的一批数据。  下面分别是Q67的查询计划树和user define profiling,可以通过对照计划树,便于了解user define profiling中各个plan node id对应的算子操作。====== Query Summary ===== 这部分主要打印一些查询总结信息。包括:DataNode executor start time:DN上执行器的开始时间第一个括号中是两个DN的名字,第一个是执行器开始时间最短的DN,第二个是执行器开始时间最长的DN第二个括号中是对应第一个括号中两个DN的执行器启动时间Datanode executor end time: DN上执行器的结束时间后面两个括号中的含义类似DN上执行器的开始时间,分别代表执行器结束时间最短和最长的DN名字,及其对应的结束用时Remote query poll time: stream gather算子用于监听是否有各DN数据到达CN的网络poll时间System available mem: 当前预计执行时系统可用内存Query Max mem: 查询执行所需最大内存Query estimated mem: 查询执行所需使用内存估计Avail/Max core: 可用/最大CPU核数Cpu util: 最大CPU数Active statement: 当前语句生成计划时,GaussDB(DWS)上正在运行的其它语句数Query estimated cpu: 计划的CPU使用估计,它是首先找出所有stream算子中cpu使用最多的cpu使用值(此处简写为max_cpu_usage),然后用所有stream算子的cpu使用之和/max_cpu_usage计算得出Mem allowed dop: 内存允许的dop限制。是根据DN所在主机的空闲内存情况、主机上DN个数、计划中stream个数、当前可用的CPU数及估计要使用的CPU数计算出来最大dop数。如果设置了query_dop不为0的值,则dop不能超过query_dop的限制,具体参考如何开启SMP。如果query_dop设置为自适应,则dop不能超过GaussDB(DWS)支持的最大dop(即Min non-spill dop)。Min non-spill dop: dop不能超过此限制。限制为64Initial dop: 初始dopFinal dop: 最终dopCoordinator executor start time: CN上执行器的启动用时Coordinator executor run time: CN上执行器的运行用时Coordinator executor end time: CN上执行器的结束用时Total network : 网络通信总共传输的数据量Planner runtime: 生成计划的时间Query Id: 该查询的query id,用来唯一标识该查询,CN和DN上同一个查询的query id相同,以便于查询其他视图中标识属于同一查询的不同节点上的信息Total runtime: 整个查询的总用时相关知识介绍常用算子介绍  算子主要分为以下五类:控制算子。控制算子是一类用于处理特殊情况的节点,用于实现特殊的执行流程。算子类型描述Result处理含有仅需一次计算的条件表达式或INSERT语句中 VALUES子句指定的将要插入的元组Append用于表示和组织需要包含多个子查询执行流程BitmapAnd用于需要对两个或多个位图进行并操作的流程BitmapOr用于需要对两个或多个位图进行或操作的流程RecursiveUnion用于处理WITH子句中递归定义的UNION子查询扫描算子。扫描类算子一般是执行计划树的叶子节点,不仅可以扫描表,还可以扫描函数的结果集、Values链表结构、子查询结果集等,每次获取一条元组作为上层节点的输入。算子类型描述SeqScan顺序扫描,用于行存表Cstore Scan列存表扫描IndexScan基于索引扫描,通过索引找到物理表中的元组IndexOnlyScan基于索引扫描,直接从索引返回元组BitmapScan(BitmapIndexScan, BitmapHeapScan)利用bitmap获取元组TidScan通过元组tid获取元组SubqueryScan子查询扫描FunctionScan处理范围表中含有函数的扫描ValuesScan用于Values链表扫描CteScan用于扫描CommonTableExprWorkTableScan用于扫描RecursiveUnion迭代的中间数据ForeignScan外部表扫描物化算子。物化算子是一类可以缓存元组的算子。在执行过程中,很多扩展的物理操作符需要首先获取所有的元组才能进行操作(例如聚集函数操作、没有索 引辅助的排序等),这是要用物化算子将元组缓存起来。算子类型描述Material对子查询结果进行缓存。对于需要重复多次扫描的子节点,特别是扫描 结果每次都相同时,可以减少执行的代价Sort对下层算子返回的元组进行排序,该算子只有左子节点Group对下层排序元组进行分组操作。用于处理GROUP BY子句,分组后只返回该分组的第一个元组。该算子只有一个左子节点,且子节点必须返回在分组属性上已排好序的元组Agg用于执行聚集函数Unique执行去重操作HashHashjoin辅助节点,将从Hashjoin左子节点获取的元组放入构造好的Hash表中,Hash算子也只有一个左子节点SetOp处理集合操作Exist、Intersect查询Limit处理Limit/offset子句,从下层节点的输出中挑选处于一定范围内的元组WindowAgg处理窗口函数连接算子。连接算子对应于关系代数中的连接操作。连接算子按实现方式可以分为:Nestloop、HashJoin、 MergeJoin算子类型执行方式限制优势劣势适用情况Nestloop循环连接。对于外表的每一行,嵌套扫描内表返回结果无当内表使用索引时,可以快速定位连接元组每个外表均需重新执行内节点操作外表结果集小HashJoinHash连接。内表根据join列建立hash表,外表使用相同hash值仅匹配相应hash桶连接两端必须为类型相同的 等值连接,且支持hash散列通过哈希散列,一次性定位 连接元组内表在内存放不下可能导致 使用多轮hash,列重复值太 多可能导致分桶内表可在内存里放下,列重 复值和倾斜不要太多MergeJoin归并连接。内外表均排序后,进行排序后的归并连接操作(1)等值连接(2)内外表有序(否则需要排序)通过归并连接,一次性定位连接元组内外表需要有序,因此必须承受内外表IndexScan或Sort的代价内外表已有有序,不需要重新排序Streaming是一个特殊的算子,它实现了分布式架构的核心数据shuffle功能,Streaming共有三种形态,分别对应了分布式结构下不同的数据shuffle功能:Streaming (type: GATHER):作用是CN从DN收集数据。Streaming(type: REDISTRIBUTE):作用是DN根据选定的分布列把数据重分布到所有的DN。Streaming(type: BROADCAST):作用是把当前DN的数据广播给其他所有的DN针对以上算子,如果出现了Vector前缀的算子是指向量化执行引擎算子,一般出现在含有列存表的Query中。SMP特性  SMP特性通过算子并行来提升性能,同时会占用更多的系统资源,包括CPU、内存、网络、I/O等等。本质上SMP是一种以资源换取时间的方式,计划并行之后必定会引起资源消耗的增加,当上述资源成为瓶颈的情况下,SMP无法提升性能,反而可能导致性能的劣化。在出现资源瓶颈的情况下,建议关闭SMP。  在使用了SMP特性的查询计划中,可能会看到类似Streaming(type: SPLIT REDISTRIBUTE dop: 10/10)的算子,这其中的dop是degree of parallel的缩写,后面的两个数字分别表示该算子在每个DN上执行时的线程数,和其子节点执行时的线程数。SMP适用的场景支持并行的算子计划中存在以下算子支持并行:Scan:支持行存普通表和行存分区表顺序扫描、列存普通表和列存分区表顺序扫描、HDFS内外表顺序扫描;支持GDS数据导入的外表扫描并行。以上均不支持复制表。Join:HashJoin、NestLoopAgg:HashAgg、SortAgg、PlainAgg、WindowAgg(只支持partition by,不支持order by)。Stream:Redistribute、Broadcast其他:Result、Subqueryscan、Unique、Material、Setop、Append、VectoRow、RowToVecSMP特有算子为了实现并行,新增了并行线程间的数据交换Stream算子供SMP特性使用。这些新增的算子可以看做Stream算子的子类。Local Gather:实现DN内部并行线程的数据汇总Local Redistribute:在DN内部各线程之间,按照分布键进行数据重分布Local Broadcast:将数据广播到DN内部的每个线程Local RoundRobin:在DN内部各线程之间实现数据轮询分发Split Redistribute:在集群跨DN的并行线程之间实现数据重分布Split Broadcast:将数据广播到集群所有DN的并行线程上述新增算子可以分为Local与非Local两类,Local类算子实现了DN内部并行线程间的数据交换,而非Local类算子(即stream算子)实现了跨DN的并行线程间的数据交换。如何开启SMP使用SMP特性通过设置query_dop参数的值来控制。query_dop=1(默认值),表示不启用SMP。query_dop=0(自适应),系统会根据资源情况和计划特征,动态为每个查询选取[1,8]之间的最优的并行度,最大化提升查询性能。query_dop=-value,在考虑资源情况和计划特征基础上,限制dop选取的范围为[1,value]。query_dop=value,不考虑资源情况和计划特征,强制选取dop为1或value。原文链接:https://bbs.huaweicloud.com/blogs/193434【推荐阅读】【最新活动汇总】DWS活动火热进行中,互动好礼送不停(持续更新中)  HOT  【博文汇总】GaussDB(DWS)博文汇总1,欢迎大家交流探讨~(持续更新中)【维护宝典汇总】GaussDB(DWS)维护宝典汇总贴1,欢迎大家交流探讨(持续更新中)【项目实践汇总】GaussDB(DWS)项目实践汇总贴,欢迎大家交流探讨(持续更新中)【DevRun直播汇总】GaussDB(DWS)黑科技直播汇总,欢迎大家交流学习(持续更新中)【培训视频汇总】GaussDB(DWS) 培训视频汇总,欢迎大家交流学习(持续更新中)扫码关注我哦,我在这里↓↓↓
  • [SQL] 数据仓库中数据模型以及ETL算法
    【摘要】 数据模型在数据仓库平台中具有重要的意义,客户的业务场景,流程规则,行业知识都体现在通过数据模型表现出来,在业务人员和技术人员之间搭建起来了一个沟通的桥梁,所以在国外一些数据仓库的文献中,把数据模型称之为数据仓库的心脏“The Heart of the DataWarehouse”。一、数据仓库的“心脏”首先来谈谈数据模型。模型是现实世界特征的模拟和抽象,比如地图、建筑设计沙盘,飞机模型等等。而数据模型Data Model是现实世界数据特征的抽象。在数据仓库项目建设中,数据模型的建立具有重要的意义,客户的业务场景,流程规则,行业知识都体现在通过数据模型表现出来,在业务人员和技术人员之间搭建起来了一个沟通的桥梁,所以在国外一些数据仓库的文献中,把数据模型称之为数据仓库的心脏“The Heart of the DataWarehouse”数据模型设计的好坏直接影响数据的稳定性易用性访问效率存储容量维护成本二、数据仓库中数据模型,数据分层和ETL程序2.1 概述        数据仓库是一种通过(准)实时/批量的方式把各种外部数据源集成起来后,采用多种方式提供给最终用户进行数据消费的信息系统。       面对繁多的上游业务系统而言,数据仓库的一个重要任务就是进行数据清洗和集成,形成一个标准化的规范化的数据结构,为后续的一致性的数据分析提供可信的数据基础。       另一方面数据仓库里面的数据要发挥价值就需要通过多种形式表现,有用于了解企业生产状况的固定报表,有用于向管理层汇报的KPI驾驶舱,有用于大屏展示的实时数据推送,有用于部门应用的数据集市,也有用于分析师的数据实验室...对于不同的数据消费途径,数据需要从高度一致性的基础模型转向便于数据展现和数据分析的维度模型。不同阶段的数据因此需要使用不同架构特点的数据模型与之相匹配,这也就是数据在数据仓库里面进行数据分层的原因。       数据在各层数据中间的流转,就是从一种数据模型转向另外一种数据模型,这种转换的过程需要借助的就是ETL算法。打个比方,数据就是数据仓库中的原材料,而数据模型是不同产品形态的模子,不同的数据层就是仓库的各个“车间”,数据在各个“车间”的形成流水线式的传动就是依靠调度工具这个流程自动化软件,执行SQL的客户端工具是流水线上的机械臂,而ETL程序就是驱动机械臂进行产品加工的算法核心。上图是数据仓库工具箱-维度建模权威指南一书中的数据仓库混合辐射架构2.2 金融行业中的分层模型        金融行业中的数据仓库是对模型建设要求最高也是最为成熟的一个行业,在多年的金融行业数据仓库项目建设过程中,基本上都形成了缓冲层,基础模型层,汇总层(共性加工层),以及集市层。不同的客户会依托这四层模型做不同的演化,可能经过合并形成三层,也可能经过细分,形成5层或者6层。本文简单介绍最常见的四层模型:       缓冲层:有的项目也称为ODS层,简单说这一层数据的模型就是贴源的,对于仓库的用户就是在仓库里面形成一个上游系统的落地缓冲带,原汁原味的生产数据在这一层得以保存和体现,所以这一层数据保留时间周期较短,常见的是7~15天,最大的用途是直接提供基于源系统结构的简单原貌访问,如审计等。        基础层:也称为核心层,基础模型层,PDM层等等。数据按照主题域进行划分整合后,较长周期地保存详细数据。这一层数据高度整合,是整个数据仓库的核心区域,是所有后面数据层的基础。这一层保存的保存的数据最少13个月,常见的是2~5年。        集市层:先跳到最后一层。集市层的数据模型具备强烈的业务意义,便于业务人员理解和使用,是为了满足部门用户,业务用户,关键管理用户的访问和查询所使用的,而往往对接前段门户的数据查询,报表工具的访问,以及数据挖掘分析工具的探索。           汇总层:汇总层其实并不是一开始就建立起来的。往往是基础层和集市层建立起来后,发现众多的集市层数据进行汇总,统计,加工的时候存在对基础层数据的反复查询和扫描,而不同部门的数据集市的统计算法实际上是有共性的,所以主键的在两层之间,把具有共性的汇总结果形成一个独立的数据层次,承上启下,节省整个系统计算资源。2.3数据仓库常见ETL算法        虽然数据仓库里面数据模型对于不同行业,不同业务场景有着千差万别,但从本质上从缓冲层到基础层的数据加工就是对于增/全量数据如何能够高效地追加到基础层的数据表中,并形成合理的数据历史变化信息链条;而从基础层到汇总层进而到集市层,则是如何通过关联,汇总,聚合,分组这几种手段进行数据处理。所以长期积累下来,对于数据层次之间的数据转换算法实际上也能形成固定的ETL算法,这也是市面上很多数据仓库代码生成工具能够自动化地智能化地形成无编码方式开发数据仓库ETL脚本的原因所在。这里由于篇幅关系,只简单列举一下缓冲层到基础层常见的几种ETL算法,具体的算法对应的SQL脚本可以找时间另起篇幅详细地介绍。1. 全表覆盖A1算法说明:删除目标表全部数据,再插入当前数据 来源数据量:全量数据 适用场景:无需保留历史轨迹,只使用最新状态数据2. 更新插入(Upsert)A2算法说明:本日数据按照主键比对后更新数据,新增的数据采用插入的方式增加数据 来源数据量:增量或全量数据 适用场景:无需保留历史轨迹,只使用最新状态数据3. 历史拉链(History chain)A3算法说明:数据按照主键与上日数据进行比对,对更新数据进行当日的关链和当日开链操作,对新增数据增加当日开链的记录 来源数据:增量或全量数据 适用场景:需要保留历史变化轨迹的数据,这部分数据会忽略删除信息,例如客户表、账户表等4. 全量拉链(Full History chain)A4算法说明:本日全量数据与拉链表中上日数据进行全字段比对,比对结果中不存在的数据进行当日关链操作,对更新数据进行当日关链和当日开链操作,对新增数据增加当日开链的记录 来源数据量:全量数据 适用场景:需要保留历史变化轨迹的数据,这部分数据会由数据比对出删除信息进行关链 5. 带删除增量拉链(Fx:Delta History Chain) A5  算法说明:本日增量数据根据增量中变更标志对删除数据进行当日关链操作,对更新和新增数据与上日按主键比对后根据需要进行当日关链和当日开链操作,对新增数据增加当日开链的记录  来源数据量:增量数据  适用场景:需要保留历史变化轨迹的数据,这部分数据会根据CHG_CODE来判断删除信息 6. 追加算法(Append)A6  算法说明:删除当日/月的增量数据,插入本日/月的增量数据  来源数据量:增量数据  适用场景:流水类或事件类数据三、GaussDB(DWS)和数据仓库       华为的GaussDB(DWS)服务是一种基于公有云基础架构的分布式MPP数据库。其主要面向海量数据分析场景。MPP数据库是业界实现数据仓库系统最主流的数据库架构,这种架构的主要特点就是Shared-nothing分布式架构,由众多拥有独立且互不共享的CPU、内存、存储等系统资源的逻辑节点(也就是DN节点)组成。       在这样的系统架构中,业务数据被分散存储在多个节点上,SQL被推送到数据所在位置就近执行,并行地完成大规模的数据处理工作,实现对数据处理的快速响应。基于Shared-Nothing无共享分布式架构,也能够保证随着集群规模地扩展,业务处理能力得到线性增长。原文链接:https://bbs.huaweicloud.com/blogs/185082【推荐阅读】【最新活动汇总】DWS活动火热进行中,互动好礼送不停(持续更新中)  HOT  【博文汇总】GaussDB(DWS)博文汇总1,欢迎大家交流探讨~(持续更新中)【维护宝典汇总】GaussDB(DWS)维护宝典汇总贴1,欢迎大家交流探讨(持续更新中)【项目实践汇总】GaussDB(DWS)项目实践汇总贴,欢迎大家交流探讨(持续更新中)【DevRun直播汇总】GaussDB(DWS)黑科技直播汇总,欢迎大家交流学习(持续更新中)【培训视频汇总】GaussDB(DWS) 培训视频汇总,欢迎大家交流学习(持续更新中)扫码关注我哦,我在这里↓↓↓
  • [SQL] 华为云数仓GaussDB(DWS)之地理数据库: PostGIS介绍(一)
    【摘要】 PostGIS为PostgreSQL提供了空间数据库分析能力,是目前业界主流的地理数据库之一,提供如下空间信息服务功能:空间对象、空间索引、空间操作函数和空间操作符等。在GaussDB 中,目前已支持PostGIS地理数据库扩展,并已广泛应用于国内外公安、农业、安平等政企客户。地理数据库能做什么地理数据库属于空间数据库,为地理数据提供了标准的格式和存贮方法,能够方便迅速地进行检索、更新和数据分析,最终达到为多种应用服务的目的。地理数据则包括观测数据、分析测定数据、遥感数据和统计调查数据。地理数据库已广泛的应用于单车、导航,旅游、水利,农业、安平城市等应用场景,渗透到人民生活点点滴滴中。图1. 地理数据库典型应用场景PostGIS功能介绍对于如上介绍的使用场景中,地理数据通常存储为点、线或者多边形的集合。在PostgreSQL中,已经提供了点、线、多边形等空间数据类型,但其提供的数据处理方法和性能很难达到GIS的要求,主要表现在:缺乏复杂的空间类型;没有提供空间分析;没有提供投影变换功能。为了使得PostgreSQL更好的提供空间信息服务,PostGIS也就应运而生。一、PostGIS支持数据类型PostGIS完全遵循OpenGIS规范,支持OpenGIS中所有空间数据类型:a.POINT, LINESTRING, POLYGON, MULTI-POINT,b.MULTI-LINESTRING, MULTI-POLYGON,c.GEOMETRY COLLECTION除了OpenGIS定义的地理数据类型之外,PostGIS还对数据类型进行了扩展,在WKT和WKB数据类型基础上扩展出EWKT和EWKB数据类型:a.EWKT, EWKB(包含了SRID信息的WKT/WKB)b.SRID(Spatial Referencing System Identifier):每个空间实例都有一个空间引用标识符 (SRID)。SRID 对应于基于特定椭圆体的空间引用系统,可用于平面球体映射或圆球映射。此外,PostGIS还支持栅格数据raster分析,可以基于已有的影像或者卫星数据,实现影像或者卫星数据不同类别的统计分析。二、PostGIS支持函数类型PostGIS常见函数大致可以分为以下六类,对于各函数具体用法参考《PostGIS使用手册》:1.    字段处理函数AddGeometryColumn为已有的数据表增加一个地理几何数据字段;DropGeometryColumn删除一个地理数据字段的;ST_SetSRID设置SRID值2.    几何关系函数这类函数描述几何对象的距离、包含、范围、相等等几何关系,常见函数如下:ST_Distance、ST_Equals、ST_Disjoint、ST_Intersects、ST_Touches、ST_Within、 ST_Overlaps、ST_Contains。3.    读写函数这类函数主要用于各种数据类型之间的转换,尤其是Geometry数据类型与其他字符型等数据类型之间的转换,如ST_AsText、ST_GeomFromText、ST_AsGeoJSON ST_AsHEXEWKB、ST_AsKML、 ST_AsLatLonText。4.    几何对象创建函数这类函数用于点、线、多变形等几何对象创建,如ST_GeomFromEWKT、ST_GeomFromEWKB、ST_MakePoint、ST_MakeBox2D、ST_LineFromText、ST_Polygon。5.    几何对象编辑函数这类函数提供对几何图像的平移、翻转、旋转、放大等功能,如ST_AddPoint、ST_Reverse、ST_Rotate、ST_Scale、ST_Snap、ST_Transform、ST_Translate、ST_TransScale。6.    空间关系及测量函数这类函数实现几何对象最远、最近、长度、面积等计算,如ST_3DClosestPoint、ST_3DDistance、 ST_3DDWithin、ST_3DDFullyWithin、ST_3DIntersects、ST_3DLongestLine、ST_3DMaxDistance、ST_3DShortestLine、ST_Area。PostGIS性能介绍目前市场上的空间数据库包括MySQL的Spatial Extension、PostgreSQL的PostGIS、Oracle Spatial、ArcGIS的ArcSDE及MongoDB等。对于这几款数据库的性能对比,之前有一篇文档《常用地理数据库对比测试》有一个比较详细的对比和介绍。从图2至图5中的测试数据可以看出,对于点数据,在相同查询条件下,PostGIS数据库的空间查询速度最快。对于线数据,PostGIS则相比于其它数据库要慢一些,这可能与不同地理数据库使用不同索引技术有关。图2. 第一次点查数据结果图3. 第二次点查数据结果图4. 第一次线查数据结果图5. 第二次线查数据结果GaussDB作为分布式数据库,对PostGIS做了深度适配。目前GaussDB对PostGIS中绝大多数函数均已支持下推至DN处理。因此对于绝大多数地理数据运算,都可以充分利用GaussDB的分布式计算优势,带来相比于PostgreSQL近似线性扩展比的性能加速,满足客户在大数据场景的地理数据处理和分析需求。     本篇博文主要介绍了GaussDB中PostGIS的使用场景、基本功能和性能分析,在下篇博客中,则会进一步深入介绍GaussDB中PostGIS的安装和使用,欢迎大家持续跟进。原文链接:https://bbs.huaweicloud.com/blogs/190410【推荐阅读】【最新活动汇总】DWS活动火热进行中,互动好礼送不停(持续更新中)  HOT  【博文汇总】GaussDB(DWS)博文汇总1,欢迎大家交流探讨~(持续更新中)【维护宝典汇总】GaussDB(DWS)维护宝典汇总贴1,欢迎大家交流探讨(持续更新中)【项目实践汇总】GaussDB(DWS)项目实践汇总贴,欢迎大家交流探讨(持续更新中)【DevRun直播汇总】GaussDB(DWS)黑科技直播汇总,欢迎大家交流学习(持续更新中)【培训视频汇总】GaussDB(DWS) 培训视频汇总,欢迎大家交流学习(持续更新中)扫码关注我哦,我在这里↓↓↓
  • [SQL] 华为云数仓GaussDB(DWS)内存知识梳理
    前言在日常数据库的使用中,难免会遇到一些内存问题。此次博文主要向大家分享一些华为云数仓GaussDB(DWS)内存的基本框架以及基本视图的使用,以便遇到内存问题后可以有一个基本的判断。注意,本篇博文基于华为云数仓GaussDB(DWS) 8.0版本,其他版本细节上或许稍有不同。内存常用视图1.   PV_TOTAL_MEMORY_DETAIL视图该视图会展示当前数据库节点的内存使用信息,单位为MB。视图中个字段的含义:nodename:节点名称,memorytype:内存类型,memorymbytes:对应内存类型的大小。常用的内存类型有以下几种:max_process_memory:取自GUC参数max_process_memory的配置,表示一个数据库节点最大可使用的物理内存。process_used_memory:取自/proc/pid/statm(第二个值) * pagesize,pid替换为当前节点所在的进程号。表示当前节点所处进程已使用的内存。max_dynamic_memory:由下面公式计算而来,表示Gaussdb内核所能使用的最大内存。max_dynamic_memory = max_process_memory- max_cstore_memory - udf_reserved_memory - max_shared_memory ;dynamic_used_memory:GaussDB内核已使用内存,由GaussDB内存管理在申请内存时统计而来。dynamic_peak_memory:GaussDB内核使用内存峰值,由GaussDB内存管理在申请内存时统计而来。dynamic_used_shrctx:GaussDB内核已使用线程间共享内存上下文内存大小,由GaussDB内存管理在申请内存时统计而来。dynamic_peak_shrctx:GaussDB内核已使用线程间共享内存上下文内存峰值,由GaussDB内存管理在申请内存时统计而来。max_shared_memory:进程间最大共享内存大小shared_used_memory:进程间已使用共享内存大小,由/proc/pid/statm(第三个值) * pagesize值统计而来。max_cstore_memory:列存允许的最大使用内存,由GUC参数cstore_buffers配置。cstore_used_memory:列存已使用内存,一般包含列存或HDFS使用过程中所消耗的内存。other_used_memory:通常表示除去GaussDB内核使用的内存以外的内存使用,通常是三方库使用所消耗的内存,例如LLVM,Kerberos等。postgres=# select * from  PV_TOTAL_MEMORY_DETAIL;    nodename   |       memorytype        | memorymbytes --------------+-------------------------+--------------  coordinator1 | max_process_memory      |        12288  coordinator1 | process_used_memory     |          240  coordinator1 | max_dynamic_memory      |        11564  coordinator1 | dynamic_used_memory     |          229  coordinator1 | dynamic_peak_memory     |          234  coordinator1 | dynamic_used_shrctx     |            1  coordinator1 | dynamic_peak_shrctx     |            1  coordinator1 | max_shared_memory       |          211  coordinator1 | shared_used_memory      |          139  coordinator1 | max_cstore_memory       |          512  coordinator1 | cstore_used_memory      |            0  coordinator1 | max_sctpcomm_memory     |            0  coordinator1 | sctpcomm_used_memory    |            0  coordinator1 | sctpcomm_peak_memory    |            0  coordinator1 | other_used_memory       |            0  coordinator1 | gpu_max_dynamic_memory  |            0  coordinator1 | gpu_dynamic_used_memory |            0  coordinator1 | gpu_dynamic_peak_memory |            0  coordinator1 | pooler_conn_memory      |            0  coordinator1 | pooler_freeconn_memory  |            0  coordinator1 | storage_compress_memory |            0  coordinator1 | udf_reserved_memory     |            0 (22 rows)2. PV_SESSION_MEMORY_DETAIL视图华为云数仓GaussDB(DWS)的内存管理框架沿用了之前的内存上下文的思路。在PV_SESSION_MEMORY_DETAIL的视图中,将会统计各线程的内存上下文维度统计的内存使用情况。视图中个字段的含义如下:Sessid:表示Session ID,由线程启动时间+线程标识拼接而来。Sesstype:线程名称Contextname:内存上下文名称。Level:内存上下文层级。Parent:父内存上下文名称。Totalsize:当前内存上下文内存大小Freesize:当前内存上下文已释放内存大小Usedsize:当前内存上下文已使用大小。postgres=# select * from PV_SESSION_MEMORY_DETAIL order by totalsize desc;            sessid           |        sesstype         |         contextname          | level |            parent            | totalsize | freesize | usedsize ----------------------------+-------------------------+------------------------------+-------+------------------------------+-----------+----------+----------  0.140169093357952          | postmaster              | Postmaster                   |     1 | TopMemoryContext             |  26566912 |    23912 | 26543000  0.140169093357952          | postmaster              | gs_signal                    |     1 | TopMemoryContext             |   4272464 |  2050224 |  2222240  1594694378.140168361137920 | WLMCollectWorker        | CacheMemoryContext           |     1 | TopMemoryContext             |   1455032 |   268488 |  1186544  1594694378.140168296134400 | WLMarbiter              | CacheMemoryContext           |     1 | TopMemoryContext             |   1455032 |   266696 |  1188336  1594694378.140168465999616 | JobScheduler            | CacheMemoryContext           |     1 | TopMemoryContext             |   1455032 |   239584 |  1215448  1594708276.140168270964480 | postgres                | CacheMemoryContext           |     1 | TopMemoryContext             |   1455032 |   316392 |  1138640  1594694438.140168207001344 | postgres                | CacheMemoryContext           |     1 | TopMemoryContext             |   1455032 |   329944 |  1125088  1594694378.140168344356608 | WLMmonitor              | CacheMemoryContext           |     1 | TopMemoryContext             |   1455032 |   269528 |  1185504  1594708276.140168270964480 | postgres                | TempSmallContextGroup        |     0 |                              |    550592 |   160320 |      114  1594694438.140168207001344 | postgres                | TempSmallContextGroup        |     0 |                              |    530816 |   148256 |      107  1594708276.140168270964480 | postgres                | SRF multi-call context       |     5 | FunctionScan_140168270964480 |    496704 |     8032 |   488672  1594694378.140168465999616 | JobScheduler            | TempSmallContextGroup        |     0 |                              |    489152 |   120672 |      102  1594694378.140168361137920 | WLMCollectWorker        | TempSmallContextGroup        |     0 |                              |    477184 |   118168 |       98  1594694378.140168344356608 | WLMmonitor              | TempSmallContextGroup        |     0 |                              |    477184 |   118280 |       98  1594694378.140168296134400 | WLMarbiter              | TempSmallContextGroup        |     0 |                              |    477184 |   118136 |       98  1594694438.140168207001344 | postgres                | TopMemoryContext             |     0 |                              |    460808 |    24728 |   436080  1594708276.140168270964480 | postgres                | TopMemoryContext             |     0 |                              |    452616 |     5352 |   447264  1594694378.140168361137920 | WLMCollectWorker        | TopMemoryContext             |     0 |                              |    411528 |     3272 |   408256  1594694378.140168296134400 | WLMarbiter              | TopMemoryContext             |     0 |                              |    411528 |     3032 |   408496  1594694378.140168344356608 | WLMmonitor              | TopMemoryContext             |     0 |                              |    411528 |     3272 |   408256  1594694378.140168465999616 | JobScheduler            | TopMemoryContext             |     0 |                              |    255240 |    10552 |   244688  0.140169093357952          | postmaster              | TopMemoryContext             |     0 |                              |    140680 |     7856 |   132824  1594694438.140168207001344 | postgres                | VecFuncHash                  |     1 | TopMemoryContext             |    122272 |    20928 |   101344  1594708276.140168270964480 | postgres                | VecFuncHash                  |     1 | TopMemoryContext             |    122272 |    20928 |   101344  1594694378.140168539399936 | CheckPointer thread     | TopMemoryContext             |     0 |                              |    116104 |     5944 |   110160  1594694378.140168482780928 | WalWriter thread        | TopMemoryContext             |     0 |                              |    107848 |     7224 |   100624  1594694378.140168505317120 | BackgroundWriter thread | TopMemoryContext             |     0 |                              |    107848 |     7144 |   100704  1594694378.140168394700544 | TwoPhaseCleaner thread  | TopMemoryContext             |     0 |                              |    107848 |     8280 |    99568  1594694378.140168377919232 | FaultMonitor thread     | TopMemoryContext             |     0 |                              |    107848 |     8280 |    99568  1594694378.140168442930944 | PgstatCollector         | TopMemoryContext             |     0 |                              |    107848 |     6696 |   101152  1594694378.140168482780928 | WalWriter thread        | Timezones                    |     1 | TopMemoryContext             |     83488 |     2832 |    80656  1594694378.140168465999616 | JobScheduler            | Timezones                    |     1 | TopMemoryContext             |     83488 |     2832 |    80656  1594694378.140168505317120 | BackgroundWriter thread | Timezones                    |     1 | TopMemoryContext             |     83488 |     2832 |    80656  0.140169093357952          | postmaster              | Timezones                    |     1 | TopMemoryContext             |     83488 |     2832 |    80656  1594694378.140168296134400 | WLMarbiter              | Timezones                    |     1 | TopMemoryContext             |     83488 |     2832 |    80656  1594694438.140168207001344 | postgres                | Timezones                    |     1 | TopMemoryContext             |     83488 |     2832 |    80656  1594694378.140168377919232 | FaultMonitor thread     | Timezones                    |     1 | TopMemoryContext             |     83488 |     2832 |    80656  1594694378.140168539399936 | CheckPointer thread     | Timezones                    |     1 | TopMemoryContext             |     83488 |     2832 |    80656  1594694378.140168442930944 | PgstatCollector         | Timezones                    |     1 | TopMemoryContext             |     83488 |     2832 |    80656  1594694378.140168361137920 | WLMCollectWorker        | Timezones                    |     1 | TopMemoryContext             |     83488 |     2832 |    806563. PG_SHARED_MEMORY_DETAIL视图华为云数仓GaussDB(DWS)除了通用内存上下文以外,还包含共享内存上下文类型用于线程间共享数据。由于共享内存上下文是属于一个进程的,故该视图相比PV_SESSION_MEMORY_DETAIL,不存在sessid,其他的字段含义相同。postgres=# select * from PG_SHARED_MEMORY_DETAIL order by totalsize desc;               contextname               | level |                 parent                 | totalsize | freesize | usedsize ----------------------------------------+-------+----------------------------------------+-----------+----------+----------  Workload manager memory context        |     1 | ProcessMemory                          |   1056832 |     6080 |  1050752  PoolerAgentContext                     |     2 | PoolerMemoryContext                    |     57344 |    36000 |    21344  PoolerCoreContext                      |     2 | PoolerMemoryContext                    |     57344 |    30544 |    26800  ProcessMemory                          |     0 |                                        |     57344 |    28304 |    29040  wlm iostat info hash table             |     2 | Workload manager memory context        |     24576 |    10832 |    13744  WaitCountGlobalContext                 |     1 | ProcessMemory                          |     24576 |     9984 |    14592  wlm user info hash table               |     2 | Workload manager memory context        |     24576 |    10832 |    13744  OBS connector cache                    |     1 | ProcessMemory                          |     24576 |    15056 |     9520  Resource pool hash table               |     2 | Workload manager memory context        |     17984 |     2704 |    15280  Dummy server cache                     |     1 | ProcessMemory                          |      8192 |     2832 |     5360  Node Pool                              |     3 | PoolerCoreContext                      |      8192 |      768 |     7424  dywlm register hash table              |     2 | Workload manager memory context        |      8192 |     2704 |     5488  node group hash table                  |     2 | Workload manager memory context        |      8192 |     2832 |     5360  sql count lookup hash                  |     2 | WaitCountGlobalContext                 |      8192 |     8000 |      192  wlm session info hash table            |     2 | Workload manager memory context        |      8192 |     2704 |     5488  wlm collector hash table               |     2 | Workload manager memory context        |      8192 |     2704 |     5488  DFS connector cache                    |     1 | ProcessMemory                          |      8192 |      768 |     7424  PoolerMemoryContext                    |     1 | ProcessMemory                          |      8192 |     5456 |     2736  operator collector hash table          |     3 | Operator resource track memory context |      8192 |      640 |     7552  operator running hash table            |     3 | Operator resource track memory context |      8192 |      640 |     7552  Query resource track memory context    |     2 | Workload manager memory context        |      8192 |     8144 |       48  bad block stat global hash table       |     2 | bad block stat global memory context   |      8192 |     2704 |     5488  global info hash table                 |     2 | Workload manager memory context        |      8192 |     2832 |     5360  StreamInfoContext                      |     1 | ProcessMemory                          |         0 |        0 |        0  Operator resource track memory context |     2 | Workload manager memory context        |         0 |        0 |        0  bad block stat global memory context   |     1 | ProcessMemory                          |         0 |        0 |        0  ProcSubXidCacheContext                 |     1 | ProcessMemory                          |         0 |        0 |        0 (27 rows)内存相关数据收集通过前面讲述的几个内存视图,我们可以对华为云数仓GaussDB(DWS)内存有一个整体的理解。下面将分享几个内存相关数据收集的功能。注意: 鉴于论坛中的问题多是release版本,故debug版本的各种内存相关功能将不再此次介绍以免混淆。同时收集数据就会带来一些消耗,避免长期大规模的使用下面的方案,仅用作问题诊断数据分析使用。 1.   pv_session_memctx_detail函数       通过上面的视图介绍我们了解到了PV_SESSION_MEMORY_DETAIL视图的作用。我们可以通过pv_session_memctx_detail打印出该线程内存上下文的详细信息。注意第一个参数表示线程ID,我们根据上线的介绍得知sessid的后半部分就是线程ID。第二个参数表示需要打印内存上下文的名称,在release为空才可以生效即由TopMemoryContext开始递归打印内存上下文信息。Release版本不包含chunk的详细信息。例如:select * from pv_session_memctx_detail(140168207001344,'');生成的文件默认在/tmp/dumpmem下,文件中三列分别表示内存上下文名称,总大小,剩余大小。文件内容样例:140168207001344_1594695418.logTopMemoryContext, 460808, 24728 Record information cache, 24576, 14928 TableSpace cache, 8192, 2304 set params hash table, 8192, 2832 VecFuncHash, 122272, 20928 MaskPasswordCtx, 8192, 8144 RowDescriptionContext, 8192, 7104 MessageContext, 8192, 7104 Operator class cache, 8192, 768 smgr relation table, 24576, 8880 tokenize file cxt, 0, 0 hba parser context, 3072, 480 TransactionAbortContext, 32768, 32720 bad block stat thread hash table, 8192, 1664 bad block thread memory context, 0, 0 Portal hash, 8192, 768 PortalMemory, 8192, 8144 Partcache by OID, 8192, 2832 Relcache by OID, 24576, 11904 CacheMemoryContext, 1455032, 329944 pg_index_indrelid_index, 3776, 280 pg_toast_2618_index, 5824, 1760 pg_prepared_xacts, 31744, 3488 pg_db_role_setting_databaseid_rol_index, 5824, 1808 pg_opclass_am_name_nsp_index, 5824, 1768 pg_directory_name_index, 3776, 328 pg_foreign_data_wrapper_name_index, 3776, 328 pg_enum_oid_index, 3776, 328 pg_class_relname_nsp_index, 5824, 1760 pg_foreign_server_oid_index, 3776, 328 pg_statistic_relid_kind_att_inh_index, 5184, 760 pg_cast_source_target_index, 5824, 1808 pg_language_name_index, 3776, 328 pg_collation_oid_index, 3776, 328 pg_amop_fam_strat_index, 5184, 760 pg_index_indexrelid_index, 3776, 280 pg_ts_template_tmplname_index, 5824, 1808 pg_ts_config_map_index, 5824, 1768 pg_partition_partoid_index, 5824, 17682.   memory_tracking_mode参数     除了上面的内存上下文数据统计,我们还可以通过memory_tracking_mode设置内存信息统计的模式,共支持四种模式:    none:不启动内存统计功能。    normal:仅做内存实时统计,不生成文件。    executor:生成统计文件,包含执行层使用过的所有已分配内存的上下文信息。当为executor模式时,将在GaussDB进程(取决于在哪个数据节点最终执行了该算子)的pg_log目录下生成cvs格式文件,命名方式为:memory_track_<DN名称>_query_<queryid>.csv。作业执行时,执行器postgres线程和所有stream线程执行的算子信息,都将输入该文件。其中各字段分别为:输出顺序号、线程内分配内存上下文的顺序号、当前内存上下文的名称、父内存上下文的输出顺序号、父内存上下文的名称、内存上下文树形层次级别号、当前内存上下文使用的内存峰值、当前内存上下文及其所有子内存上下文使用的内存峰值、当前线程所在query的plannodeid。    fullexec:生成文件包含执行层申请过的所有内存上下文信息。当设置为fullexec模式时,输出信息和executor模式相同,但可能增加部分内存上下文分配信息,因为所有申请内存(无论是否申请成功)相关的信息都会被打印出来。由于仅记录内存申请信息,故记录中内存上下文使用的峰值均为0。csv文件内容样例:memory_track_datanode1_query_72339069014639220.csv0, 0, ExecutorState, 0, (null), 0, 8K, 656K, 4 1, 4, CStoreScan_139944754403072, 0, ExecutorState, 1, 272K, 625K, 4 2, 9, cstore scan per scan memory context, 1, CStoreScan_139944754403072, 2, 24K, 24K, 4 3, 8, cstore scan memory context, 1, CStoreScan_139944754403072, 2, 328K, 328K, 4 4, 2, VecToRow_139944754403072, 0, ExecutorState, 1, 23K, 23K, 4 0, 0, ExecutorState, 0, (null), 0, 8K, 144K, 0 1, 13, Stream_72339069014639220_4, 0, ExecutorState, 1, 72K, 72K, 0 2, 10, Sort_72339069014639220_3, 0, ExecutorState, 1, 8K, 40K, 0 3, 16, TupleSort, 2, Sort_72339069014639220_3, 2, 32K, 32K, 0 4, 2, Agg_72339069014639220_2, 0, ExecutorState, 1, 24K, 24K, 0一些诊断方案:1.   内存膨胀       在release版本调试工具以及信息比较受限,基本都是先通过前面介绍的三种视图初步定位大致功能。首先查看PV_TOTAL_MEMORY_DETAIL视图确定是哪一块内存出现了膨胀或者泄露。若是other_used_memory则要考虑三方仓的场景。若是dynamic_used_memory较大,则要查PV_SESSION_MEMORY_DETAIL视图,查看哪个线程,哪个内存上下文占用内存过多。根据这些信息推断出大致问题场景。2.   内存不足在内核发现内存不足的时候会有memory is temporarily unavailable的日志提示。首先观察日志,若日志里是reaching the database memory limitation则说明内核使用内存到达了max_dynamic_memory,则需要根据PV_SESSION_MEMORY_DETAIL视图分析是那个内存上下文占用内存较多,分析出业务场景。若日志里是reaching the OS memory limitation,则表示是操作系统分配内存失败导致,需要看操作系统参数配置以及内存硬件等情况。小结:       生产环境出现内存问题一般会比较棘手,而且release版本内存检测工具以及数据信息使用都比较受限,遇到问题需要通过上述的方案以及手段快速定位出出现内存问题的相关业务场景。有了业务场景,后面通过debug版本使用ASAN地址消毒技术以及Jemalloc Profiling便可以较快的定位出来。原文链接:https://bbs.huaweicloud.com/blogs/184725【推荐阅读】【最新活动汇总】DWS活动火热进行中,互动好礼送不停(持续更新中)  HOT  【博文汇总】GaussDB(DWS)博文汇总1,欢迎大家交流探讨~(持续更新中)【维护宝典汇总】GaussDB(DWS)维护宝典汇总贴1,欢迎大家交流探讨(持续更新中)【项目实践汇总】GaussDB(DWS)项目实践汇总贴,欢迎大家交流探讨(持续更新中)【DevRun直播汇总】GaussDB(DWS)黑科技直播汇总,欢迎大家交流学习(持续更新中)【培训视频汇总】GaussDB(DWS) 培训视频汇总,欢迎大家交流学习(持续更新中)扫码关注我哦,我在这里↓↓↓
  • [SQL] GaussDB(DWS)的stream执行机制
    GaussDB(DWS)架构简介    近期刚刚接触GaussDB(DWS),它是一个shared nothing的分布式架构,下图是一个简化的GaussDB(DWS)架构图。    其中各组件的功能如下:CN(Coordinator Node)为对外服务和协调节点,负责接受客户端连接以及对用户SQL命令解析下发,并收集DN节点执行的结果进行汇总,将结果展现给客户端。DN(Datanode)为内部数据节点,承载内部数据存储及计算单元的功能。GTM(Global Transaction Manager)负责集群全局事务控制,其与Datanode均有本地主备双机功能。分布式执行框架    对应于分布式架构,GaussDB(DWS)提供了分布式执行框架,这也是GaussDB(DWS)中最核心的技术,旨在充分利用DN的资源,尽量将计算下推到DN进行,避免CN成为瓶颈,以提升查询效率和系统扩展性。    分布式执行框架的技术特点如下:CN负责查询请求的解析、基于代价进行优化以及向DN进行任务下发,并收集DN节点执行的结果进行汇总DN上运行执行计划进程,基于本节点存储的数据执行任务执行过程中每个算子都是接收下级算子的数据输入,并向上级算子输出数据。是一个生产者—消费者的流水线工作模型  针对分布式框架,GaussDB(DWS)增加了支撑分布式计划的Stream算子。Stream算子有三种类型:Gather Stream(N:1):每个源节点都将其数据发送给目标节点            Redistribute Stream(N:N):每个源节点将其数据根据连接条件计算Hash值,根据重新计算的Hash值进行分布,发给对应的目标节点    Broadcast Stream(1:N):有一个源节点将其数据发给N个目标节点      下面通过tpch中的Q1和Q2为例,使用explain查看这两个SQL的执行计划来认识一下这几个算子。查看执行计划查看与Gather Stream和Redistribute Stream算子相关的执行计划  以tpch的Q1为例说明,Q1的SQL语句如下SET explain_perf_mode=pretty; --以Oracle-like风格打印执行计划,便于查看EXPLAINSELECT          l_returnflag,          l_linestatus,          SUM(l_quantity) as sum_qty,          SUM (l_extendedprice) as sum_base_price,          SUM (l_extendedprice * (1 - l_discount)) as sum_disc_price,          SUM (l_extendedprice * (1 - l_discount) * (1 + l_tax)) as sum_charge,          AVG(l_quantity) as avg_qty,          AVG (l_extendedprice) as avg_price,          AVG (l_discount) as avg_disc,          COUNT(*) as count_orderFROM          row_engine.lineitemWHERE          l_shipdate <= DATE '1998-12-01' - INTERVAL '3 day'GROUP BY          l_returnflag,          l_linestatusORDER BY          l_returnflag,          l_linestatus;      执行结果如下: id |                 operation                  | E-rows  | E-memory | E-width |  E-costs   ----+--------------------------------------------+---------+----------+---------+-----------   1 | ->  Streaming (type: GATHER)               |       5 |          |     257 | 146811.70   2 |    ->  Sort                                |       5 | 16MB     |     257 | 146811.20   3 |       ->  HashAggregate                    |       6 | 16MB     |     257 | 146811.19   4 |          ->  Streaming(type: REDISTRIBUTE) |      18 | 2MB      |     257 | 146810.87   5 |             ->  HashAggregate              |      18 | 16MB     |     257 | 146809.83   6 |                ->  Seq Scan on lineitem    | 6001622 | 1MB      |      25 | 66788.09(6 rows)                   Predicate Information (identified by plan id)                    ------------------------------------------------------------------------------------    3 --HashAggregate          Skew Agg Optimized by Statistic   6 --Seq Scan on lineitem          Filter: (l_shipdate <= '1998-11-28 00:00:00'::timestamp without time zone)(4 rows)    ====== Query Summary =====    ---------------------------------  System available mem: 9252864KB  Query Max mem: 9473228KB  Query estimated mem: 3123KB(3 rows)    为了便于说明,我在执行计划的每一行的行首加了一个序号。下面对这个计划进行一下说明:从第2行的Sort算子开始直到第6行,是CN下发到在DN上执行的部分;第1行是在CN上执行执行顺序首先从id为6的行开始,对lineitem表执行seqscanid为5的行,对下层扫描得到的数据根据GROUP BY分组键执行hashaggregate操作id为4的行,是一个Redistribute Stream算子,它将在DN上的local数据执行agg后结果,重分布给其他DNid为3的行,各DN收到其他DN上的数据,重新做aggid为2的行,对下层的agg结果进行排序id为1的行,是一个Gather Stream算子,CN节点收到DN返回的结果,汇集后将最终结果展示给客户端    在这个执行计划中,我们看到了两个和Stream算子相关的节点:Gather Stream,用于CN收集DN的结果Redistribute Stream,用于将DN上的数据重分布给其他DN做HashAgg。    这里有两个问题:Q1查询是一个单表查询,为什么需要在DN之间重分布数据呢?tpch的Q1是对lineitem表的单表查询,进行分组聚集计算。因为lineitem表是按照l_orderkey列作为分布列,将数据分布到各DN的。而聚集操作分组键是l_returnflag和l_linestatus,而不 是分布键l_orderkey,所以,属于同一个分组的数据分布在不同的DN上,这就需要各DN重新按照分组键作为分布键,将数据分发给其他DN,使得各DN上拥有相同分组键的数据完成聚集操作。从以上的计划中,可以看到在DN上先做了hashagg,再又重分发给其他DN,再次做hashagg,如下图中的右侧。为什么不是先把数据重分布发给其他DN后,做一次hashagg即可,如下图的左侧       这两个计划的区别在于:如果scan后数据量非常大,而聚集后数据量比较小的情况,就适合用第二个计划,可以减少DN之间的数据流动,降低网络开销。从上面Q1的执行计划中,可以明显看到,Seq Scan on lineitem对应的E-rows为6001622,即seqscan后的数据估计有6001622行,重分布之前HashAggregate的的结果数据估计只有18行,数据量大大减少。根据代价估算,重分布前做一次hashagg的代价,比直接重分布scan的结果的代价要小很多,故选择了重分布前先做一次hashagg。查看与Gather Stream和Broadcast Stream算子相关的执行计划    以tpch的Q2为例说明,Q2的SQL语句如下SET explain_perf_mode=pretty; --以Oracle-like风格打印执行计划,便于查看EXPLAIN     SELECT s_acctbal, s_name, n_name, p_partkey, p_mfgr, s_address, s_phone, s_comment    FROM row_engine.part, row_engine.supplier, row_engine.partsupp, row_engine.nation, row_engine.region    WHERE p_partkey = ps_partkey AND s_suppkey = ps_suppkey AND p_size = 15 AND p_type LIKE 'SMALL%' AND s_nationkey = n_nationkey AND n_regionkey = r_regionkey AND r_name = 'EUROPE ' AND ps_supplycost = ( SELECT MIN(ps_supplycost) FROM row_engine.partsupp, row_engine.supplier, row_engine.nation, row_engine.region WHERE p_partkey = ps_partkey AND s_suppkey = ps_suppkey AND s_nationkey = n_nationkey AND n_regionkey = r_regionkey AND r_name = 'EUROPE ' )ORDER BY s_acctbal DESC, n_name, s_name, p_partkeyLIMIT 100;   执行结果如下: id |                                            operation                                             | E-rows | E-memory | E-width | E-costs      ----+--------------------------------------------------------------------------------------------------+--------+----------+---------+----------   1 | ->  Limit                                                                                        |      3 |          |     192 | 23979.08   2 |    ->  Streaming (type: GATHER)                                                                  |      3 |          |     192 | 23979.08   3 |       ->  Limit                                                                                  |      3 | 1MB      |     192 | 23978.89   4 |          ->  Sort                                                                                |      3 | 16MB     |     192 | 23978.89   5 |             ->  Nested Loop (6,10)                                                               |      3 | 1MB      |     192 | 23978.88   6 |                ->  Nested Loop (7,9)                                                             |      5 | 1MB      |      30 | 2.48   7 |                   ->  Streaming(type: BROADCAST)                                                 |      3 | 2MB      |       4 | 1.30   8 |                      ->  Seq Scan on region                                                      |      1 | 1MB      |       4 | 1.02   9 |                   ->  Seq Scan on nation                                                         |     25 | 1MB      |      34 | 1.08   10 |                ->  Materialize                                                                   |      3 | 16MB     |     170 | 23976.35   11 |                   ->  Streaming(type: REDISTRIBUTE)                                              |      3 | 2MB      |     170 | 23976.34   12 |                      ->  Nested Loop (13,14)                                                     |      3 | 1MB      |     170 | 23976.14   13 |                         ->  Seq Scan on supplier                                                 |  10000 | 1MB      |     144 | 108.33   14 |                         ->  Materialize                                                          |      3 | 16MB     |      34 | 23767.83   15 |                            ->  Streaming(type: REDISTRIBUTE)                                     |      3 | 2MB      |      34 | 23767.82   16 |                               ->  Hash Join (17,21)                                              |      3 | 1MB      |      34 | 23767.71   17 |                                  ->  Hash Join (18,19)                                           |   2538 | 1MB      |      44 | 11916.85   18 |                                     ->  Seq Scan on partsupp                                     | 800000 | 1MB      |      14 | 8532.67   19 |                                     ->  Hash                                                     |    651 | 16MB     |      30 | 2373.01   20 |                                        ->  Seq Scan on part                                      |    651 | 1MB      |      30 | 2373.01   21 |                                  ->  Hash                                                        |    507 | 16MB     |      36 | 11841.97   22 |                                     ->  Subquery Scan on subquery                                |    507 | 1MB      |      36 | 11841.97   23 |                                        ->  HashAggregate                                         |    507 | 16MB     |      42 | 11840.28   24 |                                           ->  Streaming(type: REDISTRIBUTE)                      |    507 | 2MB      |      10 | 11837.75   25 |                                              ->  Hash Join (26,31)                               |    507 | 1MB      |      10 | 11833.54   26 |                                                 ->  Streaming(type: REDISTRIBUTE)                |   2538 | 2MB      |      14 | 11687.60   27 |                                                    ->  Hash Semi Join (28, 29)                   |   2538 | 1MB      |      14 | 11617.80   28 |                                                       ->  Seq Scan on partsupp                   | 800000 | 1MB      |      14 | 8532.67   29 |                                                       ->  Hash                                   |    651 | 16MB     |       4 | 2373.01   30 |                                                          ->  Seq Scan on part                    |    651 | 1MB      |       4 | 2373.01   31 |                                                 ->  Hash                                         |   2001 | 16MB     |       4 | 126.89   32 |                                                    ->  Hash Join (33,34)                         |   2000 | 1MB      |       4 | 126.89   33 |                                                       ->  Seq Scan on supplier                   |  10000 | 1MB      |       8 | 108.33   34 |                                                       ->  Hash                                   |     15 | 16MB     |       4 | 2.97   35 |                                                          ->  Streaming(type: BROADCAST)          |     15 | 2MB      |       4 | 2.97   36 |                                                             ->  Hash Join (37,38)                |      5 | 1MB      |       4 | 2.43   37 |                                                                ->  Seq Scan on nation            |     25 | 1MB      |       8 | 1.08   38 |                                                                ->  Hash                          |      3 | 16MB     |       4 | 1.30   39 |                                                                   ->  Streaming(type: BROADCAST) |      3 | 2MB      |       4 | 1.30   40 |                                                                      ->  Seq Scan on region      |      1 | 1MB      |       4 | 1.02(40 rows)    在这个计划中我们看到对region表的扫描结果使用Broadcast方式广播给其他DN节点,然后在各DN上和nation表做Nestloop连接。    那么什么时候用Broadcast Stream,什么时候用Redistribute Stream呢?    一般来说,Broadcast Stream比较适用于表要广播的表数据量比较小的情况,从上面的计划可以看到Streaming(type: BROADCAST)对应的E-rows 为3,即要广播的数据仅有3条。但是对于小表作为外连接的NonNullable-side时,是不适合用Broadcast Stream的。因为小表全表广播到所有DN后,和Nullable-side的表的数据进行外连接,因为Nullable-side的表在DN上存储的只是集群中该表的部分数据,而NonNullable-side表是所有数据,导致外连接的结果中Nullable-side的NULL行数增加。DN的结果再发给CN进行汇总后,会使整个结果的数据中结果增多。原文链接:https://bbs.huaweicloud.com/blogs/176347【推荐阅读】【最新活动汇总】DWS活动火热进行中,互动好礼送不停(持续更新中)  HOT  【博文汇总】GaussDB(DWS)博文汇总1,欢迎大家交流探讨~(持续更新中)【维护宝典汇总】GaussDB(DWS)维护宝典汇总贴1,欢迎大家交流探讨(持续更新中)【项目实践汇总】GaussDB(DWS)项目实践汇总贴,欢迎大家交流探讨(持续更新中)【DevRun直播汇总】GaussDB(DWS)黑科技直播汇总,欢迎大家交流学习(持续更新中)【培训视频汇总】GaussDB(DWS) 培训视频汇总,欢迎大家交流学习(持续更新中)扫码关注我哦,我在这里↓↓↓
总条数:2746 到第 页
上滑加载中