Oracle GoldenGate对接 Oracle 11g和Kafka

1环境背景

(1)机器ip和其对于的服务

ogg源端:192.168.15.6

服务:oracle, ogg的mgr(端口7809), ext_test, dpe_test

ogg目标端:192.168.15.6

服务:ogg的mgr(端口7909), rep_test,zookeeper, kafka

(2)oracle 版本,11g release 2

(3)kafka 版本,2.11-0.10.0.0

(4)zookeeper 版本, 3.5.2

(5)JVM 版本,1.8(ogg forbig data必须1.8 以上,否者无法启动)

(6)ogg 源端安装包文件名,123010_fbo_ggs_Linux_x64_shiphome

(7)ogg 目标端安装包文件名,123010_ggs_Adapters_Linux_x64

 

2 安装部署

2.1 zookeeper

(1)解压安装

使用下面的命令,解压 zookeeper 安装包:

[spark@master ~]$ tar -zxvf  ~/zookeeper-3.4.8.tar.gz 
[spark@master ~]$ cd ./zookeeper-3.4.8 

执行一下 ls -l 命令会看到下面的图片所示内容,这些内容是Zookeeper 包含的文件:

(2)配置 zookeeper 属性文件

根据 zookeeper 集群节点情况,创建zookeeper 配置文件 conf/zoo.cfg 后,将基本配置添加到配置文件中。

①配置服务器核心属性

使用复制命令生成配置文件,代码如下:

[spark@master zookeeper-3.4.8]$ cd conf 
[spark@master conf]$ cp zoo_sample.cfg zoo.cfg 

编辑系统配置文件:执行

[spark@master conf]$ gedit zoo.cfg 

然后将下面的代码追加到配置文件zoo.cfg 中:

server.1=master:2888:3888 
server.2=slave1:2888:3888 

接下来,添加 myid 文件,在 dataDir 目录(默认是/tmp/zookeeper)下创建 myid 文件,文件中只包含一行,且内容为该节点对应的 server.id 中的 id 编号。例如,master 和slave1 分别对应的 myid 文件中的值是 1 和 2 。所以在 master 节点上,编辑系统配置文件,执行:

[spark@master ~]$ mkdir -p /tmp/zookeeper
[spark@master ~]$ vi /tmp/zookeeper/myid 

然后将下面的内容添加到 myid 中:

1

在 slave1 节点上,编辑系统配置文件,执行

[zkpk@slave11 ~]$ mkdir -p /tmp/zookeeper 
[zkpk@slave11 ~]$ vi /tmp/zookeeper/myid 

然后将下面的内容添加到 myid 中:

2

(3)将 zookeeper 安装文件复制到slave1 节点,使用下面的命令操作:

[spark@master zookeeper-3.4.8]$ cd 
[spark@master ~]$ scp -r zookeeper-3.4.8 spark@slave1:~/ 

(4)启动 zookeeper 集群

分别登陆master和slave1节点,进入zookeeper安装主目录,启动服务

[spark@master ~]$ cd /home/spark/zookeeper-3.4.8 
[spark@master zookeeper-3.4.8]$ bin/zkServer.sh start 

使用下面的 Zookeeper 客户端命令可以测试服务是否可用:

[spark@master zookeeper-3.4.8]$ bin/zkCli.sh -server master:2181 

如果安装并启动成功,执行上面进入交互终端后,输入 help 命令会得到如下的打印信息:

其中,[zk:master:2181(CONNECTED) 0]前缀表示已经成功连接 Zookeeper,help 命令表示查看当前交互 客户端支持的命令

2.2 kafka

(1)解压安装

安装 Kafka 只需要三步操作:下载、修改配置和启动,下面介绍详细流程。注意,需在每台机器上该操作,比如你准备在三台机器 master 和 slave 上安装kafka,则需要在每个节点上进行如下操作。

[spark@master ~]$ tar –zxvf ~/kafka_2.10.tgz 
[spark@master ~]$ cd ~/kafka_2.10 

(2)配置 Kafka

只需要修改 brokerid 和 zookeeper.connect 项,在 master 节点完成如下操作:

[spark@master ~]$ cd /home/spark/kafka_2.10 
[spark@master kafka_2.10]$ vi ~/kafka_2.10/config/server.properties 

 

