Hadoop的110道简答题

1      简述hadoop的安装配置

1.创建hadoop账户

2.配置主机名

3.配置hosts文件

4.配置免密码登录

5.安装和配置jdk、修改/etc/profile文件,配置环境变量

6.上传和安装hadoop

7.配置hadoop配置文件(hadoop-env.sh、core-site.xml、hdfs-site.xml、mapred-site.xml、yarn-site.xml)

8.配置slaves文件

9.配置hadoop的环境变量

10.格式化namenode ----》hadoop namenode –format

11.启动hadoop ./start-all.sh

2        列出hadoop的进程名,作用分别是什么

Namenode:维护元数据信息,当jobClient进行读写请求的时候,返回block和datanode的位置信息。

SecondaryNameNode:协助namenode进行元数据的合并,一定范围内的数据备份。

Datanode:存储数据,向namenode发送心跳报告,接收namenode节点的指令以及Block副本的复制

ResourceManager:在yarn中,resourceManager负责集群中所有资源的统一管理和分配,接收来自各个节点的资源回报信息,并把这些信息按照一定的策略分配给各个应用程序。

NodeManager:是yarn中每个节点上的代理,他管理hadoop集群中单个计算节点包括与resourcesManager保持通信,监督Container的生命周期管理,监控每个Container的资源使用情况,追踪节点健康状况,管理日志和不同应用程序用到的附属服务。

在1.x版本中是Jobtracker:管理任务,并将任务分配给taskTracker

Taskreacker:任务的执行方。

3        写出下面的命令

1)杀死一个job

Hadoop job –list  拿到job-id , hadoop job –kill job-id

2)删除hdfs上的/tmp/aaa目录

Hadoop fs –rmr /tmp/aaa

3)加入一个新的存储节点和删除一个计算节点需要刷新集群状态命令

加新节点:

Hadoop-daemon.sh start datanode

Hadoop-daemon.sh start tasktracker

删除时:

Hadoop mradmin –refreshnodes

Hadoop dfsadmin -refreshnodes

4        简述hadoop的调度器,并说明其工作方法

(1)FIFO:默认调度器,先按照作业的优先级高低,再按照到达时间的先后选择被执行的作业。

(2)Capacity Scheduler:计算能力调度器,支持多个队列,计算每个队列中正在运行的任务数与其应该分得的计算资源之间的比值,选择一个该比值最小的队列;然后按照作业优先级和提交事件顺序选择,同时考虑用户资源量限制和内存限制。

(3)Fair Scheduler:公平调度器,支持多队列多用户,每个队列中的资源量可以配置,统一队列中的作业公平共享对列中所有资源。

除以上三点外:还有新型应用的hadoop调度器

(4)适用于异构集群的调度器LATE:当一个节点出现空闲资源且系统中总的备份任务数小于SpeculativeCap时,(1)如果该节点是慢节点(节点得分高于SlowNodeThreshold),则忽略这个请求。 (2)对当前正在运行的task按估算的剩余完成时间排序 (3)选择剩余完成时间最大且进度低于SlowTaskThreshold的task,为该task启动备份任务。

(5)适用于实时作业的调度器Deadline Scheduler和Constraint-basedScheduler:Deadline Scheduler(参考资料[5])主要针对的是软实时作业,该调度器根据作业的运行进度和剩余时间动态调整作业获得的资源量,以便作业尽可能的在deadline时间内完成。

 

Constraint-basedScheduler(参考资料[6])主要针对的是硬实时作业,该调度器根据作业的deadline和当前系统中的实时作业运行情况,预测新提交的实时作业能不能在deadline时间内完成,如果不能,则将作业反馈给用户,让他重调整作业的deadline。

5        你认为用java,Streaming,pipe方式开发map\reduce,各有哪些优缺点

(1)java写mapreduce可以实现复杂的逻辑,如果需求简单,则显得繁琐。

(2)Hiveql基本都是针对hive中的表数据进行编写,但对复杂的逻辑很难进行实现。

6        请简述mapreduce中combiner、partition作用

Combiner是实现在mapper端进行key的归并,在MapperTask端对输出先做一次合并,以减少传输到reducerTask的数据量。

Partition是shuffle操作中的一个重要过程,作用就是将map的结果,按照规则分发到不同的reduce中进行处理,从而按照分区得到多个输出结果。默认的是reducer=(key.hashCode()&Integer.MAX_VALUE)%numReduceTasks;

7        shuffle阶段你怎么理解的

MapReduce确保每个reducer的输入都是按键排序的,系统执行排序的过程称为shuffle。我们可以理解为map产生输出到reduce的消化输入的整个工程。

Map端:每个mapperTask有一个环形内存缓冲区,用于存储map任务的输出,一旦达到阈值,一个后台线程把内容写到磁盘的指定目录下的新建的一个溢出写文件,写磁盘前要经过partition、sort、Combiner。等最后记录写完,合并全部溢出写文件为一个分区且排序的文件。

Reduce端:可以分为复制阶段、排序阶段、reduce阶段

复制阶段:map输出文件位于运行map任务的tasktracker的本地磁盘上,reduce通过http的方式获取输出文件的分区,tasktracker为分区文件运行reduce任务,只要有一个map任务完成,reduce任务就开始复制输出。

排序阶段:更恰当的说法是合并阶段,因为排序是在map端进行的。这个阶段将合并map输出,维持其顺序排序,循环进行。

最后阶段就是reduce阶段,对已排序输出中的每个键调用reduce函数,此阶段的输出直接写到输出文件系统,一般为hdfs。、

8      具体可查看什么是Zookeeper,Zookeeper 的作用是什么,在 Hadoop 及 hbase 中具体作用是什么。

Zookeeper是一个分布式的,开放源码的分布式应用程序协调服务,以Fast Paxos算法为基础,实现同步服务,配置维护和命名服务等分布式应用。这比较官方,而我认为zookeeper是hadoop的整体监控系统。如果namenode、Hmaster宕机后,这时候zookeeper重新选出leader,继续服务。

