深入剖析zookeeper原理

深度剖析 ZooKeeper 核心原理 从 0 到 1 深入浅出 ZooKeeper 核心技术:你不仅会掌握 ZooKeeper 核心设计思想,而且还会对其底层源码有深刻认识,更会学习到一些优秀的代码设计。 阅读详情
转

深入剖析zookeeper原理

一.简介

ZooKeeper是一个分布式的,开放源码的分布式应用程序协调服务,是Google的Chubby一个开源的实现,是Hadoop和Hbase的重要组件。它是一个为分布式应用提供一致性服务的软件,提供的功能包括:配置维护、域名服务、分布式同步、组服务等。
ZooKeeper的目标就是封装好复杂易出错的关键服务,将简单易用的接口和性能高效、功能稳定的系统提供给用户。


二.基本概念

2.1角色

角色主要有以下三类:


系统模型:



2.2特性

1.最终一致性:client不论连接到哪个Server,展示给它都是同一个视图,这是zookeeper最重要的性能。

2 .可靠性:具有简单、健壮、良好的性能,如果消息m被到一台服务器接受,那么它将被所有的服务器接受。

3 .实时性:Zookeeper保证客户端将在一个时间间隔范围内获得服务器的更新信息,或者服务器失效的信息。但由于网络延时等原因,Zookeeper不能保证两个客户端能同时得到刚更新的数据,如果需要最新数据,应该在读数据之前调用sync()接口。

4 .等待无关(wait-free):慢的或者失效的client不得干预快速的client的请求,使得每个client都能有效的等待。

5.原子性:更新只能成功或者失败,没有中间状态。

6 .顺序性:包括全局有序和偏序两种:全局有序是指如果在一台服务器上消息a在消息b前发布,则在所有Server上消息a都将在消息b前被发布;偏序是指如果一个消息b在消息a后被同一个发送者发布,a必将排在b前面。


三.工作原理

Zookeeper的核心是原子广播,这个机制保证了各个Server之间的同步。实现这个机制的协议叫做Zab协议。Zab协议有两种模式,它们分别是恢复模式(选主)和广播模式(同步)。当服务启动或者在领导者崩溃后,Zab就进入了恢复模式,当领导者被选举出来,且大多数Server完成了和leader的状态同步以后,恢复模式就结束了。状态同步保证了leader和Server具有相同的系统状态。

为了保证事务的顺序一致性,zookeeper采用了递增的事务id号(zxid)来标识事务。所有的提议(proposal)都在被提出的时候加上了zxid。实现中zxid是一个64位的数字,它高32位是epoch用来标识leader关系是否改变,每次一个leader被选出来,它都会有一个新的epoch,标识当前属于那个leader的统治时期。低32位用于递增计数。

每个Server在工作过程中有三种状态:

LOOKING:当前Server不知道leader是谁,正在搜寻

LEADING:当前Server即为选举出来的leader

FOLLOWING:leader已经选举出来,当前Server与之同步


3.1选主流程

当leader崩溃或者leader失去大多数的follower,这时候zk进入恢复模式,恢复模式需要重新选举出一个新的leader,让所有的Server都恢复到一个正确的状态。Zk的选举算法有两种:一种是基于basic paxos实现的,另外一种是基于fast paxos算法实现的。系统默认的选举算法为fast paxos。先介绍basic paxos流程:

1 .选举线程由当前Server发起选举的线程担任,其主要功能是对投票结果进行统计,并选出推荐的Server;

2 .选举线程首先向所有Server发起一次询问(包括自己);

3 .选举线程收到回复后,验证是否是自己发起的询问(验证zxid是否一致),然后获取对方的id(myid),并存储到当前询问对象列表中,最后获取对方提议的leader相关信息(id,zxid),并将这些信息存储到当次选举的投票记录表中;

4. 收到所有Server回复以后,就计算出zxid最大的那个Server,并将这个Server相关信息设置成下一次要投票的Server;

5. 线程将当前zxid最大的Server设置为当前Server要推荐的Leader,如果此时获胜的Server获得n/2 + 1的Server票数, 设置当前推荐的leader为获胜的Server,将根据获胜的Server相关信息设置自己的状态,否则,继续这个过程,直到leader被选举出来。