修改如下:

broker.id=0 
host.name=master 
zookeeper.connect=master:2181,slave1:2181

master 配置为 0,默认值不变即可。保存退出。

(3)将 kafka 安装文件复制到 slave1 节点,操作如下:

[spark@master ~]$ scp –r ~/kafka_2.10 spark@slave1:~/ 

在 slave1 节点完成如下操作:

[zkpk@slave1 ~]$ cd ~/kafka_2.10 
[zkpk@slave1 kafka_2.10]$ vi config/server.properties 

修改如下:

broker.id=1 
host.name=slave1
zookeeper.connect=master:2181,slave1:2181 

保存退出。

(4)启动 Kafka

在 master 和 slave1 节点分别启动 Kafka,代码如下:

[spark@master kafka_2.10]$ bin/kafka-server-start.sh -daemon config/server.properties 

最后,检验是否安装成功。使用 Kafka 自带的客户端检测。进入 Kafka 安装主目录,先启动生产者进入 交互客户端模式,

在 master 节点进行下面的操作,命令如下:

①创建一个名为 test 的主题

[spark@master kafka_2.10]$ bin/kafka-topics.sh --create --zookeeper master:2181 --replication-factor 1 --partitions 1 --topic test 

②在一个终端上启动一个生产者

[spark@master kafka_2.10]$ bin/kafka-console-producer.sh --broker-list master:9092 --topic test 

然后,键盘输入下面的信息:

明天会更好
hello world! 

③之后在另一个终端中启动消费者,进入交互客户端,命令如下:

[spark@master kafka_2.10]$ bin/kafka-console-consumer.sh --zookeeper master:2181 --topic test --from-beginning 

会发现屏幕上有同样的信息输出,证明Kafka 集群已经搭建成功。输出的内容如下:

明天会更好
hello world!

2.3 源端OGG

2.3.1 创建OGG home路径

实验分别在同一台机器上的/home/oracle/ogg/ogg_src目录下安装源端,/home/oracle/ogg/ogg_trg目录下安装目标端为例;

[oracle@ogg ~]$ mkdir -p /home/oracle/ogg/ogg_src

[oracle@ogg ~]$ mkdir -p /home/oracle/ogg/ogg_trg

2.3.2 设置response参数

[oracle@ogg ~]$ vi /home/oracle/ogg/fbo_ggs_Solaris_sparc_shiphome/Disk1/response/oggcore.rsp

 

INSTALL_OPTION=ORA11g

SOFTWARE_LOCATION=/home/oracle/ogg/ogg_src

START_MANAGER=false

MANAGER_PORT=7809

DATABASE_LOCATION=$ORACLE_HOME

注意:由于我用的oracle版本是11.2.0.2.0,因此installoption设置为ORA11g,如果用的是12C,这里要设置ORA12c

2.3.3 运行安装程序

[oracle@ogg ~]$ cdfbo_ggs_Linux_x64_shiphome/Disk1/

[oracle@ogg Disk1]$ ./runInstaller -silent-responseFile ./response/oggcore.rsp

2.3.4 图像安装方式

[oracle@ogg ~]$ /oracle/ogg/fbo_ggs_Linux_x64_shiphome/Disk1/runInstaller 


根据数据库版本选择对应的GoldenGate选项;

更改GoldenGateSoftware 安装位置,将其安装到/u01/app/product/ogg_src目录下,检查数据库安装位置是否正确,并配置端口;

检查安装信息,确认无误后开始安装;

这样源端的安装就完成了。

 

3 配置和实现

3.1 OGG用户和权限分配

GoldenGate需要从在线日子或归档日志抽取捕获系统的变更数据信息,这些信息可能来源于业务用户,可能来源于系统用户,为了使GoldenGate能够抽取这些数据应为GoldenGate创建独立的用户和分配必要的权限以满足系统运行需求,这些权限包括读取业务用户表数据的权限、读取系统表的权限、执行某个系统包的权限等。

3.1.1 Oracle 配置

源数据库要开归档,置成forcelogging,开追加日志。

(1)检查oracle 是否已经开启 Archive logging(日志自动归档)

[oracle@ogg ~]$ sqlplus /as sysdba

SQL> archive log list

Database log mode                      Archive Mode

Automatic archival                     Enabled