作用:(1)加强集群稳定性:实现了高性能,高可靠性和有序的访问。高性能保证了zookeeper能应用在大型的分布式系统上,高可靠性保证它不会由于单一节点的故障而造成任何问题,有序的访问能保证客户端可以实现较为复杂的通过操作。(2)加强集群持续性:客户端连接到一个zookeeper服务器,并且维护tcp连接,并且发送请求,获取回复,获取事件,并且发送连接信号,如果这个tcp连接断掉了,那么客户端可以连接另外一个服务器。(3)保证集群有效性:Zookeeper使用数字来对每一个更新进行标记。这样能保证Zookeeper交互的有序。后续的操作可以根据这个顺序实现诸如同步操作这样更高更抽象的服务。(4)保证集群高效:Zookeeper的高效更表现在以读为主的系统上。Zookeeper可以在千台服务器组成的读写比例大约为10:1的分布系统上表现优异。

zookeeper在Hadoop及hbase中具体作用

一个Zookeeper的集群中,3个Zookeeper节点.一个leader,两个follower的情况下,停掉leader,然后两个follower选举出一个leader.获取的数据不变.我想Zookeeper能够帮助Hadoop做到:

 

Hadoop,使用Zookeeper的事件处理确保整个集群只有一个NameNode,存储配置信息等.

HBase,使用Zookeeper的事件处理确保整个集群只有一个HMaster,察觉HRegionServer联机和宕机,存储访问控制列表等.

 

9        Mapreduce的原理

可以从两个方面来说,一个是map任务,一个是reduce任务

Map任务处理:对输入文件的每一行解析成key、value对,对每一个键值对调用一次map函数,在map函数中写自己的逻辑,对输入的key、value进行处理,转换成新的key、value输出,对输出的key、value进行分区,对相同分区的数据,按照key进行排序分组,相同key的value放到一个集合中。

Reduce任务处理:对多个map任务的输出,按照不同的分区,通过网络copy到不同的reduce节点,这个过程并不是map将数据发送给reduce,而是reduce主动去获取数据。对多个map任务的输出进行合并、排序,在reduce函数中写自己的逻辑,对输入的key、value处理,转换成新的key、value输出,将reduce输出保存到hdfs中。

Mapreduce是一种编程思想,map的作用就是过滤一些原始数据,reduce则是处理这些数据,得到我们想要的结果。

10    单机(本地)模式中的注意点?

在单机模式(standalone)中不会存在守护进程,所有东西都运行在一个JVM上。这里同样没有DFS,使用的是本地文件系统。单机模式适用于开发过程中运行MapReduce程序,这也是最少使用的一个模式。

11    伪分布模式中的注意点?

伪分布式(Pseudo)适用于开发和测试环境,在这个模式中,所有守护进程都在同一台机器上运行。

12    VM是否可以称为Pseudo?

不是,两个事物,同时Pseudo只针对Hadoop。

13    全分布模式又有什么注意点?

全分布模式通常被用于生产环境,这里我们使用N台主机组成一个Hadoop集群,Hadoop守护进程运行在每台主机之上。这里会存在Namenode运行的主机,Datanode运行的主机,以及task tracker运行的主机。在分布式环境下,主节点和从节点会分开。

14    Hadoop是否遵循UNIX模式?

是的,在UNIX用例下,Hadoop还拥有“conf”目录。

15    Hadoop安装在什么目录下?使用hadoop的版本

Cloudera和Apache使用相同的目录结构,Hadoop被安装在cd/usr/lib/hadoop-0.20/。

使用hadoop的版本是2.7.4

16    Namenode、Job tracker和task tracker的端口号是?

Namenode,70;Job tracker,30;Task tracker,60。

17    Hadoop的核心配置是什么?

Hadoop的核心配置通过两个xml文件来完成:1,hadoop-default.xml;2,hadoop-site.xml。这些文件都使用xml格式,因此每个xml中都有一些属性,包括名称和值,但是当下这些文件都已不复存在。

18    那当下又该如何配置?

Hadoop现在拥有3个配置文件:1,core-site.xml(用来指定namenode的地址,和产生临时文件的存放目录);2,hdfs-site.xml(设置hdfs

保存数据副本的数量以及操作权限);3,mapred-site.xml(用来指定mapreduce运行在yarn上)。这些文件都保存在etc/hadoop目录下。还有一个yarn-site.xml文件(指定resourcesmannager的地址,nodemanager获取数据的方式)

19    RAM的溢出因子是?

溢出因子(Spill factor)是临时文件中储存文件的大小,也就是Hadoop-temp目录。

20    fs.mapr.working.dir只是单一的目录?

fs.mapr.working.dir只是一个目录。

21      hdfs-site.xml的3个主要属性?

dfs.name.dir决定的是元数据存储的路径以及DFS的存储方式(磁盘或是远端)
dfs.data.dir决定的是数据存储的路径
fs.checkpoint.dir用于第二Namenode

22    当你输入hadoopfsck/造成“connection refusedjava exception’”时,系统究竟发生了什么?

这意味着Namenode没有运行在你的VM之上。

23    我们使用Ubuntu及Cloudera,那么我们该去哪里下载Hadoop,或者是默认就与Ubuntu一起安装?

这个属于Hadoop的默认配置,你必须从Cloudera或者Edureka的dropbox下载,然后在你的系统上运行。当然,你也可以自己配置,但是你需要一个Linux box,Ubuntu或者是Red Hat。在Cloudera网站或者是Edureka的Dropbox中有安装步骤。

24    如何重启Namenode?

1.备份主节点 的current 目录

2.在second namenode 上执行./hadoop-daemon.sh start namenode -checkpoint

3.等待30-40分钟,待checkpoint 完成后。到主节点上的current文件check fsimage 的修改时间,看是否已经同步成功。

然后执行./hadoop-daemon.shstop namenode ,停止second Namenode

4.修改主节点的conf 目录下的 hadoop-env.sh文件,修改其中的JVM参数。注意提前做好实验和计算估计

5.在主节点上 执行 ./hadoop-daemon.sh stop namenode,如果不成功就 kill -9 PID

6.重启NameNode ./hadoop-daemon.sh start namenode

   1).加载元数据文件fsimage(~10 min)

   2).加载操作日志edits(1~2 min)

   3).存储元数据到fsimage(3~4 min)

7.查看nameNode 日志,等待块汇报信息完成(10~15 min)

8.手动触发一次Full GC ,将重启过程中old区临时对象回收 

9.服务正常后,发送邮件说明集群恢复正常

10.后续定期观察邮件报表的GC情况

25    如何检查Namenode是否正常运行?

如果要检查Namenode是否正常工作,使用命令/etc/init.d/hadoop-0.20-namenodestatus或者就是简单的jps。