通过流程分析我们可以得出:要使Leader获得多数Server的支持,则Server总数必须是奇数2n+1,且存活的Server的数目不得少于n+1.

每个Server启动后都会重复以上流程。在恢复模式下,如果是刚从崩溃状态恢复的或者刚启动的server还会从磁盘快照中恢复数据和会话信息,zk会记录事务日志并定期进行快照,方便在恢复时进行状态恢复。选主的具体流程图如下所示:



fast paxos流程是在选举过程中,某Server首先向所有Server提议自己要成为leader,当其它Server收到提议以后,解决epoch和zxid的冲突,并接受对方的提议,然后向对方发送接受提议完成的消息,重复这个流程,最后一定能选举出Leader。其流程图如下所示:



3.2同步流程

选完leader以后,zk就进入状态同步过程。

1. leader等待server连接;

2 .Follower连接leader,将最大的zxid发送给leader;

3 .Leader根据follower的zxid确定同步点;

4 .完成同步后通知follower 已经成为uptodate状态;

5 .Follower收到uptodate消息后,又可以重新接受client的请求进行服务了。

流程图如下所示:



3.3工作流程

3.3.1leader工作流程
Leader主要有三个功能:

1 .恢复数据;

2 .维持与Learner的心跳,接收Learner请求并判断Learner的请求消息类型;

3 .Learner的消息类型主要有PING消息、REQUEST消息、ACK消息、REVALIDATE消息,根据不同的消息类型,进行不同的处理。

PING消息是指Learner的心跳信息;REQUEST消息是Follower发送的提议信息,包括写请求及同步请求;ACK消息是Follower的对提议的回复,超过半数的Follower通过,则commit该提议;REVALIDATE消息是用来延长SESSION有效时间。
Leader的工作流程简图如下所示,在实际实现中,流程要比下图复杂得多,启动了三个线程来实现功能。


3.3.2Follower工作流程
Follower主要有四个功能:

1. 向Leader发送请求(PING消息、REQUEST消息、ACK消息、REVALIDATE消息);

2 .接收Leader消息并进行处理;

3 .接收Client的请求,如果为写请求,发送给Leader进行投票;

4 .返回Client结果。

Follower的消息循环处理如下几种来自Leader的消息:

1 .PING消息: 心跳消息;

2 .PROPOSAL消息:Leader发起的提案,要求Follower投票;

3 .COMMIT消息:服务器端最新一次提案的信息;

4 .UPTODATE消息:表明同步完成;

5 .REVALIDATE消息:根据Leader的REVALIDATE结果,关闭待revalidate的session还是允许其接受消息;

6 .SYNC消息:返回SYNC结果到客户端,这个消息最初由客户端发起,用来强制得到最新的更新。

Follower的工作流程简图如下所示,在实际实现中,Follower是通过5个线程来实现功能的。

对于observer的流程不再叙述,observer流程和Follower的唯一不同的地方就是observer不会参加leader发起的投票。



四.主流应用场景

4.1配置管理

集中式的配置管理在应用集群中是非常常见的,一般商业公司内部都会实现一套集中的配置管理中心,应对不同的应用集群对于共享各自配置的需求,并且在配置变更时能够通知到集群中的每一个机器。

Zookeeper很容易实现这种集中式的配置管理,比如将APP1的所有配置配置到/APP1 znode下,APP1所有机器一启动就对/APP1这个节点进行监控(zk.exist("/APP1",true)),并且实现回调方法Watcher,那么在zookeeper上/APP1 znode节点下数据发生变化的时候,每个机器都会收到通知,Watcher方法将会被执行,那么应用再取下数据即可(zk.getData("/APP1",false,null));

以上这个例子只是简单的粗颗粒度配置监控,细颗粒度的数据可以进行分层级监控,这一切都是可以设计和控制的


4.2集群管理

应用集群中,我们常常需要让每一个机器知道集群中(或依赖的其他某一个集群)哪些机器是活着的,并且在集群机器因为宕机,网络断链等原因能够不在人工介入的情况下迅速通知到每一个机器。

