Zookeeper架构与原理

ZooKeeper基础架构和原理详解 摘要 Apache ZooKeeper是一个开源的分布式协调服务,提供配置管理、命名服务和分布式锁等核心功能。本文解析了ZooKeeper的基础架构与工作原理,包括其层次化的ZNode数据模型(持久节点、临时节点、顺序节点)、会话管理和Watch机制。ZooKeeper采用主从架构,通过ZAB协议保证分布式事务一致性,包含崩溃恢复和消息广播两个阶段。文章还展示了Java客户端操作示例,涵盖连接创建、节点操作及分布式锁实现,为开发者提供了实用的分布式协调解决方案。 阅读详情

Zookeeper的特点:

  • 最终一致性:为客户端展示同一视图,这是zookeeper最重要的功能。
  • 可靠性:如果消息被到一台服务器接受,那么它将被所有的服务器接受。
  • **非实时性:**Zookeeper不能保证两个客户端能同时得到刚更新的数据,如果需要最新数据,应该在读数据之前调用sync()接口。
  • 等待无关(wait-free):慢的或者失效的client不干预快速的client的请求。
  • 原子性:更新只能成功或者失败,没有中间状态。
  • 顺序性:所有Server,同一消息发布顺序一致。

1. 安装与配置

Linux 下的启动脚本是 zkServer.sh;Zookeeper 的配置文件在 conf 目录下,这个目录下有 zoo_sample.cfg 和 log4j.properties,你需要做的就是将 zoo_sample.cfg 改名为 zoo.cfg:

tickTime=2000 
dataDir=D:/devtools/zookeeper-3.2.2/build 
clientPort=2181
  • tickTime:这个时间是作为 Zookeeper 服务器之间或客户端与服务器之间维持心跳的时间间隔,也就是每个 tickTime 时间就会发送一个心跳。
  • dataDir:顾名思义就是 Zookeeper 保存数据的目录,默认情况下,Zookeeper 将写数据的日志文件也保存在这个目录里。
  • clientPort:这个端口就是客户端连接 Zookeeper 服务器的端口,Zookeeper 会监听这个端口,接受客户端的访问请求。

1.1 集群模式

zoo.cfg:

initLimit=5 
syncLimit=2 
server.1=192.168.211.1:2888:3888 
server.2=192.168.211.2:2888:3888
  • initLimit:Follower初始连接到Leader时能忍受的最长心跳间隔数(initLimit * tickTime);
  • syncLimit: Leader 与 Follower 之间发送消息,请求和应答的最长时延(syncLimit * tickTime);
  • server.A=B:C:D:
    • 其中 A 是一个数字,表示这个是第几号服务器;
    • B 是这个服务器的 ip 地址;
    • C 与Leader 交换信息的端口;
    • D 选举通信的端口;

2. 基本架构

这里写图片描述

这里写图片描述

2.1 数据同步

整个集群完成Leader选举后,Learner会向Leader进行注册,当Learner向Leader完成注册后,就进入数据同步环节,同步过程就是Leader将那些没有在Learner服务器上提交过的事务请求同步给Learner服务器,大体过程如下:

这里写图片描述

对于集群数据同步而言,通常分为四类,直接差异化同步(DIFF同步)、先回滚再差异化同步(TRUNC+DIFF同步)、仅回滚同步(TRUNC同步)、全量同步(SNAP同步),在初始化阶段,Leader会优先以全量同步方式来同步数据。同时,会根据Leader和Learner之间的数据差异情况来决定最终的数据同步方式。

2.2 数据一致性

ZooKeeper通过复制来实现高可用性,只要集合体中半数以上的机器处于可用状态,它就能够提供服务。例如,在一个有5个节点的集合体中,每个Follower节点的数据都是Leader节点数据的副本,也就是说我们的每个节点的数据视图都是一样的,这样就可以有五个节点提供ZooKeeper服务。并且集合体中任意2台机器出现故障,都可以保证服务继续,因为剩下的3台机器超过了半数。

