关于大数据系统及Hadoop系统中的概念

什么是大数据

大数据(Big Data)姑且定义为无法被符合服务等级协议(service level agreement,SLA)的单台计算机处理或存储的任何数据集。理论上讲,单台计算机可以处理任意规模的数据,对于超过单台计算机存储量的海量数据,可以存放到类似网络附属存储(network attached storage,NAS)这样的共享存储设备中,然后输入到单台计算机去计算处理。但是这样处理数据所花费的时间往往会大大超过允许的数据处理时间。

大数据技术背后的核心思想

下面列出了所有大数据处理方法中的一些共同特征:

  • 数据分布在多个节点(网络I/O)速度<<本地磁盘I/O速度)
  • 计算程序离数据更近(集群上的节点),而不是相反
  • 数据的处理尽量在本地完成(网络I/O速度<<本地磁盘I/O速度)
  • 使用可顺序读取磁盘I/O代替随机读取磁盘I/O(数据交换速度<<数据寻道时间)

所有大数据计算处理模式都有一个目的,就是使输入/输出(I/O)并行化,从而提高数据处理性能

把数据分发到多个节点

根据定义,大数据是无法仅靠单台计算机资源来处理的。大数据的一个特点就是使用商用服务器。
需要注意的是,把要处理的数据分布存放在多个计算节点,并不是因为这些数据的数据量比较巨大。大数据处理系统会有条不紊的在各个计算节点上计算处理所分配的数据。把数据分布到各个服务器节点的最终目的是为了让计算节点同时参与数据的处理过程中来。
这样的数据分发会有两点好处:
1.每个数据块会在多个节点上有多份拷贝(Hadoop默认是一个数据块有3份拷贝),这使得系统具备容错性,当一个节点发生故障,其他节点还备份有故障节点上的数据。
2.为了达到数据并行处理的目的,多个节点可以同时参与数据处理过程,每个节点仅处理分配给自己的数据集,可以达到数据处理性能5-10倍的提升。

把计算逻辑移动到数据附近

大数据系统无法处理网络过载的问题。传输动辄数T的数据量给应用层,使得网络带宽耗尽,网络拥挤不堪,导致传输效率大幅下降,甚至有可能导致系统故障。从大数据的观念来看,应该把数据分布存放到各个计算节点上,程序也要移动到数据附近。如果大数据系统的集群拥有数百个计算节点,显然那将是程序维护、部署人员的噩梦。所以,大数据系统可以让我们集中式地部署程序代码,大数据系统后台会在计算任务启动之前把这些程序移动到各个数据处理节点。

计算节点进行本地数据处理

虽然典型的大数据处理系统都希望把数据处理过程放在拥有数据的节点本地完成,但并不是每次都能实现。大数据系统会把计算任务尽量调度到离数据最近的节点。

优选顺序读,次之随机读

首先,需要理解的是数据是如何从磁盘上读取的,磁盘头首先要移动到所寻找的数据所在的磁盘位置。这个过程称为寻道(seek)操作,是需要花费很多时间的。一旦磁盘头移动到目的位置后,数据便会顺序的读取出来。这叫做数据的传输(transfer)操作。

寻道时间需要10毫秒,数据传输速度量级为20毫秒(1MB),如果从磁盘上彼此不相邻的1MB扇区来读取100MB数据会花费10(寻道时间)*100(寻道100次)=1秒再加上20(每兆数据传输所需时间)*100=2秒,读取100MB数据总共需要3秒钟。如果从磁盘上彼此相邻的扇区来顺序读取100MB数据,则将花费10(寻道时间)1(寻道)+20100=2.01秒

大多数数据读取密集型的大数据编程模型都利用了这个特征,数据被顺序的从磁盘上读出,然后在内存中过滤数据。于此不同的典型的关系型数据库管理系统(RDBMS)模型,往往是以随机读写数据为主

大数据编程模型

  • 大规模并行处理(Massively Parallel Processiong,MPP)数据库系统:EMC公司的Greenplum系统和IBM公司的Netezza系统就是这样的系统

  • 内存数据库系统:Oracle公司的Exalytics和SAP公司的HANA正是此类系统

  • MapReduce系统:这样的系统包括所有大数据系统中最广泛使用的Hadoop

  • 整体同步并行(Bulk synchronous parallel,BSP)系统:Apache HAMA和Apache Giraph就是这样的系统

