MogDB/openGauss 教程 浓缩版

概述

MogDB是EnMotech openGauss DataBase Enterprise Edition的缩写,是云和恩墨基于openGauss开源数据库进行定制、推出的企业发行版。它将围绕高可用、安全、自动化运维、数据库一体机和SQL审核优化等企业需求,解决企业用户落地。其核心价值是易用性、高性能、高可用等和全天候的企业支持。

MogDB与openGauss的关系

MogDB是在openGauss开源内核的基础上封装和改善的对于企业应用更加友好的企业级数据库。在openGauss内核的基础上,MogDB增加了MogHA组件,用于进行主备架构下高可用的自动化管理,这对于企业级应用来说是至关重要的。同时也同步研发了MogDB Manager管理软件,其中包括备份恢复,监控,自动化安装等等针对企业级易用性需求的组件。

安装MogDB

配置文件

<?xml version="1.0" encoding="UTF-8"?>
<ROOT>
    <!-- MogDB整体信息 -->
    <CLUSTER>
        <PARAM name="clusterName" value="dbCluster" />
        <PARAM name="nodeNames" value="node1" />
        <PARAM name="backIp1s" value="192.168.0.11"/>
        <PARAM name="gaussdbAppPath" value="/opt/mogdb/app" />
        <PARAM name="gaussdbLogPath" value="/var/log/mogdb" />
        <PARAM name="gaussdbToolPath" value="/opt/mogdb/tools" />
        <PARAM name="corePath" value="/opt/mogdb/corefile"/>
        <PARAM name="clusterType" value="single-inst"/>
    </CLUSTER>

    <!-- 每台服务器上的节点部署信息 -->
    <DEVICELIST>
        <!-- node1上的节点部署信息 -->
        <DEVICE sn="1000001">
            <PARAM name="name" value="node1"/>
            <PARAM name="azName" value="AZ1"/>
            <PARAM name="azPriority" value="1"/>
            <!-- 如果服务器只有一个网卡可用,将backIP1和sshIP1配置成同一个IP -->
            <PARAM name="backIp1" value="192.168.0.11"/>
            <PARAM name="sshIp1" value="192.168.0.11"/>

            <!--dbnode-->
            <PARAM name="dataNum" value="1"/>
            <PARAM name="dataPortBase" value="26000"/>
            <PARAM name="dataNode1" value="/mogdb/data/db1"/>
        </DEVICE>
    </DEVICELIST>
</ROOT>
参数说明
clusterNameMogDB名称。
nodeNamesMogDB中主机名称。
backIp1s主机在后端存储网络中的IP地址(内网IP)。所有MogDB主机使用后端存储网络通讯。
gaussdbAppPathMogDB程序安装目录。此目录应满足如下要求:
- 磁盘空间>1GB
- 与数据库所需其它路径相互独立,没有包含关系。
gaussdbLogPathMogDB运行日志和操作日志存储目录。此目录应满足如下要求:
- 磁盘空间建议根据主机上的数据库节点数规划。数据库节点预留1GB空间的基础上,再适当预留冗余空间。
- 与MogDB所需其它路径相互独立,没有包含关系。
此路径可选。不指定的情况下,MogDB安装时会默认指定“$GAUSSLOG/安装用户名”作为日志目录。
tmpdbPath数据库临时文件存放目录。
若不配置tmpdbPath,默认存放在/opt/mogdb/tools/perfadm_db目录下。
gaussdbToolPathMogDB系统工具目录,主要用于存放互信工具等。此目录应满足如下要求:
- 磁盘空间>100MB
- 固定目录,与数据库所需其它目录相互独立,没有包含关系。
此目录可选。不指定的情况下,MogDB安装时会默认指定“/opt/mogdb/tools”作为数据库系统工具目录。
corePathMogDB core文件的指定目录。
clusterTypeMogDB类型,MogDB拓扑类型;可选字段。
“single-inst”表示单机一主多备部署形态。

初始化脚本

执行以下命令以初始化脚本:

/opt/software/mogdb/script/gs_preinstall -U omm -G dbgrp -X /opt/software/mogdb/clusterconfig.xml

执行安装

依次执行以下命令安装MogDB:

su - omm
/opt/software/mogdb/script/gs_install -X /opt/software/mogdb/clusterconfig.xml --gsinit-parameter="--locale=en_US.UTF-8" --gsinit-parameter="--encoding=UTF-8"

运维

启动MogDB

  1. 以操作系统用户omm登录数据库主节点。
  2. 使用以下命令启动MogDB。
gs_om -t start

停止MogDB

  1. 以操作系统用户omm登录数据库主节点。
  2. 使用以下命令停止MogDB。
gs_om -t stop

使用gsql连接数据库

本地连接数据库

  1. 以操作系统用户omm登录数据库服务器。
  2. 连接数据库。

数据库安装完成后,默认生成名称为postgres的数据库。第一次连接数据库时可以连接到此数据库。

执行如下命令连接数据库。

gsql -d postgres -p 26000

其中postgres为需要连接的数据库名称,26000为数据库主节点的端口号。请根据实际情况替换。

连接成功后,系统显示类似如下信息:

gsql ((MogDB x.x.x build 56189e20) compiled at 2022-01-07 18:47:53 commit 0 last mr  )
Non-SSL connection (SSL connection is recommended when requiring high-security)
Type "help" for help.

postgres=#

omm用户是管理员用户,因此系统显示"postgres=#“。若使用普通用户身份登录和连接数据库,系统显示"postgres=>”。

"Non-SSL connection"表示未使用SSL方式连接数据库。如果需要高安全性时,请使用SSL连接。

  1. 退出数据库。
postgres=# \q

远程连接数据库

说明:

  • 由于安全性限制,数据库初始用户omm无法进行远程连接。
通过gs_guc配置白名单(更新pg_hba.conf文件)
  1. 以操作系统用户omm登录数据库主节点。
  2. 配置客户端认证方式,允许客户端以"jack"用户连接到本机,远程连接禁止使用"omm"用户(即数据库初始化用户)。

例如,下面示例中配置允许IP地址为172.16.0.245的客户端访问本机。

gs_guc set -N all -I all -h "host all jack 172.16.0.245/24 sha256"

注意:

  • 使用"jack"用户前,需先本地连接数据库,并在数据库中使用如下语句建立"jack"用户:
postgres=# CREATE USER jack PASSWORD 'Test@123';
  • -N all表示MogDB的所有主机。
  • -I all表示主机的所有实例。
  • -h表示指定需要在"pg_hba.conf"增加的语句。
  • all表示允许客户端连接到任意的数据库。
  • jack表示连接数据库的用户。
  • 172.16.0.245/24表示只允许IP地址为172.16.0.245的主机连接。此处的IP地址不能为MogDB内的IP,在使用过程中,请根据用户的网络进行配置修改。24表示子网掩码为1的位数,即255.255.255.0。
  • sha256表示连接时jack用户的密码使用sha256算法加密。

这条命令在数据库主节点实例对应的"pg_hba.conf"文件中添加了一条规则,用于对连接数据库主节点的客户端进行鉴定。

  1. 连接数据库。

数据库安装完成后,默认生成名称为postgres的数据库。第一次连接数据库时可以连接到此数据库。

gsql -d postgres -h 172.16.0.176 -U jack -p 26000 -W Test@123

postgres为需要连接的数据库名称,172.16.0.176为数据库主节点所在的服务器IP地址,jack为连接数据库的用户,26000为数据库主节点的端口号,Test@123为连接数据库用户jack的密码。

数据库设计

Database和Schema设计

MogDB中可以使用Database和Schema实现业务的隔离,区别在于Database的隔离更加彻底,各个Database之间共享资源极少,可实现连接隔离、权限隔离等,Database之间无法直接互访。Schema隔离的方式共用资源较多,可以通过grant与revoke语法便捷地控制不同用户对各Schema及其下属对象的权限。

  • 从便捷性和资源共享效率上考虑,推荐使用Schema进行业务隔离。
  • 建议系统管理员创建Schema和Database,再赋予相关用户对应的权限。