从概念上来说,ZooKeeper它所做的就是确保对Znode树的每一个修改都会被复制到集合体中超过半数的机器上,客户端可以连接任意ZooKeeper服务节点来读写数据。如果少于半数的机器出现故障,则最少有一台机器会保存最新的状态,那么这台机器就是我们的Leader。其余的副本最终也会更新到这个状态。如果 Leader挂了,由于其他机器保存了Leader的副本,那就可以从中选出一台机器作为新的Leader继续提供服务。

Zookeeper使用简单的同步策略,通过以下两条基本保证来实现数据的一致性:

① 全局串行化所有的写操作;

② 保证同一客户端的指令被FIFO执行(以及消息通知的FIFO);

所有的读请求由Zk Server 本地响应,所有的更新请求将转发给Leader,由Leader实施。

2.3 ZooKeeper写流程

这里写图片描述

  1. 客户端首先和一个Server或者Observe(可以认为是一个Server的代理)通信,发起写请求;
  2. 然后Server将写请求转发给Leader;
  3. Leader再将写请求转发给其他Server;
  4. Server在接收到写请求后写入数据并响应Leader;
  5. Leader在接收到大多数写成功回应后,认为数据写成功,响应Server;
  6. 由当初提交写请求的Server响应Client。

3. 常用接口列表

客户端要连接 Zookeeper 服务器可以通过创建 org.apache.zookeeper. ZooKeeper 的一个实例对象,然后调用这个类提供的接口来和服务器交互。

3.1 接口

(1)String create(String path, byte[] data, List acl, CreateMode createMode)

创建一个给定的目录节点 path, 并给它设置数据,CreateMode 标识有四种形式的目录节点,分别是:

  • PERSISTENT:持久化目录节点,这个目录节点存储的数据不会丢失;
  • PERSISTENT_SEQUENTIAL:顺序自动编号的目录节点,这种目录节点会根据当前已近存在的节点数自动加 1,然后返回给客户端已经成功创建的目录节点名;
  • EPHEMERAL:临时目录节点,一旦创建这个节点的客户端与服务器端口也就是 session 超时,这种节点会被自动删除;
  • EPHEMERAL_SEQUENTIAL:临时自动编号节点。

(2)void delete(String path, int version)

删除 path 对应的目录节点,version 为 -1 可以匹配任何版本,也就删除了这个目录节点所有数据。

(3)List getChildren(String path, boolean watch)

获取指定 path 下的所有子目录节点,同样 getChildren方法也有一个重载方法可以设置特定的 watcher 监控子节点的状态。

(4)Stat exists(String path, boolean watch)

判断某个 path 是否存在,并设置是否监控这个目录节点,这里的 watcher 是在创建 ZooKeeper 实例时指定的 watcher,exists方法还有一个重载方法,可以指定特定的 watcher:

Statexists(String path, Watcher watcher)

(5)Stat setData(String path, byte[] data, int version)

给 path 设置数据,可以指定这个数据的版本号,如果 version 为 -1 怎可以匹配任何版本。

(6)byte[] getData(String path, boolean watch, Stat stat)

获取这个 path 对应的目录节点存储的数据,数据的版本等信息可以通过 stat 来指定,同时还可以设置是否监控这个目录节点数据的状态。

(7)Stat setACL(String path, List acl, int version)

给某个目录节点重新设置访问权限,需要注意的是 Zookeeper 中的目录节点权限不具有传递性,父目录节点的权限不能传递给子目录节点。目录节点 ACL 由两部分组成:perms 和 id。
Perms 有 ALL、READ、WRITE、CREATE、DELETE、ADMIN 几种
而 id 标识了访问目录节点的身份列表,默认情况下有以下两种:
ANYONE_ID_UNSAFE = new Id(“world”, “anyone”) 和 AUTH_IDS = new Id(“auth”, “”) 分别表示任何人都可以访问和创建者拥有访问权限。

3.2 基本操作演示

