Kafka笔记

Kafkfa笔记

一、简介

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DC3ZFZeg-1630938851023)(C:\Users\等待\AppData\Roaming\Typora\typora-user-images\1624285209787.png)]

二、部署(伪分布)

2.1、准备工作

#上传、解压、更名、配置环境变量
tar -zxvf kafka_2.11-2.3.0.tgz -C /usr/local/


#配置KAFKA_HOME环境变量  
vim /etc/profile
mv /usr/local/kafka_2.11-2.3.0/ /usr/local/kafka-2.3.0
export KAFKA_HOME=/usr/local/kafka-2.3.0
export PATH=$PATH:$KAFKA_HOME/bin

2.2、修改kafka配置文件

#修改$KAFKA_HOME/config/server.properties
vim $KAFKA_HOME/config/server.properties

1)broker.id
broker.id=0  # 数字可以任意数字只要在你的集群唯一  多机环境时复制时需要注意不相同

2)log.dirs

log.dirs=/tmp/kafka-logs  #默认就是这个,但是在生产环境下,肯定不是默认的目录,需要自己手动创建目录
3)zk
zookeeper.connect=master:2181  # 多个以,分隔

4)
host.name=192.168.1.101  #可选 写IP可以解决后面Nginx发送数据时,域名解析异常的问题

2.3、启动kafka

注意:启动kafka之前一定要提前开启zookeeper(暂时使用的kafka内置的zookeeper,可以使用外置的zookeeper)

cd $KAFKA_HOME

bin/zookeeper-server-start.sh config/zookeeper.properties

bin/kafka-server-start.sh config/server.properties

或者下面

${KAFKA_HOME}/bin/zookeeper-server-start.sh ${KAFKA_HOME}/config/zookeeper.properties

${KAFKA_HOME}/bin/kafka-server-start.sh  ${KAFKA_HOME}/config/server.properties

启动kafka后,zookeeper服务出现以下信息:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DmuTjaSk-1630938851024)(C:\Users\等待\AppData\Roaming\Typora\typora-user-images\1624281236649.png)]

其实没事的,只是INFO,能正常运行

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HbAj4lXP-1630938851026)(C:\Users\等待\AppData\Roaming\Typora\typora-user-images\1624281413557.png)]

2.4、kafka服务验证

方式一:(使用Kafka shell验证)
kafka-topics.sh 用于主题创建 查看 (不建议删除主题)

kafka-topics.sh  --zookeeper master:2181 -- list  # 在kafka-2.3.0中已过时

#查看topic的列表
kafka-topics.sh  --bootstrap-server master:9092 --list 

kafka-topics.sh  --bootstrap-server master:9092 --create  --topic test0621 \
--partitions 1 \
--replication-factor 1

可显示各种参数

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HUQWLdtG-1630938851029)(C:\Users\等待\AppData\Roaming\Typora\typora-user-images\1624283547102.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GSMkfh7p-1630938851032)(C:\Users\等待\AppData\Roaming\Typora\typora-user-images\1624284324046.png)]

查看topic的列表

查看kafka主题**,如以下命令 需要带参数

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FUVQ1EAN-1630938851034)(C:\Users\等待\AppData\Roaming\Typora\typora-user-images\1624283848921.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kvnfnFL3-1630938851035)(C:\Users\等待\AppData\Roaming\Typora\typora-user-images\1624283910059.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CfNLr0hU-1630938851037)(C:\Users\等待\AppData\Roaming\Typora\typora-user-images\1624283996683.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0nO0MubO-1630938851038)(C:\Users\等待\AppData\Roaming\Typora\typora-user-images\1624284152962.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vpblLTcz-1630938851039)(C:\Users\等待\AppData\Roaming\Typora\typora-user-images\1624284219071.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZokgecDJ-1630938851040)(C:\Users\等待\AppData\Roaming\Typora\typora-user-images\1624284284410.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sOdIWdPs-1630938851041)(C:\Users\等待\AppData\Roaming\Typora\typora-user-images\1624284447931.png)]

查看kafka主题的一个信息

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-raCo3CAF-1630938851042)(C:\Users\等待\AppData\Roaming\Typora\typora-user-images\1624284573386.png)]

方式二:进入zk(了解即可)

进入zookeeper

1、zk验证Kafka Brokers

$KAFKA_HOME/bin/zookeeper-shell.sh master:2181

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tYxuCql9-1630938851043)(C:\Users\等待\AppData\Roaming\Typora\typora-user-images\1624281515208.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6RxoSWLv-1630938851045)(C:\Users\等待\AppData\Roaming\Typora\typora-user-images\1624281949722.png)]

Kafka Broker端口默认是:9092 对应ZK: /brokers/ids/xxx

2、zk验证topics

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uR11FkpH-1630938851046)(C:\Users\等待\AppData\Roaming\Typora\typora-user-images\1624282158851.png)]

2.3、停止kafka

注意:先停止kafka、再停止zookeeper

cd $KAFKA_HOME
bin/kafka-server-stop.sh

2.4、将进程放入supervisor(守护进程,自动重启)(可接2.2后)

这个是一个后台进程,若出现异常进程退出,supervisor会自动重启

官网:http://www.supervisord.org/introduction.html

进程管理与监控工具,可以将命令行进程变成Deamon进程,并监控其状态,在异常退出时可以自动启动进程

2.4.1、supervisor安装与启动