大规模并行处理数据库系统

大规模并行处理(MPP)数据库系统的核心思想是把数据按照某一列或者某一组列的值,按照某种形式进行划分,以分别处理。
这样的系统有个明显的缺陷,需要在算法设计的时候就决定数据如何划分,而划分的准则通常由底层的用例来决定。
为了解决这个缺陷,大规模并行处理数据库系统经常采用的办法是把数据存储多份,并按照不同的准则来进行划分。

内存数据库系统

从系统运行的角度看,内存数据库系统类似于MPP系统。它们不同之处在于,内存数据库系统的每个计算节点拥有巨大容量的内存,并且大部分数据会被预先加载到内存中。就本质来说,内存数据库系统就像是带有SQL接口的内存MPP数据库系统。

MapReduce系统

MapReduce框架已被广泛的用于大数据处理过程(four methods)。Hadoop系统对MapReduce框架的实现具有如下几个重要特征:

  • 使用商用级别的硬件。
  • 无需事先定义数据划分准则来把数据分配到各计算节点
  • 用户仅需要定义两个独立的处理过程:Map和Reduce
整体同步并行系统

整体同步并行(BSP)系统的运行过程跟MapReduce过程非常相似。与MapReduce程序在它的处理循环结束后即可终止不同的是,BSP系统程序执行由一系列超步(processes)组成,这些超步保持栅栏同步,向主节点发送数据并进行相关的信息交换。每当一次迭代执行完毕,主节点就会通知每个数据处理节点进行下一次迭代。
间隔通信是在并行计算处理中经常提到的概念。间隔通信指的是许多线程在分别执行各自的任务,这些线程在运行之前需要协商出一个检查点。

大数据和事务性系统

大多数的RDBMS使用者都要求数据库必须遵守ACID准则,但是遵守这些准则是有系统代价的。当数据库后台需要处理峰值为每秒数百万次的事务操作的时候,要求苛刻的遵守ACID准则对数据库来说是个巨大的挑战。

ACID是atomicity(原子性)、consistency(一致性)、isolation(隔离性)和durability(持久性)的首字母简写。
对苛刻的ACID准则做出妥协是必要的。做出妥协的理论依据就是著名的CAP理论。

  • Consistency(一致性):在分布式系统中的所有数据备份,在同一时刻有同样的值
  • Availability(可用性):在合理且明确的时间内,保证每个请求都能获得成功或者失败的响应
  • Partition tolerance(分区容忍性):在集群中一部分节点故障后,集群整体仍可使用。

这个理论用来证明,任何分布式系统只能同时满足其中两个特性,而无法三者兼顾。

Hadoop简介

Hadoop是以谷歌在2004年发表的一篇关于MapReduce的论文为基础开发的。Hadoop项目开始于2005年,Hadoop项目是开源的网页搜索引擎Nutch项目下的一个子项目。后来Hadoop从Nutch项目分离出来,并最终成为Apache基金会的顶级项目。

项目名内容
Hadoop Streaming任何命令行脚本都可以通过Streaming调用MapReduce框架。Unix脚本程序员,Python程序员等都可以使用MapReduce来开发一些临时任务
Hadoop Hive使用MapReduce平台的用户发现,开发一个MapReduce程序往往需要大量的编码工作,而且易于出错,难于测试。这就需要一个更有效地类似SQL的语言,用户可以关注于业务问题而不必关系类似SQL命令功能的底层实现(比如WHERE子句,GROUP BY子句,JOIN子句等)。Apache Hive可以把海量数据集放入数据仓库中,用户可以编写类似SQL语句的Hive查询语句来查找数据。Hive引擎把Hive查询语句透明的转换为底层MapReduce任务来执行。高级用户可以使用Java语言来编写用户自定义函数(UDF)。Hive也支持标准的ODBC、JDBC数据库驱动
Hadoop Pighi用Pig的目的与使用Hive的目的是一样的,但是Hive是一个类SQL语言,属于陈述性语言;而Pig是一种过程性语言,非常适合数据管道应用场景。它非常适合开发抽取、加载和传输(ETL)类型的程序
Hadoop HBase所有之前的项目,包括MapReduce程序,都是批处理程序。Hadoop并不是一个原生的键值存储系统,HBase用来对Hadoop进行实时查询数据
MapReduce编程模型简介

