阿里云-云小站(无限量代金券发放中)
【腾讯云】云服务器、云数据库、COS、CDN、短信等热卖云产品特惠抢购

OGG心得笔记

206次阅读
没有评论

共计 26012 个字符,预计需要花费 66 分钟才能阅读完成。

OGG 学习笔记 01- 基础概述
OGG(Oracle Golden Gate), 最近几年在数据同步、容灾领域特别火,甚至比 Oracle 自己的原生产品 DataGuard 还要风光,主要是因为其跨平台、跨数据库、跨版本的强大特性。

OGG 理论概念

我们可以搜索到网上对它的简单介绍:

Oracle Golden Gate 软件是一种基于日志的结构化数据复制备份软件,它通过解析源数据库在线日志或归档日志获得数据的增量变化,再将这些变化应用到目标数据库,从而实现源数据库与目标数据库同步。
Oracle Golden Gate 可以在异构的 IT 基础结构(包括几乎所有常用操作系统平台和数据库平台)之间实现大量数据亚秒一级的实时复制, 从而可以在应急系统、在线报表、实时数据仓库供应、交易跟踪、数据同步、集中 / 分发、容灾、数据库升级和移植、双业务中心等多个场景下应用。同时,Oracle Golden Gate 可以实现一对一、广播(一对多)、聚合(多对一)、双向、点对点、级联等多种灵活的拓扑结构.

目前许多客户环境都已经在广泛使用 OGG。由于工作需要,近期我也会系统的学习下 OGG,目前学习主要以 OGG 在 Oracle 数据库之间的同步来说明一些基本概念,后续看时间情况可能了解 OGG 对其他主流数据库的同步。
假设已有源数据库和目标数据库,且分别部署好 OGG 软件。
源数据库部署的 OGG,简称源 OGG;目标数据库部署的 OGG,简称目标 OGG。

同步的过程就是源 OGG 的 EXTRACT 进程从源数据库的联机 redologs 中抽取获得变化,把它写到本地 trail 文件中,然后源 OGG 的 Data pump 进程再从本地 trail 文件中抽取变化传给目标 OGG 的 collector 进程,目标的 collector 进程再把这些变化写入目标 trail 文件中,最后目标 OGG 的 Replicat 进程把目标 trail 文件中记录的变化应用到目标数据库中。
如果要同步的表数量比较多或是业务有区分,需要分开管理,OGG 是支持分开多个 extract 进程,多个 datapump 进程,多个 replicat 进程,这样,可以启动或停止其中任意一类同步,而不影响其他的同步。

由此,我们可以得到一张 Oracle Golden Gate 的简要体系图:
OGG 心得笔记

需要注意的是,每套 OGG 所有的进程都是由其 Manager 进程来管理的,也就是说 Manager 进程负责管理,启动关闭其他进程。OGG 用组来表示它的进程,上面简单提到的 extract、replicat 这些进程,实际上需要各自的参数文件、检查点文件等。这些内容共同组成一个组,且每个组需要有一个组名字。
可以将上面的简要体系图再标注一些内容,便于理解 OGG 实际的工作方式。
OGG 心得笔记

OGG 的检查点信息,对于源 OGG 只能以文件形式默认存放在 GGHOME/dirchk 目录下,一个组对应一个文件。
而对于目标 OGG 检查点信息可以存放在数据库表中,且建议存放到数据库表中。

对于源数据库,如果要使用 OGG,需要配置 supplemental logging,原因是 OGG 相当于逻辑同步,除了要记录被修改的记录,还要把能够标识这条记录的信息同时记录在日志中。这样的话,Oracle 默认情况是不达标的,需要额外开启 supplemental logging 才可以。
具体做法是:在数据库级别开启最小附加日志,在需要同步的表级别开启详细附加日志。

# 数据库级别开启最小附加日志:
SQL> alter database add supplemental log data;
# 表级别开启详细附加日志(这里举例是 jy 用户下的 t_second 表):
GGSCI> add trandata jy.t_second

对于目标数据库,配置检查点信息到目标数据库表中,具体做法:

#1. 目标 GG 的全局参数 (./globals) 配置
checkpointtable ggt.chkpt
#2. 命令添加 checkpointtable
GGSCI> add checkpointtable ggt.chkpt

复制进程可以指定 checkpointtable 从而使用数据库表记录检查点信息。

OGG 安装介绍

OGG 介质下载,在 ORACLE 官网就有提供最新版本下载,如果需要下载历史版本的,就需要 MOS 账号。
下载地址:https://edelivery.oracle.com
OGG 的安装也非常简单,在期望的安装目录下,直接解压压缩文件即可。

[ogg@oradb30 ~]$ cd /u01/app
[ogg@oradb30 app]$ ls
oracle
[ogg@oradb30 app]$ mkdir ogg
[ogg@oradb30 app]$ cd ogg/
[ogg@oradb30 ogg]$ pwd
/u01/app/ogg
[ogg@oradb30 ogg]$ tar xvf /u01/media/fbo_ggs_Linux_x64_ora10g_64bit.tar 

为了便于管理维护,我们创建新的操作系统用户和数据库用户,专门给 OGG 使用。

# 创建系统用户 ogg,隶属于 oinstall 组
useradd ogg -g oinstall

环境变量,除了设置 OGG 自己,还需要设置可以访问到库文件,这也是为何将系统用户 ogg 隶属于 oinstall 组,保证其有权限访问 oracle 安装目录的库文件。

export ORACLE_HOME=/u01/app/oracle/product/10.2.0/db_1
export LD_LIBRARY_PATH=$ORACLE_HOME/lib:$LD_LIBRARY_PATH
export GG_HOME=/u01/app/ogg
export PATH=$GG_HOME:$PATH

确定 ggsci 可以正常使用,然后使用 create subdirs 创建 OGG 的子目录,最后配置好 Manager。

#1. 确定 ggsci 可以正常使用
[ogg@oradb30 ~]$ ggsci
ggsci: error while loading shared libraries: /u01/app/oracle/product/10.2.0/db_1/lib/libclntsh.so.10.1: cannot restore segment prot after reloc: Permission denied

我这里遇到的这个错误关键点是“cannot restore segment prot after reloc: Permission denied”是因为主机系统 SELinux 开启的原因。关闭 SELinux 即可解决。[root@oradb30 ~]# su - ogg
[ogg@oradb30 ~]$ cd /u01/app/ogg/
[ogg@oradb30 ogg]$ ggsci