Zookeeper同样很容易实现这个功能,比如我在zookeeper服务器端有一个znode叫/APP1SERVERS,那么集群中每一个机器启动的时候都去这个节点下创建一个EPHEMERAL类型的节点,比如server1创建/APP1SERVERS/SERVER1(可以使用ip,保证不重复),server2创建/APP1SERVERS/SERVER2,然后SERVER1和SERVER2都watch /APP1SERVERS这个父节点,那么也就是这个父节点下数据或者子节点变化都会通知对该节点进行watch的客户端。因为EPHEMERAL类型节点有一个很重要的特性,就是客户端和服务器端连接断掉或者session过期就会使节点消失,那么在某一个机器挂掉或者断链的时候,其对应的节点就会消失,然后集群中所有对/APP1SERVERS进行watch的客户端都会收到通知,然后取得最新列表即可。

另外有一个应用场景就是集群选master,一旦master挂掉能够马上能从slave中选出一个master,实现步骤和前者一样,只是机器在启动的时候在APP1SERVERS创建的节点类型变为EPHEMERAL_SEQUENTIAL类型,这样每个节点会自动被编号

我们默认规定编号最小的为master,所以当我们对/APP1SERVERS节点做监控的时候,得到服务器列表,只要所有集群机器逻辑认为最小编号节点为master,那么master就被选出,而这个master宕机的时候,相应的znode会消失,然后新的服务器列表就被推送到客户端,然后每个节点逻辑认为最小编号节点为master,这样就做到动态master选举。




五.zookeeper的安装

5.1单机版

第一步:安装jdk
第二步:把zookeeper的压缩包上传到linux系统。
第三步:解压缩压缩包
tar -zxvf zookeeper-3.4.6.tar.gz
第四步:进入zookeeper-3.4.6目录,创建data文件夹。
第五步:把zoo_sample.cfg改名为zoo.cfg
[root@localhost conf]# mv zoo_sample.cfg zoo.cfg
第六步:修改data属性:dataDir=/root/zookeeper-3.4.6/data
第七步:启动zookeeper
[root@localhost bin]# ./zkServer.sh start
关闭:[root@localhost bin]# ./zkServer.sh stop
查看状态:[root@localhost bin]# ./zkServer.sh status

注意:需要关闭防火墙。

5.2集群版

第一步:需要安装jdk环境。
第二步:把zookeeper的压缩包上传到服务器。
第三步:解压缩。
第四步:把zookeeper复制三份。
[root@localhost ~]# mkdir /usr/local/solr-cloud
[root@localhost ~]# cp -r zookeeper-3.4.6 /usr/local/solr-cloud/zookeeper01
[root@localhost ~]# cp -r zookeeper-3.4.6 /usr/local/solr-cloud/zookeeper02
[root@localhost ~]# cp -r zookeeper-3.4.6 /usr/local/solr-cloud/zookeeper03
第五步:在每个zookeeper目录下创建一个data目录。
第六步:在data目录下创建一个myid文件,文件名就叫做“myid”。内容就是每个实例的id。例如1、2、3
[root@localhost data]# echo 1 >> myid
[root@localhost data]# ll
total 4
-rw-r--r--. 1 root root 2 Apr  7 18:23 myid
[root@localhost data]# cat myid 
1
第七步:修改配置文件。把conf目录下的zoo_sample.cfg文件改名为zoo.cfg

server.1=192.168.25.154:2881:3881
server.2=192.168.25.154:2882:3882
server.3=192.168.25.154:2883:3883


  
  1. 第八步:启动每个zookeeper实例。
  2. 启动bin/zkServer.sh start
  3. 查看zookeeper的状态:
  4. bin/zkServer.sh status


六.作为dubbo的注册中心