Hadoop系统支持MapReduce编程模型,这个编程模型由谷歌公司发明,该模型可以利用由大量商用服务器构成的大规模集群来解决千兆级数据量的问题。MapReduce模型有两个彼此独立的步骤,这两个步骤可以配置并需要用户在程序中自定义:

  • Map:数据初始读取和转换步骤,在这个步骤中,每个独立的输入数据记录都进行并行处理。
  • Reduce:一个数据整合或者家和的步骤。在这个步骤中,相关联的所有数据记录要放在一个计算节点来处理

Hadoop系统中的MapReduce核心思路是,将输入的数据在逻辑上分割成多个数据块,每个逻辑数据块被Map任务单独的处理。数据块处理后所得结果会被划分到不同的数据集,且将数据集排序完成。每个经过排血的数据集传输到Reduce任务进行处理。

一个Map任务可以在集群的任何计算节点上运行,多个Map任务可以并行的运行在集群上。Map任务的主要作用就是把输入的数据记录转换为一个一个键值对。所有Map人物的输出数据都会进行分区,并且将每个分区的数据排序。每个分区对应一个Reduce任务。每个分区内已排好序的键和与该键对应的值会由一个Reduce任务处理。有多个Reduce任务在集群上并行的运行。

一般情况下,应用程序开发者根据Hadoop系统的框架要求,仅需要关注以下丝格蕾:一个类是用来读取输入的数据记录,并将每条数据记录转换成一个键值对;一个Mapper类;一个Reducer类;一个类是将Reduce方法输出的键值对转换成输出记录进行输出。

Hadoop系统的组成

守护进程:

名称作用
名称节点(NameNode)维护着存储在HDFS上的所有文件的元数据信息。这些元数据信息包括组成文件的数据块信息,及这些数据块在数据节点上的位置
辅助名称节点(Secondary NameNode)这不是名称节点的热备份。实际上它作为Hadoop平台的一个组件,明明不是很恰当,它为名称节点组件执行一些内务处理功能
数据节点(DataNode)把真正的数据块存放在本地硬盘上,这些数据块组成了保存在HDFS上的每个文件
作业跟踪器(JobTracker)这是Hadoop系统的主要组件之一,它负责一个任务的整个执行过程。它的具体功能包括:调度各个子任务(Mapper任务和Reducer任务各自的子任务)到各自的计算节点运行,时刻监控任务运行和计算节点的健康状况,对失败的子任务重新调度执行。
任务跟踪器(TaskTracker)运行在各个数据节点上,用来启动和管理各个Map/Reduce任务
Hadoop分布式文件系统

Hadoop分布式文件系统(HDFS)用于支持数据处理程序要处理的大文件。这样的程序在处理数据的时候,有一次写、多次读的特点。
HDFS文件系统由以下几个守护进程协调运行来提供服务:

  • 名称节点进程
  • 辅助名称节点进程
  • 数据节点进程
    HDFS系统也是主从架构。运行名称节点进程的服务器为主节点,运行数据节点进程的服务器为从节点。一般情况下,集群中的每个从节点都会运行一个数据节点进程,这个数据节点进程管理着挂载到这个数据节点上的存储设备。HDFS系统提供一个统一的文件系统命名空间,用户就像是使用一个文件系统一样来存取集群节点上的数据。名称节点负责管理这些存储在集群上的文件的元数据。
Hadoop文件的本质是块存储

首先,在Hadoop系统中,每个文件被分隔为多个数据块。一个典型的数据块大小为64MB,也可以将其配置为32MB或者128MB。在HDFS中,文件块大小是按照文件的大小来配置的。
每个数据块存储在数据节点上。为了防止节点故障,这些数据块是有备份的。在Hadoop系统中,备份数量默认配置为3。具备机架感知感知功能的Hadoop系统把文件的一个数据块存放在本地机架的上的一台计算节点上。这个数据块的第二个备份会被存放在另一个远程机架上的计算节点中。这个数据块的第三个备份会被存放在第二个数据块备份机架上的另一台计算节点中。Hadoop系统借助一个单独配置的网络拓扑文件实现机架感知功能,这个网络拓扑文件配置了机架到计算节点的域名系统(DNS)名称之间的映射,该网络拓扑文件的路径配置在Hadoop配置文件中。

