华为高斯数据库(GaussDB
)是目前国产数据库中综合实力比较靠前的数据库之一。高斯数据库有单机开源版openGauss和企业版(包括集中式和分布式)。本文接上文《GaussDB 企业版轻量化部署探索》继续分享如何使用TPOPS
在小规格内存服务器上部署GaussDB
实例。原本使用自动化平台TPOPS
部署GaussDB
很简单,完全看产品能力,没有什么特别写的。然而实际难在平台对部署用的服务器内存规格要求是8U64G
以上经常看我文章的朋友都了解,在小规格服务器上部署国产数据库是一大挑战,也是熟悉产品运维原理的一个独特的途径。对于大部分初学者想了解GaussDB
,第一个门槛就是服务器配置。所以希望本文能带给大家一些启发破除这个限制。跟前面一样,整个过程困难很多,都是个人理解,仅用于学习。欢迎懂行的朋友留言或加好友交流。
部署准备
安装软件包准备
TPOPS
作为自动化运维平台,需要管理 GaussDB
相关软件包。
TPOPS
上传安装包
GaussDB
的软件包比较多且大,可以通过界面上传,也可以直接复制软件到TPOPS
服务器上指定路径(/opt/sftphome/sftpservice/package/scan/
)下,然后再在平台里选择"扫描上传"。为避免上传文件损坏,还需要提供每个软件包对应的校验文件。这个功能非常用心。
TPOPS
扫描上传历史记录
主机准备
上篇文章没有介绍服务器和操作系统,这里补充说明一下。CPU 是Intel
的,服务器是虚拟机,操作系统必须是麒麟操作系统(SP2
)或者通信系统(uniotech
)。操作系统实际我用的是Kylin V10 SP2
(SP3
不行,可能跟我下载的软件版本有关)。
主机上除了操作系统盘外,还需要一块独立的物理盘(如果没有盘会在添加主机的时候报错),物理盘不需要格式化文件系统。
数据库主机总是要做一些内核参数修改之类,这个TPOPS
会在添加主机的时候做。相关的基础软件包需要自己安装,这个文档里说的很具体就不重复了。
添加主机
添加主机前先创建好对应的机房信息。
TPOPS
机房维护
然后就是在对应的机房里添加主机。
网络方面支持三个网段到 IP ,这个贴合企业实际运维环境。这里有个概念"沙箱目录",暂时还不知道做什么用的。
添加主机会以任务流的方式执行。
添加任务可能会因为一些准备不符合条件而失败。比如说主机的字符集不是英文。
failed due to application method exception; exception=message:host detection [Character Set Parameters] not pass, please view host detect report and configure host.
修复方法,在主机上设置 LANG
变量值,然后重跑任务。
echo 'export LANG=en_US.UTF-8' >> /etc/profile
选择失败的子任务,重跑任务后就成功了。
部署 GaussDB
实例
实例管理包含两个功能:部署(新)实例和纳管(旧)实例。后者推测可以用于纳管通过脚本部署的GaussDB
或者纳管其他低版本TPOPS
部署的实例。这些确实是运维常见场景。
部署新实例
这次只测试了部署新实例功能。
在部署形态上有很多种选择,既有主备版本又有分布式版本。主备版本又分单节点、2节点、3节点、5节点。5节点还分1主4备或1主3备1仲裁。分布式版本分单节点、3节点、4节点、5节点、9节点多种形态。
这也是GaussDB
使用场景多样化决定,里面的原理展开说很多,以后再专门总结。
这次我选择简单一点的主备版本2节点。
实例部署选项里还要选择一个 NAS
路径,推测是备份路径。最终申请实例前会汇总确认一下信息。
提交申请后,正常情况下后台任务中心会新增一条安装实例的任务。
安装实例的任务流就相对更复杂一些。下面记录一下任务流子任务步骤,方便以后研究各个子任务的功能。
安装实例任务流(1/3)
安装实例任务流(2/3)
安装实例任务流(3/3)
说到任务流设计,这是自动化运维平台的基本功能,一般使用一种框架编程技术。这样能降低新增子任务的开发成本。任务流都有详细的日志,了解日志的分析方法也是运维的基本要求。否则,碰到任务报错就只能看着错误码去找官网文档。而文档在这方面的解释上都是"惜字如金"。
实例简单介绍
实例部署成功后就出现在实例管理页面里。
查看实例详情,信息也不是很多。
可以看到主备2节点实例有2个CM
节点(互为主备)、3个DN
节点(1主2备,2个备共用一个节点)
实例参数页面提供参数描述和修改,大部分参数跟 PostgreSQL
参数同理。
TPOPS
实例参数
实例性能诊断页面也是包含 SQL诊断、会话管理、性能报告等功能。这些功能都比较基础。前文提过如果要使用 AI 诊断能力,还需要部署一个 DBMind
实例,这个等以后再说。
TPOPS
实例诊断
其他数据库运维基本功能也都具备,包括数据库管理、用户管理、备份恢复管理、日志分析等。
TPOPS
日志分析
大部分精力耗在解决下面这个部署规格限制上了,所以这次就不去分析实例的物理结构特征了。
TPOPS
平台分析
实例部署规格分析
正常情况下,上面实例部署会很顺利,大概几分钟到十几分钟就可以部署好。
下面就是我部署实例之前的报错信息:DBS.280240:所选规格不存在。
这里从这个问题入手尝试分析讨论一下TPOPS
这个自动化运维产品的一些功能设计考虑点。
查看该版本 TPOPS
使用文档里,明确说明GaussDB
主备版支持4U16G
、8U32G
。
多次尝试无果,最终从一个现场技术得到一个答复建议主机规格不低于8U64G
。
使用手册里的文档内容自然是没有错的,只是没有跟产品版本保持同步。文档这么写也自然是以前部署时支持小内存规格的服务器上部署GaussDB
实例。很有可能是内部本来是这么用的,只是当GaussDB
要产品化对外输出时,面临千奇百怪的用户环境和很多小白用户时,小内存规格的GaussDB
很可能因为使用者运维不当而出现稳定性问题、性能问题等等。
所以为了减少数据库使用问题带来的售后成本,产品 TPOPS
在部署GaussDB
实例的时候对服务器规格设置了一个技术限制(门槛)。这个门槛能否破除呢?文档不会解释,只能靠自己摸索了。
如果这个技术限制是写在应用代码里(如JAVA
),那普通用户就毫无办法了,只可能通过另外一条路径去实现了(如用脚本在小规格服务器上部署GaussDB
,然后通过TPOPS
纳管实例。还不知道行不行。)。但是好的自动化运维平台在设计上不会有这种硬编码的逻辑,而是采取配置化的方法。相关的参数写在配置文件里或者元数据库表里。
平台元数据库
这里就说到自动化运维平台的核心:元数据库了。学习一个自动化运维平台的设计最快的方法就是研究它的元数据库表结构设计以及平台发出的 SQL。TPOPS
平台的元数据库必须是一个GaussDB
。这里就看看元数据库,也顺便初步了解一些 GaussDB
用法(绝大部分跟PostgreSQL
用法一样)。
[dbadmin@gauss68 dn_6001]$ rlwrap gsql -h127.0.0.1 -p 8635 -U rdsAdmin -W ****** core
gsql ((GaussDB Kernel 505.1.RC1.SPC0100 build b579cd12) compiled at 2024-03-24 16:42:44 commit 8436 last mr 16721 release)
SSL connection (cipher: ECDHE-RSA-AES128-GCM-SHA256, bits: 128)
Type "help" for help.
core=# \l+
List of databases
Name | Owner | Encoding | Collate | Ctype | Access privileges | Size | Tablespace | Description
-----------+----------+-----------+---------+-------+-----------------------+--------+------------+-------------------------------------------------
backup | root | SQL_ASCII | C | C | | 77 MB | pg_default |
core | root | SQL_ASCII | C | C | | 105 MB | pg_default |
log | root | SQL_ASCII | C | C | | 24 MB | pg_default |
metric | rdsAdmin | SQL_ASCII | C | C | | 24 MB | pg_default |
postgres | rdsAdmin | SQL_ASCII | C | C | =Tc/rdsAdmin +| 741 MB | pg_default | default administrative connection database
| | | | | rdsAdmin=CTc/rdsAdmin+| | |
| | | | | backupUser=c/rdsAdmin+| | |
| | | | | repUser=c/rdsAdmin +| | |
| | | | | root=c/rdsAdmin +| | |
| | | | | metricUser=c/rdsAdmin+| | |
| | | | | jxy001=c/rdsAdmin | | |
template0 | rdsAdmin | SQL_ASCII | C | C | =c/rdsAdmin +| 24 MB | pg_default | default template for new databases
| | | | | rdsAdmin=CTc/rdsAdmin | | |
template1 | rdsAdmin | SQL_ASCII | C | C | =c/rdsAdmin +| 24 MB | pg_default | unmodifiable empty database
| | | | | rdsAdmin=CTc/rdsAdmin | | |
templatem | rdsAdmin | SQL_ASCII | C | C | =c/rdsAdmin +| 19 MB | pg_default | unmodifiable MySQL compatible template database
| | | | | rdsAdmin=CTc/rdsAdmin | | |
wfs | root | SQL_ASCII | C | C | | 37 MB | pg_default |
(9 rows)
元数据库核心的表在core
下,监控数据在metric
下。其他还有几个模块分别有自己的数据库。在 core
数据库下又细分了很多 schema
,对应的是 TPOPS
的某些功能。
core=# \dn+
List of schemas
Name | Owner | Access privileges | Description | WithBlockChain
----------------------+----------+----------------------+----------------------------------+----------------
agilex | agilex | | | f
blockchain | rdsAdmin | | blockchain schema | f
core | core | | | f
cstore | rdsAdmin | | reserved schema for DELTA tables | f
db4ai | rdsAdmin | rdsAdmin=UC/rdsAdmin+| db4ai schema | f
| | =U/rdsAdmin | |
dbe_application_info | rdsAdmin | rdsAdmin=UC/rdsAdmin+| | f
| | =U/rdsAdmin | |
dbe_compression | rdsAdmin | rdsAdmin=UC/rdsAdmin+| | f
| | =U/rdsAdmin | |
dbe_describe | rdsAdmin | rdsAdmin=UC/rdsAdmin+| | f
| | =U/rdsAdmin | |
dbe_file | rdsAdmin | rdsAdmin=UC/rdsAdmin+| | f
| | =U/rdsAdmin | |
dbe_heat_map | rdsAdmin | rdsAdmin=UC/rdsAdmin+| | f
| | =U/rdsAdmin | |
dbe_ilm | rdsAdmin | rdsAdmin=UC/rdsAdmin+| | f
| | =U/rdsAdmin | |
dbe_ilm_admin | rdsAdmin | | | f
dbe_lob | rdsAdmin | rdsAdmin=UC/rdsAdmin+| | f
| | =U/rdsAdmin | |
dbe_match | rdsAdmin | rdsAdmin=UC/rdsAdmin+| | f
| | =U/rdsAdmin | |
dbe_output | rdsAdmin | rdsAdmin=UC/rdsAdmin+| | f
| | =U/rdsAdmin | |
dbe_perf | rdsAdmin | | dbe_perf schema | f
dbe_pldebugger | rdsAdmin | rdsAdmin=UC/rdsAdmin+| dbe_pldebugger schema | f
| | =U/rdsAdmin | |
dbe_pldeveloper | rdsAdmin | rdsAdmin=UC/rdsAdmin+| dbe_pldeveloper schema | f
| | =U/rdsAdmin | |
dbe_profiler | rdsAdmin | rdsAdmin=UC/rdsAdmin+| | f
| | =U/rdsAdmin | |
dbe_random | rdsAdmin | rdsAdmin=UC/rdsAdmin+| | f
| | =U/rdsAdmin | |
dbe_raw | rdsAdmin | rdsAdmin=UC/rdsAdmin+| | f
| | =U/rdsAdmin | |
dbe_scheduler | rdsAdmin | rdsAdmin=UC/rdsAdmin+| | f
| | =U/rdsAdmin | |
dbe_session | rdsAdmin | rdsAdmin=UC/rdsAdmin+| | f
| | =U/rdsAdmin | |
dbe_sql | rdsAdmin | rdsAdmin=UC/rdsAdmin+| | f
| | =U/rdsAdmin | |
dbe_sql_util | rdsAdmin | rdsAdmin=UC/rdsAdmin+| sql util schema | f
| | =U/rdsAdmin | |
dbe_stats | rdsAdmin | rdsAdmin=UC/rdsAdmin+| | f
| | =U/rdsAdmin | |
dbe_task | rdsAdmin | rdsAdmin=UC/rdsAdmin+| | f
| | =U/rdsAdmin | |
dbe_utility | rdsAdmin | rdsAdmin=UC/rdsAdmin+| | f
| | =U/rdsAdmin | |
dbe_xml | rdsAdmin | rdsAdmin=UC/rdsAdmin+| | f
| | =U/rdsAdmin | |
dbe_xmldom | rdsAdmin | rdsAdmin=UC/rdsAdmin+| | f
| | =U/rdsAdmin | |
dbe_xmlgen | rdsAdmin | rdsAdmin=UC/rdsAdmin+| | f
| | =U/rdsAdmin | |
dbe_xmlparser | rdsAdmin | rdsAdmin=UC/rdsAdmin+| | f
| | =U/rdsAdmin | |
jxy001 | jxy001 | | | f
mq | mq | | | f
pkg_service | rdsAdmin | rdsAdmin=UC/rdsAdmin+| pkg_service schema | f
| | =U/rdsAdmin | |
pkg_util | rdsAdmin | rdsAdmin=UC/rdsAdmin+| | f
| | =U/rdsAdmin | |
prvt_ilm | rdsAdmin | | private ilm schema | f
public | rdsAdmin | rdsAdmin=UC/rdsAdmin+| standard public schema | f
| | =U/rdsAdmin | |
snapshot | rdsAdmin | | snapshot schema | f
sqladvisor | rdsAdmin | rdsAdmin=UC/rdsAdmin+| sqladvisor schema | f
| | =U/rdsAdmin | |
sys | rdsAdmin | | | f
(41 rows)
核心的表在用户 core
默认的 schema
下。且看看有什么。
core=> \c - core
Password for user core:
SSL connection (cipher: ECDHE-RSA-AES128-GCM-SHA256, bits: 128)
You are now connected to database "core" as user "core".
core=> \dt+ dbs_resource*
List of relations
Schema | Name | Type | Owner | Size | Storage | Description
--------+--------------------------------------+-------+-------+---------+------------------------------------------------------------------+--------------
core | dbs_resource_domain | table | core | 0 bytes | {orientation=row,compression=no,storage_type=ustore,segment=off} |
core | dbs_resource_domain_bucket | table | core | 0 bytes | {orientation=row,compression=no,storage_type=ustore,segment=off} |
core | dbs_resource_domain_user | table | core | 0 bytes | {orientation=row,compression=no,storage_type=ustore,segment=off} |
core | dbs_resource_package | table | core | 0 bytes | {orientation=row,compression=no,storage_type=ustore,segment=off} | 套餐包表
core | dbs_resource_package_policy | table | core | 0 bytes | {orientation=row,compression=no,storage_type=ustore,segment=off} | 套餐包策略表
core | dbs_resource_pool | table | core | 0 bytes | {orientation=row,compression=no,storage_type=ustore,segment=off} |
core | dbs_resource_pool_preset | table | core | 0 bytes | {orientation=row,compression=no,storage_type=ustore,segment=off} |
core | dbs_resource_specification | table | core | 296 kB | {orientation=row,compression=no,storage_type=ustore,segment=off} |
core | dbs_resource_specification_attribute | table | core | 1168 kB | {orientation=row,compression=no,storage_type=ustore,segment=off} |
core | dbs_resource_specification_price | table | core | 80 kB | {orientation=row,compression=no,storage_type=ustore,segment=off} |
(10 rows)
在 PostgreSQL
数据库里,用户(user
)、数据库(db
)和模式(schema
)是三个概念,彼此可以设置一定关联关系,实现复杂的权限管控。学院派数据库就是这样,喜欢整得很复杂,GaussDB
沿用了这个底层设计。TPOPS
元数据库本身的总体设计就是一个GaussDB
数据库设计的最佳实践模板。
不过TPOPS
平台也是从内部运维平台孵化出来的,有很多年的历史了,历经很多版本迭代。数据库架构设计可以参考,但某些细节处可能不一定最优,就不要学了。这个也很正常,企业客户的应用也都是这个特点。所有 IT 系统的设计都遵循熵增的特点,经年累月后维护成本高到接手的人无法运维后必然就要兴起技术架构的重构。这是往远处说了。当前TPOPS
的使用就目前体验而言还是很顺畅的。本身架构上采用了服务化设计,能灵活应对纷繁复杂的企业运维场景。
破除实例部署规格限制的方法
前面说了学习一款自动化运维平台最好的方法就是研究它的元数据库,那么要破除TPOPS
部署GaussDB
实例规格的方法入口也是研究元数据库。
首先开启GaussDB
的日志中的 SQL 日志功能。修改对应参数,然后重启数据库。
[dbadmin@gauss68 dn_6001]$ pwd
/opt/gaussdb/data/dn/dn_6001
[dbadmin@gauss68 dn_6001]$ cat gaussdb.conf |grep log_statement
#log_statement = 'none' # none, ddl, mod, all
log_statement = 'all' # none, ddl, mod, all
#log_statement_stats = off
其次查看GaussDB
的运行日志。
[dbadmin@gauss68 dn_6001]$ cat gaussdb.conf |grep log_directory
log_directory = '/opt/gaussdb/logs/gaussdb/dbadmin/gs_log/dn_6001' # directory where log files are written,
/opt/gaussdb/logs/gaussdb/dbadmin/gs_log/dn_6001
[dbadmin@gauss68 dn_6001]$ cd /opt/gaussdb/logs/gaussdb/dbadmin/gs_log/dn_6001
[dbadmin@gauss68 dn_6001]$ ls -lrth gaussdb-2024-11-*.log
-rw------- 1 dbadmin dbgrp 21M Nov 20 07:04 gaussdb-2024-11-20_150353.log
-rw------- 1 dbadmin dbgrp 21M Nov 20 07:06 gaussdb-2024-11-20_150459.log
-rw------- 1 dbadmin dbgrp 21M Nov 20 07:07 gaussdb-2024-11-20_150606.log
查看最新的日志,发现下面这段日志跟规格报错很可能有联系。
65744 2024-11-19 23:33:00.218 dn_6001 core core 127.0.0.1 139637747087104 0[0:0#0] 0 PostgreSQL JDBC Driver 1947525363863979756 [BACKEND] LOG: [Current Statement] execute <unnamed>: SELECT
65745 rs.ID, rs.CREATED_AT, rs.UPDATED_AT, rs.VERSION, rs.STATUS, rs.TYPE_CODE, rs.CODE,
65746 rs.ADDIONAL_CODE_WRITTEN_TO_BILL, rs.BSS_PRODUCT_ID, rs.COMMENT
65747 FROM DBS_RESOURCE_SPECIFICATION rs
65748 LEFT JOIN DBS_RESOURCE_SPECIFICATION_ATTRIBUTE rsa1 on rs.id = rsa1.SPECIFICATION_ID and rsa1.NAME = 'serverType'
65749 LEFT JOIN DBS_RESOURCE_SPECIFICATION_ATTRIBUTE rsa2 on rs.id = rsa2.SPECIFICATION_ID and rsa2.NAME = 'groupType'
65750 LEFT JOIN DBS_RESOURCE_SPECIFICATION_ATTRIBUTE rsa3 on rs.id = rsa3.SPECIFICATION_ID and rsa3.NAME = 'architecture'
65751 WHERE rs.id in (
65752 SELECT es.SPECIFICATION_ID from DBS_ENGINE_SPECIFICATION es
65753 WHERE es.ENGINE_ID = $1
65754 AND es.INSTANCE_MODE = $2
65755 AND es.STATUS = 'ENABLED'
65756 )
65757 AND rsa1.VALUE = $3
65758 AND rsa2.VALUE = $4
65759 AND rsa3.VALUE = $5
65760 2024-11-19 23:33:00.218 dn_6001 core core 127.0.0.1 139637747087104 0[0:0#0] 0 PostgreSQL JDBC Driver 1947525363863979756 [BACKEND] DETAIL: parameters: $1 = 'b3fc465b-8ef3-4ba1-9250-e3936a90b187', $2 = 'ha', $3 = 'BMS', $4 = 'bms', $5 = 'X86'
65761 2024-11-19 23:33:00.222 dn_6001 core core 127.0.0.1 139637747087104 0[0:0#0] 0 PostgreSQL JDBC Driver 1947525363863979757 [BACKEND] LOG: [Current Statement] execute S_36: select
65762
65763 'true' as QUERYID,
65764
65765 ID, CREATED_AT, UPDATED_AT, VERSION, STATUS, SPECIFICATION_ID, NAME, VALUE, COMMENT
65766
65767 from DBS_RESOURCE_SPECIFICATION_ATTRIBUTE
65768
65769
65770 WHERE ( SPECIFICATION_ID = $1 )
65771 2024-11-19 23:33:00.222 dn_6001 core core 127.0.0.1 139637747087104 0[0:0#0] 0 PostgreSQL JDBC Driver 1947525363863979757 [BACKEND] DETAIL: parameters: $1 = 'ff78b3e0-cb94-34ca-996f-8e2223bc3611'
65772 2024-11-19 23:33:00.223 dn_6001 core core 127.0.0.1 139637747087104 0[0:0#0] 0 PostgreSQL JDBC Driver 1947525363863979758 [BACKEND] LOG: [Current Statement] execute S_36: select
65773
65774 'true' as QUERYID,
65775
65776 ID, CREATED_AT, UPDATED_AT, VERSION, STATUS, SPECIFICATION_ID, NAME, VALUE, COMMENT
65777
65778 from DBS_RESOURCE_SPECIFICATION_ATTRIBUTE
65779
65780
65781 WHERE ( SPECIFICATION_ID = $1 )
65782 2024-11-19 23:33:00.223 dn_6001 core core 127.0.0.1 139637747087104 0[0:0#0] 0 PostgreSQL JDBC Driver 1947525363863979758 [BACKEND] DETAIL: parameters: $1 = '012253b5-a1b2-3f1d-b2e1-7ba4dfea08b2'
实际上我看了多个表的很多记录(dbs_resource_*
)才将范围缩小到上面这段日志。所以后面的办法就是分析这个查询结果,插入相关记录,使得TPOPS
能从实例规格表里找到内存32G
对应的规格。
这个补数据的SQL 每个人环境可能 ID 值不一样,我就不写了,直接给出相关表的查询记录。
select * from core.dbs_resource_specification where id='f35cd334-88af-713d-082d-000c294d8f45';
select * from core.dbs_resource_specification_attribute where specification_id in ('f35cd334-88af-713d-082d-000c294d8f45') order by name, specification_id ;
select * from core.dbs_engine_specification where specification_id ='f35cd334-88af-713d-082d-000c294d8f45';
结果集分别如下:
最后补充说明一下:
-
硬件环境和操作系统不一样,对应的实例规格 ID 就不一样。我这里补的记录不一定涵盖了所有的部署场景。
-
补元数据的方法只是适用于学习,生产环境没有小规格服务器问题,不要轻易的去修改元数据。因为
TPOPS
的设计逻辑不是公开的,可能会变化。
总结
国产分布式数据库的规模往往很大,所以需要借助自动化运维平台来运维。自动化运维平台本质上是将运维流程标准化、自动化。好的自动化运维平台设计上架构清晰、扩展性好、运维便利性高。大厂出口的自动化运维平台都久经考验,可学习研究借鉴的价值很高。GaussDB
数据库体系庞大,架构复杂,学习和运维难度也非同一般,所以也很依赖自动化运维平台 TPOPS
。
作者:数据库技术闲谈