Archive destination                   /oracle/arc

Oldest online logsequence       9

Next log sequence toarchive     11

Current log sequence             11

SQL>

用户还可以使用以下命令查看 oracle 是否已经开启了自动归档模式,

SQL> selectname,log_mode from v$database;

LOG_MODE 显示NOARCHIVELOG则代表没有开启。

如果没有开启Archive logging,需要先停止数据库,执行以下命令:

SQL> shutdownimmediate;

SQL> startup mount;

SQL> alter databasearchivelog;

Database altered.

SQL> alter databaseopen;

(2) 检查是否开启 forcelogging 和 minimal supplemental logging

注意:如果不指定Primary key 和unique 属性,OGG将不会传送PK字段或Unique indiex字段信息。这样,下游的应用,在处理update数据时将失去依据

SQL> SELECT supplemental_log_data_min,force_loggingFROM v$database;

环境没有开启屏幕输出NO、开启输出YES,所以还需要执行开启命令,执行完毕后,我们再来查看forcelogging和minimal supplemental logging 的开启情况

SQL> alter database addsupplemental log data (primary key) columns;

SQL> alter database addsupplemental log data (unique) columns;

SQL> alter databaseforce logging;

SQL> alter systemswitch logfile;

检查开启情况,显示如下则代表ok

SUPPLEME FOR

-------- ---

IMPLICIT YES

在oracle 中开启 enable_goldengate_replication 参数

SQL> alter system setENABLE_GOLDENGATE_REPLICATION=true;

3.1.2 创建 ogg 用户

创建OGG 用户,用户名为ogg,密码也为ogg

SQL> create user oggidentified by ogg;

SQL> grantconnect,resource to ogg;

SQL> grant select anydictionary to ogg;

SQL> grant select anytable to ogg;

3.1.3 创建测试用户

建立一个oggkafka用户,并在下面建了一个t1的表

SQL> create table T1

(

 id NUMBER not null,

 name VARCHAR2(100)

);

3.2 配置源端GoldenGate

3.2.1 设置环境变量

Linux下安装GoldenGate要配置ORACLE_SID、ORACLE_HOME和$SOGG_HOME LD_LIBRARY_PATH;

exportJAVA_HOME=/home/oracle/Java/jdk1.8

export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar

exportORACLE_HOME=/home/oracle/oracle11g/product/11.2.0/dbhome_1

export ORACLE_SID=orcl

exportSOGG_HOME=/home/oracle/ogg/ogg_src

exportLD_LIBRARY_PATH=$ORACLE_HOME/lib:$ORACLE_HOME/lib32:$SOGG_HOME

##ZOOKEEPER

export ZOOKEEPER_HOME=/home/oracle/zookeeprt-3.5.2

##KAFKA

exportKAFKA_HOME=/home/oracle/kafka_2.11-0.10.0.0

 

PATH=$PATH:$HOME/.local/bin:$HOME/bin:$JAVA_HOME/bin:$ORACLE_HOME/bin:$ORACLE_HOME/OPatch:$ZOOKEEPER_HOME/bin:$KAFKA_HOME/bin:$SOGG_HOME

export PATH

3.2.2 GoldenGate MGR进程

MGR进程管理启动OracleGoldenGate进程、启动动态进程、分配端口给GoldenGate进程、管理trail file、创建事件,错误和诊断报告工作,必须在第一时间启动;当某些原因导致GoldenGate崩溃或重启机器时,默认情况MGR是没有启动

[oracle@ogg ogg_src]$ ./ggsci

GGSCI (ogg) 1> info mgr

Manager is DOWN!

(1)配置GoldenGate MGR进程

可以通过直接编辑GoldenGate_home/dirprm/mgr.prm文件或进入GGSCI命令行后键入edit param mgr命令回车进入MGR配置文件vi编辑界面;

GGSCI (ogg) 2> editparam mgr

PORT 7809

DYNAMICPORTLIST 7810-7820

AUTOSTART ER E*

AUTORESTART ER P*,RETRIES4, WAITMINUTES 4

STARTUPVALIDATIONDELAY 5

 

参数

说明

PORT

表示MGR进程端口号

DYNAMICPORTLIST

表示MGR进程动态为其它进程如Extract进程、Replicat进程分配的端口,可以是具体端口号或区间值