spring.xml配置中加入dubbo约束并且使用zookeeper注册中心暴露服务地址

  
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans"
  3. xmlns:xsi= "http://www.w3.org/2001/XMLSchema-instance" xmlns:dubbo= "http://code.alibabatech.com/schema/dubbo"
  4. xsi:schemaLocation= "http://www.springframework.org/schema/beans
  5. http://www.springframework.org/schema/beans/spring-beans.xsd
  6. http://code.alibabatech.com/schema/dubbo
  7. http://code.alibabatech.com/schema/dubbo/dubbo.xsd
  8. ">
  9. <!-- 具体的实现bean -->
  10. <bean id="demoService" class="com.unj.dubbotest.provider.impl.DemoServiceImpl" />
  11. <!-- 提供方应用信息,用于计算依赖关系 -->
  12. <dubbo:application name="xs_provider" />
  13. <!-- 使用multicast广播注册中心暴露服务地址 -->
  14. <!--<dubbo:registry address="multicast://224.5.6.7:1234" /> -->
  15. <!-- 使用zookeeper注册中心暴露服务地址 --即zookeeper的所在服务器ip地址和端口号 -->
  16. <dubbo:registry address="zookeeper://192.168.24.213:2181" />
  17. <!-- 用dubbo协议在20880端口暴露服务 -->
  18. <dubbo:protocol name="dubbo" port="20880" />
  19. <!-- 声明需要暴露的服务接口 -->
  20. <dubbo:service interface="com.unj.dubbotest.provider.DemoService"
  21. ref= "demoService" />
  22. </beans>


大数据领域中Zookeeper的核心原理深度剖析 在大数据技术栈中,分布式系统面临节点故障、状态同步、资源竞争等复杂协调问题。Zookeeper作为Hadoop、Kafka、HBase等核心组件的底层协调引擎,其设计原理直接影响整个集群的稳定性。本文聚焦Zookeeper的核心技术架构,包括数据模型设计、集群管理机制、一致性协议实现等,结合具体代码示例和数学分析,揭示其底层工作原理。背景知识体系构建核心概念与架构解析算法原理与协议实现数学模型与一致性分析实战案例与生态整合未来趋势与挑战分析ZNode。 阅读详情

相关推荐

YOLOv8工业级增强实战:小目标检测与HDR鲁棒性优化

YOLO(You Only Look Once)作为主流实时目标检测框架,其核心价值在于模块化架构与工程可扩展性。理解YOLOv8的Anchor-Free设计、C2f特征融合机制及Detect头部解耦原理,是实现性能突破的基础。在工业落地中,真实瓶颈往往不是模型版本迭代,而是小目标漏检、高动态范围(HDR)场景适应差、密集遮挡ID断裂等具体问题。通过配置层动态多尺度训练、物理感知数据增强、Neck跨尺度注意力注入、质量感知损失函数升级等七层增强策略,可在不更换主干的前提下显著提升mAP与边缘设备推理效率。本

weixin_32667439的博客 259

数据结构--知识点16--搜索算法(二叉树)

文章目录一、树的概念1、特点2、树的术语3、树的种类4、树的存储与表示5、常见的树的应用场景二、二叉树1、概念2、性质 一、树的概念 树是一种抽象数据类型(ADT)或是视作这种抽象数据类型的数据结构 1、特点 每个节点有零个或多个子节点 没有父节点的节点称为根节点 每一个非根节点有且只有一个父节点 除了根节点外,每个子节点可以分为**多个不相交(因为都只有一个父节点)**的子树 2、树的术语 节点的度:一个节点含有的子树的个数称为该节点的度 树的度:一棵树中,最大的节点的度称为树的度 叶节点或终端节点

ANingL的博客 3543

统信UOS安装CH384串口卡驱动

本文讲解如何在统信UOS系统下安装CH384 PCIE多串口驱动安装过程,CPU为飞腾D2000。其他Linux内核系统安装亦可参照类似方法。

shjhuang的专栏 1884

zeekooper集群搭建_zookeeper的集群搭建

1.介绍使用集群的方式避免单点故障时目前分布式应用实现高可用的重要手段,ZooKeeper同样可以搭建集群环境。2.说明1)服务器名称与地址:集群信息(服务器编号,服务器地址,LF通信端口,选举端口);配置项的格式为:server.N=IP:A:BN:服务器编号IP:服务器的IP地址A:LF通信端口,用来和leader交换信息B:leader挂掉后选举新leader的端口注:一般来说,集群中每个服...

weixin_30521175的博客 475