26    mapred.job.tracker命令的作用?

可以让你知道哪个节点是JobTracker。

27    /etc /init.d命令的作用是?

/etc /init.d说明了守护进程(服务)的位置或状态,其实是LINUX特性,和Hadoop关系不大。

28    如何在浏览器中查找Namenode?

如果你确实需要在浏览器中查找Namenode,你不再需要localhost:8021,Namenode的端口号是50070。

29    如何从SU转到Cloudera?

从SU转到Cloudera只需要键入exit。

30    启动和关闭命令会用到哪些文件?

Slaves及Masters。

31    Slaves由什么组成?

Slaves由主机的列表组成,每台1行,用于说明数据节点。

32    Masters由什么组成?

Masters同样是主机的列表组成,每台一行,用于说明第二Namenode服务器。

33    hadoop-env.sh是用于做什么的?

hadoop-env.sh提供了Hadoop中. JAVA_HOME的运行环境。

34    请列出正常的hadoop集群中hadoop都分别需要启动 哪些进程,他们的作用分别都是什么,请尽量列的详细一些。

namenode:负责管理hdfs中文件块的元数据,响应客户端请求,管理datanode上文件block的均衡,维持副本数量

Secondname:主要负责做checkpoint操作;也可以做冷备,对一定范围内数据做快照性备份。

Datanode:存储数据块,负责客户端对数据块的io请求

Jobtracker :管理任务,并将任务分配给 tasktracker。

Tasktracker: 执行JobTracker分配的任务。

35    请写出以下的shell命令 

(1)杀死一个job

答:hadoop job –list   得到job的id,然后执行 hadoopjob  -kill  jobId就可以杀死一个指定jobId的job工作了。

(2)删除hdfs上的 /tmp/aaa目录

答:hadoop fs  -rmr  /tmp/aaa

(3)加入一个新的存储节点和删除一个节点需要执行的命令

Hadoop  daemon.sh start  datanode

Hadooop  daemon.sh start   tasktracker/nodemanager

下线时,要在conf目录下的excludes文件中列出要下线的datanode机器主机名

然后在主节点中执行  hadoop  dfsadmin  -refreshnodes  à下线一个datanode

删除一个节点的时候,只需要在主节点执行

 hadoop mradmin -refreshnodes  ---à下线一个tasktracker/nodemanager

36    你认为用java , streaming , pipe方式开发map/reduce , 各有哪些优点

就用过 java 和 hiveQL。

Java 写 mapreduce 可以实现复杂的逻辑,如果需求简单,则显得繁琐。

HiveQL 基本都是针对 hive 中的表数据进行编写,但对复杂的逻辑(杂)很难进行实现。写起来简单。

37    请简述hadoop怎样实现二级排序(就是对key和value双排序)

   第一种方法是,Reducer将给定key的所有值都缓存起来,然后对它们再做一个Reducer内排序。但是,由于Reducer需要保存给定key的所有值,可能会导致出现内存耗尽的错误。

第二种方法是,将值的一部分或整个值加入原始key,生成一个组合key(实现WritableComparable接口或者调用 setSortComparatorClass函数),这样reduce获取的结果便是先按key排序,后按value排序的结果。

这两种方法各有优势,第一种方法编写简单,但并发度小,数据量大的情况下速度慢(有内存耗尽的危险),第二种方法则是将排序的任务交给MapReduce框架shuffle,更符合Hadoop/Reduce的设计思想。我们将编写一个Partitioner,确保拥有相同key(原始key,不包括添加的部分)的所有数据被发往同一个Reducer,还将编写一个Comparator,以便数据到达Reducer后即按原始key分组。

38    简述hadoop实现join的几种方法

假设要进行join的数据分别来自File1和File2.

reduceside join:

在map阶段,map函数同时读取两个文件File1和File2,对每条数据打一个标签(tag),比如:tag=0表示来自文件File1,tag=2表示来自文件File2。即:map阶段的主要任务是对不同文件中的数据打标签。

在reduce阶段,reduce函数获取key相同的来自File1和File2文件的value list, 然后对于同一个key,对File1和File2中的数据进行join(笛卡尔乘积)。即:reduce阶段进行实际的连接操作。

Mapside join:

Map side join是针对以下场景进行的优化:两个待连接表中,有一个表非常大,而另一个表非常小,以至于小表可以直接存放到内存中。这样,我们可以将小表复制多份,让每个map task内存中存在一份(比如存放到hash table中),然后只扫描大表:对于大表中的每一条记录key/value,在hash table中查找是否有相同的key的记录,如果有,则连接后输出即可。

为了支持文件的复制,Hadoop提供了一个类DistributedCache

SemiJoin:

SemiJoin,也叫半连接,是从分布式数据库中借鉴过来的方法。它的产生动机是:对于reduce side join,跨机器的数据传输量非常大,这成了join操作的一个瓶颈,如果能够在map端过滤掉不会参加join操作的数据,则可以大大节省网络IO。

实现方法很简单:选取一个小表,假设是File1,将其参与join的key抽取出来,保存到文件File3中,File3文件一般很小,可以放到内存中。在map阶段,使用DistributedCache将File3复制到各个TaskTracker上,然后将File2中不在File3中的 key对应的记录过滤掉,剩下的reduce阶段的工作与reduce side join相同。

reduceside join + BloomFilter:

在某些情况下,SemiJoin抽取出来的小表的key集合在内存中仍然存放不下,这时候可以使用BloomFiler以节省空间。

BloomFilter最常见的作用是:判断某个元素是否在一个集合里面。它最重要的两个方法是:add() 和contains()。最大的特点是不会存在false negative,即:如果contains()返回false,则该元素一定不在集合中,但会存在一定的true negative,即:如果contains()返回true,则该元素可能在集合中。

因而可将小表中的key保存到BloomFilter中,在map阶段过滤大表,可能有一些不在小表中的记录没有过滤掉(但是在小表中的记录一定不会过滤掉),这没关系,只不过增加了少量的网络IO而已。

39    请简述mapreduce中的combine和partition的作用

combiner是发生在map的最后一个阶段,其原理也是一个小型的reducer,主要作用是减少输出到reduce的数据量,缓解网络传输瓶颈,提高reducer的执行效率。