// 创建一个与服务器的连接
ZooKeeper zk = new ZooKeeper("localhost:" + CLIENT_PORT, 
       ClientBase.CONNECTION_TIMEOUT, new Watcher() { 
           // 监控所有被触发的事件
           public void process(WatchedEvent event) { 
               System.out.println("已经触发了" + event.getType() + "事件!"); 
           } 
       }); 

// 创建一个目录节点
zk.create("/testRootPath", "testRootData".getBytes(), Ids.OPEN_ACL_UNSAFE,
  CreateMode.PERSISTENT); 

// 创建一个子目录节点
zk.create("/testRootPath/testChildPathOne", "testChildDataOne".getBytes(),
  Ids.OPEN_ACL_UNSAFE,CreateMode.PERSISTENT); 
System.out.println(new String(zk.getData("/testRootPath",false,null))); 

// 取出子目录节点列表
System.out.println(zk.getChildren("/testRootPath",true)); 

// 修改子目录节点数据
zk.setData("/testRootPath/testChildPathOne","modifyChildDataOne".getBytes(),-1); 
System.out.println("目录节点状态:["+zk.exists("/testRootPath",true)+"]"); 

// 创建另外一个子目录节点
zk.create("/testRootPath/testChildPathTwo", "testChildDataTwo".getBytes(), 
  Ids.OPEN_ACL_UNSAFE,CreateMode.PERSISTENT); 
System.out.println(new String(zk.getData("/testRootPath/testChildPathTwo",true,null))); 

// 删除子目录节点
zk.delete("/testRootPath/testChildPathTwo",-1); 
zk.delete("/testRootPath/testChildPathOne",-1); 

// 删除父目录节点
zk.delete("/testRootPath",-1); 

// 关闭连接
zk.close();

4. 应用场景

4.1 监控服务器状态

EPHEMERAL节点 + getChildren操作

它们的实现方式都是在 Zookeeper 上创建一个 EPHEMERAL 类型的目录节点,然后每个 Server 在它们创建目录节点的父目录节点上调用 getChildren(String path, boolean watch) 方法并设置 watch 为 true,由于是 EPHEMERAL 目录节点,当创建它的 Server 死去,这个目录节点也随之被删除,所以 Children 将会变化,这时 getChildren上的 Watch 将会被调用,所以其它 Server 就知道已经有某台 Server 死去了。新增 Server 也是同样的原理。


4.2 Leader选举

EPHEMERAL_SEQUENTIAL节点,选最小编号的节点作为Leader/Master

每台 Server 创建一个 EPHEMERAL_SEQUENTIAL 目录节点,选择当前是最小编号的 Server 为 Master。

假如这个最小编号的 Server 死去,由于是 EPHEMERAL 节点,死去的 Server 对应的节点也被删除,所以当前的节点列表中又出现一个最小编号的节点,我们就选择这个节点为当前 Master。

这样就实现了动态选择 Master,避免了传统意义上单 Master 容易出现单点故障的问题。


4.3 分布式锁

需要获得锁的 Server 创建一个 EPHEMERAL_SEQUENTIAL 目录节点,然后调用 getChildren方法获取当前的目录节点列表中最小的目录节点是不是就是自己创建的目录节点,如果正是自己创建的,那么它就获得了这个锁,如果不是那么它就调用 exists(String path, boolean watch) 方法并监控 Zookeeper 上目录节点列表的变化,一直到自己创建的节点是列表中最小编号的目录节点,从而获得锁,释放锁很简单,只要删除前面它自己所创建的目录节点就行了。


4.4 分布式FIFO队列

实现的思路也非常简单,就是在特定的目录下创建 SEQUENTIAL 类型的子目录 /queue_i,这样就能保证所有成员加入队列时都是有编号的,出队列时通过 getChildren( ) 方法可以返回当前所有的队列中的元素,然后消费其中最小的一个,这样就能保证 FIFO。

生产者代码:

boolean produce(int i) throws KeeperException, InterruptedException{ 
       ByteBuffer b = ByteBuffer.allocate(4); 
       byte[] value; 
       b.putInt(i); 
       value = b.array(); 
       zk.create(root + "/element", value, ZooDefs.Ids.OPEN_ACL_UNSAFE, 
                   CreateMode.PERSISTENT_SEQUENTIAL); 
       return true; 
   }