Oracle GoldenGate Command Interpreter for Oracle
Version 11.2.1.0.1 OGGCORE_11.2.1.0.1_PLATFORMS_120423.0230_FBO
Linux, x64, 64bit (optimized), Oracle 10g on Apr 23 2012 07:30:46

Copyright (C) 1995, 2012, Oracle and/or its affiliates. All rights reserved.

GGSCI (oradb30) 1> 

#2.使用create subdirs 创建 OGG 的子目录
GGSCI (oradb30) 1> create subdirs

Creating subdirectories under current directory /u01/app/ogg

Parameter files                /u01/app/ogg/dirprm: already exists
Report files                   /u01/app/ogg/dirrpt: created
Checkpoint files               /u01/app/ogg/dirchk: created
Process status files           /u01/app/ogg/dirpcs: created
SQL script files               /u01/app/ogg/dirsql: created
Database definitions files     /u01/app/ogg/dirdef: created
Extract data files             /u01/app/ogg/dirdat: created
Temporary files                /u01/app/ogg/dirtmp: created
Stdout files                   /u01/app/ogg/dirout: created


#3.配置好 Manager
GGSCI (oradb30) 2> edit param mgr   
port 7777
GGSCI (oradb30) 3> info mgr
Manager is DOWN!
GGSCI (oradb30) 4> start mgr
Manager started.
GGSCI (oradb30) 5> info mgr
Manager is running (IP port oradb30.7777).

后续 extract、replicate 等 OGG 实际工作的进程(组)配置,将在下篇《OGG 学习笔记 02- 单向复制配置实例》详细说明。

Reference

  • 张晓明. 大话 Oracle Grid[M]. 人民邮电出版社, 2014. PDF 下载见 http://www.linuxidc.com/Linux/2017-01/139861.htm

更多详情见请继续阅读下一页的精彩内容:http://www.linuxidc.com/Linux/2017-01/139863p2.htm

OGG 学习笔记 02- 单向复制配置实例

实验环境:
源端:192.168.1.30,Oracle 10.2.0.5 单实例
目标端:192.168.1.31,Oracle 10.2.0.5 单实例

  • 1. 模拟源数据库业务持续运行
  • 2. 配置 OGG 前期准备
  • 3. 配置 OGG 单向复制

1. 模拟源数据库业务持续运行

OGG 的单向配置比较简单,但实际生产过程很多业务要求不间断运行,
所以我创建了 2 张模拟业务表,简单模拟在业务不间断运行场景下 OGG 的配置。

1.1 创建模拟的业务用户

首先我创建业务用户 jy,并指定密码,赋予基本业务用户的角色权限。

--user
create user jy identified by jy default tablespace users;
--grant
grant resource, connect to jy;

1.2 在业务用户下创建表和存储过程

连接到业务用户 jy 下,创建 1 个序列,2 张表(其中一张表有主键):

--connect
conn jy/jy
--sequence
create sequence s1;
--tables 
--table t_second 无主键
create table t_second as select s1.nextval id, to_char(sysdate,'yyyy-mm-dd hh24:mi:ss') time from dual;
--table t_second_p 有主键
create table t_second_p as select s1.nextval id, to_char(sysdate,'yyyy-mm-dd hh24:mi:ss') time from dual;
alter table t_second_p add constraint pk_t_second_p primary key(id);

创建存储过程, 功能是:每秒向 2 张业务表分别插入 1 条数据;
用来模拟持续运行的业务;

--procedure
create or replace procedure p1  is
begin
for i in  1..86400
loop
insert into  t_second select s1.nextval, to_char(sysdate,'yyyy-mm-dd hh24:mi:ss') from dual;
commit;
insert into  t_second_p select s1.nextval, to_char(sysdate,'yyyy-mm-dd hh24:mi:ss') from dual;
commit;
dbms_lock.sleep(1);
end loop;
end;
/

执行存储过程,相当于模拟业务正式启动:

--execute
[oracle@oradb30 scripts]$ cat business.sh 
#!/bin/bash

sqlplus jy/jy <<EOF
exec p1;
EOF
[oracle@oradb30 scripts]$ nohup sh business.sh &

2. 配置 OGG 前期准备

2.1 创建源端和目标端 OGG 的管理员用户

-- 源数据库端:
create user ggs_admin identified by ggs_admin;
grant dba to ggs_admin;

-- 目标数据库端:
create user ggt_admin identified by ggt_admin;
grant dba to ggt_admin;

2.2 配置源数据库端的附加日志

-- 查看数据库附加日志开启状态:SQL> select SUPPLEMENTAL_LOG_DATA_MIN, SUPPLEMENTAL_LOG_DATA_PK,
SUPPLEMENTAL_LOG_DATA_UI from v$database;
-- 数据库级别开启最小附加日志:SQL> alter database add supplemental log data;
-- 表级别开启详细附加日志:GGSCI (oradb30) 6> dblogin userid ggs_admin@ora10, password ggs_admin
Successfully logged into database.
GGSCI (oradb30) 7> add trandata jy.t_second
2017-01-13 23:37:38  WARNING OGG-00869  No unique key is defined for table 'T_SECOND'. All viable columns will be used to represent the key, but may not guarantee uniqueness.  KEYCOLS may be used to define the key.
Logging of supplemental redo data enabled for table JY.T_SECOND.
GGSCI (oradb30) 8> add trandata jy.t_second_p
Logging of supplemental redo data enabled for table JY.T_SECOND_P.
GGSCI (oradb30) 9> 

2.3 配置源端和目标端的 OGG 所需进程

配置进程(组)名没有具体的规范,我这里参考晓明在书中所用的组命名方式:
对于复杂环境,第一位字母,local、immdiate、remote 分别对应 l、i、r;
后面根据进程属性属于 extract、datapump、replicat 而分别对应 x、p、r;

源端:
源端在上篇已经配置好 Manager 进程。
接下来继续配置源端的 extract 进程:
GGSCI (oradb30) 3> edit params lxjy1

--Local Extract lxjy1
--Author: Alfred Zhao
--
EXTRACT lxjy1
SETENV(NLS_LANG=american_america.ZHS16GBK)
SETENV(ORACLE_SID=ora10)
USERID ggs_admin, PASSWORD ggs_admin
EXTTRAIL ./dirdat/sa
TABLE JY.T_SECOND;
TABLE JY.T_SECOND_P;