partition的主要作用将map阶段产生的所有kv对分配给不同的reducer task处理,可以将reduce阶段的处理负载进行分摊。

40    用mapreduce怎么处理数据倾斜问题

数据倾斜:map /reduce程序执行时,reduce节点大部分执行完毕,但是有一个或者几个reduce节点运行很慢,导致整个程序的处理时间很长,这是因为某一个key的条数比其他key多很多(有时是百倍或者千倍之多),这条key所在的reduce节点所处理的数据量比其他节点就大很多,从而导致某几个节点迟迟运行不完,此称之为数据倾斜。

 

用hadoop程序进行数据关联时,常碰到数据倾斜的情况,这里提供一种解决方法。

自己实现partition类,用key和value相加取hash值:

方式1:

源代码:

publicint getPartition(K key, V value,

                          intnumReduceTasks) {

    return (key.hashCode() &Integer.MAX_VALUE) % numReduceTasks;

  }

修改后

publicint getPartition(K key, V value,

                          intnumReduceTasks) {

    return (((key).hashCode()+value.hashCode())& Integer.MAX_VALUE) % numReduceTasks;

  }

 

方式2:

publicclassHashPartitioner<K, V> extends Partitioner<K,V> {

privateintaa= 0;

  /** Use {@linkObject#hashCode()} to partition. */

  publicintgetPartition(K key, V value,

                          intnumReduceTasks) {

    return (key.hashCode()+(aa++)& Integer.MAX_VALUE) % numReduceTasks;

  }

41    hadoop框架怎么来优化

(1)  从应用程序角度进行优化。由于mapreduce是迭代逐行解析数据文件的,怎样在迭代的情况下,编写高效率的应用程序,是一种优化思路。

(2)  对Hadoop参数进行调优。当前hadoop系统有190多个配置参数,怎样调整这些参数,使hadoop作业运行尽可能的快,也是一种优化思路。

(3) 从系统实现角度进行优化。这种优化难度是最大的,它是从hadoop实现机制角度,发现当前Hadoop设计和实现上的缺点,然后进行源码级地修改。该方法虽难度大,但往往效果明显。

(4)linux内核参数调整

从应用程序角度进行优化

(1) 避免不必要的reduce任务

如果mapreduce程序中reduce是不必要的,那么我们可以在map中处理数据, Reducer设置为0。这样避免了多余的reduce任务。

(2) 为job添加一个Combiner

为job添加一个combiner可以大大减少shuffle阶段从map task拷贝给远程reduce task的数据量。一般而言,combiner与reducer相同。

(3) 根据处理数据特征使用最适合和简洁的Writable类型

Text对象使用起来很方便,但它在由数值转换到文本或是由UTF8字符串转换到文本时都是低效的,且会消耗大量的CPU时间。当处理那些非文本的数据时,可以使用二进制的Writable类型,如IntWritable, FloatWritable等。二进制writable好处:避免文件转换的消耗;使map task中间结果占用更少的空间。

(4) 重用Writable类型

很多MapReduce用户常犯的一个错误是,在一个map/reduce方法中为每个输出都创建Writable对象。例如,你的Wordcout mapper方法可能这样写:

 

public void map(...) {

  …

 

  for(String word : words) {

   output.collect(new Text(word), new IntWritable(1));

  }

}

这样会导致程序分配出成千上万个短周期的对象。Java垃圾收集器就要为此做很多的工作。更有效的写法是:

class MyMapper … {

 Text wordText = new Text();

 IntWritable one = new IntWritable(1);

 public void map(...) {

   for (String word: words) {

     wordText.set(word);

     output.collect(wordText, one);

    }

  }

}

(5) 使用StringBuffer而不是String

当需要对字符串进行操作时,使用StringBuffer而不是String,String是read-only的,如果对它进行修改,会产生临时对象,而StringBuffer是可修改的,不会产生临时对象。

对参数进行调优

查看linux的服务,可以关闭不必要的服务

ntsysv

停止打印服务

#/etc/init.d/cups stop

#chkconfig cups off

关闭ipv6

#vim /etc/modprobe.conf

添加内容

alias net-pf-10 off

alias ipv6 off

 

调整文件最大打开数

查看: ulimit -a    结果:open files (-n) 1024

临时修改: ulimit -n4096

持久修改:

vi /etc/security/limits.conf在文件最后加上:

* soft nofile 65535
* hard nofile 65535
* soft nproc 65535
* hard nproc 65535

修改linux内核参数

vi /etc/sysctl.conf

添加

net.core.somaxconn= 32768

#web应用中listen函数的backlog默认会给我们内核参数的net.core.somaxconn限制到128,而nginx定义的NGX_LISTEN_BACKLOG默认为511,所以有必要调整这个值。

调整swap分区什么时候使用:

查看:cat/proc/sys/vm/swappiness

设置:vi /etc/sysctl.conf 

            在这个文档的最后加上这样一行: vm.swappiness=10

            表示物理内存使用到90%(100-10=90)的时候才使用swap交换区

关闭noatime

vi /etc/fstab

/dev/sda2    /data    ext3  noatime,nodiratime  0 0

设置readahead buffer

blockdev --setra READAHEAD 512 /dev/sda

 

一下是修改mapred-site.xml文件

修改最大槽位数

槽位数是在各个tasktracker上的mapred-site.xml上设置的,默认都是2

<property>  

           <name>mapred.tasktracker.map.tasks.maximum</name> #++++maptask的最大数

           <value>2</value>  

        </property>                 

     <property>  

           <name>mapred.tasktracker.reduce.tasks.maximum</name> #++++reducetask的最大数

               <value>2</value>  

      </property>  

调整心跳间隔

集群规模小于300时,心跳间隔为300毫秒

mapreduce.jobtracker.heartbeat.interval.min  心跳时间

mapred.heartbeats.in.second  集群每增加多少节点,时间增加下面的值

mapreduce.jobtracker.heartbeat.scaling.factor 集群每增加上面的个数,心跳增多少

启动带外心跳

mapreduce.tasktracker.outofband.heartbeat  默认是false

配置多块磁盘

mapreduce.local.dir

配置RPC hander数目

mapred.job.tracker.handler.count 默认是10,可以改成50,根据机器的能力

配置HTTP线程数目

tasktracker.http.threads  默认是40,可以改成100 根据机器的能力

选择合适的压缩方式

以snappy为例:

<property>  

           <name>mapred.compress.map.output</name>

           <value>true</value>  

        </property>                 

     <property>  

           <name>mapred.map.output.compression.codec</name> 

               <value>org.apache.hadoop.io.compress.SnappyCodec</value>  

      </property>  

启用推测执行机制

推测执行(Speculative Execution)是指在分布式集群环境下,因为程序BUG,负载不均衡或者资源分布不均等原因,造成同一个job的多个task运行速度不一致,有的task运行速度明显慢于其他task(比如:一个job的某个task进度只有10%,而其他所有task已经运行完毕),则这些task拖慢了作业的整体执行进度,为了避免这种情况发生,Hadoop会为该task启动备份任务,让该speculative task与原始task同时处理一份数据,哪个先运行完,则将谁的结果作为最终结果。

推测执行优化机制采用了典型的以空间换时间的优化策略,它同时启动多个相同task(备份任务)处理相同的数据块,哪个完成的早,则采用哪个task的结果,这样可防止拖后腿Task任务出现,进而提高作业计算速度,但是,这样却会占用更多的资源,在集群资源紧缺的情况下,设计合理的推测执行机制可在多用少量资源情况下,减少大作业的计算时间。

mapred.map.tasks.speculative.execution  默认是true

mapred.rduce.tasks.speculative.execution  默认是true

设置是失败容忍度

mapred.max.map.failures.percent   作业允许失败的map最大比例  默认值0,即0%

mapred.max.reduce.failures.percent  作业允许失败的reduce最大比例  默认值0,即0%

mapred.map.max.attemps  失败后最多重新尝试的次数 默认是4

mapred.reduce.max.attemps  失败后最多重新尝试的次数 默认是4

启动jvm重用功能

mapred.job.reuse.jvm.num.tasks  默认值1,表示只能启动一个task,若为-1,表示可以最多运行数不限制

设置任务超时时间

mapred.task.timeout  默认值600000毫秒,也就是10分钟。

合理的控制reduce的启动时间

mapred.reduce.slowstart.completed.maps  默认值0.05  表示map任务完成5%时,开始启动reduce任务

跳过坏记录

 当任务失败次数达到该值时,才会进入skip mode,即启用跳过坏记录数功能,也就是先试几次,不行就跳过

mapred.skip.attempts.to.start.skipping 默认值 2

map最多允许跳过的记录数

mapred.skip.map.max.skip.records 默认值0,为不启用

reduce最多允许跳过的记录数

mapred.skip.reduce.max.skip.records 默认值0,为不启用

换记录存放的目录

mapred.skip.out.dir  默认值${mapred.output.dir}/_logs/ 

 

42    我们在开发分布式计算job的时候,是否可以去掉reduce阶段

可以,例如我们的集群就是为了存储文件而设计的,不涉及到数据的计算,就可以将mapReduce都省掉。

比如,流量运营项目中的行为轨迹增强功能部分

43  怎么样才能实现去掉reduce阶段

在配置文件中将reduce设置为0

44    hadoop中常用的数据压缩算法

Lzo

Gzip

Default

Snapyy

如果要对数据进行压缩,最好是将原始数据转为SequenceFile  或者 Parquet File(spark)

45    mapreduce的调度模式(题意模糊,可以理解为yarn的调度模式,也可以理解为mr的内部工作流程)

appmaster作为调度主管,管理maptask和reducetask

Appmaster负责启动、监控maptask和reducetask

Maptask处理完成之后,appmaster会监控到,然后将其输出结果通知给reducetask,然后reducetask从map端拉取文件,然后处理;

当reduce阶段全部完成之后,appmaster还要向resourcemanager注销自己

46    reduce之后数据的输出量有多大(结合具体场景,比如pi)

Sca阶段的增强日志(1.5T---2T)

过滤性质的mr程序,输出比输入少

解析性质的mr程序,输出比输入多(找共同朋友)

47    datanode在什么情况下不会备份数据

在客户端上传文件时指定文件副本数量为1

datanode在强制关闭或者非正常断电不会备份

48    hdfs的体系结构

集群架构: 

namenode  datanode  secondarynamenode

 (active namenode ,standby namenode)journalnode  zkfc

内部工作机制:

数据是分布式存储的

对外提供一个统一的目录结构

对外提供一个具体的响应者(namenode)

数据的block机制,副本机制

Namenode和datanode的工作职责和机制

读写数据流程

Namenode负责管理datanode和记录元数据

Secondarynamenode负责合并日志

Datanode负责存储数据

49    flush的过程

答:flush是在内存的基础上进行的,首先写入文件的时候,会先将文件写到内存中,当内存写满的时候,一次性的将文件全部都写到硬盘中去保存,并清空缓存中的文件,

50    三个datanode中当有一个datanode出现错误时会怎样?

Namenode会通过心跳机制感知到datanode让其下线

在这个过程中会将这个datanode上的block块在集群中重新复制一份,恢复文件的副本数量

会引发运维团队快速响应,派出同事对下线datanode进行检测和修复,然后重新上线。

51    sqoop在导入数据到mysql中,如何不重复导入数据,如果存在数据问题,sqoop如何处理?

 

52    描述一下hadoop中,有哪些地方使用到了缓存机制,作用分别是什么?

答:缓存机制就是DistributedCash,就是在job任务执行前,将需要的文件拷贝到Task机器上进行缓存,提高mapreduce的执行效率。

53    MapReduce优化经验

答:

1)设置合理的map和reduce的个数。合理设置blocksize