1、安装部署
# 我们通过yum安装,先按照epel源
yum install -y  epel-release
# 安装supervisor
yum install -y supervisor
# 安装完毕后,我们的supervisord的配置文件默,安装在/etc/supervisord.conf, 我们不需要默认的配置文件,我们编写自己的配置文件,因此我们先把默认配置文件备份一下,执行如下命令
mv /etc/supervisord.conf /etc/supervisord.conf.bak
#之后我们编写自己的配置文件supervisord.conf 放到 /etc/ 目录下
2、修改Supervisord 配置文件
; filename supervisord.conf
[unix_http_server]
file=/var/run/supervisor/supervisor.sock   ; socket 文件路径,supervisorctl使用XML_RPC和supervisord 的通信就是通他进行,必须设置,不然supervisorctl就不可用了
;username=user              ; 可以指定用户名密码,我们这里不开启了
;password=123               ; 

[inet_http_server]         ; 监听在TCP上的scoket,如果想使用Web Server或者使用远程的Supervisorclt,就必须开启,默认不开启,我们这里开启
port=0.0.0.0:9001        ; 监听的地址和端口
;username=user             ; 可以指定用户名密码,我们这里不开启了
;password=123              ; 

[supervisord] ; supervisord 主进程的相关配置
logfile=/var/log/supervisor/supervisord.log ; 主进程的日志文件
logfile_maxbytes=50MB        ; 日志文件多大后会滚动生成一个新的日志文件 默认50MB
logfile_backups=10           ; 最多备份多少个日志文件,默认10 个
loglevel=info                ; log level; default info; others: debug,warn,trace
pidfile=/var/run/supervisor/supervisord.pid ;主进程的 pid文件路径
nodaemon=false               ; 主进程是否在前台运行,默认是false,在后台运行
minfds=1024       ; 最少系统空闲的文件描述符,低于这个值,supervisor将不会启动 默认 1024
minprocs=1024                ; 最小可用进程描述符 低于这个值,supervisor将不会启动 默认200
user=root					; 启动supervisord 的用户


[rpcinterface:supervisor]; 这个选项是给XML_RPC用的,如果使用supervisord 和webserver这个选项必须开启
supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface


[supervisorctl]
serverurl=unix:///var/run/supervisor/supervisor.sock ; 本地连接supervisord的时候使用,注意和[unix_http_server]配置对应
serverurl=http://0.0.0.0:9001 ; 远程连接supervisord
;username=              ; 可以指定用户名密码,我们这里不开启了
;password=                ; 