添加 lxjy1 进程(local extract):

GGSCI (oradb30) 1> add extract lxjy1, tranlog, begin now, threads 1
EXTRACT added.
GGSCI (oradb30) 2> add exttrail ./dirdat/sa, extract lxjy1, megabytes 50
EXTTRAIL added. 

配置源端的 datapump 进程:

--Local datapump lpjy1
--Author: Alfred Zhao
--
EXTRACT lpjy1
PASSTHRU
RMTHOST 192.168.1.31, MGRPORT 7777
RMTTRAIL ./dirdat/ta
TABLE JY.T_SECOND;
TABLE JY.T_SECOND_P;

添加 lpjy1 进程(本地 datapump 进程):

GGSCI (oradb30) 2> add extract lpjy1, exttrailsource ./dirdat/sa, begin now
EXTRACT added.
GGSCI (oradb30) 17> ADD RMTTRAIL ./dirdat/ta, EXTRACT LPJY1, MEGABYTES 50
RMTTRAIL added.

查看目前源端进程状态:

GGSCI (oradb30) 7> info all

Program     Status      Group       Lag at Chkpt  Time Since Chkpt

MANAGER     RUNNING                                           
EXTRACT     STOPPED     LPJY1       00:00:00      00:07:01    
EXTRACT     STOPPED     LXJY1       00:00:00      00:18:55    

可以看到 Manager 进程启动,LXJY1 和 LPJY1 没有启动。
目标端:
参考《OGG 学习笔记 01- 基础概述》中安装配置,对目标端也配置 Manager 进程。
配置 checkpointtable:

GGSCI (oradb31) 1> view params ./GLOBALS
checkpointtable ggt_admin.chkpt
GGSCI (oradb31) 2> dblogin userid ggt_admin@ora10dg, password ggt_admin
Successfully logged into database.
GGSCI (oradb31) 3> add checkpointtable
No checkpoint table specified, using GLOBALS specification (ggt_admin.chkpt)...
Successfully created checkpoint table ggt_admin.chkpt.

然后继续配置 replicat 进程:

--replicat rjy1
--Author: Alfred Zhao
--
REPLICAT rjy1
SETENV (ORACLE_SID=ora10)
USERID ggt_admin, PASSWORD ggt_admin
DISCARDFILE ./dirrpt/rjy1.dsc, PURGE
HandleCollisions
AssumeTargetDefs
Map jy.*,Target jy.*;

添加 rjy1 进程(replicat 进程):

GGSCI (oradb31) 8> add replicat rjy1, exttrail ./dirdat/ta
REPLICAT added.

查看当前目标端进程状态:

GGSCI (oradb31) 9> info all

Program     Status      Group       Lag at Chkpt  Time Since Chkpt

MANAGER     RUNNING                                           
REPLICAT    STOPPED     RJY1        00:00:00      00:00:18    

可以看到 Manager 已经启动,RJY1 还没有启动。

3. 配置 OGG 单向复制

注意以下 3 个步骤执行的顺序不能更改,否则很可能会造成数据不一致。

3.1 启动源库 extract 进程

确认已经启动 Manager 进程。
启动 lxjy1

GGSCI (oradb30) 12> start extract lxjy1

启动 lpjy1

GGSCI (oradb30) 19> start extract lpjy1

查看源端进程状态:

GGSCI (oradb30) 20> info all

Program     Status      Group       Lag at Chkpt  Time Since Chkpt

MANAGER     RUNNING                                           
EXTRACT     RUNNING     LPJY1       01:08:28      00:00:00    
EXTRACT     RUNNING     LXJY1       00:00:00      00:00:10    

可以看到所有进程都是正常 RUNNING 状态。如果启动后状态不是 RUNNING,就需要检查配置和查看 ggserr.log 日志信息定位原因。

现在可以查看源端 extract 进程信息:

GGSCI (oradb30) 21> info extract lxjy1

EXTRACT    LXJY1     Last Started 2017-01-14 00:57   Status RUNNING
Checkpoint Lag       00:00:00 (updated 00:00:03 ago)
Log Read Checkpoint  Oracle Redo Logs
                     2017-01-14 01:05:56  Thread 1, Seqno 133, RBA 41481856
                     SCN 0.1517654 (1517654)


GGSCI (oradb30) 22> info extract lpjy1

EXTRACT    LPJY1     Last Started 2017-01-14 01:02   Status RUNNING
Checkpoint Lag       00:00:00 (updated 00:00:09 ago)
Log Read Checkpoint  File ./dirdat/sa000000
                     2017-01-14 01:06:00.000000  RBA 1551197

可以看到 OGG 的 extract 进程抓取到的信息:

GGSCI (oradb30) 26> STATS ext lxjy1

Sending STATS request to EXTRACT LXJY1 ...

Start of Statistics at 2017-01-14 01:09:21.

Output to ./dirdat/sa:

Extracting from JY.T_SECOND to JY.T_SECOND:

*** Total statistics since 2017-01-14 00:58:01 ***
        Total inserts                                   5217.00
        Total updates                                      0.00
        Total deletes                                      0.00
        Total discards                                     0.00
        Total operations                                5217.00

*** Daily statistics since 2017-01-14 00:58:01 ***
        Total inserts                                   5217.00
        Total updates                                      0.00
        Total deletes                                      0.00
        Total discards                                     0.00
        Total operations                                5217.00

*** Hourly statistics since 2017-01-14 01:00:00 ***
        Total inserts                                    560.00
        Total updates                                      0.00
        Total deletes                                      0.00
        Total discards                                     0.00
        Total operations                                 560.00

*** Latest statistics since 2017-01-14 00:58:01 ***
        Total inserts                                   5217.00
        Total updates                                      0.00
        Total deletes                                      0.00
        Total discards                                     0.00
        Total operations                                5217.00

Extracting from JY.T_SECOND_P to JY.T_SECOND_P:

*** Total statistics since 2017-01-14 00:58:01 ***
        Total inserts                                   5217.00
        Total updates                                      0.00
        Total deletes                                      0.00
        Total discards                                     0.00
        Total operations                                5217.00

*** Daily statistics since 2017-01-14 00:58:01 ***
        Total inserts                                   5217.00
        Total updates                                      0.00
        Total deletes                                      0.00
        Total discards                                     0.00
        Total operations                                5217.00

