15章 分布式大数据处理平台Hadoop习题
选择题
1、分布式系统的特点不包括以下的( D )。
A. 分布性 B. 高可用性 C. 可扩展性 D.串行性
2、Hadoop平台中的( B )负责数据的存储。
A. Namenode B. Datanode C. JobTracker D. SecondaryNamenode
3、HDFS中block的默认副本数量是( A )。
A.3 B.2 C.1 D.4
4、下面与HDFS类似的框架是( C )。
A. NTFS B. FAT32 C. GFS D. EXT3
5、以下关于SecondaryNamenode的说法正确的是( B )。
A.是元数据节点出现故障时的备用节点
B.周期性地将元数据节点的命名空间镜像文件与修改日志进行合并
C.与元数据节点之间无需交互
D.对内存没有要求
6、下列关于MapReduce的说法不正确的是( C )。
A.MapRecuce可用于处理分布在几千台机器上的数据
B.MapReduce是一种处理大数据的分布式计算模式
C.MapReduce程序只能用C语言编写
D.MapReduce隐藏了并行计算的细节,方便使用
7、下面哪一个是一种编程模型,将大规模的数据处理工作拆分成互相独立的任务然后进行并行处理( A )。
A.MapReduce B.HDFS C.HBase D.Pig
8、HBase基于( A )存储底层数据。
A.HDFS B.Hadoop C.内存 D.MapReduce
9、下面关于HBase错误的是( A )。
A.不是开源的 B.面向列的 C.分布式的 D.NoSQL数据库
10、配置Hadoop时,JAVA_HOME包含在( B )配置文件中。
A.Hadoop-default.xml B.hadoop-env.sh
C.Hadoop-site.xml D.Configuration.xsl
15.2 填空题
1、HDFS的基本数据存储单位是( 数据块 )。
2、MapReduce按照时间顺序可以分为输入分片、( Map阶段 )、Combiner阶段、( Shuffle阶段 )和( Reduce阶段 )。
15.3 简答题
1、Hadoop主要有哪些优点?
答:
- 扩容能力强。Hadoop 能可靠存储和处理PB级的数据。
- 成本低。Hadoop 能通过普通机器组成的服务器集群来分发和处理数据,服务器集群规模可达数千个节点。
- 效率高。Hadoop 能通过分发数据,在数据所在的节点上并行地进行处理,使得处理非常快速。
- 可靠性。Hadoop 能自动维护数据的多份副本,并在任务失败后自动地重新部署计算任务。
- 高容错性。Hadoop能在不同的节点上维护多份副本,对于访问失败的节点,Hadoop会自动寻找副本所在的节点进行访问
2、请用描述HDFS读取文件的具体步骤。
答:
- 客户端用分布式文件系统的open()函数打开文件。
- 分布式文件系统远程调用RPC,获取元数据节点的文件数据块信息;对于返回的每一个数据块信息,元数据节点只返回保存数据块的数据节点的地址;接着分布式文件系统返回FSDataInputStream对象给客户端,其中封装了读取数据的方法。
- 客户端调用FSDataInputStream中的read()函数开始读取数据;FSDataInputStream封装了DFSInputStream对象中用于管理元数据节点和数据节点的I/O操作的方法,客户端调用read()函数后,使用DFSInputStream对象中的I/O操作;DFSInputStream连接一直保持,直到当前读取的文件中第一个数据块的最近数据节点中的数据读到客户端后,DFSInputStream会关闭和此数据节点的连接;然后连接此文件的下一个数据块的最近数据节点。若在读取数据的过程中,客户端与数据节点的通信出现错误,则尝试连接包含此数据块的下一个数据节点;失败的数据节点将被记录,以后不再连接。
- 当客户端读取完数据时,调用DFSInputStream的close()函数,结束读取过程。
3、请描述HDFS写文件的具体过程。
答:
- 客户端调用create()函数来创建文件。
- 分布式文件系统远程调用RPC,在元数据节点的命名空间中创建一个新的文件。元数据节点在确定文件不存在,并且客户端有创建文件的权限后,创建新文件。创建完成后,分布式文件系统返回DFSOutputStream对象给客户端,用于写数据。文件系统返回DFSOutputStream对象给客户端,用于写数据。
- 当客户端开始写数据时,调用DFSOutputStream中的方法将数据分成块并写入数据队列;数据队列由Data Streamer读取,并通知元数据节点分配数据节点,用来存储数据块(每个数据块均默认复制3份),分配的数据节点放在一个管道(Pipeline)里。其中,Data Streamer是在调用DFSOutputStream对象过程中开启的线程。
- Data Streamer将数据块写入管道涉及的第一个数据节点,第一个数据节点将数据块发送给第二个数据节点,第二个数据节点将数据发送给第三个数据节点。
- DFSOutputStream将发送出去的数据块信息保存在ack queue队列里。如果数据块传输成功的话,就会删除ack queue队列里对应的数据块;如果不成功的话就将ack queue里的数据块取出来放到数据队列的末尾,等待重新传输。
- 当客户端结束写入数据过程,则调用DFSOutputStream中的close()函数,此时客户端不再向管道中写入数据,并关闭管道。在等到所有的写入数据的成功应答后,通知元数据节点写入完毕。
15.4 解答题
1、根据用户手机上网的行为记录,基于 MapReduce编程模型设计程序统计不同手机号的用户使用的总流量。其中,数据记录的字段描述如下。
序号 字段 字段类型 描述 0 reportTime long 记录报告时间戳 1 msisdn String 手机号码 2 apmac String AP mac 3 acmac String AC mac 4 host String 访问的网址 5 siteType String 网址种类 6 upPackNum long 上行数据包数,单位:个 7 downPackNum long 下行数据包数,单位:个 8 upPayLoad long 上行总流量,要注意单位的转换:byte 9 downPayLoad long 下行总流量。要注意单位的转换:byte 10 httpStatus String HTTP Response
数据文件具体内容如下。
1363157985066 13726230503 00-FD-07-A4-72-B8:CMCC 120.196.100.82 i02.c.aliimg.com 24 27 2481 24681 200
1363157995052 13826544101 5C-0E-8B-C7-F1-E0:CMCC 120.197.40.4 4 0 264 0 200
1363157991076 13926435656 20-10-7A-28-CC-0A:CMCC 120.196.100.99 2 4 132 1512 200
1363154400022 13926251106 5C-0E-8B-8B-B1-50:CMCC 120.197.40.4 4 0 240 0 200
1363157993044 18211575961 94-71-AC-CD-E6-18:CMCC-EASY 120.196.100.99 iface.qiyi.com 视频网站 15 12 1527 2106 200
1363157993055 13560439658 C4-17-FE-BA-DE-D9:CMCC 120.196.100.99 18 15 1116 954 200
1363157995033 15920133257 5C-0E-8B-C7-BA-20:CMCC 120.197.40.4 sug.so.360.cn 信息安全 20 20 3156 2936 200
1363157983019 13719199419 68-A1-B7-03-07-B1:CMCC-EASY 120.196.100.82 4 0 240 0 200
1363157984041 13660577991 5C-0E-8B-92-5C-20:CMCC-EASY 120.197.40.4 s19.cnzz.com 站点统计 24 9 6960 690 200
1363157973098 15013685858 5C-0E-8B-C7-F7-90:CMCC 120.197.40.4 rank.ie.sogou.com 搜索引擎 28 27 3659 3538 200
1363157986029 15989002119 E8-99-C4-4E-93-E0:CMCC-EASY 120.196.100.99 www.umeng.com 站点统计 3 3 1938 180 200
1363157992093 13560439658 C4-17-FE-BA-DE-D9:CMCC 120.196.100.99 15 9 918 4938 200
1363157986041 13480253104 5C-0E-8B-C7-FC-80:CMCC-EASY 120.197.40.4 3 3 180 180 200
1363157995093 13922314466 00-FD-07-A2-EC-BA:CMCC 120.196.100.82 img.qfc.cn 12 12 3008 3720 200
1363157982040 13502468823 5C-0A-5B-6A-0B-D4:CMCC-EASY 120.196.100.99 y0.ifengimg.com 综合门户 57 102 7335 110349 200
1363157986072 18320173382 84-25-DB-4F-10-1A:CMCC-EASY 120.196.100.99 input.shouji.sogou.com 搜索引擎 21 18 9531 2412 200
1363157990043 13925057413 00-1F-64-E1-E6-9A:CMCC 120.196.100.55 t3.baidu.com 搜索引擎 69 63 11058 48243 200
1363157988072 13760778710 00-FD-07-A4-7B-08:CMCC 120.196.100.82 2 2 120 120 200
1363157985079 13823070001 20-7C-8F-70-68-1F:CMCC 120.196.100.99 6 3 360 180 200
1363157985069 13600217502 00-1F-64-E2-E8-B1:CMCC 120.196.100.55 18 138 1080 186852 200
答:
我们需要从数据中统计出每个用户的所有请求的使用的总流量,即统计用户所有请求的上行流量(索引为8)、下行流量(索引为9)之和。得到结果后输出到单独的文件中。
编程环境搭建:
创建一个maven项目,并导入Hadoop的相关依赖。
集群环境准备:将题目中给定的数据文件上传到hdfs中。
Step1:将用户手机号、上行流量、下行流量、总流量封装到一个自定义的bean中,由于这个bean需要在Hadoop中进行传输,我们还需要让bean实现hadoop中的序列化接口。
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import org.apache.hadoop.io.Writable;
public class Flow implements Writable{
private String phone; //手机号
private long up; //上行流量
private long down; //下线流量
private long sum; //总流量
//无参构造函数
public Flow() {
}
//有参构造函数
public Flow(String phone, long up, long down) {
super();
this.phone = phone;
this.up = up;
this.down = down;
this.sum=this.up+this.down;
}
@Override
public void write(DataOutput out) throws IOException {
out.writeUTF(this.phone);
out.writeLong(this.up);
out.writeLong(this.down);
out.writeLong(this.sum);
}
@Override
public void readFields(DataInput in) throws IOException {
this.phone=in.readUTF();
this.up=in.readLong();
this.down=in.readLong();
this.sum=in.readLong();
}
@Override
public String toString() {
return this.up+" "+this.down+" "+this.sum;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public long getUp() {
return up;
}
public void setUp(long up) {
this.up = up;
}
public long getDown() {
return down;
}
public void setDown(long down) {
this.down = down;
}
public long getSum() {
return sum;
}
}
Step2:编写Map方法
import java.io.IOException;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.commons.lang.StringUtils;
public class FlowSumMapper extends Mapper<LongWritable, Text, Text, Flow>{
@Override
protected void map(LongWritable key, Text value,
Context context)
throws IOException, InterruptedException {
//拿一行数据
String line = value.toString();
//切分成各个字段
String[] fields = StringUtils.split(line, " ");
//拿到我们需要的字段
String phone = fields[1];
long up= Long.parseLong(fields[8]);
long down = Long.parseLong(fields[9]);
//封装数据为kv并输出 <phone:flow>
context.write(new Text(phone), new Flow(phone,up,down));
}
}
Step3:编写Reduce方法
import java.io.IOException;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Reducer;
public class FlowSumReducer extends Reducer<Text, Flow, Text, Flow> {
@Override
protected void reduce(Text key, Iterable<Flow> values,
Context context)
throws IOException, InterruptedException {
// <phone:{flow,flow,flow,flow}>
// reduce中的业务逻辑就是遍历values,然后进行累加求和再输出
long up = 0;//
long down = 0;
for (Flow flow : values) {
up += flow.getUp();
down += flow.getDown();
}
context.write(key, new Flow(key.toString(), up, down));
}
}
Step4:编写方法入口函数
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.conf.Configured;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import org.apache.hadoop.util.Tool;
import org.apache.hadoop.util.ToolRunner;
public class FlowSumRunner extends Configured implements Tool{
@Override
public int run(String[] args) throws Exception {
Configuration conf = new Configuration();
Job job = Job.getInstance(conf);
job.setJarByClass(FlowSumRunner.class);
job.setMapperClass(FlowSumMapper.class);
job.setReducerClass(FlowSumReducer.class);
//设置map程序的输出key、value
job.setMapOutputKeyClass(Text.class);
job.setMapOutputValueClass(Flow.class);
//设置 输出 key、value
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(Flow.class);
FileInputFormat.setInputPaths(job, new Path(args[0]));//输入数据路径 /flow/input
//检查一下参数所指定的输出路径是否存在,如果已存在,先删除
Path output = new Path(args[1]);
FileSystem fs = FileSystem.get(conf);
if(fs.exists(output)){
fs.delete(output, true);
}
FileOutputFormat.setOutputPath(job, new Path(args[1]));//输出数据路径 /flow/output
return job.waitForCompletion(true)?0:1;
}
public static void main(String[] args) throws Exception {
int status = ToolRunner.run(new Configuration(), new FlowSumRunner(), args);
System.exit(status);
}
}
Step4:至此,程序编写完毕,使用maven工具将程序打包成一个jar包,并提交到hadoop集群中进行运行。具体的命令如下。其中,{}中写FlowSumRunner的全限定类名。
hadoop jar flow.jar {FlowSumRunner} /flow/input/ /flow/output/
Step5:查看运行结果 hadoop fs -cat /flow/output/part-r-00000
13480253104 720 800 1520
13502468823 408 29340 29748
13560439658 23568 1600 25168
13600217502 747408 800 748208
13602846565 48 7752 7800
13660577991 36 27840 27876
13719199419 0 800 800
13726230503 9924 98724 108648
13760778710 480 800 1280
13823070001 720 800 1520
13826544101 0 800 800
13922314466 12032 14880 26912
13925057413 252 44232 44484
13926251106 56 6908 6964
13926435656 6048 800 6848
15013685858 108 14636 14744
15920133257 80 12624 12704
15989002119 12 7752 7764
18320173382 72 38124 38196
原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/290917.html