文件元数据和名称节点

当客户端向HDFS请求读取或者存储一个文件的时候,它需要知道要访问的数据节点是哪一个。知道这个信息后,客户端可以直接访问哪个数据节点。文件的元数据信息由名称节点来负责维护。

HDFS系统提供一个统一的文件系统命名空间,用户就像是使用一个文件系统一样来存取集群节点上的数据。HDFS把存储在目录中的文件按照一定的层级展示出来,目录可以是嵌套的。所有文件和目录的元数据信息都由名称节点来负责管理。

名称节点存储的一些元数据包括:

  • 文件/目录名称及相对于其父目录的位置
  • 文件和目录的所有权及权限
  • 各个数据块的文件名。所有数据块以文件的形式存放在数据节点的本地文件系统的目录中,该目录可以被Hadoop系统管理员配置
HDFS系统写文件的机制

客户端把一个文件写入到HDFS文件系统需要经过如下几个步骤:
1)客户端在联系名称节点之前,会把文件数据流式地读入到客户端本地文件系统中地一个临时文件。
2)当文件数据的大小达到一个数据块的大小时,客户端就联系名称节点。
3)名称节点会在HDFS文件系统的层级结构中创建一个文件,然后把数据块的标识符和数据节点上的位置信息发送给客户端。这个数据节点块信息列表里面还包括了其备份节点的数据块信息列表。
4)进行完上述的步骤之后,客户端就会根据上一步的数据块信息把本地临时文件中的数据刷新(flush)到集群上的数据块中(只写入到第一个数据节点中)。这样,真实的文件数据就放在了集群数据节点本地文件存储系统中。
5)当文件(客户端可以访问的HDFS文件)被关闭时,名称节点会执行一个提交操作,从而使得该文件在集群中为可见状态。如果在提交操作完成之前名称节点挂掉了,这个文件就丢失了。

客户端从HDFS中读取文件的步骤

1)客户端访问名称节点,名称节点返回组成文件的数据块列表及数据块的位置(包括备份数据块的位置)。
2)客户端会直接访问数据节点以获取数据块中的数据。如果此时其访问的数据节点出现故障,就会访问存放备份数据块的数据节点。
3)读取数据块的时候会计算该数据块的检验和,并将该校验和与写入文件时的校验和作比较。如果检验失败,则从其他数据节点获取备份数据块。

HDFS系统删除文件机制

1)名称节点仅仅重命名了文件路径,使其移动到/trash目录。需要注意的是,这个操作过程是链接到重命名文件路径的元数据的更新操作。/trash目录中的文件会保存一段时间,这个保存时间是预先确定的(当前设定为6小时而且当前不可配置)。在这段时间里,把删除的文件从/trash目录中移动出来即可迅速地恢复该文件。
2)当/trash目录中的文件超过了保存时间时,名称节点就会将该文件从HDFS命名空间中删除。
3)删除文件会使得该文件的相关的数据块被释放,HDFS系统随后会显示增加了一些空闲空间。

确保HDFS系统的可靠性

Hadoop系统和HDFS系统都有很强的抗故障能力。以下两种情况下会造成数据丢失:

  • 数据节点故障:每个数据节点周期性地发送心跳信息到名称节点(默认3秒一次)。如果名称节点在预先设定地时间段内没有收到心跳信息,它就会认为数据节点故障了。此刻,名称节点就会主动地对存储在故障数据节点上的数据块重新备份,把相关数据块(从其他健康节点地备份数据块获取)转移到状态健康地数据节点。这样就可以确保数据块备份数量不变。

  • 位腐现象导致的数据损坏:这是指当电荷(在传输过程中)发生衰减而导致的数据丢失的情况。在HDFS系统读取数据块的操作过程中会进行数据校验和核对,这种情况的数据损坏就会被发现。如果数据块的校验失败了,便认为这个数据块已经损坏,就会读取该数据块的备份,然后名称节点会重新备份这个损坏了数据块,使得数据块的备份数量达到预先设定的数据块备份数量。