*** Hourly statistics since 2017-01-14 01:00:00 ***
        Total inserts                                    560.00
        Total updates                                      0.00
        Total deletes                                      0.00
        Total discards                                     0.00
        Total operations                                 560.00

*** Latest statistics since 2017-01-14 00:58:01 ***
        Total inserts                                   5217.00
        Total updates                                      0.00
        Total deletes                                      0.00
        Total discards                                     0.00
        Total operations                                5217.00

End of Statistics.


GGSCI (oradb30) 27> stats ext lpjy1

Sending STATS request to EXTRACT LPJY1 ...

Start of Statistics at 2017-01-14 01:09:31.

Output to ./dirdat/ta:

Extracting from JY.T_SECOND to JY.T_SECOND:

*** Total statistics since 2017-01-14 01:02:43 ***
        Total inserts                                   4509.00
        Total updates                                      0.00
        Total deletes                                      0.00
        Total discards                                     0.00
        Total operations                                4509.00

*** Daily statistics since 2017-01-14 01:02:43 ***
        Total inserts                                   4509.00
        Total updates                                      0.00
        Total deletes                                      0.00
        Total discards                                     0.00
        Total operations                                4509.00

*** Hourly statistics since 2017-01-14 01:02:43 ***
        Total inserts                                   4509.00
        Total updates                                      0.00
        Total deletes                                      0.00
        Total discards                                     0.00
        Total operations                                4509.00

*** Latest statistics since 2017-01-14 01:02:43 ***
        Total inserts                                   4509.00
        Total updates                                      0.00
        Total deletes                                      0.00
        Total discards                                     0.00
        Total operations                                4509.00

Extracting from JY.T_SECOND_P to JY.T_SECOND_P:

*** Total statistics since 2017-01-14 01:02:43 ***
        Total inserts                                   4509.00
        Total updates                                      0.00
        Total deletes                                      0.00
        Total discards                                     0.00
        Total operations                                4509.00

*** Daily statistics since 2017-01-14 01:02:43 ***
        Total inserts                                   4509.00
        Total updates                                      0.00
        Total deletes                                      0.00
        Total discards                                     0.00
        Total operations                                4509.00

*** Hourly statistics since 2017-01-14 01:02:43 ***
        Total inserts                                   4509.00
        Total updates                                      0.00
        Total deletes                                      0.00
        Total discards                                     0.00
        Total operations                                4509.00

*** Latest statistics since 2017-01-14 01:02:43 ***
        Total inserts                                   4509.00
        Total updates                                      0.00
        Total deletes                                      0.00
        Total discards                                     0.00
        Total operations                                4509.00

End of Statistics.


GGSCI (oradb30) 28> 

3.2 初始化目标库数据

我这里使用 Oracle 的 exp/imp 工具,从源端导出数据,导入到目标端。
exp 导出源库表数据
–exp 导出
exp jy/jy tables=t_second,t_second_p file=source_jy.dmp log=exp_source_jy.log

SQL> select count(1) from t_second;

  COUNT(1)
----------
     11056

SQL> select count(1) from t_second_p;  

  COUNT(1)
----------
     11072

[oracle@oradb30 ~]$ exp jy/jy tables=t_second,t_second_p file=source_jy.dmp log=exp_source_jy.log

Export: Release 10.2.0.5.0 - Production on Sat Jan 14 01:15:26 2017

Copyright (c) 1982, 2007, Oracle.  All rights reserved.


Connected to: Oracle Database 0g Enterprise Edition Release 10.2.0.5.0 - 4bit Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options
Export done in US7ASCII character set and AL16UTF16 NCHAR character set
server uses ZHS16GBK character set (possible charset conversion)

About to export specified tables via Conventional Path ...
. . exporting table                       T_SECOND      11096 rows exported
EXP-00091: Exporting questionable statistics.
. . exporting table                     T_SECOND_P      11097 rows exported
EXP-00091: Exporting questionable statistics.
EXP-00091: Exporting questionable statistics.
Export terminated successfully with warnings.

imp 导入目标库数据
– 创建用户
create user jy identified by jy default tablespace users;
grant resource, connect to jy;
–imp 导入
imp jy/jy tables=t_second,t_second_p file=source_jy.dmp log=imp_source_jy.log

[oracle@oradb31 ~]$ imp jy/jy tables=t_second,t_second_p file=source_jy.dmp log=imp_source_jy.log

Import: Release 10.2.0.5.0 - Production on Sat Jan 14 01:20:08 2017

Copyright (c) 1982, 2007, Oracle.  All rights reserved.


Connected to: Oracle Database 10g Enterprise Edition Release 10.2.0.5.0 - 64bit Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options

Export file created by EXPORT:V10.02.01 via conventional path
import done in US7ASCII character set and AL16UTF16 NCHAR character set
import server uses ZHS16GBK character set (possible charset conversion)
. importing JY's objects into JY
. importing JY's objects into JY
. . importing table                     "T_SECOND"      11096 rows imported
. . importing table                   "T_SECOND_P"      11097 rows imported
Import terminated successfully without warnings.

3.3 开启目标库 replicat 应用

确认已经启动 Manager 进程。
启动 replicat 应用

GGSCI (oradb31) 2> start replicat rjy1
Sending START request to MANAGER ...
REPLICAT RJY1 starting

GGSCI (oradb31) 3> info all
Program     Status      Group       Lag at Chkpt  Time Since Chkpt
MANAGER     RUNNING                                           
REPLICAT    RUNNING     RJY1        00:00:00      00:41:50    

下面我来验证数据:
– 开启 replicat 之前查询目标库,也就是初始化导入的数据:

SQL> select count(1) from t_second;
  COUNT(1)
----------
     11096
SQL> select count(1) from t_second_p;
  COUNT(1)
----------
     11097

– 开启 replicat 后查询目标库:

SQL> select count(1) from t_second_p;
  COUNT(1)
----------
     11581
SQL> select count(1) from t_second;
  COUNT(1)
----------
     16459     

为了更清晰的看到差异,我将模拟应用的会话杀掉,这样两表的数量不再变化。

– 查询源库两个表的数量:

SQL> select count(1) from t_second_p;
  COUNT(1)
----------
     11966
SQL> select count(1) from t_second;
  COUNT(1)
----------
     11966

– 查看目标库两个表的数量:

SQL>  select count(1) from t_second_p;
  COUNT(1)
----------
     11966
SQL> select count(1) from t_second;
  COUNT(1)
----------
     16840