AUTOSTARTAUTORESTART

表示当MGR进程启动后失败时自动启动或重启的GoldenGate进程

(2)启动mgr进程

GGSCI (ogg) 3> startmgr

Manager started.

GGSCI (ogg) 4> info mgr

Manager is running (IPport sywu.7909, Process ID 17400).

启动原理:通过读取$OGG_HOME/dirprm/mgr.prm文件,然后根据该文件的配置信息启动进程分配端口号,如果该进程启动失败,首先请检查预使用的端口是否被占用:

netstat -lntup|grep 7809

tcp        0     0 :::7809                    :::*                        LISTEN      32426/./mgr

然后检查相关的配置文件或重新配置MGR

3.2.3 在源端创建和配置Extract进程

创建和配置Extract进程的工作有:

①创建和配置主抽取进程(PrimaryExtract)

②创建和配置Data Pump进程(Secondly Extract)

(1)创建主抽取进程(Primary Extract)

进入GGSCI命令行使用add extract 命令创建主抽取进程

GGSCI (ogg) 5> addextract ext_test,tranlog,begin now

EXTRACT added.

因为主进程的作用是抽取捕获系统变更数据并将这些数据保存到trail文件里,所以必须为其配置trail文件目录和trail文件名的两个字符名,trail文件名共8个字符,其余6个字符由GoldenGate系列填充;

GGSCI (ogg) 6> ADDEXTTRAIL ./dirdat/ex , EXTRACT ext_test, MEGABYTES 200

EXTTRAIL added.

①配置主抽取进程(Primary Extract)参数

GGSCI (ogg) 7> edit param ext_test
 
extract esydb001
SETENV(ORACLE_SID="orcl")
SETENV(NLS_LANG=AMERICAN_AMERICA.AL32UTF8)
userid ogg_owner, password ogg_owner
EXTTRAIL ./dirdat/ex
table ogg_owner.togg;

userid指定GoldenGate 抽取用户的用户名和密码;

SETENV 设置环境变量,如实例名、数据库字符集;

table 指定抽取的用户和表名,如果指定多个以相同字符开头或结尾的表名,可以使用“前缀* ”的方式代替,这里仅以ogg_owner.togg表为测试案例;

启动该日志抽取服务,注意:此操作是在ggsci 中执行

GGSCI (ogg) 8> startext_test

(2)创建和配置Data Pump进程(Secondly Extract)

添加Data Pump Extract进程时要注意,如果源端和目标端OGG物理路径都相同,可以按照常规方式处理,但是如果不相同,就像我本例的一样源端和目标端都在同一台机器上,但GoldenGate物理路径不相同,请按如下方式处理

①创建Data Pump Extract进程

GGSCI (ogg) 26> ADDEXTRACT dpe_test, EXTTRAILSOURCE ./dirdat/ex

EXTRACT added.

EXTTRAILSOUCE 指定源端的trail路径,必须包含两个字符,这个路径和主抽取进程(Primary Extract)中指定的trail目录和trail文件命名必须相同,因为Data Pump进程要读取主抽取进程生成的trail文件;

②配置Data Pump Extract进程

edit param dpe_test

 

extract dpe_test

SETENV(ORACLE_SID="sydb")

SETENV(NLS_LANG=AMERICAN_AMERICA.AL32UTF8)

userid ogg,password 123456

RMTHOST 192.168.15.6,mgrport7909

RMTTRAIL ./dirdat/re

table oggkafka.t1;

RMTHOST 指定目标端地址和端口等信息;

RMTTRAIL 指定目标端保存trail文件的目录和两个字符文件名;

TABLE 指定同步的表,配置的方式同在主抽取进程(PrimaryExtract)的配置一样,但这里多了许多额外的功能,比如实现数据过滤和其它复杂操作;

③将目标端trail文件添加到队列中

源端可以配置多个主抽取进程,也可以配置多个DataPump进程,但必须为每个要同步的目标端配置一个Data Pump进程;

GGSCI (ogg) 10> ADDRMTTRAIL ./dirdat/re, EXTRACT dpe_test, MEGABYTES 200

RMTTRAIL added.

大家注意,红色字体是ext_test 的路径,绿色字体是发送到远端服务的路径