[include] ;分离的配置文件,我们可以总是将我们应用的配置文件放到单独的目录文件下管理,这样配置清晰,下面是配置的分离配置文件的路径,supervisord会加载我们配置到对于文件加下的文件
files = /etc/supervisord.d/*.conf ; 匹配 /etc/supervisord.d/ 下所有以 .conf 结尾的文件
3、启动supervisord
# 将上述配置文件命名为supervisord.conf 放到 /etc/ 目录下
# 创建pid文件
mkdir -p /var/run/supervisor/
touch /var/run/supervisor/supervisord.pid
# 创建分类配置目录
mkdir -p /etc/supervisord.d/
# 创建日志目录
mkdir -p /var/log/supervisor/
# 开机启动
systemctl enable supervisord
# 启动supervisord
systemctl start supervisord
# 查看启动状态
systemctl status supervisord
# 查看tcp端口是否在监听中
netstat -antp |grep 9001
# 如果看到如下监听,说明supervisord 已经正常工作
4、加入zk+kafka
# 将上述编写配置文件zk.conf kafka.conf 放到 /etc/supervisord.d/ 目录后,执行如下命令
# 读取配置文件
supervisorctl reread
# 更新启动Prometheus
supervisorctl update zk
# 查看启动状态,如果一切ok,将看到如下图信息
supervisorctl status  zk
# 如果想停止grafana
supervisorctl stop zk
# 如果想再次启动
supervisorctl start zk
# 注意一旦你修改了配置文件内容,一定要先reread,然后 update 就可以了

2.5.2、zk.conf配置文件

# zk(需要配置的属性)
# 0.program名字唯一,可以跟配置文件相同
# 1.directory
# 2.command 
# 3.logfile
# 4.user
================================================================================
; zk配置
[program:zk] ; 我们的应用配置格式为 program:我们应用名称(自己定义)
directory=/Users/ly/apps/kafka_2.11-2.3.0 ; 运行程序前会切换到配置的目录中
command=/Users/ly/apps/kafka_2.11-2.3.0/bin/zookeeper-server-start.sh /Users/ly/apps/kafka_2.11-2.3.0/config/zookeeper.properties 		;我们要执行的命令
stderr_logfile=/usr/local/var/log/supervisor/zk.err	;错误日志文件
stdout_logfile=/usr/local/var/log/supervisor/zk.log ;标准输出日志文件,我们通过该文件查看agent运行日志
stdout_logfile_maxbytes=10MB  ; 标准输出日志文件多大滚动一次
stdout_logfile_backups=10 ; 标准输出日志文件最多备份多少个
user=ly	; 以什么用户启动
autostart=true ; 是否在supervisord启动时,直接就启动应用
autorestart=true ; crash 后是否自动重启
startsecs=10	;应用进程启动多少秒之后,此时状态如果是running状态,就认为是成功
startretries=3 ; 当进程启动失败后,最大尝试启动的次数, 如果超过指定次数,应用会被标记为Fail状态
stopasgroup=true ; 是否停止由应用本身创建的子进程,此选项接受的停止信号是stop信号
killasgroup=true ; 是否停止由应用本身创建的子进程,此选项接受的停止信号是SIGKILL信号
redirect_stderr=true ; 如果是true,stderr的日志会被写入stdout日志文件中

2.4.3、kafka.conf配置文件

# kafka同上(需要配置的属性)
================================================================================
; kafka-broker-0配置
[program:kafka-broker-0] ; 我们的应用配置格式为 program:我们应用名称(自己定义)
directory=/Users/ly/apps/kafka_2.11-2.3.0 ; 运行程序前会切换到配置的目录中
command=/Users/ly/apps/kafka_2.11-2.3.0/bin/kafka-server-start.sh /Users/ly/apps/kafka_2.11-2.3.0/config/server.properties;我们要执行的命令
stderr_logfile=/usr/local/var/log/supervisor/kafka-broker-0.err	;错误日志文件
stdout_logfile=/usr/local/var/log/supervisor/kafka-broker-0.log ;标准输出日志文件,我们通过该文件查看agent运行日志
stdout_logfile_maxbytes=10MB  ; 标准输出日志文件多大滚动一次
stdout_logfile_backups=10 ; 标准输出日志文件最多备份多少个
user=ly	; 以什么用户启动
autostart=true ; 是否在supervisord启动时,直接就启动应用
autorestart=true ; crash 后是否自动重启
startsecs=10	;应用进程启动多少秒之后,此时状态如果是running状态,就认为是成功
startretries=3 ; 当进程启动失败后,最大尝试启动的次数, 如果超过指定次数,应用会被标记为Fail状态
stopasgroup=true ; 是否停止由应用本身创建的子进程,此选项接受的停止信号是stop信号
killasgroup=true ; 是否停止由应用本身创建的子进程,此选项接受的停止信号是SIGKILL信号
redirect_stderr=true ; 如果是true,stderr的日志会被写入stdout日志文件中

访问:ip:9001


三、kafka的topic基本操作

1、关于topic的操作脚本:kafka-topics.sh操作

具体实现的功能截图在下方

kafka-topics.sh 用于主题创建 查看 (不建议删除主题)

kafka-topics.sh  --zookeeper master:2181 -- list  # 在kafka-2.3.0中已过时

#查看topic的列表
kafka-topics.sh  --bootstrap-server 192.168.1.101:9092 --list 

kafka-topics.sh  --bootstrap-server master:9092 --create  --topic test0621 \
--partitions 1 \
--replication-factor 1

kafka-topics.sh  --bootstrap-server master:9092 --describe --topic test0621

kafka-topics.sh  --bootstrap-server master:9092 --create --topic test0621-1 \
--partitions 3 # 分区的数量可以⼤于broker数量 分区提⾼并⾏度
--replication-factor 1 # 副本因⼦不⼤于broker数量

kafka-topics.sh  --bootstrap-server master:9092 --describe --topic test0621-1

可显示各种参数

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DKBTb5Bw-1630938851047)(C:\Users\等待\AppData\Roaming\Typora\typora-user-images\1624283547102.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-puNUtoOj-1630938851049)(C:\Users\等待\AppData\Roaming\Typora\typora-user-images\1624284324046.png)]

1、查看topic的列表,如以下命令 需要带参数

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zcetPeuu-1630938851050)(C:\Users\等待\AppData\Roaming\Typora\typora-user-images\1624283848921.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wdGl1Skd-1630938851051)(C:\Users\等待\AppData\Roaming\Typora\typora-user-images\1624283910059.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-h2Qgyzcy-1630938851052)(C:\Users\等待\AppData\Roaming\Typora\typora-user-images\1624283996683.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UOmMlOdi-1630938851053)(C:\Users\等待\AppData\Roaming\Typora\typora-user-images\1624284152962.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9QUmIjXh-1630938851055)(C:\Users\等待\AppData\Roaming\Typora\typora-user-images\1624284219071.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ScIK4Am8-1630938851056)(C:\Users\等待\AppData\Roaming\Typora\typora-user-images\1624284284410.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LrUzf1tW-1630938851057)(C:\Users\等待\AppData\Roaming\Typora\typora-user-images\1624284447931.png)]

2、查看每⼀个topic的信息

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zenBo0uF-1630938851058)(C:\Users\等待\AppData\Roaming\Typora\typora-user-images\1624284573386.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YjbQxxBS-1630938851059)(C:\Users\等待\AppData\Roaming\Typora\typora-user-images\1624284923307.png)]

再次创建topic

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2bALPerL-1630938851060)(C:\Users\等待\AppData\Roaming\Typora\typora-user-images\1624285644380.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-obDrVDmY-1630938851061)(C:\Users\等待\AppData\Roaming\Typora\typora-user-images\1624285775768.png)]

提示:

Partition: 当前topic对应的分区编号
Replicas : 副本因⼦,当前kafka对应的partition所在的broker实例的broker.id的列表
Leader : 该partition的所有副本中的leader领导者,处理所有kafka该partition读写请求
ISR : 该partition的存活的副本对应的broker实例的broker.id的列表

大白话如下:
Isr 副本同步列表
Replicas 副本号

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qbuxWCMC-1630938851062)(C:\Users\等待\AppData\Roaming\Typora\typora-user-images\1624285356888.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-F0EkNx55-1630938851065)(C:\Users\等待\AppData\Roaming\Typora\typora-user-images\1624286448907.png)]

不要求你实时同步,最终能同步过去就好了。

3、修改一个topic


请注意:partition个数,只能增加,不能减少

2、⽣产数据

往主题中写⼊消息

[root@master kafka-2.3.0]# bin/kafka-console-producer.sh --broker-list 192.168.1.101:9092 --topic test0621-1

此时在这里,
--topic 指定数据被⽣产的topic
--broker-list 指定kafka的broker列表(其实只写一个就好)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wj6Txdwk-1630938851066)(C:\Users\等待\AppData\Roaming\Typora\typora-user-images\1624287528365.png)]

3、消费数据

从主题中消费消息

# 表示从最新的位置开始消费 latest
[root@master kafka-2.3.0]# bin/kafka-console-consumer.sh --bootstrap-server 192.168.1.101:9092 --topic test0621-1

# 表示从头开始消费 earliest
# 随机产⽣消费组id⽆法记录 offset 
# 比如CURRENT-OFFSET是未知
[root@master kafka-2.3.0]# bin/kafka-console-consumer.sh --bootstrap-server 192.168.1.101:9092 --topic test0621-1 \
--from-beginning

# ⾃定义group id可以从上次消费的地⽅开始
kafka-console-consumer.sh --bootstrap-server 192.168.1.101:9092 --topic test0621-1 --group bk2101


[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BgP4PkX2-1630938851068)(C:\Users\等待\AppData\Roaming\Typora\typora-user-images\1624322235549.png)]

若未消费,生产数据就会造成积压

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YqozpIRR-1630938851072)(C:\Users\等待\AppData\Roaming\Typora\typora-user-images\1624322343498.png)]

若再次消费,就没有积压了

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BMpOp8yS-1630938851074)(C:\Users\等待\AppData\Roaming\Typora\typora-user-images\1624322479300.png)]

4、消费组(跟踪消费进度)
查看当前所有消费组 ,只要消费组相同则共享消费进度

[root@master kafka-2.3.0]# bin/kafka-consumer-groups.sh --bootstrap-server master:9092 --list
console-consumer-2506
console-consumer-12386

#注:consumer停止之后就查不到了
[root@master kafka-2.3.0]# bin/kafka-consumer-groups.sh --bootstrap-server master:9092 --describe --group console-consumer-2506

GROUP                 TOPIC           PARTITION  CURRENT-OFFSET  LOG-END-OFFSET  LAG             CONSUMER-ID                                     HOST            CLIENT-ID
console-consumer-2506 test0621-1      0          -               1               -               consumer-1-16308718-2589-426a-9eed-09008ad9c2f7 /192.168.1.101  consumer-1
console-consumer-2506 test0621-1      1          -               1               -               consumer-1-16308718-2589-426a-9eed-09008ad9c2f7 /192.168.1.101  consumer-1
console-consumer-2506 test0621-1      2          -               2               -               consumer-1-16308718-2589-426a-9eed-09008ad9c2f7 /192.168.1.101  consumer-1

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GZlVD0PC-1630938851076)(C:\Users\等待\AppData\Roaming\Typora\typora-user-images\1624321665909.png)]

注:CURRENT-OFFSET 之所以默认未知,是因为消费者已经消费了,也就是说消息已经读过了,并没有告诉kafka已经读过了,kafka并不知道.

5、kafka的消费的总结
6、kafka中的分区策略

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3DmyDu7I-1630938851077)(C:\Users\等待\AppData\Roaming\Typora\typora-user-images\1624323707523.png)]

7、kafka的常用命令
#启动ZK
./bin/zookeeper-server-start.sh ./config/zookeeper.properties 

#启动Kafka
./bin/kafka-server-start.sh ./config/server.properties

#创建主题
kafka-topics.sh --zookeeper localhost:2181 --create --topic test --partitions 1 --
replication-factor 1

#查看主题
kafka-topics.sh --zookeeper localhost:2181 --list

#发送消息
./bin/kafka-console-producer.sh --broker-list localhost:9092 --topic test

#有key类型消息
./bin/kafka-console-producer.sh --broker-list localhsot:9092 --topic topicName --
property parse.key=true #默认消息键与消息值间使⽤“Tab键”进⾏分隔,切勿使⽤转义字符(\t)

#消费消息
./bin/kafka-console-consumer.sh --bootstrap-server localhost:9092 --topic test --frombeginning

#有key类型消息
kafka-console-consumer.sh --bootstrap-server master:9092 --topic test2 --from-beginning --property print.key=true

#删除Kafka主题 kafka_2.11_2.30
#只需要在当前broker上设置server.properties
delete.topic.enable=true
./kafka-topics.sh --zookeeper master:2181 --delete --topic test1

#查看主题offset,消息数量
kafka-run-class.sh kafka.tools.GetOffsetShell --broker-list hadoop02:9092 -topic news -
-time -1

#查询__consumer_offsets topic所有内容
kafka-console-consumer.sh --topic __consumer_offsets --bootstrap-server master:9092 -
-formatter "kafka.coordinator.group.GroupMetadataManager\$OffsetsMessageFormatter" --
consumer.config ../config/consumer.properties --from-beginning

#查询消费者组列表
kafka-consumer-groups.sh --bootstrap-server master:9092 --list

#查询消费组消费进度
 kafka-consumer-groups.sh --bootstrap-server master:9092 --describe --group group01

#Kafka会使⽤下⾯公式计算该group位移保存在__consumer_offsets的哪个分区上
scala:
Math.abs("perf-consumer-74133".hashCode)%50

#Producer Consumer API关键参数
properties.put("bootstrap.servers", "localhost:9092"); // kafka 集群broker地址情况
 properties.put("key.serializer",StringDeserializer.class.getName()); // key 反序列化
 properties.put("value.serializer",StringDeserializer.class.getName()); // value 反序列化
 props.put("group.id", "my.group.201");// 消费者组,默认值为"",如果为"",会抛错
 
#使⽤config/consumer.properties,需要参数指定 ,可在该配置⽂件中的配置常⽤属性,如group.id。也可以
不使⽤该配置⽂件
kafka-console-consumer.sh --bootstrap-server master:9092 --topic test --
consumer.config ../config/consumer.properties
相应的--producer.config ...
comsumer重置offset的策略
earliest:重置offset为最⼩的未被消费的offset 
latest:重置offset为最新的offset 
none:没有offset时直接抛出异常
consumer.poll(timeout)中timeout是控制客户端如果有数据则返回数据,否则客户端阻塞timeout时⻓持续消费
数据
max.poll.records : consumer⼀次拿到的最⼤记录
max.poll.interval.ms:consumer两次poll的最⼤间隔( 如果处理线程死掉,则需要max.poll.interval.ms
来检测它, kafka默认是300s)。设置过⾼会使故障检测周期过⻓。


#7.重置kafka offset
./kafka-consumer-groups.sh --bootstrap-server ip:9092 --group groupName --reset-offsets
--to-offset 1000 --topic topicName --execute
kafka-streams-application-reset.sh --zookeeper hadoop01:2181 --bootstrap-server
hadoop01:9092 --application-id xxx --input-topics xxx

#8.查看组对所有主主题的offset
/opt/kafka_2.11-2.3.0/bin/kafka-consumer-groups.sh --bootstrap-server hadoop01:9092 --
group grpUsers --offsets --describe

#9.打印主题key
kafka-console-consumer.sh --bootstrap-server sandbox-hdp.hortonworks.com:6667 --
topic train --from-beginning --property print.key=true
会把key打印出来。
kafka-console-consumer.sh --bootstrap-server sandbox-hdp.hortonworks.com:6667 --
topic train --from-beginning --property print.key=false
只打印值。

#10、查看consumer组内消费的offset (0.9后不再⽀持kafka.tools.ConsumerOffsetChecker)
./kafka-run-class.sh kafka.tools.ConsumerOffsetChecker --zookeeper localhost:2181 --
group test --topic testKJ1

#11.查看主题offset
/opt/kafka_2.11-2.3.0/bin/kafka-run-class.sh kafka.tools.GetOffsetShell --broker-list
hadoop01:9092 --topic test-0903

test:0:1522
test:1:1020
test:2:1258
其中:test:0:1522 #表示分区0 共1522记录

#12.查看index log⽂件
kafka-run-class.sh kafka.tools.DumpLogSegments --files /tmp/kafka-logs/test0/00000000000000000000.index
kafka-run-class.sh kafka.tools.DumpLogSegments --files /tmp/kafka-logs/test0/00000000000001051625.log --print-data-log
--print-data-log可以打印消息内容

#13.监控各个 topic-partition 在 disk 上的占⽤空间情况
 kafka-log-dirs.sh --bootstrap-server master:9092 --describe --broker-list 0
Querying brokers for log directories information
Received log directory information from brokers 0
{"version":1,"brokers":[{"broker":0,"logDirs":[{"logDir":"/tmp/kafkalogs","error":null,"partitions":[{"partition":"test1112-
0","size":0,"offsetLag":0,"isFuture":false},{"partition":"__consumer_offsets13","size":549,"offsetLag":0,"isFuture":false},{"partition":"__consumer_offsets46","size":0,"offsetLag":0,"isFuture":false},{"partition":"__consumer_offsets9","size":0,"offsetLag":0,"isFuture":false},{"partition":"__consumer_offsets42","size":552,"offsetLag":0,"isFuture":false},{"partition":"test_p2r1-
1","size":138,"offsetLag":0,"isFuture":false},....


#14 写压测
kafka-producer-perf-test.sh

四、kafka编程的api操作

首先、pom.xml中导入依赖

<!--kafka-->
<dependency>
	<groupId>org.apache.kafka</groupId>
    <artifactId>kafka_2.11</artifactId>
    <version>2.3.0</version>
</dependency>

入门案例如下:

4.1、Producer API

既可以java代码实现、也可以scala代码实现

此处用的是java代码(为了怕忘),scala可自己实现

注意:运行Producer API时候 需要提前开启kafka服务

Producer API中
最重要的两个类是 KafkaProducer 和 ProducerRecord

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sznFBBme-1630938851078)(C:\Users\等待\AppData\Roaming\Typora\typora-user-images\1624442330743.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-40js7x2a-1630938851080)(C:\Users\等待\AppData\Roaming\Typora\typora-user-images\1624445922214.png)]

ProducerConfig.BOOTSTRAP_SERVERS_CONFIG 的值 可以点进去 会提示的

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tt5NMOMt-1630938851084)(C:\Users\等待\AppData\Roaming\Typora\typora-user-images\1624447313947.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AT6hJldD-1630938851085)(C:\Users\等待\AppData\Roaming\Typora\typora-user-images\1624446856239.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9hE174Ju-1630938851087)(C:\Users\等待\AppData\Roaming\Typora\typora-user-images\1624446817501.png)]

ProducerConfig.BOOTSTRAP_SERVERS_CONFIG 的值若是不知道,去查看Serializer

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uQ5moroE-1630938851088)(C:\Users\等待\AppData\Roaming\Typora\typora-user-images\1624446681539.png)]

加上序列化后,运行成功

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Eed7z4S1-1630938851090)(C:\Users\等待\AppData\Roaming\Typora\typora-user-images\1624446954253.png)]

验证:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6wAjRoA7-1630938851092)(C:\Users\等待\AppData\Roaming\Typora\typora-user-images\1624447031172.png)]

package kafka_day08;

import org.apache.kafka.clients.producer.KafkaProducer;
import org.apache.kafka.clients.producer.ProducerConfig;
import org.apache.kafka.clients.producer.ProducerRecord;

import java.util.Properties;

/**
 * Producer API
 * 最重要的两个类是 KafkaProducer 和 ProducerRecord
 *
 * 逻辑思路:
 *      逐渐养成尽量倒着写,根据缺少的东西往前找的习惯
 */