辅助名称节点

名称节点在内存中维护着所有的元数据。名称节点最先从存放在本地文件系统中的fsimage文件将元数据加载到内存中。在Hadoop系统中的一系列操作运行过程中,元数据信息在内存中不断更新。为了防止数据丢失,这些数据操作记录还会被持久存储到另外一个名为edits的本地文件中。
edits文件是用来在Hadoop系统运行期间收集元数据的变化的。如果Hadoop系统重启了,在Hadoop重启的过程中,edits文件中的内容会与fsimage文件的内容合并。辅助名称节点就是来处理这个会拖慢Hadoop系统的重启时间这个问题的。
辅助名称节点的作用就是周期性地把edits文件中的内容与fsimage文件中的内容合并。
辅助名称节点会周期性的顺序执行下列步骤:
1)辅助名称节点会请求名称节点来结转(roll over) edits文件,确保新的更新保存到一个新的文件。这个新的文件名字叫做edits.new
2)辅助名称节点向名称节点请求获取fsimage文件和edits文件
3)辅助名称节点把edits文件和fsimage文件合并,生成一个新的fsimage文件
4)名称节点从辅助名称节点接收到新生成的fsimage文件,并替代旧的fsimage文件。同时将edits文件中的内容替换成步骤1中创建的edit.new文件的内容。
5)更新fstime文件来记录发生的检查点操作

名称节点上的关键文件

文件名功能描述
fsimage保存了最近一次检查点的HDFS系统元数据的持久化状态信息
edits保存了最近的一次检查点之后到现在的HDFS系统元数据的状态变化信息
fstime保存了最近一次检查点的时间戳
任务跟踪器

任务跟踪器(TaskTracker)守护进程在集群中每台计算节点中运行,接收注入Map、Reduce和Shuffle这些操作任务的请求。每个任务跟踪器都会分配一定的槽位数,其槽位数的数量一般与计算节点上可用的CPU核数一致。任务跟踪器接收到一个(来自作业跟踪器)的请求之后,就会启动一个任务(task),任务跟踪器会为这个任务初始化一个新的JVM。JVM重用是可以的,但这项功能在实际用法中并不常见。任务跟踪器分配一项任务取决于它的可用槽位数量(槽位数量=实际运行的任务数量)。任务跟踪器负责向作业跟踪器发送心跳消息。除了向作业跟踪器反馈任务跟踪器的运行状况之外,心跳信息中还包括了任务跟踪器当前可用的槽位数量。

作业跟踪器

作业跟踪器守护进程负责启动和监控MapReduce作业。当一个客户端向Hadoop系统提交一个作业,详细步骤如下:
1)作业跟踪器接收到了作业请求
2)大多数的MapReduce作业都需要一个或多个输入文件目录。任务跟踪器向名称节点发出请求,获得一个数据节点列表,这个列表上的数据节点中存储了组成输入文件数据的数据块。
3)作业跟踪器为作业的执行做准备工作。在这个步骤中,任务跟踪器确定执行该作业需要的任务(Map任务和Reduce任务)数量。作业跟踪器尽量把这些任务都调度到离数据块最近的位置上运行。
4)作业跟踪器把任务提交到每个任务跟踪器节点去执行。任务跟踪器节点监控任务执行情况。任务跟踪器以预先设定的时间间隔发送心跳信息到作业跟踪器。如果作业跟踪器在预先设定的时间间隔之后,没有收到任务跟踪器发来的心跳信息,那么就认为该任务跟踪器节点出现故障,任务就会被调度到另一个节点去运行。
5)一旦所有的任务都执行完毕,作业跟踪器就会更新作业状态为成功。如果任务反复失败达到一定的数量,作业跟踪器就会宣布作业运行失败。
6)客户端会轮询作业跟踪器及时的获得作业运行状态。

YARN系统的几个组成部分
  • 全局资源管理器
  • 节点管理器
  • 针对每种应用程序的应用程序管理器
  • 调度器
  • 容器
容器