脑机接口(BCI)从原理到开发实战 07|运动想象BCI实战:基于BCI Competition IV 2a数据集

本文基于BCI Competition IV 2a数据集,详细介绍运动想象脑机接口系统的全流程实现。首先概述了该数据集的实验范式、参数特点和优势,然后指导环境准备与数据下载。通过代码示例展示了数据加载、事件标记提取和信号可视化方法。重点构建了完整的预处理流水线,包括通道选择、重参考、带通滤波(8-30Hz)和ICA去伪迹等关键步骤。文章旨在帮助读者将零散的BCI知识整合为完整的实战项目,掌握从原始脑电数据到运动意图解码的核心技术。

小明的博客 849

Jenkins测试详细使用教程(二):jenkins两种主要构建方法

Jenkins有两种定义构建作业的主要方法:(自由风格项目)和Pipeline(流水线项目)。

m0_62825058的博客 2434

Kafka快速入门

在当今信息爆炸的时代,实时数据处理已经成为许多应用程序和系统不可或缺的一部分。Apache Kafka作为一个高吞吐量、低延迟的分布式消息队列系统,广泛应用于构建实时数据管道、流式处理应用等场景。无论是大数据分析、日志收集、监控告警还是在线机器学习模型等,Kafka都发挥着重要的作用。本快速入门指南将带您进入Kafka的世界,探索其核心概念和基本操作。我们将从安装和配置开始,逐步介绍如何创建生产者和消费者,以及如何使用topic进行消息传递。

热爱编程、热爱生活、热爱探索 1559

华为昇腾Atlas 200I DK A2实战:从开箱到运行首个AI应用

本文详细介绍了华为昇腾Atlas 200I DK A2开发板从开箱到运行首个AI应用的全过程。包括硬件准备、系统烧录、开发板连接方案、AI应用运行及性能优化技巧,帮助开发者快速上手部署AI项目,提升开发效率。

weixin_27038245的博客 591

4台服务器集群搭建_How to do - ZooKeeper集群搭建(我见过最详细的完整教学)

ZooKeeper集群介绍最典型集群模式: Master/Slave 模式(主备模式)。在这种模式中,通常 Master服务器作为主服务器提供写服务,其他的 Slave 服务器从服务器通过异步复制的方式获取 Master 服务器最新的数据提供读服务。但是,在 ZooKeeper 中没有选择传统的 Master/Slave 概念,而是引入了Leader、Follower 和 Observer 三种角...

weixin_39936380的博客 547

从ORCAP-1589警告看Cadence ORCAD的DRC设置:如何避免‘网络别名’引发的潜在短路风险

本文深入解析Cadence ORCAD中ORCAP-1589警告的深层含义,探讨网络别名可能引发的短路风险及DRC设置优化方案。通过分析网络别名的设计意图、DRC规则配置及最佳实践,帮助工程师有效规避设计风险,提升电路设计的可靠性和规范性。

weixin_34194829的博客 297

【电源专题】案例:对比不同电池在不同电流下的电池放电曲线

无

一点硬件 2840

Zookeeper的数据模型是怎样的,它是如何存储数据的?

Zookeeper的数据模型是一个层次化的文件系统结构,其中数据被组织成一棵树形结构。每个节点被称为一个Znode(Zookeeper Node),Znode可以存储少量的数据(最多1MB),并且可以拥有子节点。

qq_33240556的博客 619

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

Zookeeper原理与核心深入剖析

尽管拜占庭的“幽灵”很难处理,但在实际工作应用中, 却并不需要过分去考虑它,因为对于大多数系统来说,内部环境里,硬件故障导致消息错误的概率本身就很低,还要按照拜占庭叛徒的策略来处理故障就更为困难了。3.如果N大于该Acceptor已经响应过的所有请求的编号,那么它就会将它已经接受过(已经经 过第二阶段accept的提案)的编号最大的提案作为响应反馈给Proposer,如果还没有的accept提案的话返回{pok,null,null}空信息,同时该Acceptor承诺不再接受任何编号小于N的提案。

秃了也弱了 2723

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

华为的C语言编程规范.pdf