public class MyProducer {
    public static void main(String[] args) {
        Properties properties = new Properties();
//        properties.put("bootstrap.servers", "192.168.1.101:9092");
        properties.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, "192.168.1.101:9092");
        properties.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, "org.apache.kafka.common.serialization.StringSerializer");
        properties.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, "org.apache.kafka.common.serialization.StringSerializer");
        //创建生产者
        KafkaProducer<String, String> kafkaProducer = new KafkaProducer<>(properties);
        //主题是和消息绑定,而不是和生产者
        //需要注意的是kafkaProducer 具有自动创建topic的功能
        ProducerRecord producerRecord = new ProducerRecord("spark", null, "hello spark");
        kafkaProducer.send(producerRecord);
        kafkaProducer.flush();
        kafkaProducer.close();
    }
}

如何查看源码中的api呢?步骤如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MGYmLHIa-1630938851093)(C:\Users\等待\AppData\Roaming\Typora\typora-user-images\1624441739167.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OJDUssNs-1630938851095)(C:\Users\等待\AppData\Roaming\Typora\typora-user-images\1624441702808.png)]

然后再去源码包中找到此类

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dZjuS8n4-1630938851097)(C:\Users\等待\AppData\Roaming\Typora\typora-user-images\1624441784815.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AsQzMv4n-1630938851098)(C:\Users\等待\AppData\Roaming\Typora\typora-user-images\1624441811174.png)]