发现有主键的表 t_second_p 在 ogg 同步后数据完全一致,符合预期;
而没有主键的表 t_second 在 ogg 同步后数据重复插入了一部分(即源端开启 extract 进程后捕获到的插入,和 imp 导入成功前这期间的数据重复插入了)
根据这个现象,OGG 需要同步的表还是最好有主键约束。
最后,一切正常后,把目标端 replicat 进程的参数文件中的 HandleCollisions 配置去掉。因为正式同步后是建议有冲突问题人工处理。

Reference

  • 张晓明. 大话 Oracle Grid[M]. 人民邮电出版社, 2014.
  • Oracle GoldenGate 11g Implementer’s guide

OGG 学习笔记 01- 基础概述
OGG(Oracle Golden Gate), 最近几年在数据同步、容灾领域特别火,甚至比 Oracle 自己的原生产品 DataGuard 还要风光,主要是因为其跨平台、跨数据库、跨版本的强大特性。

OGG 理论概念

我们可以搜索到网上对它的简单介绍:

Oracle Golden Gate 软件是一种基于日志的结构化数据复制备份软件,它通过解析源数据库在线日志或归档日志获得数据的增量变化,再将这些变化应用到目标数据库,从而实现源数据库与目标数据库同步。
Oracle Golden Gate 可以在异构的 IT 基础结构(包括几乎所有常用操作系统平台和数据库平台)之间实现大量数据亚秒一级的实时复制, 从而可以在应急系统、在线报表、实时数据仓库供应、交易跟踪、数据同步、集中 / 分发、容灾、数据库升级和移植、双业务中心等多个场景下应用。同时,Oracle Golden Gate 可以实现一对一、广播(一对多)、聚合(多对一)、双向、点对点、级联等多种灵活的拓扑结构.

目前许多客户环境都已经在广泛使用 OGG。由于工作需要,近期我也会系统的学习下 OGG,目前学习主要以 OGG 在 Oracle 数据库之间的同步来说明一些基本概念,后续看时间情况可能了解 OGG 对其他主流数据库的同步。
假设已有源数据库和目标数据库,且分别部署好 OGG 软件。
源数据库部署的 OGG,简称源 OGG;目标数据库部署的 OGG,简称目标 OGG。

同步的过程就是源 OGG 的 EXTRACT 进程从源数据库的联机 redologs 中抽取获得变化,把它写到本地 trail 文件中,然后源 OGG 的 Data pump 进程再从本地 trail 文件中抽取变化传给目标 OGG 的 collector 进程,目标的 collector 进程再把这些变化写入目标 trail 文件中,最后目标 OGG 的 Replicat 进程把目标 trail 文件中记录的变化应用到目标数据库中。
如果要同步的表数量比较多或是业务有区分,需要分开管理,OGG 是支持分开多个 extract 进程,多个 datapump 进程,多个 replicat 进程,这样,可以启动或停止其中任意一类同步,而不影响其他的同步。

由此,我们可以得到一张 Oracle Golden Gate 的简要体系图:
OGG 心得笔记

需要注意的是,每套 OGG 所有的进程都是由其 Manager 进程来管理的,也就是说 Manager 进程负责管理,启动关闭其他进程。OGG 用组来表示它的进程,上面简单提到的 extract、replicat 这些进程,实际上需要各自的参数文件、检查点文件等。这些内容共同组成一个组,且每个组需要有一个组名字。
可以将上面的简要体系图再标注一些内容,便于理解 OGG 实际的工作方式。
OGG 心得笔记

OGG 的检查点信息,对于源 OGG 只能以文件形式默认存放在 GGHOME/dirchk 目录下,一个组对应一个文件。
而对于目标 OGG 检查点信息可以存放在数据库表中,且建议存放到数据库表中。

对于源数据库,如果要使用 OGG,需要配置 supplemental logging,原因是 OGG 相当于逻辑同步,除了要记录被修改的记录,还要把能够标识这条记录的信息同时记录在日志中。这样的话,Oracle 默认情况是不达标的,需要额外开启 supplemental logging 才可以。
具体做法是:在数据库级别开启最小附加日志,在需要同步的表级别开启详细附加日志。

# 数据库级别开启最小附加日志:
SQL> alter database add supplemental log data;
# 表级别开启详细附加日志(这里举例是 jy 用户下的 t_second 表):
GGSCI> add trandata jy.t_second

对于目标数据库,配置检查点信息到目标数据库表中,具体做法:

#1. 目标 GG 的全局参数 (./globals) 配置
checkpointtable ggt.chkpt
#2. 命令添加 checkpointtable
GGSCI> add checkpointtable ggt.chkpt

复制进程可以指定 checkpointtable 从而使用数据库表记录检查点信息。

OGG 安装介绍

OGG 介质下载,在 ORACLE 官网就有提供最新版本下载,如果需要下载历史版本的,就需要 MOS 账号。
下载地址:https://edelivery.oracle.com
OGG 的安装也非常简单,在期望的安装目录下,直接解压压缩文件即可。

[ogg@oradb30 ~]$ cd /u01/app
[ogg@oradb30 app]$ ls
oracle
[ogg@oradb30 app]$ mkdir ogg
[ogg@oradb30 app]$ cd ogg/
[ogg@oradb30 ogg]$ pwd
/u01/app/ogg
[ogg@oradb30 ogg]$ tar xvf /u01/media/fbo_ggs_Linux_x64_ora10g_64bit.tar 

为了便于管理维护,我们创建新的操作系统用户和数据库用户,专门给 OGG 使用。

# 创建系统用户 ogg,隶属于 oinstall 组
useradd ogg -g oinstall

环境变量,除了设置 OGG 自己,还需要设置可以访问到库文件,这也是为何将系统用户 ogg 隶属于 oinstall 组,保证其有权限访问 oracle 安装目录的库文件。

export ORACLE_HOME=/u01/app/oracle/product/10.2.0/db_1
export LD_LIBRARY_PATH=$ORACLE_HOME/lib:$LD_LIBRARY_PATH
export GG_HOME=/u01/app/ogg
export PATH=$GG_HOME:$PATH

确定 ggsci 可以正常使用,然后使用 create subdirs 创建 OGG 的子目录,最后配置好 Manager。

#1. 确定 ggsci 可以正常使用
[ogg@oradb30 ~]$ ggsci
ggsci: error while loading shared libraries: /u01/app/oracle/product/10.2.0/db_1/lib/libclntsh.so.10.1: cannot restore segment prot after reloc: Permission denied