配置好dpe_test 服务后,还不能够立马启动,因为远端接收的MGR 服务还没有起来,所以这块还遗留一个小尾巴

3.2.4 附加日志

打开oggkafka.t1表级

[oracle@ogg ogg_src]$./ggsci

GGSCI>Dblogin useridogg, password 123456

Add trandata oggkafka.t1

3.3 配置目标端OGG for BigData

3.3.1 设置环境变量

要配置TOGG_HOME , LD_LIBRARY_PATH;

exportJAVA_HOME=/home/oracle/Java/jdk1.8

export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar

exportORACLE_HOME=/home/oracle/oracle11g/product/11.2.0/dbhome_1

export ORACLE_SID=orcl

exportSOGG_HOME=/home/oracle/ogg/ogg_src

exportTOGG_HOME=/home/oracle/ogg/ogg_trg

export LD_LIBRARY_PATH=$ORACLE_HOME/lib:$ORACLE_HOME/lib32:$SOGG_HOME:$TOGG_HOME:$JAVA_HOME/jre/lib/amd64/libjsig.so:$JAVA_HOME/jre/lib/amd64/server/libjvm.so:$JAVA_HOME/jre/lib/amd64/server:$JAVA_HOME/jre/lib/amd64

 

##ZOOKEEPER

export ZOOKEEPER_HOME=/home/oracle/zookeeprt-3.5.2

##KAFKA

exportKAFKA_HOME=/home/oracle/kafka_2.11-0.10.0.0

 

PATH=$PATH:$HOME/.local/bin:$HOME/bin:$JAVA_HOME/bin:$ORACLE_HOME/bin:$ORACLE_HOME/OPatch:$ZOOKEEPER_HOME/bin:$KAFKA_HOME/bin:$SOGG_HOME:$TOGG_HOME

 

export PATH

如果不设置JDK的LD_LIBRARY_PATH环境变量,会在启动后面的rep_test 服务时,报错

ERROR   OGG-15050  Error loading Java VM runtime library

用户也要注意 /etc/hosts 的设置,一定需要将机器的hostname 和 IP 地址配置好映射关系,否者也会出现错误

ERROR   OGG-15161  Could not initialize the connection with MGR MGR (No route to host).

如果用户出现此错误,需要先重启目标端的mgr服务,直接在 ggsci 命令窗口执行 stop mgr 命令是不能够停止mgr 服务的,还需要用户在shell 中通过 kill -15 PID 的方法停止mgr。

用户正确修改 /etc/hosts 配置文件后,再重启目标端的 mgr 和 rep_test 服务,然后需要 重新启动 源端 的 dpe_test 服务,因为目标段的 mgr 服务一旦停止,dpe_test 就可能出现异常。

3.3.2 配置manager

GGSCI (ogg) 10> edit param mgr
PORT 7909
DYNAMICPORTLIST 7910-7920
AUTOSTART ER E*
AUTORESTART ER P*,RETRIES 4, WAITMINUTES 4
STARTUPVALIDATIONDELAY 5

配置kafka.props,拷贝模板文件