2)避免出现数据倾斜

3)combine函数

4)对数据进行压缩

5)小文件处理优化:事先合并成大文件,combineTextInputformat,在hdfs上用mapreduce将小文件合并成SequenceFile大文件(key:文件名,value:文件内容)

6)参数优化

54    请列举出曾经修改过的/etc/下面的文件,并说明修改要解决什么问题?

答:/etc/profile这个文件,主要是用来配置环境变量。让hadoop命令可以在任意目录下面执行。

/ect/sudoers

/etc/hosts

/etc/sysconfig/network

/etc/inittab

 

55    讲一下mapreduce的大致流程,任务提交流程,任务运行流程

主要分为八个步骤

1/对文件进行切片规划

2/启动相应数量的maptask进程

3/调用FileInputFormat中的RecordReader,读一行数据并封装为k1v1

4/调用自定义的map函数,并将k1v1传给map

5/收集map的输出,进行分区和排序

6/reduce task任务启动,并从map端拉取数据

7/reduce task调用自定义的reduce函数进行处理

8/调用outputformat的recordwriter将结果数据输出

56    用mapreduce实现sql语 select  count (x) from  a  group by b;

将b作为key,结合wordcount进行讲解。

57    搭建hadoop集群 , master和slaves都运行哪些服务

答:master主要是运行我们的主节点,slaves主要是运行我们的从节点

