GoldenGate使用

@lucas  March 4, 2024

1. OGG简介

  • Golden Gate(简称OGG)提供异构环境下交易数据的实时捕捉、变换、投递。
  • OGG是一种基于日志的结构化数据复制软件,通过捕获源数据库online redo log (在线重做日志)或archive log(归档日志)获得数据变化,形成tail(队列文件 ),再将这些tail通过网络协议,传输到目标数据库,目标端通过解析,插入至目标端数据库,从而实现源端与目标端数据同步。
    2024-03-04T06:58:34.png

2. 基本原理

基于日志捕获技术的实时增量数据集成,需要在源数据库和目标数据库服务器上均安装ogg软件。
2024-03-04T06:59:15.png
Oracle GoldenGate 数据复制过程如下:

  • 利用抽取进程(Extract Process)在源端数据库中读取Online Redo Log或者Archive Log,然后进行解析,只提取其中数据的变化信息,比如DML操作——增、删、改操作
  • 将抽取的信息转换为GoldenGate自定义的中间格式存放在队列文件(trail file)中
  • 再利用传输进程将队列文件(trail file)通过TCP/IP传送到目标系统。
  • 目标端有一个进程叫Server Collector,这个进程接受了从源端传输过来的数据变化信息
  • 把信息缓存到GoldenGate 队列文件(trail file)当中,等待目标端的复制进程读取数据。
  • GoldenGate 复制进程(replicat process)从队列文件(trail file)中读取数据变化信息,并创建对应的SQL语句,通过数据库的本地接口执行,提交到目标端数据库,提交成功后更新自己的检查点,记录已经完成复制的位置,数据的复制过程最终完成。

3. 基本架构

Oracle GoldenGate主要由如下组件组成

组件说明
Manager不管是源端还是目标端必须并且只能有一个Manager进程,可以启动、关闭、监控其他进程的健康状态,报告错误事件、分配数据存储空间,发布阀值报告等,其作用: 1:监控与启动 GoldenGate 的其它进程 2:管理 trail 文件及 Reporting
ExtractExtract 进程运行在数据库源端上,它是Golden Gate的捕获机制,可以配置Extract 进程来做如下工作: 1:初始数据装载:对于初始数据装载,Extract 进程直接从源对象中提取数据 2:同步变化捕获:保持源数据与其它数据集的同步。初始数据同步完成后,Extract 进程捕获源数据的变化;如DML变化、 DDL变化等
ReplicatReplicat 进程是运行在目标端系统的一个进程,负责读取 Extract 进程提取到的数据(变更的事务或 DDL 变化)并应用到目标数据库,就像 Extract 进程一样,也可以配置 Replicat 进程来完成如下工作: 1:初始化数据装载:对于初始化数据装载,Replicat 进程应用数据到目标对象或者路由它们到一个高速的 Bulk-load 工具上; 2:数据同步,将 Extract 进程捕获到的提交了的事务应用到目标数据库中;
CollectorCollector 是运行在目标端的一个后台进程,接收从 TCP/IP 网络传输过来的数据库变化,并写到 Trail 文件里
Trails为了持续地提取与复制数据库变化,GoldenGate 将捕获到的数据变化临时存放在磁盘上的一系列文件中,这些文件就叫做 Trail 文件
Data PumpsData Pump 是一个配置在源端的辅助的 Extract 机制,Data Pump 是一个可选组件,如果不配置 Data Pump,那么由 Extract 主进程将数据发送到目标端的 Remote Trail 文件中;如果配置了 Data Pump,会由 Data Pump将Extract 主进程写好的本地 Trail 文件通过网络发送到目标端的 Remote Trail 文件中

4. 支持的环境

目前最新发布版本已经有了更多的支持,可以访问查看:https://edelivery.oracle.com/osdc/faces/SoftwareDelivery
2024-03-04T07:01:20.png

5. OGG FOR ORACLE安装部署