Database设计建议

  • 【规则】在实际业务中,根据需要创建新的Database,不建议直接使用数据库实例默认的postgres数据库。
  • 【建议】一个数据库实例内,用户自定义的Database数量建议不超过3个。
  • 【建议】为了适应全球化的需求,使数据库编码能够存储与表示绝大多数的字符,建议创建Database的时候使用UTF-8编码。
  • 【关注】创建Database时,需要重点关注字符集编码(ENCODING)和兼容性(DBCOMPATIBILITY)两个配置项。MogDB支持A、B和PG三种兼容模式,分别表示兼容Oracle语法、MySQL语法和PostgreSQL语法,不同兼容模式下的语法行为存在一定差异,默认为A兼容模式。
  • 【关注】Database的owner默认拥有该Database下所有对象的所有权限,包括删除权限。删除权限影响较大,请谨慎使用。

Schema设计建议

  • 【关注】如果该用户不具有sysadmin权限或者不是该Schema的owner,要访问Schema下的对象,需要同时给用户赋予Schema的usage权限和对象的相应权限。
  • 【关注】如果要在Schema下创建对象,需要授予操作用户该Schema的create权限。
  • 【关注】Schema的owner默认拥有该Schema下对象的所有权限,包括删除权限。删除权限影响较大,请谨慎使用。

应用开发

JDBC

CopyManager

【建议】在不使用ETL工具,数据入库实时性要求又比较高的情况下,建议在开发应用程序时,使用MogDB JDBC驱动的copyManger接口进行微批导入。

fetchsize

【关注】在应用程序中,如果需要使用fetchsize,必须关闭autocommit。开启autocommit,会令fetchsize配置失效。

ODBC

日志诊断场景

ODBC日志分为unixODBC驱动管理器日志和psqlODBC驱动端日志。前者可以用于追溯应用程序API的执行是否成功,后者是底层实现过程中的一些DFX日志,用来帮助定位问题。

unixODBC日志需要在odbcinst.ini文件中配置:

[ODBC]
Trace=Yes
TraceFile=/path/to/odbctrace.log

[GaussMPP]
Driver64=/usr/local/lib/psqlodbcw.so
setup=/usr/local/lib/psqlodbcw.so

psqlODBC日志只需要在odbc.ini加上:

[gaussdb]
Driver=GaussMPP
Servername=10.10.0.13(数据库Server IP)
...
Debug=1(打开驱动端debug日志)

说明: unixODBC日志将会生成在TraceFile配置的路径下,psqlODBC会在系统/tmp/下生成mylog_xxx.log。

高性能场景

进行大量数据插入时,建议如下:

  • 需要设置批量绑定:odbc.ini配置文件中设置UseBatchProtocol=1、数据库设置support_batch_bind=on。
  • ODBC程序绑定类型要和数据库中类型一致。
  • 客户端字符集和数据库字符集一致。
  • 事务改成手动提交。

odbc.ini配置文件:

[gaussdb]
Driver=GaussMPP
Servername=10.10.0.13(数据库Server IP)
...
UseBatchProtocol=1 (默认打开)
ConnSettings=set client_encoding=UTF8 (设置客户端字符编码,保证和server端一致)

调试

log_min_duration_statement配置语句执行持续的最短时间。
如果某个语句的持续时间大于或者等于设置的毫秒数,
则会在日志中记录该语句及其持续时间。
打开这个选项可以方便地跟踪需要优化的查询。
INT类型。
默认值: 30min。
单位: 毫秒。
设置为-1表示关闭这个功能。
只有系统管理员可以修改该参数。

编译oracle_fdw

编译oracle_fdw需要安装Oracle的开发库和头文件。

选择合适的运行环境和版本,下载Basic PackageSDK Package并安装。另外SQLPlus Package是Oracle的客户端工具,也可以根据需要安装,用于连接Oracle Server进行测试。

安装好开发包后,就可以开始编译oracle_fdw了。编译时需要在执行configure时,加入 -enable-oracle-fdw 选项。后续按照正常的MogDB编译方式编译即可。