4.2、Consumer API

package kafka_day08;

import org.apache.kafka.clients.consumer.ConsumerConfig;
import org.apache.kafka.clients.consumer.ConsumerRecord;
import org.apache.kafka.clients.consumer.ConsumerRecords;
import org.apache.kafka.clients.consumer.KafkaConsumer;
import org.apache.kafka.clients.producer.ProducerConfig;

import java.util.Collections;
import java.util.Properties;

public class MyConsumer {
    public static void main(String[] args) {
        Properties properties = new Properties();
//        properties.put("bootstrap.servers", "192.168.1.101:9092");
        properties.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, "192.168.1.101:9092");
        properties.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, "org.apache.kafka.common.serialization.StringDeserializer");
        properties.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, "org.apache.kafka.common.serialization.StringDeserializer");

        properties.put("group.id", "group01");
        //当消费组是未知的消费组(之前没有消费过)
        properties.put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, "earliest");

        KafkaConsumer<String, String> kafkaConsumer = new KafkaConsumer<>(properties);

        kafkaConsumer.subscribe(Collections.singleton("spark"));//暂时使用单例的集合
        while(true){
            ConsumerRecords<String, String> consumerRecords = kafkaConsumer.poll(1000);
            for (ConsumerRecord<String, String> consumerRecord : consumerRecords) {
                System.out.println(consumerRecord.key()+", "+consumerRecord.value());
            }
        }
    }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uCMhKdow-1630938851100)(C:\Users\等待\AppData\Roaming\Typora\typora-user-images\1624448962380.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-p4jgAl8E-1630938851101)(C:\Users\等待\AppData\Roaming\Typora\typora-user-images\1624449011062.png)]