华为技术有限公司内部技术规范。本规范制定了编写C语言程序的基本原则、规则和建议。从代码的清晰、简洁、可测试、安全、程序效率、可移植各个方面对C语言编程作出了具体指导。

03 ZooKeeper底层原理剖析与命令实战

ZooKeeper底层原理剖析与命令实战

柳杰的博客 3326

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

ZooKeeper原理剖析

ZooKeeper是一个分布式、高可用性的协调服务。帮助系统避免单点故障,建立可靠的应用程序。提供分布式协作服务和维护配置信息。

hello.reader 4万+

HoRain云--Zookeeper watcher 事件机制原理剖析

本文以Zookeeper的Watcher机制为例,详细解析了客户端与服务端交互的四个关键过程:1)客户端注册Watcher监听;2)服务端处理Watcher请求;3)服务端触发节点变更事件;4)客户端回调处理事件。通过Java代码实例演示了exists方法实现Watcher监听的完整流程,并配合流程图解说明底层TCP长连接的通信机制。文章还介绍了作者的技术专栏内容,涵盖C语言、网络协议、Docker等多个技术领域,旨在用通俗易懂的方式分享底层技术原理。全文采用理论讲解与代码实践相结合的方式,适合想深入理解Z

2401_86544677的博客 641

深入剖析Zookeeper原理(二)ZK集群选举原理

1. PAXOS选举算法 Paxos算法概述 背景: 主流分布式一致性算法包括Paxos,Raft和ZAB,它们之间有怎样的区别与关系? Google Chubby的作者Mike Burrows说过,世上只有一种一致性算法,那就是Paxos,所有其他一致性算法都是Paxos算法的不完整或衍生版。 什么是Paxos? Paxos算法是基于消息传递且具有高度容错特性的一致性算法,是目前公认的解决分布式一致性问题最有效的算法之一,其解决的问题就是在分布式系统中如何就某个值(决议)达成一致。 Paxos的作用:

Mirson - 多一些分享, 多一些进步 3万+

深入剖析Zookeeper原理(五)ZK核心源码剖析

1. ZK选举算法代码实现剖析 ZK内部有三种选举算法,分别是LeaderElection,FastLeaderElection和AuthLeaderElection,FastLeaderElection和AuthLeaderElection是类似的选举算法,唯一区别是后者加入了认证信息,但AuthLeaderElection已被ZK弃用, FastLeaderElection比LeaderElection更高效,LeaderElection在3.4.0之后的版本中已经不建议使用,后续的版本只保留Fast

Mirson - 多一些分享, 多一些进步 3万+

Zookeeper watcher 事件机制原理剖析

其中客户端注册 watcher 有三种方式,调用客户端 API 可以分别通过 getData、exists、getChildren 实现,利用前面章节创建的 maven 工程,新建 WatcherDemo 类,以 exists 方法举例说明其原理。

1152

深入剖析Zookeeper原理整体设计

1. ZK集群架构设计与特性 1. ZK集群架构设计: ZK主要分为三种角色: Leader(领导者):一个Zookeeper集群同一时间只会有一个实际工作的Leader,它会发起并维护与各Follwer及Observer间的心跳。所有的写操作必须要通过Leader完成再由Leader将写操作广播给其它服务器。 Follower(跟随者):一个Zookeeper集群可能同时存在多个Follower,它会响应Leader的心跳。Follower可以处理客户端的读请求,但写请求转发给Leader处理

希爷的博客 196

深入剖析Zookeeper原理(一)整体设计

1. ZK集群架构设计与特性 1. ZK集群架构设计: ZK主要分为三种角色: 演示查看ZK的角色状态, 命令: bin/zkServer.sh status 角色的主要职责与作用? Leader(领导者):一个Zookeeper集群同一时间只会有一个实际工作的Leader,它会发起并维护与各Follwer及Observer间的心跳。所有的写操作必须要通过Leader完成再由Leader将写操作广播给其它服务器。 Follower(跟随者):一个Zookeeper集群可能同时存在多个Follow

Mirson - 多一些分享, 多一些进步 3万+
上一篇: yarn执行流程图
下一篇: hive分桶之BUCKET详解
Alwaysdazz
博客等级 码龄8年 24粉丝 140原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值