消费者代码:

int consume() throws KeeperException, InterruptedException{ 
       int retvalue = -1; 
       Stat stat = null; 
       while (true) { 
           synchronized (mutex) { 
               List<String> list = zk.getChildren(root, true); 
               if (list.size() == 0) { 
                   mutex.wait(); 
               } else { 
                   Integer min = new Integer(list.get(0).substring(7)); 
                   for(String s : list){ 
                       Integer tempValue = new Integer(s.substring(7)); 
                       if(tempValue < min) min = tempValue; 
                   } 
                   byte[] b = zk.getData(root + "/element" + min,false, stat); 
                   zk.delete(root + "/element" + min, 0); 
                   ByteBuffer buffer = ByteBuffer.wrap(b); 
                   retvalue = buffer.getInt(); 
                   return retvalue; 
               } 
           } 
       } 
}

从零实现高精度手势检测:OpenCV+MediaPipe模型移植实战(2)(附c++完整代码) 上篇已经介绍了手掌检测的方法。本章将在手掌检测的基础上,完成手指关节的检测。 阅读详情

相关推荐

从二极管到CMOS:手把手教你搭建数字电路中的基础门电路(附原理图)

本文详细介绍了数字电路中基础门电路的搭建方法,从二极管门电路到现代CMOS门电路的设计与实现。通过原理图解析和实战案例,帮助读者掌握数字电路设计的核心知识,包括电平实现、门电路工作原理及实际调试技巧,适合电子技术爱好者和初学者学习参考。

weixin_29252171的博客 321

Zookeeper原理梳理

一,Zookeeper是什么 Zookeeper是一个高性能、高可用的分布式协调服务,提供数据的最终一致性保证。 高性能: 简单的数据结构,采用树形结构存储数据 数据量小,每个节点最多存储1m数据 follower和observer直接处理非事务请求 全量数据都保存在内存中 高可用: zookeeper是主从结构,只要超过半数的服务器能够提供服务,集群就能正常对外提供服务 自动进行 Leader 选举 最终一致性: 基于Zab协议,确保半数集群更新成功就认为更新成功,其他server会自动从lea

epitomizelu的专栏 547

Claude Code Router 401错误修复

claude code router配置相关环境变量问题

如沐春风 6360

Zookeeper原理分析

一、基础概念 官方解释: ZooKeeper是面向分布式应用程序的分布式开源协调服务。它公开了一组简单的基元,分布式应用程序可以基于这些基元来实现更高级别的服务,以实现同步,配置维护以及组和命名。它被设计为易于编程,并且使用在文件系统熟悉的目录树结构之后的样式的数据模型。它运行在Java中,并具有Java和C的绑定。协调服务是非常难以正确的。他们特别容易出现诸如竞赛状况和僵局等错误。ZooKe...

sinat_34814635的博客 4998

跨厂商网络设备的RADIUS认证:Windows NPS的兼容性与最佳实践

本文详细探讨了Windows NPS在多厂商网络环境中的RADIUS认证实践,特别针对华为、华三、思科等主流设备的兼容性问题提供解决方案。从基础配置到高级优化,涵盖VSA属性映射、认证协议选择及安全加固措施,帮助企业实现统一身份认证并提升网络安全性。

weixin_29213827的博客 421

Opencv实战:答题卡自动识别与评分系统(附完整代码解析)

本文详细介绍了如何使用OpenCV实现答题卡自动识别与评分系统,包含完整的代码解析。通过图像预处理、边缘检测、透视变换和答案识别等关键技术,系统能够快速准确地完成阅卷工作,适用于学校考试、资格认证等多种场景,大幅提升工作效率。

weixin_33737134的博客 415

Zookeeper的架构设计及原理分析