五、kafka原理

5.1、kafka与flume的整合

简单介绍:

Flume+Kafka应⽤场景:

1.Kafka可以作为Flume的Source
2.Kafka可以作为Flume的Channel
3.Kafka可以作为Flume的Sink (下面整合示例)

Flume:BTC (batchsize,transactionCapacity,capacity) B<=T<=C

KafkaSink配置:
http://flume.apache.org/releases/content/1.9.0/FlumeUserGuide.html#kafka-sink

flume-kafka-agent.conf

#a1就是flume agent的名称

#命名
a1.sources = r1
a1.sinks = k1
a1.channels = c1

#关联
a1.sources.r1.channels = c1
a1.sinks.k1.channel = c1

# 设置Source类型和属性
a1.sources.r1.type = netcat
a1.sources.r1.bind = 192.168.1.101
a1.sources.r1.port = 6161


# 设置Channel类型和属性 内存会丢失数据的
a1.channels.c1.type = memory
a1.channels.c1.capacity = 1000
a1.channels.c1.transactionCapacity = 100


# 修改sink为kafka
a1.sinks.k1.type = org.apache.flume.sink.kafka.KafkaSink
a1.sinks.k1.kafka.bootstrap.servers = 192.168.1.101:9092
a1.sinks.k1.kafka.topic = flume-kafka
a1.sinks.k1.kafka.producer.acks = 1
a1.sinks.k1.kafka.producer.linger.ms = 1

启动agent:

flume-ng agent -n a1 -c $FLUME_HOME/conf -f $FLUME_HOME/flumeconf/flume-kafka-agent.conf

若不知道命令如何写,如何一步步根据提示写出来?