编译完成后,编译产物为 oracle_fdw.so,位于安装目录的 **lib/postgresql/**下。oracle_fdw相关的sql文件和control文件,位于安装目录的 **share/postgresql/extension/**下。

如果编译安装时,没有加入 -enable-oracle-fdw 选项,可以在MogDB安装完成后,再次编译oracle_fdw,然后手动将编译产物 oracle_fdw.so 放到对应的安装目录 lib/postgresql/ ,将 oracle_fdw-1.0-1.1.sqloracle_fdw-1.1.sqloracle_fdw.control放到对应的安装目录 **share/postgresql/extension/**即可。

兼容oracle

增强Oracle兼容能力

支持Orafce插件

通过集成orafce插件,支持以下Oracle兼容语法:

  • SQL Queries
    • DUAL table
  • SQL Functions
    • Mathematical functions
      • BITAND
      • COSH
      • SINH
      • TANH
    • String functions
      • INSTR
      • LENGTH
      • LENGTHB
      • LPAD
      • LTRIM
      • NLSSORT
      • REGEXP_COUNT
      • REGEXP_INSTR
      • REGEXP_LIKE
      • REGEXP_SUBSTR
      • REGEXP_REPLACE
      • RPAD
      • RTRIM
      • SUBSTR
      • SUBSTRB
    • Date/time functions
      • ADD_MONTHS
      • DBTIMEZONE
      • LAST_DAY
      • MONTHS_BETWEEN
      • NEXT_DAY
      • ROUND
      • SESSIONTIMEZONE
      • SYSDATE
      • TRUNC
    • Data type formatting functions
      • TO_CHAR
      • TO_DATE
      • TO_MULTI_BYTE
      • TO_NUMBER
      • TO_SINGLE_BYTE
    • Conditional expressions
      • DECODE
      • LNNVL
      • NANVL
      • NVL
      • NVL2
    • Aggregate functions
      • LISTAGG
      • MEDIAN
    • Functions that return internal information
      • DUMP
  • SQL Operators
    • Datetime operator
  • Packages
    • DBMS_ALERT
    • DBMS_ASSERT
    • DBMS_OUTPUT
    • DBMS_PIPE
    • DBMS_RANDOM
    • DBMS_UTILITY
    • UTL_FILE

支持connect by语法

可更新视图

重建视图时变更列

支持systimestamp函数

支持sys_guid函数

oracle函数使用

select oracle.btrim('enmo');
select oracle.get_full_version_num();
select oracle.get_major_version();
select oracle.get_major_version_num();
select oracle.get_platform();
select oracle.get_status();
select oracle.length(1);
select oracle.lpad('enmo', 1);
select oracle.ltrim('enmo', 'enmo');
select oracle.numtodsinterval(12.22,'1232');
select oracle.nvl(1,2);
select oracle.regexp_count('enmo', 'tech');
select oracle.regexp_instr('enmo', 'tech');
select oracle.regexp_replace('enmo', 'tech', 'sss', 1);
select oracle.regexp_substr('enmo', 'tech', 1);

MTK数据库迁移工具

使用

# 生成配置文件
vi mtk_config.json

# 运行
./mtk -c mtk_config.json

# 指定迁移报告
./mtk -c mtk_config.json --reportFile mtk_report

# 指定迁移报告和日志并设置调试
./mtk -c mtk_config.json --reportFile mtk_report --logfile mtk_report.log --debug

example

{
   --  源数据配置库信息
  "source": {
    -- 源数据库类型,不区分大小写.支持MySQL,Oracle,DB2,openGauss
    "type": "oracle",
    -- 源数据库连接信息
    "connect": {
      -- 源数据库版本,无需指定.连接数据库时自动查询
      "version": "11.2.0.4.0",
      -- 源数据库主机. 支持ip,主机名,域名
      "host": "192.168.56.65",
      -- 源数据库用户,必须具有查询数据字典和数据权限
      "user": "system",
      -- 源数据库端口
      "port": 1521,
      -- 源数据库用户密码
      "password": "oracle",
      -- 源数据库名称,部分数据库类型可能不需要
      -- Mysql/Postgres/Opengauss/db2数据库名
      -- Oracle Service Name
      -- Oracle     Default : orcl
      -- Mysql      Default : mysql
      -- Postgre    Default : postgres
      -- openGauss  Default : postgres
      "dbName": "orcl",
      -- 源数据库完整连接字符串,特定场景使用
      "dsn": ""
    },
  },
  --  目标数据配置库信息
  "target": {
    -- 目标数据库类型,不区分大小写.支持MySQL,Oracle,Postgres,openGauss,file
    "type": "postgres",
    -- 目标数据库连接信息
    "Connect": {
      -- 目标数据库版本,无需指定.连接数据库时自动查询
      "version": "12.3",
      -- 目标数据库主机. 支持ip,主机名,域名
      "host": "127.0.0.1",
      -- 目标数据库用户,必须具有创建用户(schema)、序列、表、索引、约束、视图等权限、
      "user": "postgres",
      -- 目标数据库端口
      "port": 5433,
      -- 目标数据库用户密码
      "password": "root",
      -- 目标数据库名称,部分数据库类型可能不需要
      -- Mysql/Postgres/Ppengauss/db2 database name
      -- Oracle Service Name ,
      "dbName": "postgres",
      -- 目标数据库完整连接字符串,特定场景使用
      "dsn": ""
    },
    -- Related parameters
    "parameter": {
      -- 删除已存在对象. 存在一定风险时请手工删除
      "dropExistingObject":false,
      -- truncate table.当只迁移数据时,防止数据冲突使用
      "truncTable": true,
      -- 数据导出为文件时,指定导出目录
      "path": "./data/postgres",
      -- 数据导出为文件时,文件类型. 支持csv,sql
      "fileType": "sql",
      -- 数据导出为文件时,文件大小. 不指定则不限制
      "fileSize": "500MiB",
      -- 数据导出为文件时,当指定为sql,指定生成那种数据库的语法
      -- 如从Oracle迁移到MySQL,默认生成mysql的插入数据语法
      "sqlDBType": "oracle",
      -- 导出文件为csv时,指定是否包含csv文件头.默认不导出
      "csvHeader": true,
      -- csv默认间隔符
      "csvFieldDelimiter": "|",
      -- csv Optionally Enclosed
      "csvOptionallyEnclosed": "'",
      -- 并行插入,测试阶段
      "parallelInsert": 1,
      -- 时间格式
      "timeFormat": "HH:MI:SS",
      -- date Format
      "dateFormat": "YYYY-MM-DD",
      -- date Time Format
      "dateTimeFormat": "YYYY-MM-DD HH24:MI:SS",
      -- 当配置此参数时不支持的分区表转换普通表,不支持的子分区表属性自动移除
      -- Oracle的List分区和Hash分区表在openGauss里为普通表
      -- Oracle的Range List复合分区表,在openGauss里为Range分区表,子分区表自动移除
      "noSupportPartTabToNormalTab": false,
      -- In the version that does not support virtual columns, virtual columns are converted to normal columns
      "virtualColToNormalCol": false,
      -- 自动跳过mysql错误时间.如 datetime 类型里 0000-00-00 13:14:15
      "mySQLSkipErrorDateTimeData": false,
      -- 新增表结构对比功能,防止对比bug出现增加参数忽略此功能
      "ignoreTableDDLCompErr": false,
      -- 支持忽略部分不支持列默认值. 如果oracle的sys_guid. 内嵌白名单性质
      "ignoreNotSupportDefault": false,
      "remapSchema":{
        "MTK1":"MTK1_NEW",
        "SOE":"SOE_NEW"
      },
      -- 列名关键字.在目标端创建时会自动增加""`` 并将关键字进行大小写转换
      -- 格式 列名: 大小写标识.  1 代表小写 2代表大写 其他为保持不变
      "colKeyWords": {
        "STREAM": 1,
        "TID": 1
      },
      -- 同列名关键字.预留对象关键字
      "objKeyWords": {}"virtualColConv": {
        "TRUNC_TIMESTAMP(SNAPTIME,'HH')+ (MINUTE(SNAPTIME)/10*10 +10) MINUTES": "date_trunc('hour',snaptime) + (date_part('minute',snaptime) / 10 +1)::int * interval '10 min'",
        "TRUNC_TIMESTAMP(SNAPTIME,'HH')+ (MINUTE(SNAPTIME)/10*10 +10) minutes": "date_trunc('hour',snaptime) + (date_part('minute',snaptime) / 10 +1)::int * interval '10 min'",
        "TRUNC_TIMESTAMP(SNAPTIME, 'HH') + (MINUTE(SNAPTIME) / 10 * 10 + 10) MINUTES": "date_trunc('hour',snaptime) + (date_part('minute',snaptime) / 10 +1)::int * interval '10 min'",
        "TRUNC_TIMESTAMP(SNAPTIME,'HH') + (MINUTE(SNAPTIME) / 10 * 10 + 10) minutes": "date_trunc('hour',snaptime) + (date_part('minute',snaptime) / 10 +1)::int * interval '10 min'",
        "LEFT(HOST,POSSTR(HOST,':')-1)": "SPLIT_PART(HOST,':',1)"
      }
    }
  },
  "limit": {
    -- 并行度,现在只在迁移表数据时有用.后面增加在创建索引时指定并行度
    "parallel": 2,
    -- fetchSize 指定提取大小 (每次应从结果集中提取的行数)。当数据表含有数百万个行,而您想避免发生内存不足错误时,可以使用此选项
    "fetchSize": 1000,
    -- batchSize 指定“批量插入”要使用的“批次大小”. 默认批次大小为 1000,如果出现“内存不足”异常,则可以降低此值
    "batchSize": 1000,
    -- bufferSize. 暂时没用到,可以忽略
    "bufferSize": 4
  },
  "object": {
    -- 注意区分大小写
    -- 迁移用户、database、schema,
    -- schema = mysql database
    -- schema = oracle user
    -- schema = postgres schema
    -- schema = db2 schema
    -- 注意:schemas和tables参数互斥,如果两个参数都填入了值,在执行MTK时会遇到“mtk-1002 schema and table cannot exist together”错误
    "schemas": [
      "SOE",
      "BT_X",
      "CUST_X"
    ],
    "tables": [
      "TABLE1",
      "MTK.TABLE2"
    ],
    -- 排除哪些表不迁移数据. schema表
    "excludeTable":{
      "MTK":[
        "TABLE_SKIP1",
        "TABLE_SKIP2"
      ]
    },
    -- 手工定义表粒度并行
    "tableSplit":{
      "MTK":{
        "TABLE_4":[
          "ID < 10000 ",
          "ID < 20000 AND ID >=10000",
          "ID < 30000 AND ID >=20000",
          "ID < 40000 AND ID >=30000",
          "ID < 50000 AND ID >=40000",
          "ID < 60000 AND ID >=50000",
          "ID < 70000 AND ID >=60000",
          "ID < 80000 AND ID >=70000",
          "ID < 90000 AND ID >=80000",
          "ID >= 90000"
        ]
      }
    }
  },
  -- dataOnly 是否只迁移数据
  "dataOnly": false,
  -- 是否只迁移数据结构
  "schemaOnly": true,
  -- 禁用表数据select对比
  "disableTableDataComp": false,
  -- 迁移报告目录.v0.0.18之前为单个html报告.v0.0.18后是一个目录
  "reportFile": "./data/postgres/report_to_db.html",
  -- 是否开启debug
  "debug": false
}

主要修改 source、target、object、enableSyncTabTbsPro几个配置项的修改。

MVD 异构数据库对比工具

MVD 目前支持的源端与目标端数据库类型如下:

  1. Oracle >= 11.2
  2. MogDB/openGauss >= 1.0 ( MacOS 暂不支持 SHA256 加密认证方式 )
  3. MySQL >= 5.5
  4. DB2 >= 11.5

对比 Oracle 到 MogDB 的结构和数据差异:

./mvd_macos_x86_64 -s 'ORACLE:127.0.0.1:1521:orcl:hongye:pwd' -t 'MOGDB:127.0.0.1:5432:omm:hongye:pwd' -i 'mtk.*' -R './diff'

只对某一张表执行数据对比(特征值对比):

./mvd_macos_x86_64 -s 'ORACLE:127.0.0.1:1521:orcl:scott:tiger' -t 'MOGDB:127.0.0.1:5432:postgres:hongye:pwd' -T 'HONGYE.TEST'

对比数据和结构,并精确识别差异行:

./mvd_macos_x86_64 -s 'ORACLE:127.0.0.1:1521:orcl:scott:tiger' -t 'MOGDB:127.0.0.1:5432:postgres:hongye:pwd' -T 'HONGYE.TEST' -R './diff'

根据 MTK 的配置文件,进行迁移后的数据校验:

./mvd_macos_x86_64 --mtk-config oracle2opengauss.json
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

夏 克

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值