58    hadoop运行原理

答:hadoop的主要核心是由两部分组成,HDFS和mapreduce,首先HDFS的原理就是分布式的文件存储系统,将一个大的文件,分割成多个小的文件,进行存储在多台服务器上。

Mapreduce的原理就是使用JobTracker和TaskTracker来进行作业的执行。Map就是将任务展开,reduce是汇总处理后的结果。

59    mapreduce的原理

答:mapreduce的原理就是将一个MapReduce框架,由一个单独的master JobTracker和每个集群节点一个slave TaskTracker共同组成。master负责调度构成一个作业的所有任务,这些的slave上,master监控它们的执行,重新执行已经失败的任务。而slave仅负责执行由maste指派的任务。

60    HDFS存储机制

答:HDFS主要是一个分布式的文件存储系统,由namenode来接收用户的操作请求,然后根据文件大小,以及定义的block块的大小,将大的文件切分成多个block块来进行保存

hdfs写流程

 

1、 client链接namenode存数据

2、 namenode记录一条数据位置信息(元数据),告诉client存哪。

3、 client用hdfs的api将数据块(默认是64M)存储到datanode上。

4、 datanode将数据水平备份。并且备份完将反馈client。

5、 client通知namenode存储块完毕。

6、 namenode将元数据同步到内存中。

7、 另一块循环上面的过程。

hdfs读流程

 

1、 client链接namenode,查看元数据,找到数据的存储位置。

2、 client通过hdfs的api并发读取数据。

3、 关闭连接。

61    举一个例子说明mapreduce是怎么运行的。

Wordcount

62    如何确认hadoop集群的健康状况

答:有完善的集群监控体系(ganglia,nagios)

Hdfs dfsadmin –report

Hdfs haadmin  –getServiceState  nn1

通过页面监控,脚本监控。

63    mapreduce作业,不让reduce输出,用什么代替reduce的功能。

Combine具有本地的reduce功能

64  hive如何调优

答:hive最终都会转化为mapreduce的job来运行,要想hive调优,实际上就是mapreduce调优,可以有下面几个方面的调优。解决收据倾斜问题,减少job数量,设置合理的map和reduce个数,对小文件进行合并,优化时把握整体,单个task最优不如整体最优。按照一定规则分区。

65    假设公司要建一个数据中心,你会如何处理?

先进行需求调查分析

设计功能划分

架构设计

吞吐量的估算

采用的技术类型

软硬件选型

成本效益的分析

项目管理

扩展性

安全性,稳定性

66    谈谈 hadoop1 和 hadoop2 的区别

答:

hadoop1的主要结构是由HDFS和mapreduce组成的,HDFS主要是用来存储数据,mapreduce主要是用来计算的,那么HDFS的数据是由namenode来存储元数据信息,datanode来存储数据的。Jobtracker接收用户的操作请求之后去分配资源执行task任务。

在hadoop2中,首先避免了namenode单点故障的问题,使用两个namenode来组成namenode  feduration的机构,两个namenode使用相同的命名空间,一个是standby状态,一个是active状态。用户访问的时候,访问standby状态,并且,使用journalnode来存储数据的原信息,一个namenode负责读取journalnode中的数据,一个namenode负责写入journalnode中的数据,这个平台组成了hadoop的HA就是high  availableAbility高可靠。

然后在hadoop2中没有了jobtracker的概念了,统一的使用yarn平台来管理和调度资源,yarn平台是由resourceManager和NodeManager来共同组成的,ResourceManager来接收用户的操作请求之后,去NodeManager上面启动一个主线程负责资源分配的工作,然后分配好了资源之后告知ResourceManager,然后ResourceManager去对应的机器上面执行task任务。

67    文件大小默认为 64M,改为 128M 有啥影响?

答:更改文件的block块大小,需要根据我们的实际生产中来更改block的大小,如果block定义的太小,大的文件都会被切分成太多的小文件,减慢用户上传效率,如果block定义的太大,那么太多的小文件可能都会存到一个block块中,虽然不浪费硬盘资源,可是还是会增加namenode的管理内存压力。

68    RPC 原理?

答:

1.调用客户端句柄;执行传送参数

2.调用本地系统内核发送网络消息

3. 消息传送到远程主机

4. 服务器句柄得到消息并取得参数

5. 执行远程过程

6. 执行的过程将结果返回服务器句柄

7. 服务器句柄返回结果,调用远程系统内核

8. 消息传回本地主机

9. 客户句柄由内核接收消息

10. 客户接收句柄返回的数据

69    以你的实际经验,说下怎样预防全表扫描

答:

1.应尽量避免在where 子句中对字段进行null 值判断,否则将导致引擎放弃使用索引而进行全表扫描
2.应尽量避免在 where 子句中使用!=或<>操作符,否则将引擎放弃使用索引而进行全表扫

3.扫描应尽量避免在 where 子句中使用or 来连接条件,否则将导致引擎放弃使用索引而进行全表扫描

4.in 和 not  in,用具体的字段列表代替,不要返回用不到的任何字段。in 也要慎用,否则会导致全表扫描

5.避免使用模糊查询
6.任何地方都不要使用select *from t

70    把公钥追加到授权文件的命令?该命令是否在 root 用户下执行?

答:ssh-copy-id –i ~/.ssh/id_rsa.pubroot@hadoop01

哪个用户需要做免密登陆就在哪个用户身份下执行

71    HadoopHA 集群中各个服务的启动和关闭的顺序?

答:假设有三台虚拟机,主机名分别为hadoop01、hadoop02和hadoop03

部署计划:

三台机器上都部署zookeeper、journalnode、nodemanager、datanode,而只有hadoop01和hadoop02这两台机器上部署了zkfc和resourcemanager以及namenode

启动流程:

第一步:在hadoop01、hadoop02、hadoop03启动zookeeper

第二步:在hadoop01机器上启动hdfs

第三步:在hadoop01机器上启动yarn