1. Zookeeper 设计猜想 Zookeeper 作为一个分布式协调组件,很多应用系统都会依赖Zookeeper来实现相关业务的处理。 前面我们一直在提到,在分布式架构中任何节点都不能以单点状态存在,所以Zookeeper首先需要解决的是单点故障问题,而常见的解决方案就是做主从集群,这个在前面的很多组件讲解中都有提到。 那么这个集群需要满足那些功能呢? 集群中要有主节点和从节点(也就是集群要有角色)。 集群要能做到数据同步,当主节点出现故障时,从节点能够顶替主节点继续工作,但是继续工作的前提是

Java是世界上最好的语言 5871

【AI助力科研】不看一篇文献,手把手教你用chatGPT写文献综述!

这篇文章以【AI助力科研】为题,介绍了如何利用ChatGPT编写文献综述的方法。作者通过详细的指导,展示了不需要阅读大量文献,只需依靠ChatGPT模型即可完成文献综述的过程。该方法旨在提高科研工作者的效率,减少阅读负担,并且能够生成具有逻辑性和准确性的文献综述。

研究方向//图像视频处理/信号算法/红外无损检测/数值仿真/机器学习/优化算法/python/matlab 2万+

Zookeeper基本架构原理详解

目录场景一场景二一、概念理解(1)zookeeper是什么(2)zookeeper提供了什么(1)文件系统(2)通知机制(3)我们能用zookeeper做什么(1)命名服务(2)配置管理(3)集群管理(4)分布式锁(5)队列管理(4)分布式与数据复制(5)数据一致性与paxos算法二、Zookeeper的基本概念(1)角色(2)设计目的三、ZooKeeper的工作原理(1)选主流程(2)同步流程(1)Leader工作流程(2)Follower工作流程 场景一 有这样一个场景:系统中有大约100w的用户,每个

蔡政洁的博客 1772

VS(QT)调用Matlab函数的方法

调试–>窗口–>异常设置–>Win32 Exceptions全部不要勾选。选择Microsoft Visual C++ 2017。将生成的.h和.lib分别放置在对应的文件夹。输入mex -setup C++输入deploytool选择。选择Realse x64。

woshigaowei5146的博客 591

(ZOS-API)Matlab控制ZEMAX软件调整光学系统某镜面位姿

所用软件的版本:MatlabR2022a, Zemax OpticStudio2024R1交互扩展功能,Zemax和可以同时打开,操作会比较方便在ZEMAX软件中,调整次镜位置通常有两种方法:1.在次镜前后各添加一个坐标间断面,并修改其“偏心X”“偏心Y”等参数来调整次镜的位姿;2.或者直接在次镜属性选项中设置相关数值。这两种方法对Zernike系数的采集结果无显著影响。

ecilifurt的博客 911

史上最全的Zookeeper原理详解(万字长文)

ZooKeeper是一个开源的分布式协调服务框架,为分布式系统提供一致性服务。那么什么是分布式?什么是协调程序?和集群又有什么区别?举一个例子来说明,现在有一个网上商城购物系统,并发量太大单机系统承受不住,那我们可以多加几台服务器支持大并发量的访问需求,这个就是所谓的**Cluster集群**。如果我们将这个网上商城购物系统拆分成多个子系统,比如订单系统、积分系统、购物车系统等等,然后将这些子系统部署在不同的服务器上,这个时候就是 Distributed分布式。

dream_ambition的博客 2万+

AI自瞄原理剖析(四)从Yolo推理坐标到屏幕坐标:基于FOV视角与焦距的坐标变换与精准瞄准

从Yolo推理框架得到的坐标到屏幕坐标的转换是一个涉及到FOV视角、焦距以及分辨率的复杂过程。通过数学公式,我们可以将推理框坐标反推为游戏内的实际坐标,并最终映射到屏幕坐标系中。利用这些信息,AI自瞄系统能够精确计算出准星从当前位置移动到敌人位置的距离,实现精准的自动瞄准。通过这种方法,AI自瞄系统能够在不同的游戏环境下灵活应对,提供高度精确的操作体验。在AI自瞄系统中,目标检测仅仅是第一步,获取到预测框的坐标后,我们还需要将这些坐标转换为实际屏幕上的精确位置。

