各位老铁们,大家好,今天由我来为大家分享大型分分布式网站源码分享,以及大型分布式网站架构设计与实践pdf的相关问题知识,希望对大家有所帮助。如果可以帮助到大家,还望关注收藏下本站,您的支持是我们最大的动力,谢谢大家了哈,下面我们开始吧!
前言
布式计算思想
思想引入
首先,来看三个问题:
假设有1T的文件,文件中的每一行都是一个数字;如何在一台48core,64G内存的服务器上处理这个大文件,将这个大文件排序呢?
假设有两个很大的文件(内存只能读入一小部分),文件中的每一行都是一个url字符串,共有10亿行.如何在一台48core,64G内存的服务器上处理这两个大文件,将这两个大文件中相同的url找出呢?
在一座山上有三个山头,每个山头都有红木,橡木和樟木,有三个工人分别负责在一个山头砍树,砍好的树木由三辆分别运送红木,橡木和樟木的运输车运送到位于其他地方的三家加工厂,这三家加工厂分别加工红木,橡木和樟木.整个处理流程应该是怎样的?
1.对于第一个问题,这个1T的文件是无法完全读入内存中,那么我们应该怎么做呢?可以想到的是,将这个大文件按行从上而下分割成一个个小文件分别读入服务器内存中处理,服务器对每一个小文件进行排序,最后再将每个内部有序的小文件进行归并排序,从而产生一个有序文件.
整个过程的流程图如下:
虽然上述流程能够完成需求,但是它存在一个问题—-三次磁盘IO(第一次是切割文件时需要读写一次,第二次是服务器排序时读写一下,第三次是在归并排序时读写一次).像这种磁盘IO是非常耗时的,从而使得处理效率降低.有什么地方可以改善吗?
答案是有的.关键就在于第一次怎么切割,第一次切割时,去限定每个小文件的数值范围,比如说第一个小文件的数值范围是0~100,第二个是101~200,以此类推.这样当服务器对每个小文件内部排好序时,只需将这些小文件拼接即可.
整个过程的流程图如下:
上述流程相较于第一种减少一次IO(归并排序的IO),从而提高处理的效率.
2.对于第二个问题,还是要让整个过程只有两次磁盘IO.首先要知道每一个字符串对应一个HashCode编码.假设这两个文件都要拆成1000个小文件.那么切割策略就有了:先将每一个url的HashCode编码计算出来,然后将这个值与1000取模,每个&34;作为一个小文件的标识.那么,两个大文件中相同的url一定在模值相等的切割后的小文件中.
整个过程的流程图如下:
上述流程是一台服务器再处理,假设现在有1000台服务器,试想会是什么样情景呢?
整个过程的流程图如下:
上述流程的思想已经很接近MapReduce处理的思想.
3.对于第三个问题,通常会认为伐木工砍完树之后,将去掉树枝的树干运送到加工厂.加工厂加工后还会剩下一批废料,这些废料也占用了&34;,对它们的传输是无用的,因此也降低生成的效率,那能否将这些无用的废料从&34;中除去呢?
很简单,只需要在山头那边对树木进行一定程度的加工不就可以了吗.例如,可以先分别加工出红木,橡木和樟木的桌面,桌腿再进行运输,假设一次运输只能运送同一个组件,那么这会造成运输次数的增加,也降低了运输效率.
既然如此,桌面桌腿加工出来了,再对它们进行简单组装形成半成品,运输时直接输送半成品.
可以看到,我们在山头上对树干进行了两次加工,分别产出桌面桌腿和桌子的半成品,这一过程在MapReduce中称为Combiner.Combiner的过程减少了山头输出的数据,类似于减少了网络IO
上述第三个过程就跟MapReduce的过程类似了.MapReduce主要分两个过程Map和Reduce.这里工人相当于Map;每个山头上的组装称为combiner;将半成品运输到各个工厂称为shuffle;将运输过来的半成品组装成成品的过程称为reduce;
MapReduce处理流程
官方配图:
MapReduce具体分为四步:
Map阶段;
ShuffleWrite阶段
ShuffleRead阶段
Reduce阶段
MapReduce中的几个名词:
maptask–Map端开启的处理线程,一个maptask读取的数据称为一个split(切片),
split–切片的概念,假设数据存放在HDFS上,每一个maptask读取的数据就是一个切片,但这并不是在读取前就切好的.split的默认大小与一个block的大小一致,即block数=split数=maptask数.
也可设置split与block之间的大小关系,例如,2block=split=maptask;1/2block=split=maptask.也可设置split与block之间的大小关系,例如,2block=split=maptask;1/2block=split=maptask.
split是一个逻辑概念,maptask会一行一行的读取某个block中的数据,为防止数据被切分,它还会多读取下一个block的第一行数据(HDFS中按照字节存储数据,所以极有可能一条数据被拆分存放在两个block中).
key-value:MR处理过程中,数据都是通过键值对的形式传递的.起初key值为block中一条记录的偏移量(long类型),value为block中的数据(String类型),两个偏移量之间是一条记录.经过map,reduce处理过后,key-value内容根据需求而定.
map–对数据切分的方法,输入类型为<LongWritable,Text>,输出类型<key,value>由需求决定.
HashPartitioner–默认分区器.相同的分区由相同的reducetask处理,分区策略:经map处理后,将key的Hash值与reducetask的个数(NUM)取模,模值相同的key将放在同一个分区中.
bufferinmemory–内存缓冲区,map对split内容处理后先写入内存缓冲区,进入缓冲区的每一条记录都由三部分组成:分区号,key,value.buffer大小默认100M,分为两份,一份80M,一份20M.
当达到溢写比例(buffer中约有80M数据)时,会将这80M数据封锁,然后对数据进行聚合,排序,排序时先按照分区排序,分区相同的再按照key排序.排序完成后就将数据溢写到磁盘上.每次溢写产生一个磁盘小文件.
聚合排序过程中,如果还有内容继续往buffer中写的话,这些内容将被写入buffer剩余的20M中.
merge–map阶段的merge基于磁盘小文件进行合并,合并时按照分区号进行合并,将相同分区号的数据放在同一个大分区中.合并完成后会对相同分区的数据进行排序.
–reduce阶段的merge合并时会对每一个有序的磁盘小文件进行排序,这些小文件已经属于同一个分区.最后合并成一个磁盘大文件时,会根据key值进行分组,key值相同的为一组
fetch–reducetask进程从maptask产生的磁盘大文件中拉取数据,拉取的数据先放入Reduce端的内存中,内存大小默认为1G的70%.内存中数据达到一定的溢写比例后,就会将内存中的数据溢写到磁盘小文件中,溢写之前也会进行排序.
reduce–对有序的大文件中key值相同的一组数据处理的方法,输入参数由map端的输出参数决定,输出参数由需求决定,都是key-value的形式.
reducetask–Reduce端开启的处理线程,一个reducetask产生一个output文件.
MapReduce执行流程:
假设MR处理的数据存储在HDFS上,HDFS上的数据是以block的形式存放.
假设有三个maptask和三个reducetask线程.
maptask线程
执行流程
1.1map阶段
1.1.1maptask从HDFS中读取文件内容,HDFS中文件以block块的形式存在.整个过程数据以键值对的形式传输,输入map前的key为文件中一条数据的偏移量,value为这条数据的内容.
1.1.2map方法根据需求将传入的value进行切割,再根据需求设置输出类型的key和value.
1.2shufflewrite阶段
1.2.1分区器分区(打标签),分区的目的就是让同一个分区的数据被同一个reducetask来处理.默认的分区器是HashPartitioner,它的分区策略为将经map处理后得到的key的Hash值与reducetask的个数(NUM)取模,模值相同的key将放在同一个分区中.
1.2.2向内存buffer中写数据,将打上标签的map输出的数据写入到内存buffer中,内存buffer默认大小为100M.此时每一个数据记录都由三部分组成:(1)分区号;(2)key;(3)value;
1.2.3当内存buffer中写入的数据达到80M时,此时会将这80M的内存封锁,封锁后对内存中的数据进行聚合(Combiner),combiner完成后再根据分区号排序,分区号排序完之后再按照key的大小排序(Sort).此时这80M的数据中相同分区号的数据存放在一起,并且分区内的数据是有序的.
1.2.4溢写(Spill),内存buffer达到80M内存时,排序完成后对这80M数据溢写.将数据写入磁盘,形成一个磁盘小文件,文件根据分区号划分并且内部有序.每次内存buffer溢写都会产生这么一个小文件.
1.2.5合并(Merge),所有溢写完毕后,会将磁盘小文件合并成一个大文件,合并时先对数据进行聚合(Combiner),然后再使用归并算法将各个小文件合并成一个根据分区号划分且内部有序的大文件.每一个maptask都会产生这么一个大文件.
reducetask线程
执行流程:
2.1shuffleread阶段
1.1.1读取map产生的大文件中对应分区的数据.将分区数据写入内存中,内存大小默认为1G,当内存中写入的数据达到溢写比例时,内存的溢写过程与map中buffer溢写几乎一样,首先封锁数据,然后对数据排序,排序完成后将排好序的数据写入磁盘小文件中.
1.1.2当map中对应分区的数据全部读取之后.reducetask会对所有的磁盘小文件进行归并算法合并,合并成一个内部有序的磁盘大文件.大文件中相同key值的数据为同一组数据.
2.2reduce阶段
1.2.1遍历整个大文件,对同一组的数据调用一次reduce方法,将输出的<key,value>结果写入output文件中.每个reducetask产生一个输出文件,输出文件不再合并.
MapReduce整个过程流程图:
流程中可以看出,一共进行了四次排序,而这四此排序的最终目的都是在于提高最终分组的效率.
MR核心思想:“相同”的key为一组,调用一次reduce方法,方法内迭代这一组数据进行计算
MapReduce概述
MapReduce的定义
HadoopMapReduceisasoftwareframeworkforeasilywritingapplicationswhichprocessvastamountsofdata(multi-terabytedata-sets)in-parallelonlargeclusters(thousandsofnodes)ofcommodityhardwareinareliable,fault-tolerantmanner.
上文是官方对MapReduce的描述,大意为MapReduce是一个软件框架,用来写应用程序,该程序以可靠,容错的方式能够在大型集群(上千节点)上处理海量数据(多为TB级别).
换句话说,MapReduce是一个分布式计算框架,它能将用户编写的程序和其默认组件整合为一个分布式处理程序,并发运行在Hadoop集群上.
MapReduce的优缺点
优点
易于编程.实现一个分布式程序只需简单地实现几个接口即可,而且这个程序可以放到大量廉价的服务器(或PC机)上执行,门槛低.
扩展性较好.当计算资源得不到满足时,可通过简单地增加服务器数量来提升计算性能.
高容错性.既然MapReduce部署在廉价机上,那么就要求它具备较高的容错性.当一个节点挂掉后,集群内部可以自动地将计算任务转移到其他服务器节点上执行.不仅保证任务不会失败,而且还不需要开发人员的参与.
适合海量数据的离线处理.MapReduce可实现有上千台服务器集群的并发工作,从而提高计算能力.
缺点
不适合实时计算.无法像MySQL一样,在毫秒或秒级内返回结果.
不适合流式计算.MR自身设计决定它处理的数据集必须是静态的,不能动态变化.
不适合有向图(DAG)计算.当多个程序之间有相互依赖关系,比如说前一个程序的输出要作为后一个程序的输入时,MR在处理时,需要先将前一个程序的处理结果写入磁盘,然后后一个程序再去磁盘读取结果之后才能处理,从而造成大量磁盘IO,导致性能低下.
最后指定是奉上代码啊–通过mapreduce编写wordcount
写上这份代码也是因为工作的关系,频繁的重复被wordcount配置的恐惧,尤其是在scala横飞的今天,长久的不再使用有的时候真的记不住啊,从网上找各种相应的代码,五味杂陈,所以在这里将简单的wordcount的代码整理出来供大家使用,也供自己参考
首先就是我们的Mapper层
importorg.apache.hadoop.io.IntWritable;\nimportorg.apache.hadoop.io.LongWritable;\nimportorg.apache.hadoop.io.Text;\nimportorg.apache.hadoop.mapreduce.Mapper;\nimportjava.io.IOException;\npublicclassWcMapperextendsMapper<LongWritable,Text,Text,IntWritable>{\nprotectedvoidmap(LongWritablekey,Textvalue,Contextcontext)throwsIOException,InterruptedException{\n/**map阶段的业务逻辑就写在自定义的map()方法中\n*maptask会对每一行输入数据调用一次我们自定义的map()方法\n*/\n//1将maptask传给我们的文本内容先转换成String\nStringline=value.toString();\n//2根据空格将这一行切分成单词\nString[]words=line.split(&34;);\n//3将单词输出为<单词,1>\nfor(Stringword:words){\n//将单词作为key,将次数1作为value,以便于后续的数据分发,可以根据单词分发,以便于相同单词会到相同的reducetask中\ncontext.write(newText(word),newIntWritable(1));\n}\n}\n}
接下来是reduce层
importorg.apache.hadoop.io.IntWritable;\nimportorg.apache.hadoop.io.Text;\nimportorg.apache.hadoop.mapreduce.Reducer;\nimportjava.io.IOException;\npublicclassWcReduceextendsReducer<Text,IntWritable,Text,IntWritable>{\n/**\n*key,是一组相同单词kv对的key\n*/\n@Override\nprotectedvoidreduce(Textkey,Iterable<IntWritable>values,Contextcontext)throwsIOException,InterruptedException{\nintcount=0;\n//1汇总各个key的个数\nfor(IntWritablevalue:values){\ncount+=value.get();\n}\n//2输出该key的总次数\ncontext.write(key,newIntWritable(count));\n}\n}
最后是实现,但是在实现这里,主要分为三类
1、本地测试
packagecom.msb;\nimportorg.apache.hadoop.conf.Configuration;\nimportorg.apache.hadoop.fs.Path;\nimportorg.apache.hadoop.io.IntWritable;\nimportorg.apache.hadoop.io.Text;\nimportorg.apache.hadoop.mapreduce.Job;\nimportorg.apache.hadoop.mapreduce.lib.input.FileInputFormat;\nimportorg.apache.hadoop.mapreduce.lib.output.FileOutputFormat;\npublicclassWcMain{\npublicstaticvoidmain(String[]args)throwsException{\n//1获取配置信息,或者job对象实例\nConfigurationconfiguration=newConfiguration();\n//设置本地运行模式\nconfiguration.set(&34;,&34;);\nJobjob=Job.getInstance(configuration);\n//6指定本程序的jar包所在的本地路径\n//job.setJar(&34;);\njob.setJarByClass(WcMain.class);\n//2指定本业务job要使用的mapper/Reducer业务类\njob.setMapperClass(WcMapper.class);\njob.setReducerClass(WcReduce.class);\n//3指定mapper输出数据的kv类型\njob.setMapOutputKeyClass(Text.class);\njob.setMapOutputValueClass(IntWritable.class);\n//4指定最终输出的数据的kv类型\njob.setOutputKeyClass(Text.class);\njob.setOutputValueClass(IntWritable.class);\n//5指定job的输入原始文件所在目录\nFileInputFormat.setInputPaths(job,newPath(args[0]));\nFileOutputFormat.setOutputPath(job,newPath(args[1]));\n//7将job中配置的相关参数,以及job所用的java类所在的jar包,提交给yarn去运行\n//job.submit();\nbooleanresult=job.waitForCompletion(true);\nSystem.exit(result?0:1);\n}\n}
设置args[0]和args[1]的位置,也可以直接在代码中写死
注意,output路径不能有对应的文件夹
2、提交集群运行
packagecom.msb;\nimportorg.apache.hadoop.conf.Configuration;\nimportorg.apache.hadoop.fs.Path;\nimportorg.apache.hadoop.io.IntWritable;\nimportorg.apache.hadoop.io.Text;\nimportorg.apache.hadoop.mapreduce.Job;\nimportorg.apache.hadoop.mapreduce.lib.input.FileInputFormat;\nimportorg.apache.hadoop.mapreduce.lib.output.FileOutputFormat;\npublicclassWcMainCluser{\npublicstaticvoidmain(String[]args)throwsException{\n//1获取配置信息,或者job对象实例\nConfigurationconfiguration=newConfiguration();\n/*本地提交集群运行\n**/\n//configuration.set(&34;,&34;);\nconfiguration.set(&34;,&34;);\nJobjob=Job.getInstance(configuration);\n//6指定本程序的jar包所在的本地路径\n//job.setJar(&34;);\njob.setJarByClass(WcMainCluser.class);\n//2指定本业务job要使用的mapper/Reducer业务类\njob.setMapperClass(WcMapper.class);\njob.setReducerClass(WcReduce.class);\n//3指定mapper输出数据的kv类型\njob.setMapOutputKeyClass(Text.class);\njob.setMapOutputValueClass(IntWritable.class);\n//4指定最终输出的数据的kv类型\njob.setOutputKeyClass(Text.class);\njob.setOutputValueClass(IntWritable.class);\n//5指定job的输入原始文件所在目录\nFileInputFormat.setInputPaths(job,newPath(&34;));\nFileOutputFormat.setOutputPath(job,newPath(&34;));\n//7将job中配置的相关参数,以及job所用的java类所在的jar包,提交给yarn去运行\njob.submit();\nbooleanresult=job.waitForCompletion(true);\nSystem.exit(result?0:1);\n}\n}
3、提交yarn运行
packagecom.msb;\nimportorg.apache.hadoop.conf.Configuration;\nimportorg.apache.hadoop.fs.Path;\nimportorg.apache.hadoop.io.IntWritable;\nimportorg.apache.hadoop.io.Text;\nimportorg.apache.hadoop.mapreduce.Job;\nimportorg.apache.hadoop.mapreduce.lib.input.FileInputFormat;\nimportorg.apache.hadoop.mapreduce.lib.output.FileOutputFormat;\npublicclassWcMainYarn{\npublicstaticvoidmain(String[]args)throwsException{\n//1获取配置信息,或者job对象实例\nConfigurationconfiguration=newConfiguration();\n/*本地提交集群运行\n**/\nconfiguration.set(&34;,&34;);\nconfiguration.set(&34;,&34;);\nconfiguration.set(&34;,&34;);\nconfiguration.set(&34;,&34;);\nJobjob=Job.getInstance(configuration);\n//6指定本程序的jar包所在的本地路径\njob.setJar(&34;);\n//job.setJar(&34;);\njob.setJarByClass(WcMainYarn.class);\n//2指定本业务job要使用的mapper/Reducer业务类\njob.setMapperClass(WcMapper.class);\njob.setReducerClass(WcReduce.class);\n//3指定mapper输出数据的kv类型\njob.setMapOutputKeyClass(Text.class);\njob.setMapOutputValueClass(IntWritable.class);\n//4指定最终输出的数据的kv类型\njob.setOutputKeyClass(Text.class);\njob.setOutputValueClass(IntWritable.class);\n//5指定job的输入原始文件所在目录\nFileInputFormat.setInputPaths(job,newPath(&34;));\nFileOutputFormat.setOutputPath(job,newPath(&34;));\n//7将job中配置的相关参数,以及job所用的java类所在的jar包,提交给yarn去运行\njob.submit();\nbooleanresult=job.waitForCompletion(true);\nSystem.exit(result?0:1);\n}\n}
4、将代码打包提交到集群中运行
将idea中创建的项目进行打包,并上传到hadoop集群中
打包:
上传到集群之后,通过命令进行运行
hadoopjarjar包名com.msb.WordCount(需要执行文件的路径名)
注意:
在这个地方有很多人本地进行测试或者连接集群的时候没有办法进行,是因为没有进行相应的修改,需要在本地windows下进行hadoop的配置,配置过程参考hadoop配置的博客
感谢大家支持!可以转发评论关注一波!以后会多多给大家分享干货。
关于大型分分布式网站源码分享,大型分布式网站架构设计与实践pdf的介绍到此结束,希望对大家有所帮助。