容器是YARN框架中的计算单元。它是一个任务进行工作的单元子系统。YARN框架中的容器也可以理解为MapReduce v1中的一个任务执行器。集群节点与容器之间的关系是:一个节点可以运行多个容器,但一个容器智能运行在一个节点之内。

一个容器就是已分配的一组系统资源,目前支持两种类型的系统资源:

  • 中央处理器内核(CPU core)
  • 内存(单位为MB)
    拥有系统资源的容器在某一节点上执行,所以一个容器中隐含了“资源名称”的概念,这个“资源名称”就是容器所在机架和节点的名称。请求一个容器的时候,就会向一个节点发出请求。容器使得程序可以在某个节点上获得指定数量的CPU内核和一定数量的内存。
    实际上,任何任务或者程序(单个任务或者多个任务组成的有向无环图)都运行在一个或多个容器中。在YARN框架中全权负责分配容器的组件叫做节点管理器。
节点管理器

节点管理器(Node Manager)运行在集群中的一个节点上,集群中每个节点都会运行一个自己的节点管理器。它作为一个从属服务:它接受来自另一个称为资源管理器的组件的请求,然后分配容器给应用程序。它还负责监控和汇报资源使用情况给资源管理器。在Hadoop集群中,节点管理器与资源管理器一起协同工作,负责管理分配Hadoop系统资源。资源管理器是一个Hadoop集群的全局组件,节点管理器作为各个节点的代理来负责管理集群中每个节点的健康情况。
节点管理器的任务如下:

  • 接受来自资源管理器的请求,为作业的执行分配容器
  • 与资源管理器交换信息,确保整个集群的稳定运行。资源管理器依靠各个节点管理器的汇报来跟踪整个集群的健康状况,接管管理器作为代理任务来监控和管理本节点的健康状况
  • 管理每个已启动的容器的整个生命周期
  • 每个节点的日期管理
  • 运行各种YARN应用程序使用的辅助服务

当一个节点启动,它会向资源管理器注册,并且告诉资源管理器有多少资源(最终可分配给容器使用的资源)可用。在节点运行期间,节点管理器与资源管理器会协同工作,不停地更新系统资源状态,保证集群资源有效的、优化的利用
节点管理器仅对抽象出来的容器进行管理,而对单个应用程序或者应用程序类型地情况一无所知。负责管理这部分内容地是一个被称为应用程序管理器的组件。

资源管理器

资源管理器的核心是一个调度器:当多个应用程序竞争使用集群资源的时候,它来负责资源的分配调度,确保集群资源的优化合理使用。资源管理器有一个插件化的调度器,该调度器按照程序队列和集群的处理能力,负责为正在运行的多个应用程序分配其所需的集群资源。
一个任务的启动、配置及其资源的监控都由计算节点上的节点管理器来负责。这种职责的分离使得资源管理器相比传统的作业调度器具备更好的系统扩展性。

应用程序管理器

应用程序管理器是一个特定的框架函数库实例。它同资源管理器协调沟通资源,并通过节点管理器来获取这些系统资源,然后执行任务。应用程序管理器就是与资源管理器沟通以获取拥有系统资源的容器组件

应用程序管理器为YARN框架主要带来以下好处:

  • 提高了可扩展性
  • 框架更加通用
分步详解YARN请求

1)一个客户端提交作业程序。该应用程序的类型确定了,就决定了使用何种应用程序管理器。
2)资源管理器协调资源,在一个节点上获取一个用于运行应用程序管理器实例的容器
3)应用程序管理器在资源管理器中注册。注册之后,客户端就可以向资源管理器查询该应用程序的详细信息了。客户端将会与应用程序管理器通信,应用程序管理器已经通过自己的资源管理器启动了。
4)在这个操作过程中,应用程序管理器通过资源请求与资源管理器协商资源。除了内容,一个资源请求包括被请求的容器所在的节点和该容器的详细说明(CPU核数量和内存大小)
5)在启动的容器中运行的应用程序会通过该应用程序特定的协议向应用程序管理器汇报它的执行进度。
6)通过应用程序特定的协议,客户端与应用程序管理器通讯。客户端通过查询在步骤3中注册的资源管理器的信息就可以找到对应的应用程序管理器。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

盛者无名

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值