cp $TOGG_HOME/AdapterExamples/big-data/kafka/*  $TOGG_HOME /dirprm/

读者们注意了,在目标段的MGR 配置中,端口号设置是需要源端的dpe_test 配合的,这个读者注意。

启动manager 进程,并且确认,注意:此操作是在 ggsci 中执行

GGSCI (ogg)11> start mgr

确认命令,如果正常运行,则显示MANAGER RUNNING

GGSCI (ogg)12> info all

3.3.2 修改接收服务配置

GGSCI (ogg)13> edit params rep_test

修改内容如下

REPLICAT rep_test

TARGETDB LIBFILElibggjava.so SET property=dirprm/kafka.props

GETTRUNCATES

SOURCEDEFSdirdef/source.def

REPORTCOUNT EVERY 1MINUTES, RATE

GROUPTRANSOPS 10000

MAP oggkafka.*, TARGET oggkafka.*;

dirprm/kafka.props 是kafka 的配置文件,下面会介绍到。dirdef/source.def 是源端的表结构定义文件,这个暂时还没有介绍到,等一下会介绍。然后就是添加rep_test 该服务,并且指定 dirdat/re 路径作为 rep_test 服务的日志来源,读者可以留意一下,dirdat/re 路径,实际上就是远端dpe_test 指定的路径。因为rep_test 的服务作用就是将 日志文件解析,然后再做相应的处理,例如本例子就是将解析后的日志发送到kafka 上为 ogg 增加rep_test服务。

GGSCI (ogg)14> add replicat rep_test, exttrail ./dirdat/re

3.3.3 配置kafka信息

修改$TOGG_HOME/dirprm/kafka.props,主要修改以下内容

[oracle@ogg ~]$ vi $TOGG_HOME/dirprm/kafka.props

 

gg.handlerlist =kafkahandler
gg.handler.kafkahandler.type=kafka
gg.handler.kafkahandler.TopicMappingTemplate=chentest
#gg.handler.kafkahandler.TopicName=chentest
gg.handler.kafkahandler.KafkaProducerConfigFile=./dirprm/custom_kafka_producer.properties

gg.handler.kafkahandler.format=json

 

gg.handler.kafkahandler.BlockingSend=false
gg.handler.kafkahandler.includeTokens=false
gg.handler.kafkahandler.mode=tx

 

goldengate.userexit.timestamp=utc
goldengate.userexit.writers=javawriter
javawriter.stats.display=TRUE
javawriter.stats.full=TRUE

gg.log=log4j
gg.log.level=INFO

gg.report.time=30sec

#Samplegg.classpath for Apache Kafka
gg.classpath=dirprm/:/home/oracle/ogg/ggjava/resources/lib/*:/home/oracle/kafka_lib/*
#Sample gg.classpath for HDP

javawriter.bootoptions=-Xmx512m-Xms32m -Djava.class.path=ggjava/ggjava.jar

 

这里有几点需要读者们注意的:

1 gg.handler.kafkahandler.format参数需要填写json ,如果填写text 或者其他,会由于源端oracle中执行update sql 命令,从而导致 日志解析失败,因为text无法表示出修改记录的形式

2gg.handler.kafkahandler.mode 参数填写 tx,表示解析后的日志是可读的

3 gg.classpath 参数重点需要填写两个路径,分别是 oggfor kafka 的驱动路径,另外一个是kafka 产品的lib驱动路径(该路径读者可以在KAFKA_HOME 目录下寻找,直接拷贝过来即可)

4 kafka 中的topicName 要使用gg.handler.kafkahandler.TopicMappingTemplate 参数,而不能够使用gg.handler.kafkahandler.TopicName 参数(ogg 的kafka 模版中的参数竟然是错误的,简直令人发指),否者rep_test 进程将启动失败。

修改连接kafka 的配置

[oracle@ogg~]$ vi $TOGG_HOME/dirprm/custom_kafka_producer.properties

主要修改内容:

bootstrap.servers 参数是指定 用户已经部署好的 kafka 连接ip和端口

bootstrap.servers=192.168.15.7:9092

rep_test 的服务配置已经基本完了,但是源端表结构的配置还没有开始做,所以也暂时对 rep_test 服务留一个小尾巴。

3.3.4 源端表结构文件初始化

请读者回到源端的ggsci 客户端的交互命令窗口上来,执行以下命令,创建一个新的初始化源端表结构的配置文件。

GGSCI (ogg)1> edit param defgen

此时界面会跳转到VI界面上,用户直接在上面编辑以下内容。

userid 和 password 参数是 oracle 数据库中的用户名和密码登录方式

table 参数就是需要初始化的表名

DEFSFILEdirdef/source.def, PURGE

USERID ogg, PASSWORD ogg

TABLE oggkafka.t1 ;

然后用户在 linux shell 窗口下执行以下命令(源端执行shell 命令)

[oracle@ogg ogg_src]$defgen paramfile dirprm/defgen.prm

然后把在源端新生成的dirdef/source.def 文件scp 到目标端的dirdef/source.def

3.3.5 将遗留的尾巴收割

我们首先来启动rep_test 服务(目标端的ggsci 执行)。

GGSCI (ogg)1> start rep_test

再来启动 dpe_test 服务(源端的ggsci 执行)。

GGSCI (ogg)1> start dpe_test

用户也可以分别在源端和目标端的 ggsci 中查看rep_test 和 dpe_test 服务的启动状态

GGSCI (ogg)1> info  all


  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值