注:在Docker环境下,整合Oracle

  • 拉取docker镜像

    docker pull deepdiver/docker-oracle-xe-11g:latest
  • 查看镜像

    docker images
  • 启动镜像

    docker run -d -p 8521:1521 -p 8100:8100 --name oracle11g deepdiver/docker-oracle-xe-11g:latest
    
    # 设置swap空间
    docker run -d -p 8521:1521 -p 8100:8100 --memory=1G --memory-swap=2G --name oracle11g deepdiver/docker-oracle-xe-11g:latest
  • 查看镜像

    docker ps
  • 进入容器

    docker exec -it oracle11g /bin/bash
  • 设置账号密码&新建用户

    # 登录Oracle,用户名:system,密码:oracle
    sqlplus system/oracle
    
    # 设置更改sys和system用户的密码为oracle,并设置密码有效期永久
    alter user system identified by oracle; 
    alter user sys identified by oracle;
    ALTER PROFILE DEFAULT LIMIT PASSWORD_LIFE_TIME UNLIMITED;
    
    # 新建用户&授权
    create tablespace oggs_data datafile '/u01/app/oracle/oradata/XE/oggs01.dbf' size 500M autoextend on;
    CREATE USER userbd IDENTIFIED BY userbd default tablespace oggs_data;
    GRANT CONNECT, RESOURCE, DBA TO userbd;

    5.1 配置Oracle11g数据库

  • 1、开启归档日志

    • 切换到oralce用户,su - oracle
    • 创建数据需要的目录,需要提前创建,否则启用日志归档会报错目录不存在
    • 以DBA身份连接到数据库,后续操作都是终端操作

      SQL>  sqlplus /nolog
      SQL>  conn /as sysdba
    • 启用日志归档,(这里的db_recovery_file_dest归档文件夹必须存在)

      # 可跳过归档日志目录设置
      SQL> alter system set db_recovery_file_dest_size = 50G;
      SQL> alter system set db_recovery_file_dest = '/home/opt/archive_data' scope=spfile;
      
      SQL> shutdown immediate;
      SQL> startup mount;
      SQL> alter database archivelog;
      SQL> alter database open;
    • 检查日志归档是否开启,"Database log mode: Archive Mode"

      archive log list;
  • 2、数据库启用补充日志记录

    # 验证数据库是否开启辅助日志和补充日志,当显示NO的时候表示没有开启,需要调整:
    SQL> select force_logging,supplemental_log_data_min from v$database;
    
    FOR SUPPLEME
    --- --------
    NO  NO
    #开启数据库的辅助日志和补充日志,开启强制日志后数据库会记录除临时表空间或临时回滚段外所有的操作,命令:
    SQL>  ALTER DATABASE FORCE LOGGING;
    # 开启辅助日志命令:
    SQL>  ALTER DATABASE ADD SUPPLEMENTAL LOG DATA;
    # 开启主键附加日志命令:
    SQL>  ALTER DATABASE ADD SUPPLEMENTAL LOG DATA (PRIMARY KEY) COLUMNS;
    # 开启全列附加日志命令:
    SQL>  ALTER DATABASE ADD SUPPLEMENTAL LOG DATA (ALL) COLUMNS;
    1. 配置环境变量NLS_LANG(不配置中文同步会乱码)
      首先在oracle中查询select userenv( 'language') from dual;
      然后将查询的结果配置到linux环境变量中
      如export NLS_LANG=” SIMPLIFIED CHINESE_CHINA.ZHS16GBK”

      5.2 安装OGG

      a. 下载ogg

  • https://edelivery.oracle.com/osdc/faces/SoftwareDelivery
    b. 解压ogg压缩包

    [oracle@fd721ee360c5 ogg]$ ls
    OGG_README.txt  ogg_21c_Linux_x64_Oracle_services_free_shiphome.zip
    
    # 解压zip包
    [oracle@fd721ee360c5 ogg]$ unzip ogg_21c_Linux_x64_Oracle_services_free_shiphome.zip
    
    [oracle@fd721ee360c5 ogg]$ ls
    OGG_README.txt  fbo_ggs_Linux_x64_Oracle_services_free_shiphome  ogg_21c_Linux_x64_Oracle_services_free_shiphome.zip
    
    配置环境变量
    vim /etc/profile
    
    export GG_HOME=/home/opt/ogg
    export PATH=$PATH:$HOME/bin:$ORACLE_HOME/bin:$GG_HOME
    export LD_LIBRARY_PATH=$ORACLE_HOME/lib:/lib:/usr/lib:$LD_LIBRARY_PATH
    alias ggsci='cd $GG_HOME;ggsci'
    ##刷新权限
    source /etc/bashrc

    c.安装ogg,因为正常安装需要界面支持,这里采用静默安装方式,修改/home/ogg/fbo_ggs_Linux_x64_Oracle_services_free_shiphome/Disk1/response/oggcore.rsp文件

    #-------------------------------------------------------------------------------
    # Do not change the following system generated value. 
    #-------------------------------------------------------------------------------
    oracle.install.responseFileVersion=/oracle/install/rspfmt_ogginstall_response_schema_v21_1_0
    ################################################################################
    ##                                                                            ##
    ## Oracle GoldenGate installation option and details                          ##
    ##                                                                            ##
    ################################################################################
    #-------------------------------------------------------------------------------
    # Specify the installation option.
    # Specify ora21c for installing Oracle GoldenGate for Oracle Database 21c and lower supported versions
    #-------------------------------------------------------------------------------
    INSTALL_OPTION=ORA11g
    #-------------------------------------------------------------------------------
    # Specify a location to install Oracle GoldenGate
    #-------------------------------------------------------------------------------
    SOFTWARE_LOCATION=/home/opt/ogg
    ################################################################################
    ##                                                                            ##
    ## Specify details to Create inventory for Oracle installs                    ##
    ## Required only for the first Oracle product install on a system.            ##
    ##                                                                            ##
    ################################################################################
    START_MANAGER=false
    MANAGER_PORT=8809
    DATABASE_LOCATION=/u01/app/oracle/product/11.2.0/xe
    #-------------------------------------------------------------------------------
    # Specify the location which holds the install inventory files.
    # This is an optional parameter if installing on
    # Windows based Operating System.
    #-------------------------------------------------------------------------------
    INVENTORY_LOCATION=/home/opt/ogg/oraInventory
    #-------------------------------------------------------------------------------
    # Unix group to be set for the inventory directory.  
    # This parameter is not applicable if installing on
    # Windows based Operating System.
    #-------------------------------------------------------------------------------
    UNIX_GROUP_NAME=dba

    d. 执行安装命令(使用oracle用户或者ogg用户)

    ./runInstaller -silent -responseFile /home/opt/fbo_ggs_Linux_x64_Oracle_shiphome/Disk1/response/oggcore.rsp

    e. ddl操作数据捕获配置(不需要监控ddl可跳过)

    # 在ogg的安装目录下登陆sqlplus,使用sys登陆sqlplus,然后执行如下配置
    
    [oracle@local ~]$ sqlplus /nolog
    SQL> conn as sysdba
    SQL> @marker_setup.sql
    SQL> @ddl_setup.sql;
    SQL> @role_setup.sql;
    SQL> grant GGS_GGSUSER_ROLE to userbd;
    SQL> @ddl_enable.sql;