代码简单说 Vue、JAVA、PHP、Node.js 熟练运用,接口、架构、性能全搞定。 1334

zookeeper:架构原理和使用场景

zookeeper:架构原理和使用场景

weixin_46619605的博客 757

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

3.ZooKeeper集群架构以及读写原理「第五章 ZooKeeper 原理」「架构之路ZooKeeper理论和实战」

相关历史文章(阅读本文前,您可能需要先看下之前的系列????) 国内最全的SpringBoot系列之四 享元模式:共享女友-第355篇 什么是ZooKeeper-第347篇 ZooKeeper安装-第348篇 ZooKeeper数据结构和实操-第349篇 ZooKeeper的watch机制-第350篇 ZooKeeper的acl权限控制-第351篇 ZooKeeper内存数据和持久化-第352篇 ZooKeeper集群搭建-第354篇 ZooKe...

悟纤学院 7385

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

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

Zookeeper原理架构

本文纯属个人笔记,通俗易懂,转载请附上原文链接!部分资料摘自网络,如有雷同,纯属巧合!Zookeeper到底是什么!?学一个东西,不搞明白他是什么东西,哪还有心情学啊!! 首先,Zookeeper是Apache的一个java项目,属于Hadoop系统,扮演管理员的角色。 然后看到官网那些专有名词,实在理解不了。在Zookeeper的官网上有这么一句话:ZooKeeper is a central

技术大神之路 5万+

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

Zookeeper 架构原理

1.Zookeeper是什么Zookeeper 作为一个分布式的服务框架,主要用来解决分布式集群中应用系统的一致性问题,它能提供基于类似于文件系统的目录节点树方式的数据存储,但是 Zookeeper 并不是用来专门存储数据的,它的作用主要是用来维护和监控你存储的数据的状态变化。通过监控这些数据状态的变化,从而可以达到基于数据的集群管理。简单的说,zookeeper=文件系统+通知机制。2.zook...

不积跬步,无以至千里;不积小流,无以成江海。 8328

Zookeeper之Zookeeper底层客户端架构实现原理(转载)

Zookeeper的Client直接与用户打交道,是我们使用Zookeeper的interface。了解ZK Client的结构和工作原理有利于我们合理的使用ZK,并能在使用中更早的发现问题。本文将在研究源码的技术上讲述ZK Client的工作原理及内部工作机制。 在看完ZK Client的大致架构以后我希望能有一种简单的方式描述ZK Client的基本结构,想来想去我觉得还是图片比较...

dianzhouyu2189的博客 236

Zookeeper的原理和架构设计,以及应用场景

Zookeeper的原理和架构设计,以及应用场景 https://yq.aliyun.com/articles/687223?spm=a2c4e.11153940.0.0.7cb0c96a237vVY

qq_40414855的博客 280

Zookeeper的集群架构以及读写原理

本文来说下Zookeeper的集群搭建 文章目录概述 概述

wh柒八九的博客 681

深入学习ZooKeeper架构原理

深入学习ZooKeeper架构原理 ZooKeeper 是什么? ZooKeeper 是一个针对大型分布式系统的可靠协调系统;它提供的功能包括:配置维护、名字服务、分布式同步、组服务等; 它的目标就是封装好复杂易出错的关键服务,将简单易用的接口和性能高效、功能稳定的系统提供给用户; ZooKeeper 已经成为 Hadoop 生态系统中的基础组件。

u012430775的专栏 212

Zookeeper原理及架构深入

一.zookeeper介绍 1.什么是zookeeper? Zookeeper是一个开源的分布式的,为分布式应用提供协调服务的Apache项目,多用作为集群提供服务的中间件!官网也对此做了介绍: zookeeper这个词语翻译过来就是"动物园管理员",主要是为hadoop体系集群提供服务的中间件,之所以叫zookeeper,是因为hadoop体系的框架大多是以动物作为logo,所以zookeep...

qq_33265875的博客 360
上一篇: Etcd全方位解读
下一篇: HBase学习笔记
奋起直追CDS
博客等级 码龄11年 57粉丝 94原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值