请看如下步骤:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SBWHGMvm-1630938851103)(C:\Users\等待\AppData\Roaming\Typora\typora-user-images\1624362800436.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Szr07QB1-1630938851104)(C:\Users\等待\AppData\Roaming\Typora\typora-user-images\1624362950247.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-N7tINBgr-1630938851106)(C:\Users\等待\AppData\Roaming\Typora\typora-user-images\1624363002620.png)]

启动flume-kafka-agent后:

先查看下端口是否启动,再使用nc命令连接端口并发送数据

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ncTUZjXQ-1630938851107)(C:\Users\等待\AppData\Roaming\Typora\typora-user-images\1624363462917.png)]

启动kafka:

zookeeper-server-start.sh $KAFKA_HOME/config/zookeeper.properties

kafka-server-start.sh  $KAFKA_HOME/config/server.properties

查看经过flume 是否创建topic:

kafka-topics.sh  --bootstrap-server 192.168.1.101:9092 --list 

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cShd1nyr-1630938851108)(C:\Users\等待\AppData\Roaming\Typora\typora-user-images\1624363763291.png)]

消费者监听读取的数据(也就是接收数据):

注意:Kafka可以后启动,少量数据并不会丢失,flume内部事务可以重试⼀部分数据

kafka-console-consumer.sh --bootstrap-server 192.168.1.101:9092 --topic flume-kafka --from-beginning

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wetAz3Ke-1630938851109)(C:\Users\等待\AppData\Roaming\Typora\typora-user-images\1624363952830.png)]

5.2、kafka的架构之道(重难点)

5.2.1、zookeeper在kafka中的作用

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GlMbHYeG-1630938851110)(C:\Users\等待\AppData\Roaming\Typora\typora-user-images\1624365056144.png)]

5.2.2、kafka相关术语介绍

kafka有两个Leader:(结合上面的图)

1、ControllerLeader: 管理broker上下线
2、PartitionLeader: 通常说的Leader就是这个,就是负责数据的读写的Leader
5.2.4、kafka的文件存储

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-e9p3dKJe-1630938851113)(C:\Users\等待\AppData\Roaming\Typora\typora-user-images\1624365420317.png)]

总之一句话,消费者读取的时候是从Leader中读取,生产者生产的时候是往Leader中生产,一句话读写都在leader,因为Leader主要负责数据的读写。

topic是逻辑上的概念,而partition是物理上的概念

5.2.5、topic中的partition
5.2.5.1、分区分配策略
5.2.5.2、副本分配策略
5.2.5.3、数据分配策略
5.2.6、kafka分区中的segment(重点)

1、segment文件大小限制:

log.segment.bytes=1073741824   大约1G

更多配置参考server.properties
或者参考源码配置类

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QqfFDuK8-1630938851114)(C:\Users\等待\AppData\Roaming\Typora\typora-user-images\1624367731874.png)]

2、segment的组成

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7xaoi04j-1630938851115)(C:\Users\等待\AppData\Roaming\Typora\typora-user-images\1624365690957.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QvzAskgP-1630938851118)(C:\Users\等待\AppData\Roaming\Typora\typora-user-images\1624365764859.png)]

一个topic就是不同的partition,partition中有log文件,log文件分多个segment,segment中包含.log文件和.index文件

在kafka实际的底层中存储数据真正是.log文件(存储数据的)和.index文件(索引,定位位置的)
5.2.7、kafka的log

1、kafka的log文件包括:

1、 .index:索引
2、 .log:数据文件

注意:
	文件名前缀是相同的,一个log对应一个index文件,另外,.index文件大小是.log文件的10%
	.index文件初始大小为10MB,.log文件大小是1GB,则.index默认是100MB

2、kafka的存储空间是怎么算的呢?

假如一条消息1KB、一天生产消息1亿

kafka存储空间:
	1KB*1亿 = 100,000,000KB = 100GB
	考虑到索引文件:100*11% = 110GB
	考虑到副本数量:110GB*2 = 220GB
	考虑压缩比:220GB%75% = 165GB
	存储三个月的数据:(算100天) 165GB*100=16500GB

kafka需要多少节点呢?尽量多少节点就多少分区

考虑分区的数量:其实受限于流量峰值
	如果峰值是 100万/次,kafka吞吐:10~100w
		若吞吐取10万 则取10个分区

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AMWMZrOc-1630938851119)(C:\Users\等待\AppData\Roaming\Typora\typora-user-images\1624365690957.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1qwtpJcp-1630938851120)(C:\Users\等待\AppData\Roaming\Typora\typora-user-images\1624365764859.png)]

5.2.8、kafka的ACK机制

首先ack的值为 0、1、-1

1、当ack=0时,producer不需要cluster的确认即表示发送成功(发送一次 不论leader是否接收)
2、当ack=1时,producer需要Leader分区确认才算成功(等待leader接收成功即可)
3、当ack=-1时,producer需要所有分区副本确认才算成功(需等待leader将消息同步给follower)

注意不论ack如何取值,数据重复和丢失的问题都是客观存在

可能会发生的故障:

1、ack=0时,数据丢失情形

正常:producer向leader发送数据,无论leader收没收到消息,都会认为写入成功了。
故障:producer向leader发送数据,无论leader收没收到消息,但发送的过程中leader挂了,producer却认为leader确认消息了,此时数据丢失了

2、ack =1时,数据丢失情形

正常:producer向leader发送数据,会等待leader的ack,partition的leader将数据落地磁盘后,就发送ack,producer就认为成功了,不会管其他follower有没有同步这条消息。