5.3.配置Oracle端mangager进程、extract进程、replica进程

源端可以配置一个manager进程和一个extarct进程,manager负责管理整个源端ogg,extract负责捕获数据变更并往目的端传送,replica进程负责读取数据变更并同步到本地数据库。
  1. 使用oracle用户,创建子目录
oracle@9e495cc3fd40:/home/opt/files/fbo_ggs_Linux_x64_shiphome/Disk1$ ggsci

Oracle GoldenGate Command Interpreter for Oracle
Version 12.1.2.1.0 OGGCORE_12.1.2.1.0_PLATFORMS_140727.2135.1_FBO
Linux, x64, 64bit (optimized), Oracle 11g on Aug  7 2014 09:14:25
Operating system character set identified as US-ASCII.

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



GGSCI (9e495cc3fd40) 1> create subdirs

Creating subdirectories under current directory /home/opt/ogg

Parameter files                /home/opt/ogg/dirprm: already exists
Report files                   /home/opt/ogg/dirrpt: created
Checkpoint files               /home/opt/ogg/dirchk: created
Process status files           /home/opt/ogg/dirpcs: created
SQL script files               /home/opt/ogg/dirsql: created
Database definitions files     /home/opt/ogg/dirdef: created
Extract data files             /home/opt/ogg/dirdat: created
Temporary files                /home/opt/ogg/dirtmp: created
Credential store files         /home/opt/ogg/dircrd: created
Masterkey wallet files         /home/opt/ogg/dirwlt: created
Dump files                     /home/opt/ogg/dirdmp: created


GGSCI (9e495cc3fd40) 2>
  1. 登陆ogg控制台,设置需要进行同步的oracle表
