• [技术干货] 使用Apache IoTDB进行IoT相关开发的架构设计与功能实现(1)
    使用Apache IoTDB进行IoT相关开发的架构设计与功能实现(1)当今社会,物联网技术的发展带来了许多繁琐的挑战,尤其是在数据库管理系统领域,比如实时整合海量数据、处理流中的事件以及处理数据的安全性。例如,应用于智能城市的基于物联网的交通传感器可以实时生成大量的交通数据。据估计,未来5年,物联网设备的数量将达数万亿。物联网产生大量的数据,包括流数据、时间序列数据、RFID数据、传感数据等。要有效地管理这些数据,就需要使用数据库。数据库在充分处理物联网数据方面扮演着非常重要的角色。因此,适当的数据库与适当的平台同等重要。由于物联网在世界上不同的环境中运行,选择合适的数据库变得非常重要。1.什么是IoTDB有的小伙伴可能不了解什么是IoTDB,我先来给大家简单介绍一下:IoTDB即物联网数据库,是一个面向时间序列数据的集成数据管理引擎,可以为用户提供特定的数据收集、存储和分析服务。由于其轻量级结构、高性能和可用特性,以及与Hadoop和Spark ecology的紧密集成,IoTDB满足了物联网工业领域的海量数据集存储、高速数据输入和复杂数据分析的要求。2.IoTDB的体系结构IoTDB套件可以提供真实情况下的数据采集、数据写入、数据存储、数据查询、数据可视化和数据分析等一系列功能,下图显示了IoTDB套件的所有组件带来的整体应用程序架构。如图所示呢,咱们广大用户可以使用JDBC将设备上传感器收集的时间序列数据导入本地/远程IoTDB。这些时间序列数据可以是系统状态数据(如服务器负载和CPU内存等)。消息队列数据、来自应用程序的时间序列数据或数据库中的其他时间序列数据。用户也可以将数据直接写入TsFile(本地或HDFS)。对于写入IoTDB和本地TsFile的数据,大家可以使用TsFileSync工具将TsFile同步到HDFS,从而在Hadoop或Spark数据处理平台上实现异常检测、机器学习等数据处理任务。对于写入HDFS或本地TsFile的数据,用户可以使用TsFile-Hadoop-Connector或TsFile-Spark-Connector来允许Hadoop或Spark处理数据。分析的结果可以用同样的方式写回TsFile。还有呢,IoTDB和TsFile提供了客户端工具,完全可以满足用户以SQL形式、脚本形式和图形形式编写和查看数据的各种需求。3.IoTDB的体系特征灵活部署IoTDB为用户提供了云上一键安装工具、一次解压即可使用的终端工具以及云平台与终端工具之间的桥梁工具(数据同步工具)。存储成本低IoTDB可以达到很高的磁盘存储压缩比,这意味着IoTDB可以用更少的硬件磁盘成本存储同样多的数据。高效的目录结构IoTDB支持来自智能网络设备的复杂时间序列数据结构的高效组织,来自同类设备的时间序列数据的组织,海量复杂时间序列数据目录的模糊搜索策略。高吞吐量读写IoTDB支持上百万低功耗设备的强连接数据访问,支持上面提到的智能联网设备和混合设备的高速数据读写。丰富的查询语义IoTDB支持跨设备和传感器的时间序列数据的时间对齐、时间序列域的计算(频域变换)和时间维度丰富的聚合函数支持。容易上手IoTDB支持类SQL语言、JDBC标准API和易于使用的导入/导出工具。自身和开源生态系统紧密集成IoTDB支持Hadoop、Spark等。分析生态系统和Grafana可视化工具。4.IoTDB的文件类型在IoTDB中呢,需要存储的数据种类繁多。现在我来给大家介绍IoTDB的数据存储策略,方便大家对IoTDB的数据管理有一个直观的了解。首先呢,IoTDB存储的数据分为三类,即数据文件、系统文件和预写日志文件。(1)数据文件数据文件存储用户写入IoTDB的所有数据,IoTDB包含TsFile和其他文件。TsFile存储目录可以用data_dirs来配置相关项目,其他文件通过其他特定的数据来配置项目。为了更好地支持用户的磁盘空间扩展等存储需求,IoTDB支持多种文件目录存储方式进行TsFile存储配置。用户可以将多个存储路径设置为数据存储位置,大家可以指定或自定义目录选择策略。(2)系统文件系统文件包括模式文件,模式文件存储IoTDB中数据的元数据信息。它可以通过配置base_dir配置项目。(3)预写日志文件预写日志文件存储WAL文件。它可以通过配置wal_dir配置项目。(4)设置数据存储目录的示例为了更清楚地理解配置数据存储目录,我在这给出一个示例。存储目录设置中涉及的所有数据目录路径有:base_dir、data_dirs、multi_dir_strategy、wal_dir,分别指系统文件、数据文件夹、存储策略、预写日志文件。配置项的示例如下:base_dir = $IOTDB_HOME/datadata_dirs = /data1/data, /data2/data, /data3/datamulti_dir_strategy=MaxDiskUsableSpaceFirstStrategywal_dir= $IOTDB_HOME/data/wal这段代码并不复杂,相信很多小伙伴都应该可以看懂,我在这里给大家简单说明一下下,设置以上配置后,系统将:将所有系统文件保存在$io TDB _ HOME/data中将TsFile保存在/data1/data、/data2/data、/data3/data中。选择策略是MaxDiskUsableSpaceFirstStrategy,即每次数据写入磁盘时,系统会自动选择剩余磁盘空间最大的目录来写入数据。将WAL数据保存在$IOTDB_HOME/data/wal中这次先为大家介绍到这,下次我再来给小伙伴们分享之前我自己的IoTDB学习经历~
  • [技术干货] 数据库实体联系模型与关系模型
    数据库设计是指根据用户的需求,在某一具体的数据库管理系统上,设计数据库的结构和建立数据库的过程。例如,编程微课是在线编程教育项目,该项目涉及到课程、学生、老师、学习资料等数据,这些数据都要被存储下来,并且能够方便的增加、修改、删除和查询。这就需要规划课程、学生、老师、学习资料等数据构成以及相互之间的关系。因此,规划数据构成及数据间关系,并应用某一具体的数据库管理系统如MySQL构建数据库的过程就是数据库设计。由于项目需求的易变性和数据的复杂性,数据库设计不可能一蹴而就,而只能是一种“反复探寻,逐步求精”的过程。数据库设计步骤如下图所示:  图2-5 数据库设计过程流程图 需求分析阶段主要分析项目涉及的业务活动和数据的使用情况,弄清所用数据的种类、范围、数量以及在业务活动中的存储情况,确定用户对数据库系统的使用要求和各种约束条件等,形成数据库需求说明书。概念结构设计阶段根据数据库需求说明书,创建数据库概念结构,描述概念结构的有力工具是ER模型。ER模型表示的概念结构模型独立于任何一种数据模型,并独立于任何一个具体的数据库管理系统。因此,需要把概念结构设计阶段设计的ER模型转换为关系数据模型二维表结构,此阶段为逻辑结构设计阶段。物理设计阶段是在计算机的物理设备上确定应采取的数据存储结构和存取方法,以及如何分配存储空间等问题。关系数据库物理设计的主要工作是由系统自动完成的,数据库设计者只要关心索引文件的创建即可。验证设计是在上述设计的基础上,收集数据并建立数据库,运行应用任务来验证数据库的正确性和合理性,当发现设计问题时,可能需要对数据库设计进行修改。 实体联系模型(ER图)当前常用的概念数据模型是ER模型。ER模型描述数据库的概念模式,不考虑数据库的逻辑与物理结构,它充分反映现实世界,易于理解,将现实世界的事物以信息结构的形式很方便地表示出来。例如,课程是编程微课的主要内容,课程涉及到老师、学生等对象等实体,进一步分析还涉及到课程视频、课程资料、课程价格等各种数据。在用ER模型对课程分析和描述中,对这些实体以及实体之间的联系给出了确切的定义。ER模型有四个概念,分别是实体、属性、联系、实体集。 实体实体是客观存在并且可以互相区分的事物,可以是人或物,也可以是抽象的概念。在现实世界,实体并不是孤立存在的,实体与实体之间也存在联系。例如,课程与学生之间存在学生学习课程的联系,课程与老师之间存在老师创建课程的联系。 属性每个实体具有的特征称为属性,一个实体可以由若干属性来描述,属性都有其取值范围,称为值集或值域。例如,课程实体可以由课程编号、课程名称、授课老师、类别、简课程介、价格等属性组成。唯一地标识实体的属性或属性组称为实体的关键字。例如,属性值“20180603,Java编程基础,郎老师,编程语言,课程以浅显易懂的语言,以常见的生活场景为案例,带领大家逐步进入计算机编程世界,86”。其中20180603是课程编号的属性值,该编号在在所有的课程实体中是唯一的,该属性就是课程实体的关键字。 联系实体不是孤立存在的,实体之间是有联系的。实体之间的联系可以分为三类:一对一(1:1)、一对多(1:n)和多对多(m:n)。例如,一个老师可以创建多个课程,老师与课程的联系就是一对多的;如果一个老师只能创建一个课程,则老师和课程的联系就是一对一的。在进行问题分析时,要根据客观实际,抓住问题实质进行现实世界的抽象。 实体集具有相同属性的实体的集合称为实体集。在同一实体集中,每个实体的属性及其值域是相同的,但可能取不同的值。例如,所有的课程实体组成课程实体集,所有的老师实体组成老师实体集。 绘制ER图ER图是ER模型的图形化描述。俗话说:一张图胜过千言万语,用ER图可以清晰地描述出ER模型的结构。规范的ER图可以帮助人们对ER模型的统一认识,便于沟通和讨论,有助于工作效率的提高。它使用一组预定义的符号来表示ER模型的实体、属性、联系等概念,这些预先定义的符号已经标准化,从而让全世界的开发人员都可以采用这些符号而不会引起混淆。ER图的基本图素有如下的约定: 图 2-6 ER图的基本图素(1)用长方形表示实体,在框内写上实体名。(2)用椭圆表示实体的属性,并用连接线把实体与属性连接起来,属性如果是实体的关键字,可以用双线椭圆表示。(3)用菱形表示实体间的联系,菱形内写上联系名,用连接线把菱形分别与有关的实体相连接,在连接线旁标上连接的类型,如果联系也有属性,则联系的属性和菱形连接。 图 2-7 用ER图表示的课程管理图2-7所示为用ER图表示一个课程管理,这是一个简化的课程管理模型,课程由老师创建并属于老师,两者之间是一对多的联系。课程与学生直接存在学习的联系,课程与学生是多对多的联系,因此联系也有属性,分别是学生编号和课程编号。双线椭圆表示的属性编号是实体的关键字。通过图2-7可以看出,ER模型是依赖业务运营方式的,它是企业运营方式的信息化描述。企业业务的改变直接影响着ER图的结构和实体间的联系。即使是相同的业务,数据库设计人员侧重分析的数据不同,给出的ER图也可能是不同的。对于设计比较复杂的系统来说,有时为了使ER图简洁明了,在ER图中可以省略属性,只画出实体和联系,将属性以表格的形式另外列出。如图2-8所示,给出的是不包含属性的ER图, 图 2-8 不包含属性的课程管理ER图ER图直观易懂,是系统开发人员和客户之间很好的沟通工具。对于客户来说,它概况了企业运营的方式和各种联系;对于系统开发人员来说,它从概念上描述了一个应用系统数据库的信息组织。因此,如能准确画出企业运营方式的ER图,就意味着搞清楚了企业的业务运营方式,以后可以根据ER图,结合具体的数据库管理系统,把ER图转换为数据库管理系统所能支持的数据模型。这种逐步推进的数据库设计方法已经普遍应用于数据库设计中,画出应用系统的ER图成为数据库设计的一个重要步骤。 关系模型ER图给出了实体联系模型的图形化描述,增强了开发人员与客户的沟通能力。在需求开发阶段ER模型是非常重要的,也是从企业的业务运营方式到概念模型的映射。到了设计阶段。就需要在概念模型的基础上建立关系模型,关系模型是用二维表来表示实体集属性间的关系以及实体间联系的形式化模型。它将用户数据的逻辑结构ER模型归纳为满足一定条件的二维表的形式。ER模型中的一个实体或联系对应一张二维表,ER模型中的实体属性转换为二维表的列,也可称为属性,每个属性的名称称为属性名,也可称为列名。每个属性取值范围称为该属性的域。二维表每个属性或列取值后的一行数据称为二维表的一个元组,也可以称为一条记录。二维表可以包含有限个不重复的记录。图2-9给出了实体“课程”、“老师”转化为关系模型的二维表。每个课程是课程表中的一条记录或一个元组,即一行;同样,每个老师的属性也反映在老师表中的一行;课程表和老师表的联系反映在课程表属性“老师编号”字段上,该字段和老师表的编号字段为同一个字段,因此通过“老师编号”字段可以确定是哪位老师建立的课程。 图 2-9 由实体课程和老师转化的课程和由二维表的的不可重复性可知,关系中必然存在一个属性或属性组,能够唯一标识一个元组,该属性或属性组称为关键字。当关系中存在多个关键字时,称它们为候选关键字,指定其中一个为主关键字,简称主键。设计二维表时,关系应满足如下性质。(1)表中每一列的取值范围都是相同的,也就是数据类型相同。(2)不同列的取值范围可以相同,但列名称不能相同。(3)表中列的次序可以变换,不影响关系的实际意义。(4)同一个表中,不允许存在两个完全相同的元组,这是集合的一个基本性质,保证了关系中元组的唯一性。(5)行的次序可以任意交换。(6)关系中的任何一个属性值都必须是不可分的元素。
  • 戳视频了解数据仓库开发者认证优势
    戳链接了解认证详情:cid:link_0videovideovideovideovideovideo
  • [优秀实践] openGauss-MySQL在线迁移工具支持迁移对象开发合作项目实践心得
    首先十分感谢我的导师汤德佑副教授带领我参与到openGauss-MySQL在线迁移工具支持迁移对象开发项目中,让我第一次体验到正式的企业项目。同时也十分荣幸能参与到华为鲲鹏众智项目中,能为鲲鹏生态的建设出一份微薄之力。项目概要为了完善openGauss在数据库领域的生态,华为openGauss3.0.0版本发布的工具链中新增的迁移工具Chameleon,可实现MySQL5.5+版本到openGauss2.1.0+版本的数据迁移,即把数据库的表数据进行迁移,具有灵活易用、操作简便等特点。但该工具目前无法将数据库对象——视图、触发器、自定义函数、自定义存储过程进行迁移。视图、触发器、自定义函数、自定义存储过程作为数据库重要的组成成员,在业务系统开发中使用极其广泛,只有能实现上述对象的迁移才能方便用户实现全方位的自动化数据库切换。本项目将对迁移工具Chameleon进行功能扩展,设计与实现在离线迁移过程中对视图、触发器、自定义函数、自定义存储过程的支持。将MySQL端的这四类数据库对象通过Chameleon工具在openGauss端进行重演,实现兼容。方案设计根据对象迁移的特点,我们分析了数据库对象的迁移任务,得出实现的框架如下:抽取MySQL对象。驱动连接到MySQL,提取对象元数据。SQL语句翻译。除了创建视图语句、创建触发器语句、创建自定义函数语句、创建存储过程语句的翻译,更复杂的是视图涉及的select语句,触发器体涉及的及INSERT子句、UPDATE子句、DELETE子句以及控制流语句,自定义函数体和存储过程体涉及的了 DDL 语句、 DML 语句、Transaction 语句、 Compound 语句、Administraion语句等几乎涵盖所有MySQL的SQL语句的翻译。openGauss端重演。将翻译后的openGauss风格的对象创建语句重演到openGauss。记录迁移结果。语句翻译过程中难免遇到无法兼容的字段或语句,因此有必要记录对象迁移记录,以备用户查阅,包括成功与否、翻译前后语句对比等。 其中,SQL语句的翻译为本项目的重点攻克难点,在项目调研初期,我们调研了多种SQL词法语法解析器,通过多方面的对比,我们最后决定采用基于Druid工具,在Chameleon中实现MySQL语法到openGauss语法的SQL语句翻译。通过改写Druid SQL Parser的AST树的输出以达到SQL语句翻译,为此我们也开发了仓库openGauss-tools-sql-translator,通过调用openGauss-tools-sql-translator,chameleon完成MySQL语法到openGauss语法的转换。 心得体会从项目的初期调研到详细方案的确定,再到具体的开发编程(比如繁琐的SQL语句翻译及校验),还有最后的测试、解决每个问题单,我都参与其中。通过和团队成员的分工合作、默契配合,我们如期交付了项目。在这个过程中我学到了非常多的知识,比如我能更加熟练地使用git工具,对各个数据库的SQL语句语法差异有了更清晰地认识,团队协作能力、项目管理能力、编程能力等都有了很大的提高,同时,通过切身体验与企业合作进行开发的工作流程,极大丰富了我的项目实践经验。 鲲鹏众智计划提供了一个很好的平台让我们为扩大国产生态影响提供智慧和力量。希望之后我还有机会参与到其他的鲲鹏众智项目中,也相信将会有越来越多的优秀人才加入到鲲鹏的生态建设,一起为鲲鹏生态的繁荣发展做贡献。华南理工大学-软件学院-TxDB实验室-何馨誉指导老师:汤德佑
  • [技术干货] 【第四届openGauss征文活动参赛作品】openGauss 3.0学习第四天:闪回恢复
        闪回概念是Oracle最先提出来的,其本质是为了回退错误操作产生的,避免人为的“灾难”,并且要能够快速回退。    闪回恢复功能是数据库恢复技术的一环,可以有选择性的撤销一个已提交事务的影响,将数据从人为不正确的操作中进行恢复。在采用闪回技术之前,只能通过备份恢复、PITR等手段找回已提交的数据库修改,恢复时长需要数分钟甚至数小时。采用闪回技术后,恢复已提交的数据库修改前的数据,只需要秒级,而且恢复时间和数据库大小无关。openGauss的闪回分为一下两类:闪回查询闪回表一、闪回查询    基于MVCC多版本的数据恢复:适用于误删除、误更新、误插入数据的查询和恢复,用户通过配置旧版本保留时间,并执行相应的查询或恢复命令,查询或恢复到指定的时间点或CSN点。前提条件(下面三个缺一不可)undo_retention_time:参数用于设置undo旧版本的保留时间。undo_zone_count=16384 ---代表的时候undo log的一种资源个数enable_default_ustore_table=on --默认指定用户创建表时使用USTORE存储引擎。存储引擎:UstoreUstore存储引擎将最新版本的“有效数据”和历史版本的“垃圾数据”分离存储。将最新版本的“有效数据”存储在数据页面上,并单独开辟一段UNDO空间,用于统一管理历史版本的“垃圾数据”,因此数据空间不会由于频繁更新而膨胀,“垃圾数据”集中回收效率更高。设置参数命令如下:gs_guc set -N all -I all -c "undo_retention_time=2000s"gs_guc set -N all -I all -c "undo_zone_count=16384"gs_guc set -N all -I all -c "enable_default_ustore_table=on"设置完重启数据库:gs_om -t restart重启后验证参数:openGauss=# show undo_retention_time;undo_retention_time---------------------2000s(1 row)openGauss=# show undo_zone_count;undo_zone_count-----------------16384(1 row)openGauss=# show enable_default_ustore_table;enable_default_ustore_table-----------------------------on(1 row)openGauss=# 下面开始演示:创建表:openGauss=# CREATE TABLE flashback_tab(id int not null,name text not null);openGauss-# CREATE TABLE查看表存储引擎:openGauss=# \d+ flashback_tab;Table "public.flashback_tab"Column | Type | Modifiers | Storage | Stats target | Description--------+---------+-----------+----------+--------------+-------------id | integer | not null | plain | |name | text | not null | extended | |Has OIDs: noOptions: orientation=row, compression=no, storage_type=USTORE, toast.storage_type=USTORE插入数据:insert into flashback_tab values (1,'ybj');查询当前日期;openGauss=# select current_timestamp;pg_systimestamp-------------------------------2022-09-29 01:13:32.691158+08(1 row)查询数据:openGauss=# select * from flashback_tab;id | name----+------1 | ybj(1 row)插入数据:openGauss=# insert into flashback_tab values (2,'yangkai');INSERT 0 1查询结果:openGauss=# select * from flashback_tab;id | name----+---------1 | ybj2 | yangkai(2 rows)---基于timestamp的闪回查询:openGauss=# SELECT * FROM flashback_tab TIMECAPSULE TIMESTAMP to_timestamp ('2022-09-29 01:13:32.691158', 'YYYY-MM-DD HH24:MI:SS.FF');id | name----+------1 | ybj(1 row)---查询timestamp对应的CSNopenGauss=# select snptime,snpcsn from gs_txn_snapshot where snptime between '2022-09-29 01:13:32.691158' and ' 2022-09-29 01:15:24.921426'openGauss-# ;snptime | snpcsn-------------------------------+--------2022-09-29 01:13:32.841985+08 | 21122022-09-29 01:13:35.87922+08 | 21142022-09-29 01:13:38.924031+08 | 21162022-09-29 01:13:41.966247+08 | 21182022-09-29 01:13:45.013022+08 | 21202022-09-29 01:13:48.04741+08 | 21222022-09-29 01:13:51.078498+08 | 21242022-09-29 01:13:54.101686+08 | 21262022-09-29 01:13:57.123891+08 | 21282022-09-29 01:14:00.147156+08 | 21302022-09-29 01:14:03.169433+08 | 21322022-09-29 01:14:06.192879+08 | 21342022-09-29 01:14:09.216963+08 | 21362022-09-29 01:14:12.240249+08 | 21382022-09-29 01:14:15.26606+08 | 21402022-09-29 01:14:18.288409+08 | 21422022-09-29 01:14:21.309986+08 | 21442022-09-29 01:14:24.332801+08 | 21462022-09-29 01:14:27.378095+08 | 21482022-09-29 01:14:30.416234+08 | 21512022-09-29 01:14:33.460251+08 | 21532022-09-29 01:14:36.508431+08 | 2155---基于CSN的闪回查询openGauss=# SELECT * FROM flashback_tab TIMECAPSULE CSN 2116;id | name----+------1 | ybj(1 row)二、闪回表    基于类似windows系统回收站的恢复:适用于误DROP、误TRUNCATE的表的恢复。用户通过配置回收站开关,并执行相应的恢复命令,可以将误DROP、误TRUNCATE的表找回。前置条件:开启回收站、设置回收站对象保留时间enable_recyclebin=on 启用回收站。 recyclebin_retention_time=30min 参数用于设置回收站对象保留时间,超过该时间的回收站对象将被自动清理。命令如下: gs_guc set -N all -I all -c "enable_recyclebin=on" gs_guc set -N all -I all -c "recyclebin_retention_time=30min"设置完重启数据库:gs_om -t restart[omm@huaweidb ~]$ gsql -d postgres -p 15400gsql ((openGauss 3.0.0 build 02c14696) compiled at 2022-04-01 18:12:34 commit 0 last mr )Non-SSL connection (SSL connection is recommended when requiring high-security)Type "help" for help.openGauss=# show recyclebin_retention_time;recyclebin_retention_time---------------------------30min(1 row)openGauss=# show enable_recyclebin;enable_recyclebin-------------------on(1 row)openGauss=# 下面开始操作演示:[omm@huaweidb ~]$ gsql -d postgres -p 15400gsql ((openGauss 3.0.0 build 02c14696) compiled at 2022-04-01 18:12:34 commit 0 last mr )Non-SSL connection (SSL connection is recommended when requiring high-security)Type "help" for help.--查询当前表openGauss=# select * from flashback_tab ;id | name----+---------1 | ybj2 | yangkai(2 rows)--truncate表openGauss=# truncate flashback_tab;TRUNCATE TABLEopenGauss=# select * from flashback_tab ;id | name----+------(0 rows)---闪回表openGauss=# timecapsule table flashback_tab to before truncate;TimeCapsule Table--查询结果openGauss=# select * from flashback_tab ;id | name----+---------1 | ybj2 | yangkai(2 rows)--drop 表openGauss=# drop table flashback_tab;DROP TABLEopenGauss=# select * from flashback_tab;ERROR: relation "flashback_tab" does not exist on dn_6001LINE 1: select * from flashback_tab;^--查看回收站:openGauss=# sELECT rcyname,rcyoriginname,rcytablespace FROM GS_RECYCLEBIN;rcyname | rcyoriginname | rcytablespace------------------------------+----------------------+---------------BIN$3C7C4EB8014$30BE34C8==$0 | pg_toast_32783_index | 0BIN$3C7C4EB8012$30BE3AA0==$0 | pg_toast_32783 | 0BIN$3C7C4EB800F$30BE40B0==$0 | flashback_tab | 0BIN$3C7C4EB800F$30BEA658==$0 | flashback_tab | 0BIN$3C7C4EB8014$30BEAF78==$0 | pg_toast_32783_index | 0BIN$3C7C4EB8012$30BEB560==$0 | pg_toast_32783 | 0(6 rows)--通过回收站闪回表并命名flashback_yangkai;openGauss=# timecapsule table flashback_tab to before drop rename to flashback_yangkai;TimeCapsule TableopenGauss=# select * from flashback_yangkai;id | name----+---------1 | ybj2 | yangkai(2 rows)三、总结    openGauss 闪回非常强大,可以秒杀国产大部分数据库,基本可以满足日常运维需求,希望后期可以推出类似oracle数据库级别闪回、snapshot standby就完美了。
  • [技术干货] 【第四届openGauss征文活动参赛作品】openGauss学习笔记-从0开始(单机安装)
    缘起,2021年底有个客户计划采购华为的分布式数据库GuassDB(openGauss),于是去官方翻了翻文档,发现有点难以理解,我本人之前对PG派系的数据库一无所知,看上去就更吃力。后来客户选择了其他厂商的分布式数据库也就没有进行学习研究。       第二次接触openGauss是通过MogDB的征文活动,不仅可以学习MogDB数据库,还能赚几包烟钱,写了十多篇学习笔记,对MogDB有了一个大致的了解,因为MogDB是openGauss的一个商业发行版本,在学习的时候也去翻阅了一些openGauss的支持,所有也算间接的学习了openGauss。       第三次接触就是现在和将来,感谢官方推出了这次的征文活动,既可以学习opengauss又可以加深自己对MogDB的了解,学习的过程还能顺便买一包烟。本人也想通过这两次学习,可以进一步学习华为的分布式数据库GuassDB for openGauss。       高可用、高性能、主从、备份恢复等概念所有的关系型数据基本一致,这里学习还是本着先实战再总结的思路出发,附一张我本人openGauss的学习图谱,IT圈子里一直有一个PG和Mysql孰高孰低的讨论,为什么总是对比这两个关系型数据库,个人认为因为他们量级差不多,并且都是开源,很多理念都有一些相同的架构。安装企业版1、准备Linux服务器这里就不在赘述Linux的安装和配置了,可以参考《https://www.modb.pro/db/453770》,我的Linux操作系统是CentOS,选择操作系统的时候候去官网查看支持的操作系统。2、下载openGauss数据库企业版下载地址:cid:link_03、上传包并解压[root@localhost ~]# cd /soft/[root@localhost soft]# lsopenGauss-3.0.0-CentOS-64bit-all.tar.gz[root@localhost soft]# tar -zxvf openGauss-3.0.0-CentOS-64bit-all.tar.gzopenGauss-3.0.0-CentOS-64bit-cm.tar.gzopenGauss-3.0.0-CentOS-64bit-om.tar.gzopenGauss-3.0.0-CentOS-64bit.tar.bz2openGauss-3.0.0-CentOS-64bit-cm.sha256openGauss-3.0.0-CentOS-64bit-om.sha256openGauss-3.0.0-CentOS-64bit.sha256upgrade_sql.tar.gzupgrade_sql.sha2564、安装依赖包yum install libaio-devel flex bison ncurses-devel glibc-devel patch redhat-lsb-core readline-devel libnsl python35、关闭防火墙systemctl status firewalld.servicesystemctl stop firewalld.servicesystemctl status firewalld.servicesystemctl disable firewalld.service6、禁用selinuxvi /etc/selinux/config#修改“SELINUX”的值“disabled”#需要重启生效,也可以使用命令临时生效:setenforce 07、配置本机root到root的互信[root@localhost ~]# ssh-keygen -t rsa[root@localhost ~]# cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys#使用ssh命令不需要输入密码的时候就表示互信成功[root@localhost .ssh]# ssh 172.20.10.8Last login: Wed Sep 14 17:40:53 2022 from opengauss8、创建安装openGauss的配置文件#单节点安装[root@opengauss soft]# cat cluster_config.xml9、解压可执行程序所在的包tar -zxvf openGauss-3.0.0-CentOS-64bit-all.tar.gztar -zxvf openGauss-3.0.0-CentOS-64bit-om.tar.gz#会解压出script文件夹10、执行预安装#进入刚才解压得到的script文件夹cd /soft/script./gs_preinstall -U omm -G dbgrp -X /soft/cluster_config.xml#期间只需要输入是否需要创建omm用户,选择yes,并且输入omm的密码[root@opengauss script]# ./gs_preinstall -U omm -G dbgrp -X /soft/cluster_config.xmlParsing the configuration file.Successfully parsed the configuration file.Installing the tools on the local node.Successfully installed the tools on the local node.Setting host ip envSuccessfully set host ip env.Are you sure you want to create the user[omm] (yes/no)? yesPlease enter password for cluster user.Password:Please enter password for cluster user again.Password:Generate cluster user password files successfully.Successfully created [omm] user on all nodes.Preparing SSH service.Successfully prepared SSH service.Checking OS software.Successfully check os software.Checking OS version.Successfully checked OS version.Creating cluster's path.Successfully created cluster's path.Set and check OS parameter.Setting OS parameters.Successfully set OS parameters.Warning: Installation environment contains some warning messages.Please get more details by "/soft/script/gs_checkos -i A -h opengauss --detail".Set and check OS parameter completed.Preparing CRON service.Successfully prepared CRON service.Setting user environmental variables.Successfully set user environmental variables.Setting the dynamic link library.Successfully set the dynamic link library.Setting Core fileSuccessfully set core path.Setting pssh pathSuccessfully set pssh path.Setting Cgroup.Successfully set Cgroup.Set ARM Optimization.No need to set ARM Optimization.Fixing server package owner.Setting finish flag.Successfully set finish flag.Preinstallation succeeded.11、执行安装切换到omm用户,期间要输入数据库的密码su - omm[root@opengauss script]# su - ommLast login: Wed Sep 14 18:50:50 CST 2022[omm@opengauss ~]$ gs_install[GAUSS-50001] : Incorrect parameter. Parameter '-X' is required.[omm@opengauss ~]$ ^C[omm@opengauss ~]$ gs_install -X /soft/cluster_config.xmlParsing the configuration file.Check preinstall on every node.Successfully checked preinstall on every node.Creating the backup directory.Successfully created the backup directory.begin deploy..Installing the cluster.begin prepare Install Cluster..Checking the installation environment on all nodes.begin install Cluster..Installing applications on all nodes.Successfully installed APP.begin init Instance..encrypt cipher and rand files for database.Please enter password for database:Please repeat for database:begin to create CA cert filesThe sslcert will be generated in /opt/random/install/app/share/sslcert/omNO cm_server instance, no need to create CA for CM.Cluster installation is completed.Configuring.Deleting instances from all nodes.Successfully deleted instances from all nodes.Checking node configuration on all nodes.Initializing instances on all nodes.Updating instance configuration on all nodes.Check consistence of memCheck and coresCheck on database nodes.Configuring pg_hba on all nodes.Configuration is completed.Successfully started cluster.Successfully installed application.end deploy..[omm@opengauss ~]$12、连接数据库[omm@opengauss ~]$ gsql -d postgres -p 15400gsql ((openGauss 3.0.0 build 02c14696) compiled at 2022-04-01 18:12:34 commit 0 last mr )Non-SSL connection (SSL connection is recommended when requiring high-security)Type "help" for help.openGauss=#
  • [技术干货] 【第四届openGauss征文活动参赛作品】Ansible自动化部署安装openGauss3.1企业版单机
    一、背景由于IT建设的快速发展,当数据中心业务突增,需要快速部署多套的数据库时,给运维工作带来了不小的压力和挑战,作为运维人员该如何面对面对这种困境呢?另外由于个人的习惯等也会导致所部署的环境不一定与规划完全一致,那么对以后的运维也会产生一定的负面影响。很显然,这种传统的方式已经无法适应当前的情景了,自动化运维应运而生,ansible在自动化运维和devops 的应用中崭露头角。本文基于ansible工具实现 openGauss 的一键批量部署,传统的部署方式是先修改系统配置、安装依赖包、创建omm用户和组、配置环境变量、上传安装包以及解压、安装等步骤。按照这个流程和思路,我们把这些操作弄成剧本编排(playbook),交给ansible来做。二、环境准备2台主机:一台为Ansible的管理主机(10.10.10.142),操作系统为CentOS Linux release 7.9.2009 (Core);另外一台为需要部署openGauss的主机(10.10.10.150),操作系统为CentOS Linux release 7.9.2009 (Core)。三、具体实施步骤3.1、安装ansible–在10.10.10.142上进行安装Ansibleyum install epel-release -yyum install ansible –y–配置/etc/ansible/ansible.cfg# grep -v '^#' /etc/ansible/ansible.cfg |sed '/^$/d' [defaults] host_key_checking = False callback_whitelist = timer,profile_roles,log_plays log_path = /var/log/ansible.log strategy = free bin_ansible_callbacks = True [inventory] [privilege_escalation] [paramiko_connection] [ssh_connection] [persistent_connection] [accelerate] [selinux] [colors] [diff] [callback_log_plays] log_folder=/tmp/ansible/hosts/ 3.2、配置主机清单修改主机清单/etc/ansible/hosts,添加主机列表# cat /etc/ansible/hosts [openGaussdb] 10.10.10.150 ansible_ssh_user=root ansible_ssh_pass=123456 ###10.10.10.150为本次需要安装openGauss的主机 3.3、测试主机连通性# ansible -i /etc/ansible/hosts openGaussdb -m ping 3.4、创建相关目录[root@cs79-mysql:~]# cd /etc/ansible/roles/[root@cs79-mysql:/etc/ansible/roles]# mkdir -p openGauss_Install/{files,vars,tasks,templates}[root@cs79-mysql:/etc/ansible/roles]# tree openGauss_Install/openGauss_Install/├── files├── tasks├── templates└── vars4 directories, 0 files上述目录主要作用如下:files:存放需要同步到异地服务器的安装文件或者配置文件;tasks:openGauss安装过程需要进行的执行的任务;templates:用于执行openGauss安装的模板文件,一般为脚本;vars:安装openGauss定义的变量;3.5、下载openGauss软件包到files目录安装包下载地址:https://opengauss.org/zh/download.html[root@cs79-mysql:/etc/ansible/roles]# cd openGauss_Install/files/[root@cs79-mysql:/etc/ansible/roles/openGauss_Install/files]# # wget https://opengauss.obs.cn-south-1.myhuaweicloud.com/3.1.0/x86/openGauss-3.1.0-CentOS-64bit-all.tar.gz–2022-10-09 21:42:01-- https://opengauss.obs.cn-south-1.myhuaweicloud.com/3.1.0/x86/openGauss-3.1.0-CentOS-64bit-all.tar.gzResolving opengauss.obs.cn-south-1.myhuaweicloud.com (opengauss.obs.cn-south-1.myhuaweicloud.com)… 121.37.63.38, 139.159.208.64, 139.159.208.243Connecting to opengauss.obs.cn-south-1.myhuaweicloud.com (opengauss.obs.cn-south-1.myhuaweicloud.com)|121.37.63.38|:443… connected.HTTP request sent, awaiting response… 200 OKLength: 123022609 (117M) [application/gzip]Saving to: ‘openGauss-3.1.0-CentOS-64bit-all.tar.gz’100%[==================================================================================================================================================================================================>] 123,022,609 38.4MB/s in 3.2s2022-10-09 21:42:04 (37.1 MB/s) - ‘openGauss-3.1.0-CentOS-64bit-all.tar.gz’ saved [123022609/123022609]3.6、创建变量文件[root@cs79-mysql:~]# vi /etc/ansible/roles/openGauss_Install/vars/main.yml#安装包名称openGauss_software: openGauss-3.1.0-CentOS-64bit-all.tar.gz#解压目录install_dir: /opt/software/openGauss#omm用户密码omm_password: openGauss@123#数据库密码db_password: openGauss@1233.7、创建安装时需要的xml模板[root@cs79-mysql:~]# vi /etc/ansible/roles/openGauss_Install/templates/cluster_config.j2 3.8、创建任务文件[root@cs79-mysql:~]# vi /etc/ansible/roles/openGauss_Install/tasks/main.yml - name: 关闭防火墙 shell: systemctl disable firewalld.service && systemctl stop firewalld.service ignore_errors: true tags: 01_os_syscfg - name: 关闭selinux shell: sed -i 's/SELINUX=enforcing/SELINUX=disabled/g' /etc/selinux/config ignore_errors: true tags: 01_os_syscfg - name: 设置时区 shell: timedatectl set-timezone Asia/Shanghai tags: 01_os_syscfg - name: 关闭RemoveIPC lineinfile: path: /etc/systemd/logind.conf state: present line: "RemoveIPC=no" tags: 01_os_syscfg - name: 重启systemd-logind服务 shell: systemctl daemon-reload && systemctl restart systemd-logind tags: 01_os_syscfg - name: 创建组 group: name=dbgrp gid=2000 tags: 02_user_add - name: 创建用户 user: name=omm uid=2000 group=dbgrp tags: 02_user_add - name: 修改密码 shell: echo "{{omm_password}}" | passwd --stdin omm tags: 02_user_add - name: 新建目录 file: path="{{item}}" state=directory mode=0755 owner=omm group=dbgrp with_items: - /opt/software/ - /opt/software/openGauss tags: 03_unzip_db - name: 上传安装包 copy: src={{openGauss_software}} dest={{install_dir}} owner=omm group=dbgrp mode=0644 tags: install tags: 03_unzip_db - name: "解压软件包" shell: cd {{install_dir}} && tar -zxvf *all.tar.gz && tar -zxvf *om.tar.gz become: yes become_user: omm tags: 03_unzip_db - name: "安装依赖包" yum: name="libaio-devel,flex,bison,ncurses-devel,glibc-devel,patch,redhat-lsb-core,python3,bzip2,readline-devel,net-tools,tar,gcc,gcc-c++" state=installed tags: 04_os_yum - name: 替换python3版本 shell: mv /usr/bin/python /usr/bin/python2_bak && ln -s /usr/bin/python3 /usr/bin/python && python -V tags: 05_replace_py - name: 配置xml文件 template: src=cluster_config.j2 dest={{install_dir}}/clusterconfig.xml tags: 06_config_xml - name: 执行预安装脚本 shell: '{{install_dir}}/script/gs_preinstall -U omm -G dbgrp -X {{install_dir}}/clusterconfig.xml --non-interactive' register: preinstall tags: 07_pre_install - debug: var=preinstall.stdout_lines ignore_errors: true tags: 07_pre_install - name: 检查预安装环境 shell: '{{install_dir}}/script/gs_checkos -i A -h {{ ansible_hostname }} --detail' register: checkos tags: 08_check_os - debug: var=checkos.stdout_lines ignore_errors: true tags: 08_check_os - name: 更改权限 shell: chmod -R 755 {{install_dir}} tags: 09_gs_install - name: 执行gs_install shell: su - omm -c "{{install_dir}}/script/gs_install -X {{install_dir}}/clusterconfig.xml --gsinit-parameter="--pwpasswd={{db_password}}"" register: gsinstall tags: 09_gs_install - debug: var=gsinstall.stdout_lines ignore_errors: true tags: 09_gs_install - name: 启动数据库 shell: ss -anpt|grep 26000 && su - omm -c "gs_ctl restart " || su - omm -c "gs_om -t start " tags: 10_db_start - name: "登录数据库" shell: ss -anpt|grep 26000 && su - omm -c "gsql -d postgres -p26000 -r -l" tags: 10_db_start 3.9、创建剧本调用文件[root@cs79-mysql:~]# vi /etc/ansible/playbook/InstallopenGauss.yml - name: Install openGauss hosts: openGaussdb remote_user: root roles: - openGauss_Install 四、执行自动化安装4.1、校验语法# ansible-playbook -C /etc/ansible/playbook/InstallopenGauss.yml 校验语法通过后,执行下一步安装4.2、自动化安装openGauss# ansible-playbook /etc/ansible/playbook/InstallopenGauss.yml 4.3、安装完成后验证至此,整个自动化部署openGauss完毕,如果有多台机器需要部署,添加主机相关信息到/etc/ansible/hosts,再执行ansible-playbook即可。
  • [技术干货] 【第四届openGauss征文活动参赛作品】openGauss的管理与维护(上)
    笔者对openGauss的了解:①openGauss是一款高性能、高安全、高可靠的企业级开源关系型数据库。它具有多核高性能、智能运维等特色,凝聚了华为数据库内核研发团队多年的经验。②openGauss是一款开源关系型数据库管理系统。其内核源自PostgreSQL,深度融合华为在数据库领域多年的经验,结合企业级场景需求,持续构建竞争力特性。同时openGauss也是一个开源的数据库平台,鼓励社区贡献、合作。③其具有高性能、高安全、易运维、全开放的特点,非常不错。本文笔者主要讲述openGauss的管理维护原因:为保证openGauss数据库中的数据安全,满足日常业务对数据库软件的稳定性要求、可靠性要求、高效性要求,必须对数据库进行定期的管理维护。检查openGauss状态    通过openGauss提供的工具查询数据库和实例状态,确认数据库和实例都处于正常的运行状态,可以对外提供数据服务。检查实例状态gs_check -U omm -i CheckClusterState检查参数postgres=# SHOW parameter_name;修改参数gs_guc [ set | reload ] [-N NODE-NAME] [-I INSTANCE-NAME | -D DATADIR] -c "parameter“检查锁信息    锁机制是数据库保证数据一致性的重要手段,检查相关信息可以检查数据库的事务和运行状况。查询数据库中的锁信息。postgres=# SELECT * FROM pg_locks;查询等待锁的线程状态信息。postgres=# SELECT * FROM pg_thread_wait_status WHERE wait_status = 'acquire lock';查询等待锁的事件信息。postgres=# SELECT node_name, thread_name, tid, wait_status, query_id FROM pg_thread_wait_status WHERE wait_status = 'acquire lock';结束系统进程:查找正在运行的系统进程,然后使用kill命令结束此进程。统计事件数据    SQL语句长时间运行会占用大量系统资源,用户可以通过查看事件发生的时间,占用内存大小来了解现在数据库运行状态。查询事件的时间:查询事件的线程启动时间、事务启动时间、SQL启动时间以及状态变更时间。postgres=# SELECT backend_start,xact_start,query_start,state_change FROM pg_stat_activity;查询当前服务器的会话计数信息postgres=# SELECT count(*) FROM pg_stat_activity;SQL报告检查    使用EXPLAIN语句查看执行计划。备份    数据备份重于一切,日常应检查备份执行情况,并检查备份有效性,确保备份能够保障数据安全,备份安全加密也应兼顾。导出指定用户gs_dump dbname -p port -f out.sql -U user_name -W password导出tablegs_dump dbname -p port -t table_name -f out.sql基本信息检查    基本信息包括版本、组件、补丁集等信息,定期检查数据库信息并登记在案是数据库生命周期管理的重要内容之一。版本信息postgres=# SELECT version();容量检查postgres=# SELECT pg_table_size('table_name'); postgres=# SELECT pg_database_size('database_name');
  • [技术干货] 【第四届openGauss征文活动参赛作品】openGauss 3.0一主两备安装
    前期规划:环境:麒麟V10系统 + openGauss 3.0IP主机名主192.168.6.201ccf10备1192.168.6.202ccf11备2192.168.6.203ccf12目录名称所属用户目录路径权限数据库软件目录omm/opt/openGauss755数据库数据目录omm/data/openGauss700数据库备份目录omm/data/backup700数据库归档目录omm/data/archive_wals700数据库core_dump目录omm/data/core_pattern7001.查看系统环境[root@ccf10 ~]# lscpu架构: x86_64...型号名称: Intel(R) Core(TM) i7-4810MQ CPU @ 2.80GHz[root@ccf10 ~]#[root@ccf10 ~]# cat /etc/os-releaseNAME="Kylin Linux Advanced Server"VERSION="V10 (Sword)"ID="kylin"VERSION_ID="V10"PRETTY_NAME="Kylin Linux Advanced Server V10 (Sword)"ANSI_COLOR="0;31"2.安装前环境配置2.1主机名和hosts配置[root@ccf10 ~]# hostnamectl set-hostname ccf10--hostnamectl set-hostname ccf11--hostnamectl set-hostname ccf12cat >> /etc/hosts <192.168.6.201 ccf10192.168.6.202 ccf11192.168.6.203 ccf12EOF2.2关闭防火墙[root@ccf10 ~]# systemctl status firewalld.service[root@ccf10 ~]# systemctl stop firewalld.service[root@ccf10 ~]# systemctl disable firewalld.service2.3selinux设置[root@ccf10 ~]#sed -i 's/SELINUX\=enforcing/SELINUX\=disabled/g' /etc/selinux/config2.4关闭透明大页transparent_hugepage[root@ccf10 ~]# sed -i 's/quiet/quiet transparent_hugepage=never numa=off/' /etc/default/grub[root@ccf10 ~]# grub2-mkconfig -o /boot/grub2/grub.cfg[root@ccf10 ~]# reboot[root@ccf10 ~]# cat /sys/kernel/mm/transparent_hugepage/enabled[root@ccf10 ~]# grep -i huge /proc/meminfo2.5IPC参数设置[root@ccf10 ~]# echo "RemoveIPC=no">> /etc/systemd/logind.conf[root@ccf10 ~]# echo "RemoveIPC=no">> /usr/lib/systemd/system/systemd-logind.service[root@ccf10 ~]# systemctl daemon-reload[root@ccf10 ~]# systemctl stop systemd-logind[root@ccf10 ~]# systemctl start systemd-logind2.6内核参数调整/etc/sysctl.conf添加以下内容[root@ccf10 ~]# cat >> /etc/sysctl.conf <net.ipv4.tcp_max_tw_buckets=10000net.ipv4.tcp_tw_reuse = 1net.ipv4.tcp_tw_recycle = 1net.ipv4.tcp_keepalive_probes=9net.ipv4.tcp_keepalive_intvl=30net.ipv4.tcp_retries1 = 5 #默认为3net.ipv4.tcp_syn_retries = 5 #默认为6net.ipv4.tcp_synack_retries = 5net.ipv4.tcp_retries2 = 12 #默认为15net.ipv4.tcp_rmem = 8192 250000 16777216vm.overcommit_memory = 0net.ipv4.tcp_wmem = 8192 250000 16777216net.core.wmem_max = 21299200net.core.rmem_max = 21299200net.core.wmem_default = 21299200net.core.rmem_default = 21299200net.ipv4.tcp_syncookies = 1net.ipv4.tcp_sack = 1net.ipv4.tcp_timestamps = 1fs.aio-max-nr=1048576fs.file-max= 76724600kernel.sem = 4096 2147483647 2147483646 512000kernel.shmall = 1048576 # page, 80% MEMkernel.shmmax = 4294967296 # bytes, 80% MEMkernel.shmmni = 819200net.core.netdev_max_backlog = 65535net.core.somaxconn = 65535net.ipv4.tcp_fin_timeout = 60vm.swappiness = 0net.ipv4.ip_local_port_range = 26000 65535fs.nr_open = 20480000EOF2.7时区配置,如果不是CST建议调整[root@ccf10 ~]# cat /etc/localtime如果不是CST建议调整:timedatectl set-timezone 'Asia/Shanghai'datehwclock -r2.8创建用户与目录groupadd -g 1000 dbgrpuseradd -u 1000 omm -g dbgrpecho "Omm@1000"|passwd omm --stdinmkdir -p /data/{openGauss,backup,archive_wals,core_pattern}chmod 700 /data/{openGauss,backup,archive_wals,core_pattern}chown -R omm:dbgrp /data/{openGauss,backup,archive_wals,core_pattern}mkdir -p /opt/openGausschown omm:dbgrp -R /opt/openGauss/chmod 755 -R /opt/openGauss/2.9修改资源限制/etc/security/limits.conf添加以下内容[root@ccf10 ~]# cat >> /etc/security/limits.conf <omm soft nproc unlimitedomm hard nproc unlimitedomm soft nofile 1000000omm hard nofile 1000000omm soft stack unlimitedomm hard stack unlimitedomm soft core unlimitedomm hard core unlimitedomm soft memlock unlimitedEOF2.10core_pattern设置,为记录数据库异常宕机信息[root@ccf10 ~]# cat /proc/sys/kernel/core_pattern[root@ccf10 ~]# echo "/data/core_pattern/core-%e-%p-%t"> /proc/sys/kernel/core_pattern2.11配置yum源并安装依赖包umount /dev/sr0mount /dev/sr0 /mnt[root@ccf10 yum.repos.d]# vi /etc/yum.repos.d/kylin_x86_64.repo###Kylin Linux Advanced Server 10 - os repo###[local]name=Kylin Linux Advanced Server 10baseurl=file:///mntenabled=1gpgcheck=0gpgkey=file:///mnt/RPM-GPG-KEY-kylinyum repolistyum install -y zlib-devel libaio libuuid readline-devel krb5-libs libicu libxslt tcl perl openldap pam openssl-devel libxml2 python32.12修改默认python版本[root@ccf10 script]# python -VPython 2.7.18[root@ccf10 script]# which python/usr/bin/python[root@ccf10 script]# mv /usr/bin/python /usr/bin/pythonbak[root@ccf10 script]# ln -s /usr/bin/python3python3 python3.7m python3-chardetectpython3.7 python3.7m-config python3-configpython3.7-config python3.7m-x86_64-config[root@ccf10 script]# ln -s /usr/bin/python3 /usr/bin/python[root@ccf10 script]#[root@ccf10 script]# python -VPython 3.7.92.13设置root用户远程登录vim /etc/ssh/sshd_configa.修改权限配置•注释掉“PermitRootLogin no”。#PermitRootLogin no•将“PermitRootLogin”改为“yes”。PermitRootLogin yesb.修改Banner配置vim /etc/ssh/sshd_config修改Banner配置,注释掉“Banner”所在的行。#Banner XXXXsystemctl restart sshd.service2.14对于X86,MTU值推荐1500;对于ARM,MTU值推荐8192。--ifconfig 网卡名称 mtu mtu值ifconfig ens32 mtu 8192对虚拟机内存小的情况,关闭swap交换内存swapoff -a3.数据库安装配置(采用cluster_config.xml安装主从)需配置root与omm用户ssh互信# 每个节点都执行ssh-keygen -t rsa # 一路回车# 将公钥添加到认证文件中cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys# 并设置authorized_keys的访问权限chmod 600 ~/.ssh/authorized_keys# 只要在一个节点执行即可。这里在 192.168.6.201上执行ssh 192.168.6.202 cat ~/.ssh/id_rsa.pub >>~/.ssh/authorized_keysssh 192.168.6.203 cat ~/.ssh/id_rsa.pub >>~/.ssh/authorized_keys# 分发整合后的文件到其它节点scp ~/.ssh/authorized_keys 192.168.6.202:~/.ssh/scp ~/.ssh/authorized_keys 192.168.6.203:~/.ssh/3.1解压文件及配置cluster_config.xml[root@ccf10 ~]# cd /opt/openGauss/[root@ccf10 openGauss]# mv /root/openGauss-3.0.0-openEuler-64bit-all.tar.gz ./tar -zxvf openGauss-3.0.0-openEuler-64bit-all.tar.gztar -zxvf openGauss-3.0.0-openEuler-64bit-om.tar.gz[root@ccf10 openGauss]# cp script/gspylib/etc/conf/cluster_config_template.xml /home/omm/cluster_config.xml[root@ccf10 openGauss]# vi /home/omm/cluster_config.xml3.2执行预安装脚本[root@ccf10 script]# ./gs_preinstall -U omm -G dbgrp -X /home/omm/cluster_config.xml[root@ccf10 script]# chown omm:dbgrp -R /opt/openGauss/3.3执行安装脚本(默认SQL_ASCII字符)[root@ccf10 script]# su - omm[omm@ccf10 ~]$ cd /opt/openGauss/script/[omm@ccf10 script]$ ./gs_install -X /home/omm/cluster_config.xmlParsing the configuration file.Check preinstall on every node.Successfully checked preinstall on every node.Creating the backup directory.Successfully created the backup directory.begin deploy..Installing the cluster.begin prepare Install Cluster..Checking the installation environment on all nodes.begin install Cluster..Installing applications on all nodes.Successfully installed APP.begin init Instance..encrypt cipher and rand files for database.Please enter password for database:Please repeat for database:begin to create CA cert filesThe sslcert will be generated in /opt/openGauss/install/app/share/sslcert/omCreate CA files for cm beginning.Create CA files on directory [/opt/openGauss/install/app_02c14696/share/sslcert/cm]. file list: ['cacert.pem', 'server.key', 'server.crt', 'client.key', 'client.crt', 'server.key.cipher', 'server.key.rand', 'client.key.cipher', 'client.key.rand']Cluster installation is completed.Configuring.Deleting instances from all nodes.Successfully deleted instances from all nodes.Checking node configuration on all nodes.Initializing instances on all nodes.Updating instance configuration on all nodes.Check consistence of memCheck and coresCheck on database nodes.Successful check consistence of memCheck and coresCheck on all nodes.Configuring pg_hba on all nodes.Configuration is completed.Starting cluster.======================================================================Successfully started primary instance. Wait for standby instance.======================================================================.Successfully started cluster.======================================================================cluster_state : Normalredistributing : Nonode_count : 3Datanode Stateprimary : 1standby : 2secondary : 0cascade_standby : 0building : 0abnormal : 0down : 0Successfully installed application.end deploy..[omm@ccf10 script]$3.4安装完成,环境变量修改[omm@ccf10 script]$ cd[omm@ccf10 ~]$ cat >> /home/omm/.bashrc <export PGPORT=15400 #改成前面cluster_config.xml配置的端口export PGDATA=/data/openGaussEOF[omm@ccf10 ~]$ source .bashrc检查主从[omm@ccf10 ~]$ gs_ctl query[2022-10-07 09:33:52.205][99660][][gs_ctl]: gs_ctl query ,datadir is /data/openGaussHA state:local_role : Primarystatic_connections : 2db_state : Normaldetail_information : NormalSenders info:sender_pid : 77516local_role : Primarypeer_role : Standbypeer_state : Normalstate : Streamingsender_sent_location : 0/60001E8sender_write_location : 0/60001E8sender_flush_location : 0/60001E8sender_replay_location : 0/60001E8receiver_received_location : 0/60001E8receiver_write_location : 0/60001E8receiver_flush_location : 0/60001E8receiver_replay_location : 0/60001E8sync_percent : 100%sync_state : Quorumsync_priority : 1sync_most_available : Offchannel : 192.168.6.201:15401-->192.168.6.203:31106sender_pid : 77522local_role : Primarypeer_role : Standbypeer_state : Normalstate : Streamingsender_sent_location : 0/60001E8sender_write_location : 0/60001E8sender_flush_location : 0/60001E8sender_replay_location : 0/60001E8receiver_received_location : 0/60001E8receiver_write_location : 0/60001E8receiver_flush_location : 0/60001E8receiver_replay_location : 0/60001E8sync_percent : 100%sync_state : Quorumsync_priority : 1sync_most_available : Offchannel : 192.168.6.201:15401-->192.168.6.202:34426Receiver info:No information[omm@ccf10 ~]$[omm@ccf10 ~]$ gs_om -t status --detail[ CMServer State ]node node_ip instance state-------------------------------------------------------------------------1 ccf10 192.168.6.201 1 /opt/openGauss/install/cm/cm_server Primary2 ccf11 192.168.6.202 2 /opt/openGauss/install/cm/cm_server Standby3 ccf12 192.168.6.203 3 /opt/openGauss/install/cm/cm_server Standby[ Cluster State ]cluster_state : Normalredistributing : Nobalanced : Yescurrent_az : AZ_ALL[ Datanode State ]node node_ip instance state---------------------------------------------------------------1 ccf10 192.168.6.201 6001 /data/openGauss P Primary Normal2 ccf11 192.168.6.202 6002 /data/openGauss S Standby Normal3 ccf12 192.168.6.203 6003 /data/openGauss S Standby Normal[omm@ccf10 ~]$3.5设置备机可读备机可读特性为可选特性,需要修改配置参数并重启主备机器后才能使用。在开启备机可读之后,备机将支持读操作,并满足数据一致性要求。操作步骤1.如果主备机上的openGauss数据库实例正在运行,请先分别停止主备机上的数据库实例。2.分别打开主机与备机的postgresql.conf配置文件,找到并将对应参数修改为:wal_level=hot_standby;hot_standby = on。默认装完正确的3.参数max_standby_streaming_delay, max_prepared_transactions, max_standby_archive_delay, hot_standby_feedback可以参考开发者指南中参数说明按需进行设置。4.修改完成后,分别启动主备机即可。[omm@ccf10 ~]$ grep -Ev '^$|^\s*#' $PGDATA/postgresql.conf #默认值listen_addresses = 'localhost,192.168.6.201' # what IP address(es) to listen on;local_bind_address = '192.168.6.201'port = 15400 # (change requires restart)max_connections = 5000 # (change requires restart)unix_socket_directory = '/opt/openGauss/tmp' # (change requires restart)unix_socket_permissions = 0700 # begin with 0 to use octal notationsession_timeout = 10min # allowed duration of any unused session, 0s-86400s(1 day), 0 is disabledssl = on # (change requires restart)ssl_cert_file = 'server.crt' # (change requires restart)ssl_key_file = 'server.key' # (change requires restart)ssl_ca_file = 'cacert.pem' # (change requires restart)modify_initial_password = true #Whether to change the initial password of the initial usermax_process_memory = 2GBshared_buffers = 553MB # min 128kBbulk_write_ring_size = 2GB # for bulkload, max shared_buffersmax_prepared_transactions = 800 # zero disables the featurework_mem = 64MB # min 64kBmaintenance_work_mem = 128MB # min 1MBcstore_buffers = 1GB #min 16MBwal_level = hot_standby # minimal, archive, hot_standby or logicalcheckpoint_segments = 64 # in logfile segments, min 1, 16MB eachenable_incremental_checkpoint = on # enable incremental checkpointincremental_checkpoint_timeout = 60s # range 1s-1hmax_wal_senders = 16 # max number of walsender processeswal_keep_segments = 16 # in logfile segments, 16MB each; 0 disablesenable_slot_log = offmax_replication_slots = 8 # max number of replication slots.ireplconninfo1 = 'localhost=192.168.6.201 localport=15401 localheartbeatport=15405 localservice=15404 remotehost=192.168.6.202 remoteport=15401 remoteheartbeatport=15405 remoteservice=15404' # replication connection information used to connect primary on standby, or standby on primary,replconninfo2 = 'localhost=192.168.6.201 localport=15401 localheartbeatport=15405 localservice=15404 remotehost=192.168.6.203 remoteport=15401 remoteheartbeatport=15405 remoteservice=15404' # replication connection information used to connect secondary on primary or standby,synchronous_standby_names = 'ANY 1(dn_6002,dn_6003)' # standby servers that provide sync repdata_replicate_buffer_size = 128MB # data replication buffer sizewalsender_max_send_size = 8MB # Size of walsender max send sizeenable_data_replicate = offhot_standby = on # "on" allows queries during recoveryenable_mergejoin = offenable_nestloop = offenable_kill_query = off # optional: [on, off], default: offlogging_collector = on # Enable capturing of stderr and csvloglog_directory = '/var/log/omm/omm/pg_log/dn_6001' # directory where log files are written,log_filename = 'postgresql-%Y-%m-%d_%H%M%S.log' # log file name pattern,log_file_mode = 0600 # creation mode for log files,log_rotation_size = 20MB # Automatic rotation of logfiles willlog_min_duration_statement = 1800000 # -1 is disabled, 0 logs all statementslog_connections = off # log connection requirement from clientlog_disconnections = off # log disconnection from clientlog_duration = off # log the execution time of each querylog_hostname = off # log hostnamelog_line_prefix = '%m %c %d %p %a %x %n %e ' # special values:log_timezone = 'PRC'enable_alarm = onconnection_alarm_rate = 0.9alarm_report_interval = 10alarm_component = '/opt/huawei/snas/bin/snas_cm_cmd'use_workload_manager = off # Enables workload manager in the system.autovacuum = on # Enable autovacuum subprocess? default value is 'on'datestyle = 'iso, mdy'timezone = 'PRC'lc_messages = 'C' # locale for system error messagelc_monetary = 'C' # locale for monetary formattinglc_numeric = 'C' # locale for number formattinglc_time = 'C' # locale for time formattingdefault_text_search_config = 'pg_catalog.english'lockwait_timeout = 1200s # Max of lockwait_timeout and deadlock_timeout + 1spgxc_node_name = 'dn_6001_6002_6003' # Coordinator or Datanode nameaudit_enabled = onaudit_directory = '/var/log/omm/omm/pg_audit/dn_6001'explain_perf_mode = prettyjob_queue_processes = 10 # Number of concurrent jobs, optional: [0..1000], default: 10.replication_type = 1application_name = 'dn_6001'recovery_max_workers = 4enable_global_syscache = offenable_double_write = onavailable_zone = 'AZ1'以下为修改内容:sed -i 's/max_connections \= 5000/max_connections \= 8000/g' $PGDATA/postgresql.confsed -i 's/max_process_memory \= 2GB/max_process_memory \= 2GB/g' $PGDATA/postgresql.conf #75%MEMsed -i 's/shared_buffers \= 553MB/shared_buffers \= 600MB/g' $PGDATA/postgresql.conf #25%MEMsed -i 's/work_mem \= 64MB/work_mem \= 64MB/g' $PGDATA/postgresql.confsed -i 's/maintenance_work_mem \= 128MB/maintenance_work_mem \= 128MB/g' $PGDATA/postgresql.confsed -i 's/cstore_buffers \= 16MB/cstore_buffers \= 16MB/g' $PGDATA/postgresql.confsed -i 's/session_timeout \= 10min/session_timeout \= 0/g' $PGDATA/postgresql.confcat >> $PGDATA/postgresql.conf<effective_cache_size=1GB #75% OS_MEMvacuum_cost_limit = 10000archive_mode = onarchive_dest='/data/archive_wals'autovacuum_max_workers=5autovacuum_naptime=20sautovacuum_vacuum_cost_delay=0track_sql_count=onlog_statement='ddl'password_reuse_time=90password_encryption_type=0 #如果要使用pg兼容的客户端工具,建议设置成0random_page_cost=1.4 #根据实际情况来定,如果是SSD建议1.2或者1.4password_effect_time = 0 #The password effect time(0-999),默认值90dpassword_notify_time = 0 #The password notify time(0-999),默认值7dmax_files_per_process = 100000 # 允许同时打开的files的最大数量track_activity_query_size=4096 # 设置用于跟踪每一个活动会话的当前正在执行命令的字节数remote_read_mode=non_authenticationhot_standby_feedback = onEOF[omm@ccf10 ~]$ grep -Ev '^$|^\s*#' $PGDATA/postgresql.conf3.6集群状态查询及启停(1)状态查询[omm@ccf10 ~]$ cm_ctl query -Cv[ CMServer State ]node instance state-------------------------1 ccf10 1 Primary2 ccf11 2 Standby3 ccf12 3 Standby[ Cluster State ]cluster_state : Normalredistributing : Nobalanced : Yescurrent_az : AZ_ALL[ Datanode State ]node instance state | node instance state | node instance state---------------------------------------------------------------------------------------------------------------1 ccf10 6001 P Primary Normal | 2 ccf11 6002 S Standby Normal | 3 ccf12 6003 S Standby Normal[omm@ccf10 ~]$(2)集群启停启动集群,可以在任一节点执行启停。cm_ctl stopcm_ctl start单独启停节点1服务cm_ctl stop -n 1 -D $PGDATAcm_ctl start -n 1 -D $PGDATA3.7验证[omm@ccf10 ~]$ gsql -d postgres -rgsql ((openGauss 3.0.0 build 02c14696) compiled at 2022-04-01 18:12:19 commit 0 last mr )Non-SSL connection (SSL connection is recommended when requiring high-security)Type "help" for help.openGauss=# \lList of databasesName | Owner | Encoding | Collate | Ctype | Access privileges-----------+-------+-----------+---------+-------+-------------------postgres | omm | SQL_ASCII | C | C |template0 | omm | SQL_ASCII | C | C | =c/omm +| | | | | omm=CTc/ommtemplate1 | omm | SQL_ASCII | C | C | =c/omm +| | | | | omm=CTc/omm(3 rows)openGauss=# CREATE DATABASE mydb WITH ENCODING 'GBK' template = template0;CREATE DATABASEopenGauss=# CREATE DATABASE mydb1 WITH ENCODING 'UTF8' template = template0;CREATE DATABASEopenGauss=#openGauss=# \c mydbNon-SSL connection (SSL connection is recommended when requiring high-security)You are now connected to database "mydb" as user "omm".mydb=# CREATE USER ccf IDENTIFIED BY 'Ccf.1234';CREATE ROLEmydb=#mydb=# CREATE TABLESPACE tbs_ccf RELATIVE LOCATION 'tablespace/tablespace_1';CREATE TABLESPACEmydb=# GRANT CREATE ON TABLESPACE tbs_ccf TO ccf;GRANTmydb=# create table ccf.chen01(i int);CREATE TABLEmydb=# insert into ccf.chen01 values(1);INSERT 0 1mydb=# select * from ccf.chen01;i---1(1 row)mydb=#测试建库建表均成功在备库查询到,创建完成。高可用测试:模拟主节点故障,测试是否自动进行选主。[root@ccf10 ~]# shutdown -h now[omm@ccf12 ~]$ cm_ctl query -Cv[ CMServer State ]node instance state-------------------------1 ccf10 1 Down2 ccf11 2 Standby3 ccf12 3 Primary[ Cluster State ]cluster_state : Degradedredistributing : Nobalanced : Nocurrent_az : AZ_ALL[ Datanode State ]node instance state | node instance state | node instance state---------------------------------------------------------------------------------------------------------------1 ccf10 6001 P Down Unknown | 2 ccf11 6002 S Primary Normal | 3 ccf12 6003 S Standby Normal[omm@ccf12 ~]$如上节点2是主,测试成功。启动1节点自动启动并加入集群,作为standby节点[omm@ccf10 ~]$ gs_om -t status --detail[ CMServer State ]node node_ip instance state-------------------------------------------------------------------------1 ccf10 192.168.6.201 1 /opt/openGauss/install/cm/cm_server Standby2 ccf11 192.168.6.202 2 /opt/openGauss/install/cm/cm_server Standby3 ccf12 192.168.6.203 3 /opt/openGauss/install/cm/cm_server Primary[ Cluster State ]cluster_state : Normalredistributing : Nobalanced : Nocurrent_az : AZ_ALL[ Datanode State ]node node_ip instance state---------------------------------------------------------------1 ccf10 192.168.6.201 6001 /data/openGauss P Standby Normal2 ccf11 192.168.6.202 6002 /data/openGauss S Primary Normal3 ccf12 192.168.6.203 6003 /data/openGauss S Standby Normal[omm@ccf10 ~]$ cm_ctl query -Cv[ CMServer State ]node instance state-------------------------1 ccf10 1 Standby2 ccf11 2 Standby3 ccf12 3 Primary[ Cluster State ]cluster_state : Normalredistributing : Nobalanced : Nocurrent_az : AZ_ALL[ Datanode State ]node instance state | node instance state | node instance state---------------------------------------------------------------------------------------------------------------1 ccf10 6001 P Standby Normal | 2 ccf11 6002 S Primary Normal | 3 ccf12 6003 S Standby Normal[omm@ccf10 ~]$
  • [技术干货] 【第四届openGauss征文活动参赛作品】openGauss易知易会的几个实用特性
    使用openGauss已经有很长一段时间了,本文将介绍几个简单易用的数据库特性。单列显示整行数据where比较列合并独立写布尔列using关键字domain单列显示整行数据首先我们准备测试数据表:create table users(id int,name text,email text,deleted_at timestamp,delete boolean); insert into users values(1,'jerome','chong.peng@enmotech.com',null,false); insert into users values(2,'sara','lynn.wood@poland.com','2001-09-11',true); insert into users values(3,'dolores','th000@sky.com',null,false); insert into users values(4,'evan','rachel.moore@hollywood.com',null,false);通常我们使用如下语句进行查询openGauss# select * from users; id | name | email | deleted_at | delete ----+---------+----------------------------+---------------------+-------- 1 | jerome | chong.peng@enmotech.com | | f 2 | sara | lynn.wood@poland.com | 2001-09-11 00:00:00 | t 3 | dolores | th000@sky.com | | f 4 | evan | rachel.moore@hollywood.com | | f (4 rows)也可以使用下面的语句进行查询,尤其是列较多时openGauss# select users from users; users ------------------------------------------------------- (1,jerome,chong.peng@enmotech.com,,f) (2,sara,lynn.wood@poland.com,"2001-09-11 00:00:00",t) (3,dolores,th000@sky.com,,f) (4,evan,rachel.moore@hollywood.com,,f) (4 rows)上面是将所有列作为行类型返回单列,可以比较简洁的返回数据。where比较列合并假设我们有以下查询:select id, name, email from users where name = 'dolores' and email = 'th000@sky.com';根据名称和邮箱查询用户,有的时候where条件后面可能会出现1=1select id, name, email from users where 1=1 and name = 'dolores' and email = 'th000@sky.com';应用层需要比较方便进行where条件拼接。其实可以去掉and,使用如下语句:select id, name, email from users where (name, email) = ('dolores','th000@sky.com');可以查询到同样的结果 id | name | email ----+---------+--------------- 3 | dolores | th000@sky.com (1 row)我们还可以使用in来满足or条件,例如下面的查询:select id, name, email from users where deleted_at is null and ( (name = 'dolores' and email = 'th000@sky.com') or (name = 'evan' and email = 'rachel.moore@hollywood.com') );可以将其缩短为:select id, name, email from users where deleted_at is null and (name, email) in (('dolores','th000@sky.com'),('evan','rachel.moore@hollywood.com'));这可以使查询更短且更易于阅读。独立写布尔列接下来的查询,获取未删除的用户,比较常见的是这种写法:select id, name, email from users where delete = false;多数人并不知道布尔值不需要与另一个布尔值进行比较,可以这样写:select id, name, email from users where not delete;这样阅读起来也更好,结果如下: id | name | email ----+---------+---------------------------- 1 | jerome | chong.peng@enmotech.com 3 | dolores | th000@sky.com 4 | evan | rachel.moore@hollywood.com (3 rows)using关键字当我们做多张表的join连接时,如果join字段的名称相同可以使用using关键字来简化语句select ... from t1 join t2 on t1.id = t2.id;可以改写为:select ... from t1 join t2 using (id);多个字段还可以使用逗号进行分隔:on t1.a = t2.a and t1.b = t2.b改写为using (a,b);domaindomain也是比较有用的一个特性,例如可以很多需要进行相同限制的列创建自定义类型:create domain my_addr varchar(100) not null default 'n/a';或者是作为别名支持兼容性数据类型:create domain binary_float as float; 本文总结了几个有帮助的实用特性,大家在日常使用过程中可以进一步挖掘。
  • [技术干货] 【第四届openGauss征文活动参赛作品】参与鲲鹏应用创新大赛,openGuas赛道的体会
    我们是参与的是关于openGauss赛道,我们做的是关于基于openGuass全密态数据库相关的内容。收获有很多,从openGauss在本地的部署,再到对openGauss源码的学习,再到对openGauss全密态能力的了解,对openGauss的了解越来越深,也越发感觉他的丰富的功能特性。1.openGauss的本地部署,我使用的是这个教程 地址 cid:link_0由于开始对linux命令的不熟悉,从而导致使用openGauss的一键部署脚本的使用出了很多问题,所以没出一次问题,linux环境就出了很多问题,导致无法继续下去,因此只能选择重装系统,再无数次重装系统重新跑脚本,改配置下,终于成功在本地部署了openGauss数据库。主要有以下几个问题:(1).虚拟机的硬盘分配过小,导致openGauss安装部署失败,最开始我只分配了20G硬盘和1G内存,导致openGauss的最后一步python运行脚本安装部署openGauss报错,后来使用的是60G硬盘和4G内存,就能部署成功了。(2).由于在本地虚拟机使用的是centos 7.6操作系统,这个系统上的python默认版本是python2,而安装部署openGauss脚本的要使用python3版本,因此需要重新安装python版本,但是脚本那一步在部署的时候会导致python命令和yum命令都没办法使用,因此只需要使用yum install python3 并且使用python3 执行最后的python文件脚本就行。 不用改配置的bak内容,改了反而更容易报错。(3).要保住虚拟机能联网,由于教程会在线下载内容,因此不联网,也会导致安装部署不成功,而且要改教程脚本里的ip地址。2.对openGauss源码的学习,主要是对openGauss的安全特性源码进行学习,包括密态等值大小比较。目前还在学习过程中,包括openGauss的全密态数据库特性也在学习中,等后续学了内容再更新。
  • [技术干货] 【第四届openGauss征文活动参赛作品】一种可能是目前最快的从ORACLE同步数据到MogDB(openGauss)的方式
    一、前言目前openGauss支持oracle中的绝大部分数据类型,基本上不用考虑类型转换的问题。所以从oracle到MogDB(openGauss)的数据同步无非就是从oracle里查出来再插入到MogDB(openGauss)中,只是查出来的结果是存成文件还是放内存而已。用文件的形式,oracle端有sqluldr2可以快速导出,MogDB(openGauss)端可以用copy命令快速载入;如果是放内存,则需要一定量的代码开发,而且目前通用的数据同步工具在导入时,大多用的是逐行insert命令,效率很低。所以,是否存在一种可能,只利用现有的工具,就能实现数据的高速同步且不需要存文件?在说这个方案前,先简单说明一下这个方案的几个知识点。二、知识点1.sqluldr2sqluldr2是楼方鑫针对Oracle数据库开发的数据快速导出工具,应该绝大多数oracle用户都用过,因为它依旧是目前从oracle中导出文本数据最快的方式了,速度远超oracle官方的sqlplus spool导出。但是大多数人基本上都只使用其导出文件的功能,而不知道这个工具还可以导出标准输出(所谓标准输出即不生成文件,直接打印在屏幕上)sqluldr2完整文档:https://www.doc88.com/p-6522591706862.html2.gsql/psql(\copy 元命令)gsql/psql的"\copy"元命令(注意区别于sql命令中的"copy",“copy"是服务器端的,”\copy"是客户端的),常用于和表和文件之间的导入和导出,效率很快,因为已经指定了表,不需要再进行字段类型的识别,绕开了sql解析引擎,直接写入表中。但大多数人很少用到 stdin和stdout(除非是基于其他高级语言进行数据导入导出的开发),这里的stdin即为标准输入,如果执行"\copy 表名 from stdin",则会让你继续输入数据,然后客户端会把数据保存到对应的表中。3.gsql/psql (-c参数)gsql/psql 的 "-c"参数,可以在连接数据库后马上执行sql命令然后断开登录4.linux ( | 管道符)linux的管道符"|",可以用于输入的重定向,即把前面一条命令的输出,作为后面一条命令的输入三、方案说明通过以上内容,很自然的可以联想到一种方式,即使用sqluldr2的标准输出,直接作为gsql \copy的标准输入。所谓的两点之间直线最短,用最快的导出加上最快的导入,且省去中间存储文件的阶段,理想状态下,这个速度仅受限于源端或目标端最慢的那一端,比如导出7分钟,导入8分钟,一般总计传输时间就是15分钟,但是用本文的方案,这个传输时间可能就只有8分钟了,因为它是导入导出同时进行的!四、操作步骤需要有个服务器能同时连接oracle及MogDB(openGauss),当然直接用这两个服务器之一也可以,只是注意要安装另一个数据的客户端,本文测试是在mogdb数据库的服务器上执行的oracle客户端下载链接https://www.oracle.com/cn/database/technologies/instant-client/linux-x86-64-downloads.htmlMogDB(openGauss)没有提供单独的客户端压缩包,客户端在数据库的安装包中对应的tools压缩包,比如MogDB-3.0.1-CentOS-64bit-tools.tar.gzhttps://mogdb.io/downloads/mogdb/安装客户端,这两个客户端的安装方式差不多,就是解压,然后配置环境变量LD_LIBRARY_PATH,比如配置连接Oracle的环境变量如下(如果需要永久配置则要修改对应的配置文件) export LD_LIBRARY_PATH=/opt/mogdb/instantclient_21_7:$LD_LIBRARY_PATH 下载sqluldr2程序这个就自己在网上搜吧,基本下载下来是一个压缩包,里面有两个windows版的和两个linux版的,我们需要的是"sqluldr2_linux64_10204.bin"这个文件,下完后可以把文件名改短点,比如"sqluldr2"先找个小表测试下sqluldr2能否导出文件,文件正常生成,说明oracle客户端配置正确 ./sqluldr2 scott/tiger@192.168.163.108/orcl query=emp quote=0x22 field="," degree=8 file=123.csv [omm@MiWiFi-R3G-srv mogdb]$ cat 123.csv 7369,"SMITH","CLERK",7902,"1980-12-17 00:00:00",800,,20 7499,"ALLEN","SALESMAN",7698,"1981-02-20 00:00:00",1600,300,30 7521,"WARD","SALESMAN",7698,"1981-02-22 00:00:00",1250,500,30 7566,"JONES","MANAGER",7839,"1981-04-02 00:00:00",2975,,20 7654,"MARTIN","SALESMAN",7698,"1981-09-28 00:00:00",1250,1400,30 7698,"BLAKE","MANAGER",7839,"1981-05-01 00:00:00",2850,,30 7782,"CLARK","MANAGER",7839,"1981-06-09 00:00:00",2450,,10 7788,"SCOTT","ANALYST",7566,"1987-04-19 00:00:00",3000,,20 7839,"KING","PRESIDENT",,"1981-11-17 00:00:00",5000,,10 7844,"TURNER","SALESMAN",7698,"1981-09-08 00:00:00",1500,0,30 7876,"ADAMS","CLERK",7788,"1987-05-23 00:00:00",1100,,20 7900,"JAMES","CLERK",7698,"1981-12-03 00:00:00",950,,30 7902,"FORD","ANALYST",7566,"1981-12-03 00:00:00",3000,,20 7934,"MILLER","CLERK",7782,"1982-01-23 00:00:00",1300,,10在目标端建立一个同样的表 gsql -d postgres -r -p 26000 create schema scott; create table SCOTT.EMP ( empno NUMBER(4) not null, ename VARCHAR2(10), job VARCHAR2(9), mgr NUMBER(4), hiredate DATE, sal NUMBER(7,2), comm NUMBER(7,2), deptno NUMBER(2) ); ★测试通过管道传输数据,没有报错 ./sqluldr2 scott/tiger@192.168.163.108/orcl query=emp quote=0x22 field="," degree=8 file=- |gsql -d postgres -Umogdb -WEnmo@123 -hlocalhost -p26000 -c "\copy scott.emp from stdin DELIMITER ',' quote '\"' csv" 在目标端查询scott.emp表,数据和源端一致MogDB=# select * from scott.emp; empno | ename | job | mgr | hiredate | sal | comm | deptno -------+--------+-----------+------+---------------------+---------+---------+-------- 7369 | SMITH | CLERK | 7902 | 1980-12-17 00:00:00 | 800.00 | | 20 7499 | ALLEN | SALESMAN | 7698 | 1981-02-20 00:00:00 | 1600.00 | 300.00 | 30 7521 | WARD | SALESMAN | 7698 | 1981-02-22 00:00:00 | 1250.00 | 500.00 | 30 7566 | JONES | MANAGER | 7839 | 1981-04-02 00:00:00 | 2975.00 | | 20 7654 | MARTIN | SALESMAN | 7698 | 1981-09-28 00:00:00 | 1250.00 | 1400.00 | 30 7698 | BLAKE | MANAGER | 7839 | 1981-05-01 00:00:00 | 2850.00 | | 30 7782 | CLARK | MANAGER | 7839 | 1981-06-09 00:00:00 | 2450.00 | | 10 7788 | SCOTT | ANALYST | 7566 | 1987-04-19 00:00:00 | 3000.00 | | 20 7839 | KING | PRESIDENT | | 1981-11-17 00:00:00 | 5000.00 | | 10 7844 | TURNER | SALESMAN | 7698 | 1981-09-08 00:00:00 | 1500.00 | 0.00 | 30 7876 | ADAMS | CLERK | 7788 | 1987-05-23 00:00:00 | 1100.00 | | 20 7900 | JAMES | CLERK | 7698 | 1981-12-03 00:00:00 | 950.00 | | 30 7902 | FORD | ANALYST | 7566 | 1981-12-03 00:00:00 | 3000.00 | | 20 7934 | MILLER | CLERK | 7782 | 1982-01-23 00:00:00 | 1300.00 | | 10 (14 rows)五、简单性能测试由于硬盘空间不够,测试数据库也是虚拟机和docker中的,就不做详细的测试了,只做个简单的100万数据测试 SQL> select count(1) from scott.T_TEST1; COUNT(1) ---------- 1000000 直接管道传输,用时7s [omm@MiWiFi-R3G-srv mogdb]$ echo $(date) Thu Sep 15 04:24:23 EDT 2022 [omm@MiWiFi-R3G-srv mogdb]$ ./sqluldr2 scott/tiger@192.168.163.108/orcl query=SCOTT.T_TEST1 quote=0x22 field="," degree=8 file=- |gsql -d postgres -Umogdb -WEnmo@123 -hlocalhost -p26000 -c "\copy SCOTT.T_TEST1 from stdin DELIMITER ',' quote '\"' csv" [omm@MiWiFi-R3G-srv mogdb]$ echo $(date) Thu Sep 15 04:24:30 EDT 2022 在目标端删除测试表,重建,然后用导出文件再导入的方式,导出5s,导入7s,一共12s [omm@MiWiFi-R3G-srv mogdb]$ echo $(date) Thu Sep 15 04:20:00 EDT 2022 [omm@MiWiFi-R3G-srv mogdb]$ ./sqluldr2 scott/tiger@192.168.163.108/orcl query=SCOTT.T_TEST1 quote=0x22 field="," degree=8 file=1234.csv 0 rows exported at 2022-09-15 04:20:00, size 0 MB. 1000000 rows exported at 2022-09-15 04:20:05, size 48 MB. output file 1234.csv closed at 1000000 rows, size 48 MB. [omm@MiWiFi-R3G-srv mogdb]$ echo $(date) Thu Sep 15 04:20:05 EDT 2022 [omm@MiWiFi-R3G-srv mogdb]$ echo $(date) Thu Sep 15 04:23:03 EDT 2022 [omm@MiWiFi-R3G-srv mogdb]$ gsql -d postgres -Umogdb -WEnmo@123 -hlocalhost -p26000 -c "\copy SCOTT.T_TEST1 from '/opt/mogdb/1234.csv' DELIMITER ',' quote '\"' csv" [omm@MiWiFi-R3G-srv mogdb]$ echo $(date) Thu Sep 15 04:23:10 EDT 2022 大致判断,这次测试的速度上限受导入影响,如果再优化一下数据库相关参数,耗时可以更低,但这里主要是提供一个可行的快速传输数据的思路,就不去做参数调整了。六、总结了解了这个原理,完全可以写一个程序或者shell脚本,通过把配置进行参数化处理,来制作一个Oracle到openGauss的通用高速数据传输工具。本文作者: DarkAthena本文链接: https://www.darkathena.top/archives/transport-data-from-oracle-to-opengauss-faster版权声明: 本博客所有文章除特别声明外,均采用CC BY-NC-SA 3.0 许可协议。转载请注明出处!
  • [技术干货] 【第四届openGauss征文活动参赛作品】openGauss初学者快速入门
    前言我第一次接触openGauss是再2022年8月份,当时有一个鲲鹏应用大赛,我对于openGauss很陌生,在网上看了很多有关openGauss的视频,我在bilibili上看到松鼠会发布的openGauss讲解是最多的,然后我就对着视频搭建openGauss,当时还好我电脑上一直有centos7的虚拟环境,所以我直接利用centos搭建openGauss,这里给大家分享一下我入门的学习是怎么样的。一、openGauss是什么?官方解释:openGauss是一款全面友好开放,携手伙伴共同打造的企业级开源关系型数据库。openGauss提供面向多核架构的极致性能、全链路的业务、数据安全、基于AI的调优和高效运维的能力。openGauss深度融合华为在数据库领域多年的研发经验,结合企业级场景需求,持续构建竞争力特性。openGauss网站 (https://opengauss.org/zh/ ) 提供了有关openGauss软件的最新信息。个人理解:我认为是一个基于Linux的一款国内数据库,其实和Mysql等数据库一样,但是主要还是觉得这是我们骄傲的民族企业华为开发的,安全方面我会更放心。最主要的原因是openGauss属于开源数据库,对我们开发者来说是很有好的,学习起来也很方便。二、openGauss软件架构下面这张图也是我从官方的资料中找到的:这张图片,我们可以很明显的看到,在openGauss数据库中,是有一个单独的备份机制存在,也是对数据防止丢失做的一种机制吧。其中图片中的名词下面附上官方解释:OM运维管理模块(Operation Manager)。提供数据库日常运维、配置管理的管理接口、工具。个人理解:方便维护的管理员模块CM数据库管理模块(Cluster Manager)。管理和监控数据库系统中各个功能单元和物理资源的运行情况,确保整个系统的稳定运行。个人理解:针对数据库的管理模块客户端驱动客户端驱动(Client Driver)。负责接收来自应用的访问请求,并向应用返回执行结果。客户端驱动负责与openGauss实例通信,发送应用的SQL命令,接收openGauss实例的执行结果。openGauss(主备)openGauss主备(Datanode)。负责存储业务数据、执行数据查询任务以及向客户端返回执行结果。openGauss实例包含主、备两种类型,支持一主多备。建议将主、备openGauss实例分散部署在不同的物理节点中。个人理解:安全机制的考虑Storage服务器的本地存储资源,持久化存储数据。个人理解:就是长久的本地资源三、openGauss特点特点针对特点解释高性能通过列存储、向量化执行引擎、融合引擎等关键技术,实现百亿数据量查询秒级响应高可用同城跨AZ(Available Zone)容灾,数据不丢失,分钟级恢复高安全性支持访问控制、加密认证、数据库审计、动态数据脱敏等安全特性,提供全方位端到端的数据安全保护可维护性好支持WDR诊断、慢SQL诊断、Session诊断等多种维护手段,准确快速定位问题。具备AI4DB能力,能够通过AI算法实现数据库自调优、自监控、自诊断等我个人认为最大的特点就是,高安全性,但是目前还在发展阶段,openGauss的开发人员真的是需要加把劲了,之前我在学习openGauss的时候,就发现网站是存在漏洞的,而且很多,如果不更加细致的去处理好的话,对于数据的安全真的是不敢恭维!!!! 希望官方大大还是更加注意开发质量四、个人学习1.下载我个人选择的是极简版,也是为了方便,在文章开始我也说了,我主要还是搭建在centos7上面​2.安装环境centos7​3.基础配置解压之后,我们按照顺序输入下面的命令,使用VIM打开config文件。 vim /etc/selinux/config 修改“SELINUX”的值“disabled”,这里用的是vim编辑器,如果不懂的话请自学一下 SELINUX=disabled 重启centos。 reboot 检查防火墙状态。 systemctl status firewalld 在没有关闭的情况下,关闭防火墙 systemctl disable firewalld.service systemctl stop firewalld.service4.其他配置设置编码,/etc/profile文件下添加“export LANG=Unicode vim /etc/profile 设置时间 date #查看时间 将/usr/share/zoneinfo/目录下的时区文件复制为/etc/localtime文件下面 cp /usr/share/zoneinfo/配置的时间地点 /etc/localtime基本上因为centos7很多配置是已经默认的,所以相对而言搭建很简单。五、建议1.推广形式可以加强,首先,我了解到推广的形式,主要还是比赛,活动,我认为可以发布会,公众号视频,还可以找博主在一些平台上,撰写一个月,效果可能会更好。2.建议可以出版openGauss的书籍,出版,推广书籍(这个我看到捉虫活动有这样的书籍)3.另外是,我个人感觉对于openGauss的学习视频资料太少了,可以联合直播,扩展了解的人群。4.可以在行业中找到突破口,目前大厂数据库更换的话太昂贵,可以先占领中小型公司的市场。最后,支持华为,支持松鼠会,支持openGauss
  • [技术干货] 【第四届openGauss征文活动参赛作品】奇思妙想——通过Go语言自制安装openGauss二进制程序
    前言巧妙利用go语言自制openGauss安装二进制程序,经测试15s即可安装完成一、安装go语言环境1. 下载解压go[root@node1 ~]# wget https://golang.google.cn/dl/go1.19.1.linux-amd64.tar.gz[root@node1 ~]# tar -zxvf go1.19.1.linux-amd64.tar.gz -C /usr/local2. 添加环境变量export PATH=$PATH:/usr/local/go/bin3. 测试运行package main import fmt func main(){ fmt.Println("hello,world!") }[root@node1 ~]# go run test.go hello,world!二、 openGauss安装 (15s安装完成)1. 源代码[root@node1 ~]# cat gaussdb.go package main import ( "fmt" "io/ioutil" "os/exec" ) func main() { cmd := exec.Command("/bin/bash", "-c", `useradd omm ;echo "Enmo@123" | passwd --stdin omm > /dev/null ;mkdir -p /opt/mogdb/software;chown -R omm:omm /opt/;tar -xf openGauss-3.1.0-CentOS-64bit.tar.bz2 -C /opt/mogdb/software; su - omm -c "echo 'export GAUSSHOME=/opt/mogdb/software' >> /home/omm/.bashrc ;echo 'export PATH=\$GAUSSHOME/bin:\$PATH' >> /home/omm/.bashrc ;echo 'export LD_LIBRARY_PATH=\$GAUSSHOME/lib:\$LD_LIBRARY_PATH' >> /home/omm/.bashrc;source /home/omm/.bashrc;gs_initdb --pgdata=/opt/mogdb/data --nodename=primary --pwpasswd=Enmo@123 --encoding=UTF-8 --locale=en_US.UTF-8 > /dev/null ;echo \"port=26000\" >> /opt/mogdb/data/postgresql.conf;echo \"listen_addresses = '0.0.0.0'\" >> /opt/mogdb/data/postgresql.conf;echo \"password_encryption_type = 0\" >> /opt/mogdb/data/postgresql.conf;echo \"log_directory = 'pg_log'\" >> /opt/mogdb/data/postgresql.conf;echo \"remote_read_mode=non_authentication\" >> /opt/mogdb/data/postgresql.conf;echo \"host all all 0.0.0.0/0 md5\" >> /opt/mogdb/data/pg_hba.conf;gs_ctl start -D /opt/mogdb/data > /dev/null ;gsql -d postgres -p 26000 -c'select version();select pg_postmaster_start_time();';echo -e 'data_user is omm ! \ndata_port is 26000 ! \ndata_path is /opt/mogdb/data ! \ndata_soft is /opt/mogdb/software !'"`) // cmd := exec.Command("/bin/bash", "-c", `df -h;ls`) //创建获取命令输出管道 stdout, err := cmd.StdoutPipe() if err != nil { fmt.Printf("Error:can not obtain stdout pipe for command:%s\n", err) return } //执行命令 if err := cmd.Start(); err != nil { fmt.Println("Error:The command is err,", err) return } //读取所有输出 bytes, err := ioutil.ReadAll(stdout) if err != nil { fmt.Println("ReadAll Stdout:", err.Error()) return } if err := cmd.Wait(); err != nil { fmt.Println("wait:", err.Error()) return } fmt.Printf("stdout:\n\n %s", bytes) }2. go run 测试运行准备安装包[root@node1 ~]# ls openGauss-3.1.0-CentOS-64bit.tar.bz2 gaussdb.go gaussdb.go openGauss-3.1.0-CentOS-64bit.tar.bz2go run[root@node1 ~]# go run gaussdb.go stdout: version ------------------------------------------------------------------------------------------------------------------------------------------------------ (openGauss 3.1.0 build 2c0ccaf9) compiled at 2022-09-25 19:32:58 commit 0 last mr on x86_64-unknown-linux-gnu, compiled by g++ (GCC) 7.3.0, 64-bit (1 row) pg_postmaster_start_time ------------------------------- 2022-09-28 13:38:28.550462+08 (1 row) data_user is omm ! data_port is 26000 ! data_path is /opt/mogdb/data ! data_soft is /opt/mogdb/software !连接测试 ```s [root@node1 ~]# su - omm Last login: Wed Sep 28 13:39:38 CST 2022 [omm@node1 ~]$ gsql -d postgres -p26000 -r gsql ((openGauss 3.1.0 build 2c0ccaf9) compiled at 2022-09-25 19:32:58 commit 0 last mr ) Non-SSL connection (SSL connection is recommended when requiring high-security) Type "help" for help.openGauss=# select version(); version(openGauss 3.1.0 build 2c0ccaf9) compiled at 2022-09-25 19:32:58 commit 0 last mr on x86_64-unknown-linux-gnu, compiled by g++ (GCC) 7.3.0, 64-bit (1 row)openGauss=# \q [omm@node1 ~]$ logout- go build 二进制 ```s [root@node1 ~]# go build gaussdb.go [root@node1 ~]# ls gaussdb openGauss-3.1.0-CentOS-64bit.tar.bz2 gaussdb.go gaussdb gaussdb.go openGauss-3.1.0-CentOS-64bit.tar.bz2清理环境[root@node1 ~]# cat a.sh pkill -9 gaussdb rm -rf /opt/mogdb/* userdel -r omm [root@node1 ~]# sh a.sh安装 ```s [root@node1 ~]# date;./gaussdb;date Wed Sep 28 13:53:12 CST 2022 stdout: version(openGauss 3.1.0 build 2c0ccaf9) compiled at 2022-09-25 19:32:58 commit 0 last mr on x86_64-unknown-linux-gnu, compiled by g++ (GCC) 7.3.0, 64-bit (1 row)pg_postmaster_start_time2022-09-28 13:53:27.034021+08 (1 row)data_user is omm ! data_port is 26000 ! data_path is /opt/mogdb/data ! data_soft is /opt/mogdb/software ! Wed Sep 28 13:53:27 CST 2022- 连接测试 ```s [root@node1 ~]# su - omm Last login: Wed Sep 28 13:53:19 CST 2022 [omm@node1 ~]$ gsql -d postgres -p26000 -r gsql ((openGauss 3.1.0 build 2c0ccaf9) compiled at 2022-09-25 19:32:58 commit 0 last mr ) Non-SSL connection (SSL connection is recommended when requiring high-security) Type "help" for help. openGauss=# select version(); version ------------------------------------------------------------------------------------------------------------------------------------------------------ (openGauss 3.1.0 build 2c0ccaf9) compiled at 2022-09-25 19:32:58 commit 0 last mr on x86_64-unknown-linux-gnu, compiled by g++ (GCC) 7.3.0, 64-bit (1 row) openGauss=# \q
  • [技术干货] 【第四届openGauss征文活动参赛作品】openGauss账本数据库,你不知道的那些事儿
    openGauss账本数据库,你不知道的那些事儿摘要本文将通过对比官方文档关于 “设置账本数据库” 中的几个章节,结合源码来说说文档中操作步骤背后的原理。账本数据库概述你知道的那些事儿官方文档账本数据库融合了区块链思想,将用户操作记录至两种历史表中:用户历史表和全局区块表。当用户创建防篡改用户表时,系统将自动为该表添加一个hash列来保存每行数据的hash摘要信息,同时在blockchain模式下会创建一张用户历史表来记录对应用户表中每条数据的变更行为;而用户对防篡改用户表的一次修改行为将记录至全局区块表中。由于历史表具有只可追加不可修改的特点,因此历史表记录串联起来便形成了用户对防篡改用户表的修改历史。你不知道的那些事儿操作步骤1.创建防篡改模式。openGauss=# CREATE SCHEMA ledgernsp WITH BLOCKCHAIN;首先在这个SQL中我们可以看到WITH BLOCKCHAIN ,这里说明创建出来的SCHEMA与普通的SCHEMA不同,但就行不同在哪里我们后面会提到。从语法解析看,增加了对BLOCKCHAIN的处理,标记了是否为账本模式。 CreateSchema ::= CREATE SCHEMA schema_name [ AUTHORIZATION user_name ] [WITH BLOCKCHAIN] [ schema_element [ ... ] ];CreateSchemaStmt 结构中增加了bool类型字段hasBlockChaintypedef struct CreateSchemaStmt { NodeTag type; char *schemaname; /* the name of the schema to create */ char *authid; /* the owner of the created schema */ bool hasBlockChain; /* whether this schema has blockchain */ List *schemaElts; /* schema components (list of parsenodes) */ TempType temptype; /* if the schema is temp table's schema */ List *uuids; /* the list of uuid(only create sequence or table with serial type need) */ } CreateSchemaStmt;你不知道的限制账本数据库对于ALTER SCHEMA的几个限制1、dbe_perf和snapshot两个模式不能ALTER为blockchain模式。 if (withBlockchain && ((strncmp(nspName, "dbe_perf", STR_SCHEMA_NAME_LENGTH) == 0) || (strncmp(nspName, "snapshot", STR_SNAPSHOT_LENGTH) == 0))) { ereport(ERROR, (errcode(ERRCODE_OPERATE_FAILED), errmsg("The schema '%s' doesn't allow to alter to blockchain schema", nspName))); }2、系统模式不能 ALTER 为blockchain模式。 if (withBlockchain && !g_instance.attr.attr_common.allowSystemTableMods && !u_sess->attr.attr_common.IsInplaceUpgrade && IsReservedName(nspName)) ereport(ERROR, (errcode(ERRCODE_RESERVED_NAME), errmsg("The system schema \"%s\" doesn't allow to alter to blockchain schema", nspName)));3、包含了表的SCHEMA不能ALTER为blockchain模式。 /* * If the any table exists in the schema, do not change to ledger schema. */ StringInfo existTbl = TableExistInSchema(HeapTupleGetOid(tup), TABLE_TYPE_ANY); if (existTbl->len != 0) { if (withBlockchain) { ereport(ERROR, (errcode(ERRCODE_RESERVED_NAME), errmsg("It is not supported to change \"%s\" to blockchain schema which includes tables.", nspName))); } else { ereport(ERROR, (errcode(ERRCODE_RESERVED_NAME), errmsg("It is not supported to change \"%s\" to normal schema which includes tables.", nspName))); } }查看模式2.在防篡改模式下创建防篡改用户表。openGauss=# CREATE TABLE ledgernsp.usertable(id int, name text);你不知道的限制创建账本表的同时会自动创建一个“历史表”和“历史表的索引”。在建表时CreateCommand会调用AlterCreateChainTables,如果是账本表再去调用create_hist_relation来创建历史表CreateCommand -> AlterCreateChainTables -> create_hist_relation/* * AlterCreateChainTables * If it is a ledger usertable, that should invoking this function. * then create a history table. */ void AlterCreateChainTables(Oid relOid, Datum reloptions, CreateStmt *mainTblStmt) { Relation rel = NULL; rel = heap_open(relOid, AccessExclusiveLock); /* Ledger user table only support for the regular relation. */ if (!rel->rd_isblockchain) { heap_close(rel, NoLock); return; } create_hist_relation(rel, reloptions, mainTblStmt); heap_close(rel, NoLock); }历史表命名规则,参见函数get_hist_namebool get_hist_name(Oid relid, const char *rel_name, char *hist_name, Oid nsp_oid, const char *nsp_name) { errno_t rc; if (!OidIsValid(relid) || rel_name == NULL) { return false; } nsp_oid = OidIsValid(nsp_oid) ? nsp_oid : get_rel_namespace(relid); nsp_name = (nsp_name == NULL) ? get_namespace_name(nsp_oid) : nsp_name; int part_hist_name_len = strlen(rel_name) + strlen(nsp_name) + 1; if (part_hist_name_len + strlen("_hist") >= NAMEDATALEN) { rc = snprintf_s(hist_name, NAMEDATALEN, NAMEDATALEN - 1, "%d_%d_hist", nsp_oid, relid); securec_check_ss(rc, "", ""); } else { rc = snprintf_s(hist_name, NAMEDATALEN, NAMEDATALEN - 1, "%s_%s_hist", nsp_name, rel_name); securec_check_ss(rc, "", ""); } return true; }表名最大长度 #define NAMEDATALEN 64如果没有超过长度限制:schema_table_hist如果超过长度限制:schema(oid)_talbe(oid)_hist,因为oid是unsigned int 类型最大值为4294967295为10位,所以这种命名规则的最大长度为10+1+10+1+4+\0=27,因此永远不会超过最大长度64。omm=# create schema aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa with blockchain; CREATE SCHEMA omm=# create table aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.bbbbbbbbbbbbbbbbbbbbbbbbbbbbbb(id int); CREATE TABLE历史表索引命名规则,参见函数get_hist_name /* now create index for this new history table */ char hist_index_name[NAMEDATALEN]; rc = snprintf_s(hist_index_name, NAMEDATALEN, NAMEDATALEN - 1, "gs_hist_%u_index", relid);命名规则:gs_hist_$(账本表oid)_index。3、修改防篡改用户表数据对防篡改用户表执行INSERT/UPDATE/DELETE。openGauss=# INSERT INTO ledgernsp.usertable VALUES(1, 'alex'), (2, 'bob'), (3, 'peter'); INSERT 0 3 openGauss=# SELECT *, hash FROM ledgernsp.usertable ORDER BY id; id | name | hash ----+-------+------------------ 1 | alex | 1f2e543c580cb8c5 2 | bob | 8fcd74a8a6a4b484 3 | peter | f51b4b1b12d0354b (3 rows) openGauss=# UPDATE ledgernsp.usertable SET name = 'bob2' WHERE id = 2; UPDATE 1 openGauss=# SELECT *, hash FROM ledgernsp.usertable ORDER BY id; id | name | hash ----+-------+------------------ 1 | alex | 1f2e543c580cb8c5 2 | bob2 | 437761affbb7c605 3 | peter | f51b4b1b12d0354b (3 rows) openGauss=# DELETE FROM ledgernsp.usertable WHERE id = 3; DELETE 1 openGauss=# SELECT *, hash FROM ledgernsp.usertable ORDER BY id; id | name | hash ----+------+------------------ 1 | alex | 1f2e543c580cb8c5 2 | bob2 | 437761affbb7c605 (2 rows)查看账本历史操作记录你知道的那些事儿官方文档前提条件系统中需要有审计管理员或者具有审计管理员权限的角色。数据库正常运行,并且对防篡改数据库执行了一系列增、删、改等操作,保证在查询时段内有账本操作记录结果产生。你不知道的那些事儿基本操作1、查询全局区块表记录。omm=# SELECT * FROM gs_global_chain; blocknum | dbname | username | starttime | relid | relnsp | relname | relhash | globalhash | txcommand ----------+--------+----------+-------------------------------+-------+-----------+-----------+------------------+----------------------------------+---------------- -------------------------------------------------------------- 1 | omm | omm | 2022-09-17 13:59:37.84824+00 | 16404 | ledgernsp | usertable | a41714001181a294 | 83927d11ba1fd678e8f4b0723a9cd5f2 | INSERT INTO led gernsp.usertable VALUES(1, 'alex'), (2, 'bob'), (3, 'peter'); 2 | omm | omm | 2022-09-17 13:59:51.723068+00 | 16404 | ledgernsp | usertable | b3a9ed0755131181 | b5ee73b6c20c817230182f6373c78e20 | UPDATE ledgerns p.usertable SET name = 'bob2' WHERE id = 2; 3 | omm | omm | 2022-09-17 13:59:58.159596+00 | 16404 | ledgernsp | usertable | 0ae4b4e4ed2fcab5 | 0cc9938cf7f1ed7f7f1a03c29954380a | DELETE FROM led gernsp.usertable WHERE id = 3; (3 rows)注册钩子,在对账本做修改操作的时候注册的钩子函数ledger_ExecutorEnd被回调。/* * ledger_hook_init -- install of gchain block record hook. */ void ledger_hook_init(void) { t_thrd.security_ledger_cxt.prev_ExecutorEnd = (void *)ExecutorEnd_hook; ExecutorEnd_hook = ledger_ExecutorEnd; }生成globalhash规则全局区块表记录主要是生成globalhash.调用过程:ledger_ExecutorEnd --> ledger_gchain_append --> set_gchain_comb_string                                                                          --> get_next_g_blocknum                                                                          --> gen_global_hashset_gchain_comb_string,是一组字符串拼接成的:rel_name + nsp_name + query_string + rel_hashget_next_g_blocknum,用全局变量g_blocknum保存gen_global_hash,是的set_gchain_comb_string拼出来的串+上一条的hash值拼串然后再去hash——区块链的基本原理bool gen_global_hash(hash32_t *hash_buffer, const char *info_string, bool exist, const hash32_t *prev_hash) { errno_t rc = EOK; int comb_strlen; char *comb_string = NULL; /* * Previous block not exists means current insertion block is genesis, * then we use global systable as origin combine string for globalhash * generation. If previous block exists, we will use previous global * hash as combine string to calculate globalhash. */ if (!exist) { /* generate genesis block globalhash */ comb_strlen = strlen(GCHAIN_NAME) + strlen(info_string) + 1; comb_string = (char *)palloc0(comb_strlen); rc = snprintf_s(comb_string, comb_strlen, comb_strlen - 1, "%s%s", GCHAIN_NAME, info_string); securec_check_ss(rc, "", ""); } else { /* use previous globalhash and current block info to calculate globalhash. */ char *pre_hash_str = DatumGetCString(DirectFunctionCall1(hash32out, HASH32GetDatum(prev_hash))); comb_strlen = strlen(pre_hash_str) + strlen(info_string) + 1; comb_string = (char *)palloc0(comb_strlen); rc = snprintf_s(comb_string, comb_strlen, comb_strlen - 1, "%s%s", info_string, pre_hash_str); securec_check_ss(rc, "", ""); pfree_ext(pre_hash_str); } if (!pg_md5_binary(comb_string, comb_strlen - 1, hash_buffer->data)) { pfree(comb_string); ereport(ERROR, (errcode(ERRCODE_OUT_OF_MEMORY), errmsg("Failed to generate globalhash, out of memory"))); return false; } pfree(comb_string); return true; }在src/gausskernel/runtime/executor/nodeModifyTable.cpp中更新_hist表的hash值。通过set_user_tuple_hash得到账本表hash列的值。/* * set_user_tuple_hash -- calculate and fill the hash attribute of user table's tuple. * * tup: row data of user table * rel: user table * hash_exists: whether tuple comes with tuplehash. * * Note: if hash_exists is true, we should recompute * tuple hash and compare with tuplehash of itself. */ HeapTuple set_user_tuple_hash(HeapTuple tup, Relation rel, bool hash_exists) { uint64 row_hash = gen_user_tuple_hash(rel, tup); int hash_attrno = user_hash_attrno(rel->rd_att); if (hash_exists) { bool is_null; Datum hash = heap_getattr(tup, hash_attrno + 1, rel->rd_att, &is_null); if (is_null || row_hash != DatumGetUInt64(hash)) { ereport(ERROR, (errcode(ERRCODE_OPERATE_INVALID_PARAM), errmsg("Invalid tuple hash."))); } return tup; } Datum *values = NULL; bool *nulls = NULL; bool *replaces = NULL; /* Build modified tuple */ int2 nattrs = RelationGetNumberOfAttributes(rel); values = (Datum*)palloc0(nattrs * sizeof(Datum)); nulls = (bool*)palloc0(nattrs * sizeof(bool)); replaces = (bool*)palloc0(nattrs * sizeof(bool)); values[hash_attrno] = UInt64GetDatum(row_hash); replaces[hash_attrno] = true; HeapTuple newtup = heap_modify_tuple(tup, RelationGetDescr(rel), values, nulls, replaces); pfree_ext(values); pfree_ext(nulls); pfree_ext(replaces); return newtup; }校验账本数据一致性你知道的那些事儿官方文档数据库正常运行,并且对防篡改数据库执行了一系列增、删、改等操作,保证在查询时段内有账本操作记录结果产生。你不知道的那些事儿基本操作1、校验防篡改用户表ledgernsp.usertable与其对应的历史表是否一致。omm=# SELECT pg_catalog.ledger_hist_check('ledgernsp', 'usertable'); ledger_hist_check ------------------- t (1 row)校验用户权限 Only super user or audit admin have access right to blockchain nsp /* Only super user or audit admin have access right to blockchain nsp */ if (nsp_oid == PG_BLOCKCHAIN_NAMESPACE) { return gs_blockchain_aclmask(roleid, mask); }校验历史表hash值is_hist_hash_identity --> get_usertable_hash_sum                                --> get_histtable_hash_sum/* * is_hist_hash_identity -- check whether user table hash and history table hash are equal * * relid: user table oid * res_hash: hash sum of history table */ bool is_hist_hash_identity(Oid relid, uint64 *res_hash) { uint64 user_hash_sum; uint64 hist_hash_sum; char hist_name[NAMEDATALEN]; char *rel_name = get_rel_name(relid); if (!get_hist_name(relid, rel_name, hist_name)) { ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("get hist table name failed."))); } Oid histoid = get_relname_relid(hist_name, PG_BLOCKCHAIN_NAMESPACE); if (!OidIsValid(histoid)) { ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("could not find hist table of \"%s\".", rel_name))); } user_hash_sum = get_usertable_hash_sum(relid); hist_hash_sum = get_histtable_hash_sum(histoid); *res_hash = hist_hash_sum; return user_hash_sum == hist_hash_sum; }2、查询防篡改用户表ledgernsp.usertable与其对应的历史表以及全局区块表中关于该表的记录是否一致。omm=# SELECT pg_catalog.ledger_gchain_check('ledgernsp', 'usertable'); ledger_gchain_check --------------------- t (1 row)校验是否为账本表ledger_usertable_check校验用户权限has_ledger_consistent_privilege校验历史表hash值is_hist_hash_identity计算/校验全局表hash get_gchain_relhash_sum/* * get_gchain_relhash_sum -- calculate relhash from gs_global_chain * * relid: user table oid */ static uint64 get_gchain_relhash_sum(Oid relid) { uint64 relhash = 0; HeapTuple tuple = NULL; /* scan the gs_global_chain catalog by relid */ Relation gchain_rel = heap_open(GsGlobalChainRelationId, AccessShareLock); Form_gs_global_chain rdata = NULL; TableScanDesc scan = heap_beginscan(gchain_rel, SnapshotNow, 0, NULL); while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL) { rdata = (Form_gs_global_chain)GETSTRUCT(tuple); if (rdata == NULL || rdata->relid != relid) { continue; } relhash += rdata->relhash; } heap_endscan(scan); heap_close(gchain_rel, AccessShareLock); return relhash; }归档账本数据库你知道的那些事儿官方文档前提条件:系统中需要有审计管理员或者具有审计管理员权限的角色。数据库正常运行,并且对防篡改数据库执行了一系列增、删、改等操作,保证在查询时段内有账本操作记录结果产生。数据库已经正确配置审计文件的存储路径audit_directory。你不知道的那些事儿基本操作1、对指定用户历史表进行归档操作。omm=# SELECT pg_catalog.ledger_hist_archive('ledgernsp', 'usertable'); ledger_hist_archive --------------------- t (1 row) omm=# SELECT * FROM blockchain.ledgernsp_usertable_hist; rec_num | hash_ins | hash_del | pre_hash ---------+------------------+------------------+---------------------------------- 4 | e78e75b00d396899 | 84e8bfc3b974e9cf | 6475a497b7a272a92bab012d7f3d615b (1 row)主要步骤如下:Copy user history table.Do unify and truncate.sum all hash_ins and hash_del for unification.Do real truncate.heap_truncate_one_relDo insertion for unified row.simple_heap_insertFlush history hash table cache.2、执行全局区块表导出操作omm=# SELECT * FROM gs_global_chain; blocknum | dbname | username | starttime | relid | relnsp | relname | relhash | globalhash | txcommand ----------+--------+----------+-------------------------------+-------+-----------+-----------+------------------+----------------------------------+---------------- -------------------------------------------------------------- 1 | omm | omm | 2022-09-17 13:59:37.84824+00 | 16404 | ledgernsp | usertable | a41714001181a294 | 83927d11ba1fd678e8f4b0723a9cd5f2 | INSERT INTO led gernsp.usertable VALUES(1, 'alex'), (2, 'bob'), (3, 'peter'); 2 | omm | omm | 2022-09-17 13:59:51.723068+00 | 16404 | ledgernsp | usertable | b3a9ed0755131181 | b5ee73b6c20c817230182f6373c78e20 | UPDATE ledgerns p.usertable SET name = 'bob2' WHERE id = 2; 3 | omm | omm | 2022-09-17 13:59:58.159596+00 | 16404 | ledgernsp | usertable | 0ae4b4e4ed2fcab5 | 0cc9938cf7f1ed7f7f1a03c29954380a | DELETE FROM led gernsp.usertable WHERE id = 3; (3 rows) omm=# SELECT pg_catalog.ledger_gchain_archive(); ledger_gchain_archive ----------------------- t (1 row) omm=# SELECT * FROM gs_global_chain; blocknum | dbname | username | starttime | relid | relnsp | relname | relhash | globalhash | txcommand ----------+--------+----------+------------------------------+-------+-----------+-----------+------------------+----------------------------------+----------- 2 | omm | omm | 2022-09-17 13:59:37.84824+00 | 16404 | ledgernsp | usertable | 62a5b5ec53c47eca | 7252d09679b0b3836a2e63da17284ad5 | Archived. (1 row)gs_global_chain主要处理流程:Init and prepare bak dictionary.Using CopyStmt to copy global chain.Do unify and truncate.Using hash table to do unify, each hash_entry refers to one relid informations.Split gs_global_chain by relid, and accumulate rel_hash to a new record for each rel.Do rel truncate.Insert newest record to gchain order by relid.Flush global_hash cache.修复账本数据库你知道的那些事儿官方文档前提条件:系统中需要有审计管理员或者具有审计管理员权限的角色。数据库正常运行,并且对防篡改数据库执行了一系列增、删、改等操作,保证在查询时段内有账本操作记录结果产生。你不知道的那些事儿基本操作1、执行历史表修复操作omm=# select * from blockchain.ledgernsp_usertable_hist; rec_num | hash_ins | hash_del | pre_hash ---------+------------------+------------------+---------------------------------- 4 | e78e75b00d396899 | 84e8bfc3b974e9cf | 6475a497b7a272a92bab012d7f3d615b (1 row) omm=# SELECT pg_catalog.ledger_hist_repair('ledgernsp', 'usertable'); ledger_hist_repair -------------------- 0000000000000000 (1 row)[drawio] (rHmeQ8HWKS_RFXgP-oTUZINZguxBYqh2IV64Y0j5TAA.svg)2、执行全局区块表修复操作omm=# select * from gs_global_chain ; blocknum | dbname | username | starttime | relid | relnsp | relname | relhash | globalhash | txcommand ----------+--------+----------+------------------------------+-------+-----------+-----------+------------------+----------------------------------+----------- 2 | omm | omm | 2022-09-17 13:59:37.84824+00 | 16404 | ledgernsp | usertable | 62a5b5ec53c47eca | 7252d09679b0b3836a2e63da17284ad5 | Archived. (1 row) omm=# SELECT pg_catalog.ledger_gchain_repair('ledgernsp', 'usertable'); ledger_gchain_repair ---------------------- 62a5b5ec53c47eca (1 row)首先判断用户权限,之后通过get_gchain_relhash_sum函数计算relhash字段/* * get_gchain_relhash_sum -- calculate relhash from gs_global_chain * * relid: user table oid */ static uint64 get_gchain_relhash_sum(Oid relid) { uint64 relhash = 0; HeapTuple tuple = NULL; /* scan the gs_global_chain catalog by relid */ Relation gchain_rel = heap_open(GsGlobalChainRelationId, AccessShareLock); Form_gs_global_chain rdata = NULL; TableScanDesc scan = heap_beginscan(gchain_rel, SnapshotNow, 0, NULL); while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL) { rdata = (Form_gs_global_chain)GETSTRUCT(tuple); if (rdata == NULL || rdata->relid != relid) { continue; } relhash += rdata->relhash; } heap_endscan(scan); heap_close(gchain_rel, AccessShareLock); return relhash; }主要是计算并修复gs_global_chain中的relhash字段。总结账本数据库其实并不像我们想象的那么复制,实际上就是利用了区块链的最基本的原理,即当前记录的特征值 + 上一条记录特征值的hash值,再进行hash。下一条与上一条记录具有数据关联性,形成“链”的结构,如果篡改了其中的数据,则会导致“链”断开,导致不能与后面数据记录形成hash关联。_hist表记录了用户表每一步数据变化的过程,gs_global_chain表记录了所有防篡改模式下对用户表的操作记录。用户表结合_hist和global表就能完整记录和校验。
总条数:514 到第
上滑加载中