故障:落地磁盘后,若是在follower同步之前,leader宕机了,就会导致数据丢失

3、ack=-1时,数据重复情形

正常解释:producer向leader发送数据,会等待leader的ack,leader将数据落地磁盘后,等待ISR中的所有副本(follower)同步完成后,此时leader会向producer发送ack告知producer写入成功了。

故障:既会发生数据重复(producer向leader发送数据,leader收到数据并落地磁盘后,等待所有的follower同步完成后,在发送ack的一瞬间leader挂了,producer没有收到ack,会重新发送数据,则会造成数据重复),也是会发生数据丢失(只有一个副本的时候,也就是只有一个leader的时候)(还有一种情况,假如两个follower 一个leader,follower同步过程中 其中一个被踢出ISR,在向producer发送ack后,producer发送新的消息时 leader 和follower都挂掉了,此时被踢出的follower就会复活,这时数据丢失了--这时的情形极少出现)

5.2.9、kafka读写原理

无论是producer还是consumer都有重复和丢失问题。

1、kafkaProducer(ACK)

不论ack如何取值,数据重复和丢失的问题都是客观存在

会使用ISR(副本同步列表)

a) 为什么会使用ISR?

当ack=-1时,producer向leader发送数据,leader收到数据后,所有follower都开始同步数据,但有⼀个follower,因为
某种故障,迟迟不能与leader进⾏同步,那leader就要⼀直等下去?所以就想到使用ISR了

b)ISR特点:

ReplicaManager(副本管理器)依据replica.lag.time.max.ms(允许副本落后的最大时间)参数决定固定副本是否假如ISR。

只要存在ISR中的副本,肯定是与Leader同步的

c) ISR同步源码解析:ReplicaManager

2、kafkaConsumer

kafka面试题

1、Kafka如何保证数据不丢失? 如何保证不重复?
 答:a) 使用幂等机制保证了不重复实现EOS语义,可以保证数据不重复;
 	b) 保证每个分区至少有一个副本,并且使用ISR,可以保证数据不丢失
 
2、Kafka副本ISR的作⽤?为什么需要ISR?原理是什么?
 答:a) ISR作用是保证ISR中的副本与Leader同步
 	b) 当ack=-1时,producer向Leader发送数据,需要所有分区副本都确认(ack)后才算成功,也就是说Leader等待所有follower同步后才会向producer发送ack,若是follower同步过程中,断掉了,leader就会一直等这个folloer,但又不可能一直等,此时就需要ISR来解决这个问题

3、 Kafka为什么快 ?
 答:a)log文件有.index索引
    b) log文件顺序写入
    c) 可以批量处理
    d) 读取零copy技术
    
4、Kafka的应答机制是什么 ACK不同取值情况下会有哪些⻛险?
5、Kafka如何保持数据的,有没有时间限制 ?retention

kafka可缓存七天

kafka不仅仅是一个消息队列,而且也是大数据领域计算引擎(confluent)

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NgwCJ9Bq-1630938851122)(C:\Users\等待\AppData\Roaming\Typora\typora-user-images\1624243978158.png)]

启动kafka前提是 首先启动zookeeper

;代表注释,与前面的代码要有空格

创建主题topic的时候,要指定分区partitions

副本的数目,不能大于broker的实例个数

分区的数目可以大于broker的实例个数

Isr 副本同步列表

副本的好处就是 提高并发度

from-beginning 从头开始消费

在同一个消费组 里面,共享进度

kafka-topic 具有自动创建主题的功能

eplicaManager(副本管理器)依据replica.lag.time.max.ms(允许副本落后的最大时间)参数决定固定副本是否假如ISR。

只要存在ISR中的副本,肯定是与Leader同步的


c) ISR同步源码解析:ReplicaManager



##### 2、kafkaConsumer







## kafka面试题

1、Kafka如何保证数据不丢失? 如何保证不重复?
答:a) 使用幂等机制保证了不重复实现EOS语义,可以保证数据不重复;
b) 保证每个分区至少有一个副本,并且使用ISR,可以保证数据不丢失

2、Kafka副本ISR的作⽤?为什么需要ISR?原理是什么?
答:a) ISR作用是保证ISR中的副本与Leader同步
b) 当ack=-1时,producer向Leader发送数据,需要所有分区副本都确认(ack)后才算成功,也就是说Leader等待所有follower同步后才会向producer发送ack,若是follower同步过程中,断掉了,leader就会一直等这个folloer,但又不可能一直等,此时就需要ISR来解决这个问题

3、 Kafka为什么快 ?
答:a)log文件有.index索引
b) log文件顺序写入
c) 可以批量处理
d) 读取零copy技术

4、Kafka的应答机制是什么 ACK不同取值情况下会有哪些⻛险?
5、Kafka如何保持数据的,有没有时间限制 ?retention








kafka可缓存七天

kafka不仅仅是一个消息队列,而且也是大数据领域计算引擎(confluent)

[外链图片转存中...(img-NgwCJ9Bq-1630938851122)]



启动kafka前提是 首先启动zookeeper



;代表注释,与前面的代码要有空格

创建主题topic的时候,要指定分区partitions



副本的数目,不能大于broker的实例个数

分区的数目可以大于broker的实例个数

Isr 副本同步列表

副本的好处就是 提高并发度

from-beginning  从头开始消费

在同一个消费组 里面,共享进度

kafka-topic 具有自动创建主题的功能



修改offset 就会修改topic
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值