第四步:在hadoop02机器上单独启动一个resourcemanager

停止流程:

第一步:在hadoop01机器上停止hdfs

第二步:在hadoop01机器上停止yarn

第三步:在hadoop02机器上单独停止resourcemanager

第四步:在hadoop01、hadoop02、hadoop03上停止zookeeper

72    在 hadoop 开发过程中使用过哪些算法?其应用场景是什么?

答:排序,分组,topk,join,group

73    在实际工作中使用过哪些集群的运维工具,请分别阐述期作用。

答:nmon   ganglia   nagios

74    一台机器如何应对那么多的请求访问,高并发到底怎么实现,一个请求怎么产生的,在服务端怎么处理的,最后怎么返回给用户的,整个的环节操作系统是怎么控制的?

75    你们的数据是用什么导入到数据库的?导入到什么数据库?

处理完成之后的导出:利用 hive 处理完成之后的数据,通过 sqoop 导出到 mysql 数据库中,以供报表层使用.

76    你们业务数据量多大?有多少行数据?

(面试了三家,都问这个问题)开发时使用的是部分数据,不是全量数据,有将近一亿行(8、9 千万,具体不详,一般开发中也没人会特别关心这个问题)

77    你们处理数据是直接读数据库的数据还是读文本数据?

将日志数据导入到 hdfs 之后进行处理

78    你们提交的 job 任务大概有多少个?这些 job 执行完大概用多少时间?(面试了三家,都问这个问题)

没统计过,加上测试的,会与很多

Sca阶段,一小时运行一个job,处理时间约12分钟

Etl阶段,有2千多个job,从凌晨12:00开始次第执行,到早上5点左右全部跑完

79    job 的运行流程(提交一个 job 的流程)?

大致为:客户端向资源管理yarn申请资源,yarn分配好相应的资源,进行作业的运行,当作业运行完成时,yarn回收资源。具体如下: 
1、客户端Client提交job,会执行代码中的job.awitforcompletion(),在客户端创建了一个RunJar的进程,RunJar向Yarn的资源管理Resource Manager(RM)申请一个Job,过程中使用的是远程过程控制协议RPC和RM进行通信的。 
2、RM返回相关资源的提交路径staging-dir和这次job的jobID; 
3、Client向刚获得的资源路径staging-dir/jobID提交资源; 
4、向RM汇报资源提交结果; 
5、RM将job加入到任务队列中; 
6、各个Node Manager从RM中领取任务(NM时刻和RM保持通讯); 
7、RM在NM中分配运行资源容器Container; 
8、RM随机找到一台DataNode启动MRAppMaster作为这次job的管理进程; 
9、DM的MRAppMaster向RM注册自己; 
10、MRAppMaster启动Map任务进程,在RM中的container启动yarnChild进程用于maptask的运行; 
11、MRAppMaster启动Reduce任务,运行reduce任务; 
12、所有reduce任务运行完成,job完成后MRAppMaster向RM注销自己; 

80    Hadoop 生态圈中各种框架的运用场景?

HDFS:分布式文件系统,适合大数据的分布式存储

Mapreduce:并行计算框架,海量数据分析

Hbase:列式数据库,可集群化,可以使用shell、web、api等多种方式访问,适合高读写的场景

Hive:数据仓库工具,可以把hadoop下的原始结构化数据编程hive中的表,将hql语句转化为mapreduce执行。

Zookeeper:用于协调分布式系统上的各种服务,应用与hbase,实现namenode自动切换

Sqoop:用于在hadoop和关系型数据库之间交换数据。

Flume:用于日志的采集

Avro:数据序列化工具,用于支持大批数量数据交换的应用,支持二进制序列化方式,快速的处理大量的数据。

81    假如:Flume 收集到的数据很多个小文件,我需要写 MR 处理时将这些文件合并

(是在 MR 中进行优化,不让一个小文件一个 MapReduce)

他们公司主要做的是中国电信的流量计费为主,专门写 MR。

 

82    解释“hadoop”和“hadoop 生态系统”两个概念

http://www.linuxidc.com/Linux/2015-05/117499.htm

83    MapReduce 2.0”与“YARN”是否等同,尝试解释说明

MapReduce 2.0  --à mapreduce +yarn

84    MapReduce 2.0 中,MRAppMaster 主要作用是什么,MRAppMaster 如何实现任务容错的?

MRAppMaster是MapReduce的ApplicationMaster实现,它使得MapReduce应用程序可以直接运行于YARN之上。在YARN中,MRAppMaster负责管理MapReduce作业的生命周期,包括作业管理、资源申请与再分配、Container启动与释放、作业恢复等。

85    为什么会产生 yarn,它解决了什么问题,有什么优势?

MRv1架构的不足表现在大型集群上,当集群包含的节点超过4000个时,就会表现出一定的不可预测性,其中一个最大的问题是级联故障,由于要尝试复制数据和重载活动的节点,所以一个故障会通过网络泛洪形式导致整个集群严重恶化。

应该明确的一点是,旧的 Hadoop架构受到了 JobTracker 的高度约束,JobTracker 负责整个集群的资源管理和作业调度。新的 YARN 架构打破了这种模型,允许一个新 ResourceManager 管理跨应用程序的资源使用,ApplicationMaster 负责管理作业的执行。这一更改消除了一处瓶颈,还改善了将 Hadoop 集群扩展到比以前大得多的配置的能力。此外,不同于传统的 MapReduce,YARN 允许使用 MessagePassing Interface 等标准通信模式,同时执行各种不同的编程模型,包括图形处理、迭代式处理、机器学习和一般集群计算。

http://blog.csdn.net/qq_36864672/article/details/78427117

86    数据备份,你们是多少份,如果数据超过存储容量,你们怎么处理?

87    怎么提升多个 JOB 同时执行带来的压力,如何优化,说说思路?

88    你们的 hive 处理数据能达到的指标是多少?

89    hadoop中RecorderReader的作用是什么?

RecordReader负责从InputSplit中读取键值对(一个键值对属于一条记录),然后交给InputSplit对应的Mapper处理

90    在hadoop中定义的主要公用InputFormat中,哪个是默认值?

FileInputFormat

91    两个类TextInputFormat和KeyValueInputFormat的区别是什么?

答:TextInputFormat主要是用来格式化输入的文本文件的,KeyValueInputFormat则主要是用来指定输入输出的key,value类型的