我这里遇到的这个错误关键点是“cannot restore segment prot after reloc: Permission denied”是因为主机系统 SELinux 开启的原因。关闭 SELinux 即可解决。[root@oradb30 ~]# su - ogg
[ogg@oradb30 ~]$ cd /u01/app/ogg/
[ogg@oradb30 ogg]$ ggsci

Oracle GoldenGate Command Interpreter for Oracle
Version 11.2.1.0.1 OGGCORE_11.2.1.0.1_PLATFORMS_120423.0230_FBO
Linux, x64, 64bit (optimized), Oracle 10g on Apr 23 2012 07:30:46

Copyright (C) 1995, 2012, Oracle and/or its affiliates. All rights reserved.

GGSCI (oradb30) 1> 

#2.使用create subdirs 创建 OGG 的子目录
GGSCI (oradb30) 1> create subdirs

Creating subdirectories under current directory /u01/app/ogg

Parameter files                /u01/app/ogg/dirprm: already exists
Report files                   /u01/app/ogg/dirrpt: created
Checkpoint files               /u01/app/ogg/dirchk: created
Process status files           /u01/app/ogg/dirpcs: created
SQL script files               /u01/app/ogg/dirsql: created
Database definitions files     /u01/app/ogg/dirdef: created
Extract data files             /u01/app/ogg/dirdat: created
Temporary files                /u01/app/ogg/dirtmp: created
Stdout files                   /u01/app/ogg/dirout: created


#3.配置好 Manager
GGSCI (oradb30) 2> edit param mgr   
port 7777
GGSCI (oradb30) 3> info mgr
Manager is DOWN!
GGSCI (oradb30) 4> start mgr
Manager started.
GGSCI (oradb30) 5> info mgr
Manager is running (IP port oradb30.7777).

后续 extract、replicate 等 OGG 实际工作的进程(组)配置,将在下篇《OGG 学习笔记 02- 单向复制配置实例》详细说明。

Reference

  • 张晓明. 大话 Oracle Grid[M]. 人民邮电出版社, 2014. PDF 下载见 http://www.linuxidc.com/Linux/2017-01/139861.htm

更多详情见请继续阅读下一页的精彩内容:http://www.linuxidc.com/Linux/2017-01/139863p2.htm

OGG 学习笔记 03- 单向复制简单故障处理

环境:参考:OGG 学习笔记 02- 单向复制配置实例
实验目的:了解 OGG 简单故障的基本处理思路。

1. 故障现象
故障现象:启动 OGG 源端的 extract 进程,data pump 进程,一段时间后发现进程均被终止。

GGSCI (oradb30) 1> info all

Program     Status      Group       Lag at Chkpt  Time Since Chkpt

MANAGER     RUNNING                                           
EXTRACT     ABENDED     LPJY1       00:00:00      47:39:54    
EXTRACT     ABENDED     LXJY1       00:00:00      47:40:00    


GGSCI (oradb30) 2> start extract lxjy1

Sending START request to MANAGER ...
EXTRACT LXJY1 starting


GGSCI (oradb30) 3> info all

Program     Status      Group       Lag at Chkpt  Time Since Chkpt

MANAGER     RUNNING                                           
EXTRACT     ABENDED     LPJY1       00:00:00      47:40:50    
EXTRACT     RUNNING     LXJY1       00:00:00      47:40:55    


GGSCI (oradb30) 4> start extract lpjy1

Sending START request to MANAGER ...
EXTRACT LPJY1 starting


GGSCI (oradb30) 5> info all

Program     Status      Group       Lag at Chkpt  Time Since Chkpt

MANAGER     RUNNING                                           
EXTRACT     RUNNING     LPJY1       00:00:00      47:40:58    
EXTRACT     RUNNING     LXJY1       00:00:00      47:41:04    


GGSCI (oradb30) 6> info all

Program     Status      Group       Lag at Chkpt  Time Since Chkpt

MANAGER     RUNNING                                           
EXTRACT     ABENDED     LPJY1       00:00:00      47:41:15    
EXTRACT     RUNNING     LXJY1       00:00:00      47:41:21    


GGSCI (oradb30) 7> info all

Program     Status      Group       Lag at Chkpt  Time Since Chkpt

MANAGER     RUNNING                                           
EXTRACT     ABENDED     LPJY1       00:00:00      47:41:19    
EXTRACT     RUNNING     LXJY1       00:00:00      47:41:25    


GGSCI (oradb30) 8> info all

Program     Status      Group       Lag at Chkpt  Time Since Chkpt

MANAGER     RUNNING                                           
EXTRACT     ABENDED     LPJY1       00:00:00      47:41:41    
EXTRACT     ABENDED     LXJY1       00:00:00      47:41:47    

2. 查看日志
查看 ogg 日志 ggserr.log, 排查进程被终止的原因。

[ogg@oradb30 ogg]$ cd $GG_HOME
[ogg@oradb30 ogg]$ tail -200f ggserr.log
发现 datapump 进程 lpjy1 是因为连接不到目标 OGG 而终止;extract 进程 lxjy1 是因为无法找到归档日志 sequence 160 thread 1 而终止。

2017-01-19 14:51:46  INFO    OGG-00993  Oracle GoldenGate Capture for Oracle, lpjy1.prm:  EXTRACT LPJY1 started.
2017-01-19 14:51:49  ERROR   OGG-01224  Oracle GoldenGate Capture for Oracle, lpjy1.prm:  TCP/IP error 113 (No route to host).
2017-01-19 14:51:49  ERROR   OGG-01668  Oracle GoldenGate Capture for Oracle, lpjy1.prm:  PROCESS ABENDING.
2017-01-19 14:52:28  ERROR   OGG-00446  Oracle GoldenGate Capture for Oracle, lxjy1.prm:  Could not find archived log for sequence 160 thread 1 under default destinations SQL <SELECT  name    FROM v$archived_log   WHERE sequence# = :ora_seq_no AND         thread# = :ora_thread AND         resetlogs_id = :ora_resetlog_id AND         archived = 'YES' AND         deleted = 'NO' AND         name not like '+%'         AND standby_dest = 'NO' >, error retrieving redo file name for sequence 160, archived = 1, use_alternate = 0Not able to establish initial position for sequence 160, rba 7758352.
2017-01-19 14:52:28  ERROR   OGG-01668  Oracle GoldenGate Capture for Oracle, lxjy1.prm:  PROCESS ABENDING.