GGSCI (9e495cc3fd40) 1> dblogin userid userbd

GGSCI (9e495cc3fd40) 1> add trandata {user}.*    -- 改成需要监听的用户空间
  1. 配置ogg manager&启动manager(配置界面操作类似vi)
GGSCI (9e495cc3fd40) 1> edit param mgr

PORT 8809
AUTOSTART ER *
DYNAMICPORTLIST 7801-8900
AUTORESTART EXTRACT *,RETRIES 5,WAITMINUTES 1
PURGEOLDEXTRACTS /home/opt/ogg/dirdat/*,usecheckpoints, minkeepdays 3
LAGREPORTHOURS 1
LAGINFOMINUTES 30
LAGCRITICALMINUTES 45

GGSCI (9e495cc3fd40) 1> info all(查看当前mgr状态)

GGSCI (9e495cc3fd40) 1> start manager(启动manager,启动完后可以用info all再次查看状态)
  1. 添加一个ogg extract进程(仅源端需要),用于抽取源服务器数据
GGSCI (c40702021b7a) 2> dblogin userid userbd
Password:
Successfully logged into database.
GGSCI (c40702021b7a as userbd@XE) 3> add trandata {user}.*

Logging of supplemental redo data enabled for table {user}.CDA_DIAG.
TRANDATA for scheduling columns has been added on table '{user}.CDA_DIAG'.

GGSCI (local) 1> add extract exta,tranlog,begin now (增加一个抽取进程exta,exta名字可以根据需要修改)
GGSCI (local) 1> add exttrail /home/opt/ogg/dirdat/wf,extract exta (将exta抽取的源数据变更数据写到该文件夹)
GGSCI (local) 1> edit params exta (修改exta的配置参数)
extract exta
setenv(ORACLE_HOME=/u01/app/oracle/product/11.2.0/xe)
setenv(NLS_LANG="AMERICAN_AMERICA.AL32UTF8")
userid userbd password userbd
exttrail /home/opt/ogg/dirdat/wf
TRANLOGOPTIONS DBLOGREADER
ddl include mapped objname testogg.*;
table testogg.*;
配置完成后可以通过info all查看到新添加的extract的状态
  1. 启动ogg extract命令
GGSCI (local) 1> start extract exta (等目标服务器ogg配置成功后再启动ext)
GGSCI (c40702021b7a as userbd@XE) 17> stats exta, total

Sending STATS request to EXTRACT EXTA ...

Start of Statistics at 2024-02-29 05:33:02.

Output to /home/opt/ogg/dirdat/wf:

Extracting from USERBD.CDA_DIAG to USERBD.CDA_DIAG:

*** Total statistics since 2024-02-29 05:31:52 ***
    Total inserts                                  1.00
    Total updates                                  0.00
    Total deletes                                  0.00
    Total discards                                 0.00
    Total operations                               1.00

End of Statistics.

GGSCI (c40702021b7a as userbd@XE) 19> shell ls -lrt  /home/opt/ogg/dirdat/      (shell + command... 可以执行shell命令)

total 4
-rw-r----- 1 oracle dba 1576 Feb 29 05:31 wf000000
  1. 添加一个ogg pump进程(仅源端需要),用于推送到目的数据库
GGSCI (af17c182783e as userbd@XE) 13> edit param pumpa
EXTRACT pumpa
setenv(NLS_LANG="AMERICAN_AMERICA.AL32UTF8")
PASSTHRU
RMTHOST 192.168.100.2,MGRPORT 8100
RMTTRAIL /home/opt/ogg/dirdat/wf
table testogg.*;

GGSCI (af17c182783e as userbd@XE) 14> ADD EXTRACT pumpa, EXTTRAILSOURCE /home/opt/ogg/dirdat/wf
EXTRACT added.

GGSCI (af17c182783e as userbd@XE) 15> ADD RMTTRAIL /home/opt/ogg/dirdat/wf, EXTRACT pumpa, MEGABYTES 5
RMTTRAIL added.

GGSCI (af17c182783e as userbd@XE) 16>start pumpa
  1. 添加一个ogg replica进程(仅目的端需要),用于同步到本地数据库
GGSCI (c40702021b7a as userbd@XE) 15> edit param GLOBAL
GGSCHEMA userbd

CHECKPOINTTABLE userbd.checkpoint

GGSCI (c40702021b7a as userbd@XE) 16> dblogin userid userbd     (假如执行过了,可以跳过)
Password:
Successfully logged into database.
GGSCI (c40702021b7a as userbd@XE) 17> add checkpointtable userbd.checkpoint
Successfully created checkpoint table userbd.checkpoint
GGSCI (c40702021b7a as userbd@XE) 18> add replicat rep1,exttrail /home/opt/ogg/dirdat/wf, checkpointtable userbd.checkpoint          (创建同步队列)
REPLICAT added.
GGSCI (c40702021b7a as userbd@XE) 19> edit param rep1
replicat rep1
ASSUMETARGETDEFS
DYNAMICRESOLUTION
userid userbd,password userbd
discardfile /home/opt/ogg/dirdat/rep1_discard.txt,append,megabytes 10
map USERBD.*,target USERBD.*;

GGSCI (c40702021b7a as userbd@XE) 19> start rep1      (启动复制进程)

6. OGG FOR PG 安装

注:在Docker环境下,整合postgres

  • 拉取docker镜像

    docker pull postgres:latest
  • 查看镜像

    docker images
  • 启动镜像

    docker run -d -p 8432:5432 -p 8100:8100  -e POSTGRES_PASSWORD=halojeff --name postgresql postgres:latest
    
    # 设置swap空间
    docker run -d -p 8432:5432 -p 8100:8100 --memory=1G --memory-swap=2G -e POSTGRES_PASSWORD=halojeff  --name postgresql postgres:latest
  • 查看镜像

    docker ps
  • 进入容器

    docker exec -it postgresql /bin/bash
  • 设置账号密码&新建用户

    postgres@1da1c762445f:/home/opt/ogg$ psql
    could not change directory to "/home/opt/ogg": Permission denied
    psql (14.1 (Debian 14.1-1.pgdg110+1))
    Type "help" for help.
    
    postgres=# create role gguser login password '*****';
    postgres=# GRANT CONNECT ON DATABASE postgres TO gguser;
    postgres=# ALTER USER gguser WITH REPLICATION;
    postgres=# ALTER USER gguser WITH SUPERUSER;
    postgres=# grant all privileges on database test_ogg to gguser;
    
    
    -- 收回用户在 test_ogg 下的所有权限
    REVOKE ALL PRIVILEGES ON database test_ogg FROM gguser;
    

    a. 下载ogg

  • https://edelivery.oracle.com/osdc/faces/SoftwareDelivery
    b. 解压ogg压缩包,将tar包解压到ogg安装目录(可以自定义,这里都设置为/home/opt/ogg),并新建odbc.ini文件

    [ODBC Data Sources]
    GG_Postgres=DataDirect 10.10 PostgreSQL Wire Protocol
    [ODBC]
    IANAAppCodePage=106
    InstallDir=/home/opt/ogg
    [GG_Postgres]
    Driver=/home/opt/ogg/lib/GGpsql25.so
    Description=DataDirect 10.10 PostgreSQL Wire Protocol
    Database=ogg_test
    HostName=127.0.0.1
    PortNumber=5432
    LogonID=ogg
    Password=ogg

    c. 配置环境变量

    export GG_HOME=/home/opt/ogg
    export PATH=$PATH:$HOME/bin:$GG_HOME
    export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$GG_HOME:$GG_HOME/lib
    export ODBCINI=$GG_HOME/odbc.ini
    alias ggsci='cd $GG_HOME;ggsci'

    d. 配置ogg

    $ ./ggsci
    
    ------创建子目录:
    
    GGSCI (localhost.localdomain) 1>create subdirs
    
    ------配置mgr端口(与源端端口不能相同)
    
    GGSCI (localhost.localdomain) 2> edit param mgr
    
    PORT 8810
    AUTOSTART ER *
    DYNAMICPORTLIST 7801-8900
    AUTORESTART EXTRACT *,RETRIES 5,WAITMINUTES 1
    PURGEOLDEXTRACTS /home/opt/ogg/dirdat/*,usecheckpoints, minkeepdays 3
    LAGREPORTHOURS 1
    LAGINFOMINUTES 30
    LAGCRITICALMINUTES 45
    ------配置replicat进程
    
    GGSCI (826d9a037f1c) 1> dblogin sourcedb gg_postgres userid ogg
    Password:
    
    2024-02-28 10:41:56  INFO    OGG-03036  Database character set identified as UTF-8. Locale: en_US.utf8.
    
    2024-02-28 10:41:56  INFO    OGG-03037  Session character set identified as UTF-8.
    Successfully logged into database.
    
    GGSCI (826d9a037f1c as ogg@gg_postgres) 4> add checkpointtable test.checkpoint
    
    Successfully created checkpoint table test.checkpoint.
    
    GGSCI (826d9a037f1c as ogg@gg_postgres) 5> add replicat repa, exttrail /home/opt/ogg/dirdat/wf,checkpointtable test.checkpoint
    Replicat added.
    
    
    GGSCI (826d9a037f1c as ogg@gg_postgres) 6>edit param repa
    REPLICAT repa
    
    targetdb GG_Postgres, USERID ogg, PASSWORD ogg
    ASSUMETARGETDEFS
    DYNAMICRESOLUTION
    discardfile /home/opt/ogg/dirdat/repa_discard.txt,append,megabytes 10
    
    MAP userdb.*, target test.*;
    
    GGSCI (826d9a037f1c as ogg@gg_postgres) 7> info all
    
    Program     Status      Group       Lag at Chkpt  Time Since Chkpt
    
    MANAGER     STOPPED
    REPLICAT    STOPPED     REPA         00:00:00      00:04:46
    
    
    GGSCI (826d9a037f1c as ogg@gg_postgres) 8> start manager
    Manager started.
    
    GGSCI (826d9a037f1c as ogg@gg_postgres) 10> start replicat repa
    
    Sending START request to Manager ...
    Replicat group REPA starting.
    
    GGSCI (826d9a037f1c as ogg@gg_postgres) 11> info all
    
    Program     Status      Group       Lag at Chkpt  Time Since Chkpt
    
    MANAGER     RUNNING
    REPLICAT    RUNNING     REPA         00:00:00      00:00:04
    
    GGSCI (826d9a037f1c as ogg@gg_postgres) 12>

添加新评论

  1. 看的我热血沸腾啊https://www.jiwenlaw.com/

    Reply
  2. 不错不错,我喜欢看

    Reply
  3. 不错不错,我喜欢看 www.jiwenlaw.com

    Reply
  4. 文章的确不错啊https://www.cscnn.com/

    Reply
  5. 《大日本人》喜剧片高清在线免费观看:https://www.jgz518.com/xingkong/26965.html

    Reply
  6. 你的文章让我心情愉悦,每天都要来看一看。 http://www.55baobei.com/QiC4oWn0Sf.html

    Reply
  7. 你的文章让我感受到了生活的美好,谢谢! https://www.yonboz.com/video/5673.html

    Reply
  8. 你的文章内容非常卖力,让人点赞。 https://www.yonboz.com/video/65300.html

    Reply
  9. 《水的重量》剧情片高清在线免费观看:https://www.jgz518.com/xingkong/208.html

    Reply
  10. 你的文章内容非常卖力,让人点赞。 https://www.yonboz.com/video/65300.html

    Reply
  11. 《水的重量》剧情片高清在线免费观看:https://www.jgz518.com/xingkong/208.html

    Reply
  12. 你的才华让人瞩目,期待你的更多文章。 http://www.55baobei.com/TMmczW4ttb.html

    Reply
  13. 你的文章让我感受到了正能量,非常棒! https://www.4006400989.com/qyvideo/45670.html

    Reply
  14. 你的文章充满了欢乐,让人忍不住一笑。 http://www.55baobei.com/M72rL9fXpJ.html

    Reply
  15. 《巴哥正传》国产剧高清在线免费观看:https://www.jgz518.com/xingkong/30381.html

    Reply
  16. 《水的重量》剧情片高清在线免费观看:https://www.jgz518.com/xingkong/208.html

    Reply
  17. 你的文章充满了欢乐,让人忍不住一笑。 https://www.yonboz.com/video/95456.html

    Reply
  18. 建议控制调侃频率,避免消解主题深度。

    Reply
  19. 选材新颖独特,通过细节描写赋予主题鲜活生命力。

    Reply
  20. 这篇文章如同一幅色彩斑斓的画卷,每一笔都充满了独特的创意。

    Reply