92    在一个运行的hadoop任务中,什么是InputSplit?

      InputSplit是InputFormat中的一个方法,主要是用来切割输入文件的,将输入文件切分成多个小文件,然后每个小文件对应一个map任务

93    Hadoop框架中文件拆分是怎么调用的?

      InputFormat  --> TextInputFormat  -->RecordReader  --> LineRecordReader  --> LineReader

94    参考下列M/R系统的场景:hdfs块大小为64MB,输入类为FileInputFormat,有3个文件的大小分别为64KB,65MB, 127MB

会产生多少个maptask   4个    65M这个文件只有一个切片

95    如果没有自定义partitioner,那数据在被送达reducer前是如何被分区的?

      hadoop有一个默认的分区类,HashPartioer类,通过对输入的k2取hash值来确认map输出的k2,v2送到哪一个reduce中去执行。

96    分别举例什么情况要使用combiner,什么情况不使用?

      求平均数的时候就不需要用combiner,因为不会减少reduce执行数量。在其他的时候,可以依据情况,使用combiner,来减少map的输出数量,减少拷贝到reduce的文件,从而减轻reduce的压力,节省网络开销,提升执行效率

97    Hadoop中job和tasks之间的区别是什么?

Job是我们对一个完整的mapreduce程序的抽象封装

Task是job运行时,每一个处理阶段的具体实例,如maptask,reduce task,maptask和reduce task都会有多个并发运行的实例

98    hadoop中通过拆分任务到多个节点运行来实现并行计算,但某些节点运行较慢会拖慢整个任务的运行,hadoop采用全程机制应对这个情况?

Speculate 推测执行

99         有可能使hadoop任务输出到多个目录中吗?如果可以,怎么做?

      自定义outputformat或者用multioutputs工具

100         如何为一个hadoop任务设置mappers的数量?

Split机制

101         如何为一个hadoop任务设置要创建reduder的数量?

可以通过代码设置

具体设置多少个,应该根据硬件配置和业务处理的类型来决定

102         用mapreduce来实现下面需求?

现在有10个文件夹,每个文件夹都有1000000个url.现在让你找出top1000000url。

解答:topk

 

(还可以用treeMap, 到1000000了每来一个都加进去, 删掉最小的)

103         如何检查namenode是否正常运行?重启namenode的命令是什么?

通过节点信息和浏览器查看,通过脚本监控

Hadoop-deamon.sh start namenode

Hdfs-deamon.sh start namenode

104         一个datanode宕机,怎么一个流程恢复

Datanode宕机了后,如果是短暂的宕机,可以实现写好脚本监控,将它启动起来。如果是长时间宕机了,那么datanode上的数据应该已经被备份到其他机器了,那这台datanode就是一台新的datanode了,删除他的所有数据文件和状态文件,重新启动。

105         Hadoop的namenode宕机,怎么解决?

先分析宕机后的损失,宕机后直接导致client无法访问,内存中的元数据丢失,但是硬盘中的元数据应该还存在,如果只是节点挂了,重启即可,如果是机器挂了,重启机器后看节点是否能重启,不能重启就要找到原因修复了。但是最终的解决方案应该是在设计集群的初期就考虑到这个问题,做namenode的HA。

106         Mapreduce的map数量和reduce数量怎么确定,怎么配置

Map的数量由数据块决定,reduce数量随便配置

107         一个Hadoop环境,整合了Hbase和Hive,是否有必要给HDFS和Hbase都配置压缩策略,请给出压缩策略的建议。

hdfs在存储的时候不会将数据进行压缩,如果想进行压缩,我们可以在向hdfs上传数据的时候进行压缩。

1、 采用压缩流

//压缩文件

    public static void compress(String codecClassName) throws Exception{

        Class<?> codecClass = Class.forName(codecClassName);

        Configuration conf = new Configuration();

        FileSystem fs = FileSystem.get(conf);

        CompressionCodec codec = (CompressionCodec)ReflectionUtils.newInstance(codecClass, conf);

        //指定压缩文件路径

        FSDataOutputStream outputStream = fs.create(new Path("/user/hadoop/text.gz"));

        //指定要被压缩的文件路径

        FSDataInputStream in = fs.open(new Path("/user/hadoop/aa.txt"));

        //创建压缩输出流

        CompressionOutputStream out = codec.createOutputStream(outputStream); 

        IOUtils.copyBytes(in, out, conf);

        IOUtils.closeStream(in);

        IOUtils.closeStream(out);

    }

2、 采用序列化文件

public void testSeqWrite() throws Exception {

                  Configuration conf = new Configuration();// 创建配置信息

                  conf.set("fs.default.name", "hdfs://master:9000");// hdfs默认路径

                  conf.set("hadoop.job.ugi", "hadoop,hadoop");// 用户和组信息

                  String uriin = "hdfs://master:9000/ceshi2/";// 文件路径

                  FileSystem fs = FileSystem.get(URI.create(uriin), conf);// 创建filesystem

                  Path path = new Path("hdfs://master:9000/ceshi3/test.seq");// 文件名

                  IntWritable k = new IntWritable();// key,相当于int

                  Text v = new Text();// value,相当于String

                  SequenceFile.Writer w = SequenceFile.createWriter(fs, conf, path,

                                   k.getClass(), v.getClass());// 创建writer

                  for (int i = 1; i < 100; i++) {// 循环添加

                          k.set(i);

                          v.set("abcd");

                          w.append(k, v);

                  }

                  w.close();

                  IOUtils.closeStream(w);// 关闭的时候flush

                  fs.close();

         }

hbase为列存数据库,本身存在压缩机制,所以无需设计。

108         如果要存储海量的小文件(大小都是几百K~几k),请简述自己的设计方案。

1、 将小文件打成har文件存储

2、 将小文件序列化到hdfs中

109         有两个文本文件,文件中的数据按行存放,请编写MapReduce程序,找到两个文件中彼此不相同的行。

写个mapreduce链  用依赖关系,一共三个mapreduce,第一个处理第一个文件,第二个处理第二个文件,第三个处理前两个的输出结果,第一个mapreduce将文件去重,第二个mapreduce也将文件去重,第三个做wordcount,wordcount为1的结果就是不同的

110         Mapreduce 一些流程,经过哪些步骤

Map—combiner—partition—sort—copy—sort—grouping—reduce

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值