排查原因发现是归档日志被 RMAN 备份策略备份完成后删除了,既然有备份,那么下一步只需要从备份集中恢复日志中提示的 sequence 160 及其之后的日志即可。
这里,也说明配置 OGG 最好建议是归档模式,否则在这种目标端没有及时获取到源端在线日志的情况下,就没有办法继续应用了。

3. 解决问题
对于 lxjy1 进程(Extract),只需要从 RMAN 备份集中恢复 sequence 160 及其之后的归档日志:

$ rman target /
RMAN> restore archivelog from logseq 160;

然后再启动 lxjy1 进程。

对于 lpjy1 进程(Data Pump),只需要确认已经启动目标端 OGG 所在主机,网通,然后启动目标端数据库和目标 OGG,并启动目标 OGG 的 mgr 进程,replicat 进程即可。

最终确认源端和目标端 ogg 所有进程均正常 running:
源端 OGG:

GGSCI (oradb30) 1> info all

Program     Status      Group       Lag at Chkpt  Time Since Chkpt

MANAGER     RUNNING                                           
EXTRACT     RUNNING     LPJY1       00:00:00      00:00:03    
EXTRACT     RUNNING     LXJY1       00:00:00      00:00:00    

目标端 OGG:

GGSCI (oradb31) 1> info all

Program     Status      Group       Lag at Chkpt  Time Since Chkpt

MANAGER     RUNNING                                           
REPLICAT    RUNNING     RJY1        00:00:00      00:00:01    

更多 Oracle 相关信息见Oracle 专题页面 http://www.linuxidc.com/topicnews.aspx?tid=12

本文永久更新链接地址:http://www.linuxidc.com/Linux/2017-01/139863.htm

OGG 学习笔记 04-OGG 复制部署快速参考
源端:Oracle 10.2.0.5 RAC + ASM
节点 1 Public IP 地址:192.168.1.27

目标端:Oracle 10.2.0.5
IP 地址:192.168.1.30

操作目标:将源端数据库业务用户 jy 下两张表 ogg 同步到目标端数据库业务用户 ludan 下。
在源端配置 OGG extract、data pump 进程;数据初始化;目标端配置 OGG replicat 进程。

本文假设两端的 OGG 软件和环境变量已配置完成,即操作系统 ogg 用户登陆系统,确认 ggsci 可以正常使用,mgr 管理进程正常启动,dblogin 可以正常登陆到数据库。
本文意义:OGG 复制快速参考,补充一些前面未提及的 ogg 相关知识点。

  • 1. 配置源端 OGG
  • 2. 数据初始化
  • 3. 配置目标端 OGG
  • 4. ogg 相关知识点补充

1. 配置源端 OGG

这一步主要做的工作:
在源端数据库上创建一个单独的数据库用户;
开启数据库最小附加日志,需要同步的表开启详细附加日志;
配置好 extract 进程 lxjyrac1;
配置好 data pump 进程 lpjyrac1;

1.1 在源端数据库上创建一个单独的数据库用户

create user ggs_admin identified by ggs_admin;
grant dba to ggs_admin;

1.2 开启数据库最小附加日志,需要同步的表开启详细附加日志

-- 查看数据库附加日志开启状态:
SQL> 
select SUPPLEMENTAL_LOG_DATA_MIN, SUPPLEMENTAL_LOG_DATA_PK, SUPPLEMENTAL_LOG_DATA_UI from v$database;

-- 数据库级别开启最小附加日志:
SQL> 
alter database add supplemental log data;

-- 表级别开启详细附加日志:
GGSCI (oradb27) > 
dblogin userid ggs_admin@racbeq, password ggs_admin
add trandata jy.t_second
add trandata jy.t_second_p

1.3 在源端配置 extract 进程
我这里将 extract 进程起名为:lxjyrac1

编辑 lxjyrac1 进程的配置文件:

GGSCI (oradb27) >
edit param lxjyrac1

--Local Extract lxjyrac1
--Author: Alfred Zhao
--
EXTRACT lxjyrac1
SETENV(NLS_LANG=american_america.ZHS16GBK)
SETENV(ORACLE_SID=jyrac1)
USERID ggs_admin, PASSWORD ggs_admin
--TRANLOGOPTIONS ASMUSER sys@asmbeq, ASMPASSWORD oracle
TRANLOGOPTIONS DBLOGREADER
EXTTRAIL ./dirdat/sa
TABLE JY.T_SECOND;
TABLE JY.T_SECOND_P;

当前数据库版本是 10.2.0.5 RAC + ASM,由于数据库 redo 日志放在 ASM 上,所以 extract 进程需要配置 TRANLOGOPTIONS 选项,否则获取不到数据库日志。
上面的两种方式任意选择哪种都可以,使用“–”注释其中一种。

添加 lxjyrac1 进程:

GGSCI (oradb27) 1> add extract lxjyrac1, tranlog, begin now, threads 2
EXTRACT added.
GGSCI (oradb27) 2> add exttrail ./dirdat/sa, extract lxjyrac1, megabytes 50
EXTTRAIL added. 

1.4 在源端配置 datapump 进程
我这里将 datapump 进程起名为:lpjyrac1

编辑 lpjyrac1 进程的配置文件:

GGSCI (oradb27) >
edit param lpjyrac1

--Local datapump lpjyrac1
--Author: Alfred Zhao
--
EXTRACT lpjyrac1
PASSTHRU
RMTHOST 192.168.1.30, MGRPORT 7777
RMTTRAIL ./dirdat/ta
TABLE JY.T_SECOND;
TABLE JY.T_SECOND_P;

添加 lpjyrac1 进程(本地 datapump 进程):

GGSCI (oradb27) 1> add extract lpjyrac1, exttrailsource ./dirdat/sa, begin now
EXTRACT added.
GGSCI (oradb27) 2> ADD RMTTRAIL ./dirdat/ta, EXTRACT LPJYRAC1, MEGABYTES 50
RMTTRAIL added.

1.5 源端启动所有进程
启动 extract 进程 lxjyrac1、datapump 进程 lpjyrac1:

GGSCI (oradb27) > 
start extract lxjyrac1
start extract lpjyrac1

2. 数据初始化

这一步主要做的工作:
源端需要同步的数据表导出;
目标端导入数据,完成初始化。

2.1 数据导出
导出业务用户 jy 并把导出文件传输到目标数据库所在主机:

[oracle@oradb27 ~]$ exp jy/jy file=exp_jy.dmp log=exp_jy.log
[oracle@oradb27 ~]$ scp exp_jy.dmp 192.168.1.30:/home/oracle/

2.2 数据导入
创建数据库业务用户 ludan:

SQL>
create user ludan identified by ludan;
grant connect, resource to ludan;

imp 导入数据:

[oracle@oradb30 ~]$ imp ludan/ludan fromuser=jy touser=ludan file=exp_jy.dmp log=imp_jy.log ignore=y

3. 配置目标端 OGG

这一步主要做的工作:
在目标端数据库上创建一个单独的数据库用户;
在目标端数据库上创建 checkpointtable;

3.1 在目标端数据库上创建一个单独的数据库用户

SQL>
create user ggt_admin identified by ggt_admin;
grant dba to ggt_admin;

3.2 在目标端数据库上创建 checkpointtable
注意配置文件 GLOBALS 是位于 ogg 当前目录下的,确认内容正确配置了 checkpointtable。
这里配置的 checkpointtable 名字为 chkpt

GGSCI (oradb30) > 
edit param ./GLOBALS

checkpointtable ggt_admin.chkpt

GGSCI (oradb30) > 
dblogin userid ggt_admin@ora10, password ggt_admin
add checkpointtable

3.3 在目标端创建 replicat 进程
我这里将 replicat 进程起名为:rjyrac1

GGSCI (oradb30) >
edit param rjyrac1

--replicat rjyrac1
--Author: Alfred Zhao
--
REPLICAT rjyrac1
SETENV (ORACLE_SID=ora10)
USERID ggt_admin, PASSWORD ggt_admin
DISCARDFILE ./dirrpt/rjy1.dsc, PURGE
HandleCollisions
AssumeTargetDefs
Map jy.*,Target ludan.*;

添加 rjyrac1 进程(replicat 进程):

GGSCI (oradb30) > 
add replicat rjyrac1, exttrail ./dirdat/ta

3.4 目标端启动进程
启动 replicat 进程 rjyrac1:

GGSCI (oradb30) > 
start replicat rjyrac1

4. ogg 相关知识点补充

4.1 OGG 中 ASM 连接问题
ogg 连接到 ASM 实例的连接有三种方式:Net8、BEQ、DBLOGREADER,能否使用 DBLOGREADER 取决于使用的数据库版本。

上文在 lxjyrac1 进程配置中,如果选择 BEQ 这种连接方式
TRANLOGOPTIONS ASMUSER sys@asmbeq, ASMPASSWORD oracle
那么,源数据库对应的“tnsnames.ora”配置中别名 ”asmbeq” 的内容:

ASMBEQ =
  (DESCRIPTION =
    (ADDRESS = 
      (PROTOCOL = BEQ)
      (PROGRAM = /u01/app/oracle/product/10.2.0.5/dbhome_1/bin/oracle)
      (ARGV0 = oracle+ASM1)    
      (ARGS = '(DESCRIPTION=(LOCAL=YES)(ADDRESS=(PROTOCOL=BEQ)))')
      (ENVS = 'ORACLE_HOME=/u01/app/oracle/product/10.2.0.5/dbhome_1,ORACLE_SID=+ASM1')
    )
    (CONNECT_DATA =
      (SERVICE_NAME = +ASM)
      (INSTANCE_NAME = +ASM1)
    )
  )

目标数据库“tnsnames.ora”配置中别名 ”ora10″ 的内容,Net8 连接方式类似这种配置:

ORA10 =
  (DESCRIPTION =
    (ADDRESS = (PROTOCOL = TCP)(HOST = 192.168.1.30)(PORT = 1521))
    (CONNECT_DATA =
      (SERVER = DEDICATED)
      (SERVICE_NAME = ora10)
    )
  )

使用 DBLOGREADER 相当于直接利用 Oracle 中的一个 ASM API 去访问文件,不需要配置 TNS,也不需要用户名密码,是最简单的方式,但是需要要求数据库版本是“11.2.0.2”或“10.2.0.5”及以后的版本。
本文环境“10.2.0.5 RAC + ASM”,就是使用的这种最简单的方式,经测试可用。

4.2 OGG 中的复杂结构运维经验
实际上无论是 OGG 的双向复制、广播复制、级联复制,都是由两个或多个单向复制组成的,难度相比单纯的单向复制并没有增长多少,只是维护的工作量多了,建议规范好各进程的名字,有助于提高管理效率。

GGSCI (oradb30) 1> info all

Program     Status      Group       Lag at Chkpt  Time Since Chkpt

MANAGER     RUNNING                                           
EXTRACT     RUNNING     LPJY1       00:00:00      00:00:04    
EXTRACT     RUNNING     LPJY2       00:00:00      00:00:04    
EXTRACT     RUNNING     LXJY1       00:00:00      00:00:07    
REPLICAT    RUNNING     RJYRAC1     00:00:00      00:00:06    

可以看到本次作为目标端的 oradb30。一眼就可以判断出,跟本次部署有关的只有 RJYRAC1 进程,其他的 LXJY1,LPJY1,LPJY2 进程,显然是其他 OGG 配置,oradb30 作为源端端一些进程。
如果根据名字不能完全弄清楚,可以“view param 名字”看具体的配置文件,即可一目了然,比如查看进程 lxjy1 配置文件内容:

GGSCI (oradb30) 3> view param lxjy1

--Local Extract lxjy1
--Author: Alfred Zhao
--
EXTRACT lxjy1
SETENV(NLS_LANG=american_america.ZHS16GBK)
SETENV(ORACLE_SID=ora10)
USERID ggs_admin, PASSWORD ggs_admin
EXTTRAIL ./dirdat/sa
TABLE JY.T_SECOND;
TABLE JY.T_SECOND_P;

至此,OGG 学习笔记基础部分的学习就已经结束。

正文完
星哥玩云-微信公众号
post-qrcode
 0
星锅
版权声明:本站原创文章,由 星锅 于2022-01-22发表,共计26012字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
【腾讯云】推广者专属福利,新客户无门槛领取总价值高达2860元代金券,每种代金券限量500张,先到先得。
阿里云-最新活动爆款每日限量供应
评论(没有评论)
验证码
【腾讯云】云服务器、云数据库、COS、CDN、短信等云产品特惠热卖中