首页 文章 精选 留言 我的

精选列表

搜索[原理],共10002篇文章
优秀的个人博客,低调大师

MapReduce Shuffle原理 与 Spark Shuffle原理

MapReduce的Shuffle过程介绍 Shuffle的本义是洗牌、混洗,把一组有一定规则的数据尽量转换成一组无规则的数据,越随机越好。MapReduce中的Shuffle更像是洗牌的逆过程,把一组无规则的数据尽量转换成一组具有一定规则的数据。 为什么MapReduce计算模型需要Shuffle过程?我们都知道MapReduce计算模型一般包括两个重要的阶段:Map是映射,负责数据的过滤分发;Reduce是规约,负责数据的计算归并。Reduce的数据来源于Map,Map的输出即是Reduce的输入,Reduce需要通过Shuffle来获取数据。 从Map输出到Reduce输入的整个过程可以广义地称为Shuffle。Shuffle横跨Map端和Reduce端,在Map端包括Spill过程,在Reduce端包括copy和sort过程,如图所示: Spill过程 Spill过程包括输出、排序、溢写、合并等步骤,如图所示: Collect 每个Map任务不断地以<key, value>对的形式把数据输出到在内存中构造的一个环形数据结构中。使用环形数据结构是为了更有效地使用内存空间,在内存中放置尽可能多的数据。 这个数据结构其实就是个字节数组,叫Kvbuffer,名如其义,但是这里面不光放置了<key, value>数据,还放置了一些索引数据,给放置索引数据的区域起了一个Kvmeta的别名,在Kvbuffer的一块区域上穿了一个IntBuffer(字节序采用的是平台自身的字节序)的马甲。<key, value>数据区域和索引数据区域在Kvbuffer中是相邻不重叠的两个区域,用一个分界点来划分两者,分界点不是亘古不变的,而是每次Spill之后都会更新一次。初始的分界点是0,<key, value>数据的存储方向是向上增长,索引数据的存储方向是向下增长,如图所示: Kvbuffer的存放指针bufindex是一直闷着头地向上增长,比如bufindex初始值为0,一个Int型的key写完之后,bufindex增长为4,一个Int型的value写完之后,bufindex增长为8。 索引是对<key, value>在kvbuffer中的索引,是个四元组,包括:value的起始位置、key的起始位置、partition值、value的长度,占用四个Int长度,Kvmeta的存放指针Kvindex每次都是向下跳四个“格子”,然后再向上一个格子一个格子地填充四元组的数据。比如Kvindex初始位置是-4,当第一个<key, value>写完之后,(Kvindex+0)的位置存放value的起始位置、(Kvindex+1)的位置存放key的起始位置、(Kvindex+2)的位置存放partition的值、(Kvindex+3)的位置存放value的长度,然后Kvindex跳到-8位置,等第二个<key, value>和索引写完之后,Kvindex跳到-32位置。 Kvbuffer的大小虽然可以通过参数设置,但是总共就那么大,<key, value>和索引不断地增加,加着加着,Kvbuffer总有不够用的那天,那怎么办?把数据从内存刷到磁盘上再接着往内存写数据,把Kvbuffer中的数据刷到磁盘上的过程就叫Spill,多么明了的叫法,内存中的数据满了就自动地spill到具有更大空间的磁盘。 关于Spill触发的条件,也就是Kvbuffer用到什么程度开始Spill,还是要讲究一下的。如果把Kvbuffer用得死死得,一点缝都不剩的时候再开始Spill,那Map任务就需要等Spill完成腾出空间之后才能继续写数据;如果Kvbuffer只是满到一定程度,比如80%的时候就开始Spill,那在Spill的同时,Map任务还能继续写数据,如果Spill够快,Map可能都不需要为空闲空间而发愁。两利相衡取其大,一般选择后者。 Spill这个重要的过程是由Spill线程承担,Spill线程从Map任务接到“命令”之后就开始正式干活,干的活叫SortAndSpill,原来不仅仅是Spill,在Spill之前还有个颇具争议性的Sort。 Sort 先把Kvbuffer中的数据按照partition值和key两个关键字升序排序,移动的只是索引数据,排序结果是Kvmeta中数据按照partition为单位聚集在一起,同一partition内的按照key有序。 Spill Spill线程为这次Spill过程创建一个磁盘文件:从所有的本地目录中轮训查找能存储这么大空间的目录,找到之后在其中创建一个类似于“spill12.out”的文件。Spill线程根据排过序的Kvmeta挨个partition的把<key, value>数据吐到这个文件中,一个partition对应的数据吐完之后顺序地吐下个partition,直到把所有的partition遍历完。一个partition在文件中对应的数据也叫段(segment)。 所有的partition对应的数据都放在这个文件里,虽然是顺序存放的,但是怎么直接知道某个partition在这个文件中存放的起始位置呢?强大的索引又出场了。有一个三元组记录某个partition对应的数据在这个文件中的索引:起始位置、原始数据长度、压缩之后的数据长度,一个partition对应一个三元组。然后把这些索引信息存放在内存中,如果内存中放不下了,后续的索引信息就需要写到磁盘文件中了:从所有的本地目录中轮训查找能存储这么大空间的目录,找到之后在其中创建一个类似于“spill12.out.index”的文件,文件中不光存储了索引数据,还存储了crc32的校验数据。(spill12.out.index不一定在磁盘上创建,如果内存(默认1M空间)中能放得下就放在内存中,即使在磁盘上创建了,和spill12.out文件也不一定在同一个目录下。) 每一次Spill过程就会最少生成一个out文件,有时还会生成index文件,Spill的次数也烙印在文件名中。索引文件和数据文件的对应关系如下图所示: 话分两端,在Spill线程如火如荼的进行SortAndSpill工作的同时,Map任务不会因此而停歇,而是一无既往地进行着数据输出。Map还是把数据写到kvbuffer中,那问题就来了:<key, value>只顾着闷头按照bufindex指针向上增长,kvmeta只顾着按照Kvindex向下增长,是保持指针起始位置不变继续跑呢,还是另谋它路?如果保持指针起始位置不变,很快bufindex和Kvindex就碰头了,碰头之后再重新开始或者移动内存都比较麻烦,不可取。Map取kvbuffer中剩余空间的中间位置,用这个位置设置为新的分界点,bufindex指针移动到这个分界点,Kvindex移动到这个分界点的-16位置,然后两者就可以和谐地按照自己既定的轨迹放置数据了,当Spill完成,空间腾出之后,不需要做任何改动继续前进。分界点的转换如下图所示: Map任务总要把输出的数据写到磁盘上,即使输出数据量很小在内存中全部能装得下,在最后也会把数据刷到磁盘上。 Merge Map任务如果输出数据量很大,可能会进行好几次Spill,out文件和Index文件会产生很多,分布在不同的磁盘上。最后把这些文件进行合并的merge过程闪亮登场。 Merge过程怎么知道产生的Spill文件都在哪了呢?从所有的本地目录上扫描得到产生的Spill文件,然后把路径存储在一个数组里。Merge过程又怎么知道Spill的索引信息呢?没错,也是从所有的本地目录上扫描得到Index文件,然后把索引信息存储在一个列表里。到这里,又遇到了一个值得纳闷的地方。在之前Spill过程中的时候为什么不直接把这些信息存储在内存中呢,何必又多了这步扫描的操作?特别是Spill的索引数据,之前当内存超限之后就把数据写到磁盘,现在又要从磁盘把这些数据读出来,还是需要装到更多的内存中。之所以多此一举,是因为这时kvbuffer这个内存大户已经不再使用可以回收,有内存空间来装这些数据了。(对于内存空间较大的土豪来说,用内存来省却这两个io步骤还是值得考虑的。) 然后为merge过程创建一个叫file.out的文件和一个叫file.out.Index的文件用来存储最终的输出和索引。 一个partition一个partition的进行合并输出。对于某个partition来说,从索引列表中查询这个partition对应的所有索引信息,每个对应一个段插入到段列表中。也就是这个partition对应一个段列表,记录所有的Spill文件中对应的这个partition那段数据的文件名、起始位置、长度等等。 然后对这个partition对应的所有的segment进行合并,目标是合并成一个segment。当这个partition对应很多个segment时,会分批地进行合并:先从segment列表中把第一批取出来,以key为关键字放置成最小堆,然后从最小堆中每次取出最小的<key, value>输出到一个临时文件中,这样就把这一批段合并成一个临时的段,把它加回到segment列表中;再从segment列表中把第二批取出来合并输出到一个临时segment,把其加入到列表中;这样往复执行,直到剩下的段是一批,输出到最终的文件中。 最终的索引数据仍然输出到Index文件中。 Map端的Shuffle过程到此结束。 Copy Reduce任务通过HTTP向各个Map任务拖取它所需要的数据。每个节点都会启动一个常驻的HTTP server,其中一项服务就是响应Reduce拖取Map数据。当有MapOutput的HTTP请求过来的时候,HTTP server就读取相应的Map输出文件中对应这个Reduce部分的数据通过网络流输出给Reduce。 Reduce任务拖取某个Map对应的数据,如果在内存中能放得下这次数据的话就直接把数据写到内存中。Reduce要向每个Map去拖取数据,在内存中每个Map对应一块数据,当内存中存储的Map数据占用空间达到一定程度的时候,开始启动内存中merge,把内存中的数据merge输出到磁盘上一个文件中。 如果在内存中不能放得下这个Map的数据的话,直接把Map数据写到磁盘上,在本地目录创建一个文件,从HTTP流中读取数据然后写到磁盘,使用的缓存区大小是64K。拖一个Map数据过来就会创建一个文件,当文件数量达到一定阈值时,开始启动磁盘文件merge,把这些文件合并输出到一个文件。 有些Map的数据较小是可以放在内存中的,有些Map的数据较大需要放在磁盘上,这样最后Reduce任务拖过来的数据有些放在内存中了有些放在磁盘上,最后会对这些来一个全局合并。 Merge Sort 这里使用的Merge和Map端使用的Merge过程一样。Map的输出数据已经是有序的,Merge进行一次合并排序,所谓Reduce端的sort过程就是这个合并的过程。一般Reduce是一边copy一边sort,即copy和sort两个阶段是重叠而不是完全分开的。 Reduce端的Shuffle过程至此结束。 Spark的Shuffle过程介绍 Shuffle Writer Spark丰富了任务类型,有些任务之间数据流转不需要通过Shuffle,但是有些任务之间还是需要通过Shuffle来传递数据,比如wide dependency的group by key。 Spark中需要Shuffle输出的Map任务会为每个Reduce创建对应的bucket,Map产生的结果会根据设置的partitioner得到对应的bucketId,然后填充到相应的bucket中去。每个Map的输出结果可能包含所有的Reduce所需要的数据,所以每个Map会创建R个bucket(R是reduce的个数),M个Map总共会创建M*R个bucket。 Map创建的bucket其实对应磁盘上的一个文件,Map的结果写到每个bucket中其实就是写到那个磁盘文件中,这个文件也被称为blockFile,是Disk Block Manager管理器通过文件名的Hash值对应到本地目录的子目录中创建的。每个Map要在节点上创建R个磁盘文件用于结果输出,Map的结果是直接输出到磁盘文件上的,100KB的内存缓冲是用来创建Fast Buffered OutputStream输出流。这种方式一个问题就是Shuffle文件过多。 针对上述Shuffle过程产生的文件过多问题,Spark有另外一种改进的Shuffle过程:consolidation Shuffle,以期显著减少Shuffle文件的数量。在consolidation Shuffle中每个bucket并非对应一个文件,而是对应文件中的一个segment部分。Job的map在某个节点上第一次执行,为每个reduce创建bucket对应的输出文件,把这些文件组织成ShuffleFileGroup,当这次map执行完之后,这个ShuffleFileGroup可以释放为下次循环利用;当又有map在这个节点上执行时,不需要创建新的bucket文件,而是在上次的ShuffleFileGroup中取得已经创建的文件继续追加写一个segment;当前次map还没执行完,ShuffleFileGroup还没有释放,这时如果有新的map在这个节点上执行,无法循环利用这个ShuffleFileGroup,而是只能创建新的bucket文件组成新的ShuffleFileGroup来写输出。 比如一个Job有3个Map和2个reduce:(1) 如果此时集群有3个节点有空槽,每个节点空闲了一个core,则3个Map会调度到这3个节点上执行,每个Map都会创建2个Shuffle文件,总共创建6个Shuffle文件;(2) 如果此时集群有2个节点有空槽,每个节点空闲了一个core,则2个Map先调度到这2个节点上执行,每个Map都会创建2个Shuffle文件,然后其中一个节点执行完Map之后又调度执行另一个Map,则这个Map不会创建新的Shuffle文件,而是把结果输出追加到之前Map创建的Shuffle文件中;总共创建4个Shuffle文件;(3) 如果此时集群有2个节点有空槽,一个节点有2个空core一个节点有1个空core,则一个节点调度2个Map一个节点调度1个Map,调度2个Map的节点上,一个Map创建了Shuffle文件,后面的Map还是会创建新的Shuffle文件,因为上一个Map还正在写,它创建的ShuffleFileGroup还没有释放;总共创建6个Shuffle文件。 Shuffle Fetcher Reduce去拖Map的输出数据,Spark提供了两套不同的拉取数据框架:通过socket连接去取数据;使用netty框架去取数据。 每个节点的Executor会创建一个BlockManager,其中会创建一个BlockManagerWorker用于响应请求。当Reduce的GET_BLOCK的请求过来时,读取本地文件将这个blockId的数据返回给Reduce。如果使用的是Netty框架,BlockManager会创建ShuffleSender用于发送Shuffle数据。 并不是所有的数据都是通过网络读取,对于在本节点的Map数据,Reduce直接去磁盘上读取而不再通过网络框架。 Reduce拖过来数据之后以什么方式存储呢?Spark Map输出的数据没有经过排序,Spark Shuffle过来的数据也不会进行排序,Spark认为Shuffle过程中的排序不是必须的,并不是所有类型的Reduce需要的数据都需要排序,强制地进行排序只会增加Shuffle的负担。Reduce拖过来的数据会放在一个HashMap中,HashMap中存储的也是<key, value>对,key是Map输出的key,Map输出对应这个key的所有value组成HashMap的value。Spark将Shuffle取过来的每一个<key, value>对插入或者更新到HashMap中,来一个处理一个。HashMap全部放在内存中。 Shuffle取过来的数据全部存放在内存中,对于数据量比较小或者已经在Map端做过合并处理的Shuffle数据,占用内存空间不会太大,但是对于比如group by key这样的操作,Reduce需要得到key对应的所有value,并将这些value组一个数组放在内存中,这样当数据量较大时,就需要较多内存。 当内存不够时,要不就失败,要不就用老办法把内存中的数据移到磁盘上放着。Spark意识到在处理数据规模远远大于内存空间时所带来的不足,引入了一个具有外部排序的方案。Shuffle过来的数据先放在内存中,当内存中存储的<key, value>对超过1000并且内存使用超过70%时,判断节点上可用内存如果还足够,则把内存缓冲区大小翻倍,如果可用内存不再够了,则把内存中的<key, value>对排序然后写到磁盘文件中。最后把内存缓冲区中的数据排序之后和那些磁盘文件组成一个最小堆,每次从最小堆中读取最小的数据,这个和MapReduce中的merge过程类似。 MapReduce和Spark的Shuffle过程对比 MapReduce Spark collect 在内存中构造了一块数据结构用于map输出的缓冲 没有在内存中构造一块数据结构用于map输出的缓冲,而是直接把输出写到磁盘文件 sort map输出的数据有排序 map输出的数据没有排序 merge 对磁盘上的多个spill文件最后进行合并成一个输出文件 在map端没有merge过程,在输出时直接是对应一个reduce的数据写到一个文件中,这些文件同时存在并发写,最后不需要合并成一个 copy框架 jetty netty或者直接socket流 对于本节点上的文件 仍然是通过网络框架拖取数据 不通过网络框架,对于在本节点上的map输出文件,采用本地读取的方式 copy过来的数据存放位置 先放在内存,内存放不下时写到磁盘 一种方式全部放在内存; 另一种方式先放在内存 merge sort 最后会对磁盘文件和内存中的数据进行合并排序 对于采用另一种方式时也会有合并排序的过程 Shuffle后续优化方向 通过上面的介绍,我们了解到,Shuffle过程的主要存储介质是磁盘,尽量的减少IO是Shuffle的主要优化方向。我们脑海中都有那个经典的存储金字塔体系,Shuffle过程为什么把结果都放在磁盘上,那是因为现在内存再大也大不过磁盘,内存就那么大,还这么多张嘴吃,当然是分配给最需要的了。如果具有“土豪”内存节点,减少Shuffle IO的最有效方式无疑是尽量把数据放在内存中。下面列举一些现在看可以优化的方面,期待经过我们不断的努力,TDW计算引擎运行地更好。 MapReduce Shuffle后续优化方向 压缩:对数据进行压缩,减少写读数据量; 减少不必要的排序:并不是所有类型的Reduce需要的数据都是需要排序的,排序这个nb的过程如果不需要最好还是不要的好; 内存化:Shuffle的数据不放在磁盘而是尽量放在内存中,除非逼不得已往磁盘上放;当然了如果有性能和内存相当的第三方存储系统,那放在第三方存储系统上也是很好的;这个是个大招; 网络框架:netty的性能据说要占优了; 本节点上的数据不走网络框架:对于本节点上的Map输出,Reduce直接去读吧,不需要绕道网络框架。 Spark Shuffle后续优化方向 Spark作为MapReduce的进阶架构,对于Shuffle过程已经是优化了的,特别是对于那些具有争议的步骤已经做了优化,但是Spark的Shuffle对于我们来说在一些方面还是需要优化的。 压缩:对数据进行压缩,减少写读数据量; 内存化:Spark历史版本中是有这样设计的:Map写数据先把数据全部写到内存中,写完之后再把数据刷到磁盘上;考虑内存是紧缺资源,后来修改成把数据直接写到磁盘了;对于具有较大内存的集群来讲,还是尽量地往内存上写吧,内存放不下了再放磁盘。 转载:http://www.csdn.net/article/2014-05-19/2819831-TDW-Shuffle/1

优秀的个人博客,低调大师

RPC原理

Remote Procedure Call RPC——远程过程调用协议,它是一种通过网络从远程计算机程序上请求服务,而不须要了解底层网络技术的协议。 RPC协议假定某些传输协议的存在。如TCP或UDP,为通信程序之间携带信息数据。在OSI网络通信模型中,RPC跨越了传输层和应用层。RPC使得开发包含网络分布式多程序在内的应用程序更加easy。 RPC採用客户机/server模式。请求程序就是一个客户机。而服务提供程序就是一个server。首先,客户机调用进程发送一个有进程參数的调用信息到服务进程,然后等待应答信息。 在server端,进程保持睡眠状态直到调用信息的到达为止。当一个调用信息到达,server获得进程參数,计算结果,发送答复信息,然后等待下一个调用信息。最后,client调用进程接收答复信息,获得进程结果。然后调用运行继续进行。 hadoop的整个体系结构就是构建在RPC之上的(见org.apache.hadoop.ipc)。 样例 Server.java import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.ipc.RPC; import org.apache.hadoop.ipc.Server; public class RPCServer { static final String ADDRESS = "localhost"; static final int PORT = 12345; public static void main(String[] args)throws Exception { Server server = new RPC.Builder(new Configuration()) .setInstance(new RPCBiz()) .setBindAddress(ADDRESS) .setPort(PORT) .setProtocol(RPCBizable.class) .build(); server.start(); } } Client.java import java.net.InetSocketAddress; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.ipc.RPC; public class RPCClient { public static void main(String[] args) throws Exception{ RPCBizable proxy = RPC.getProxy(RPCBizable.class, 10010, new InetSocketAddress("localhost", 12345), new Configuration()); final String result = proxy.hello("yew1eb"); System.out.println(result); //关闭网络连接 RPC.stopProxy(proxy); } } RPCBiz.java public class RPCBiz implements RPCBizable{ @Override public String hello(String name){ System.out.println("我被调用"); return "hello "+name; } } RPCBizable.java public interface RPCBizable { public static final long versionID = 10010; public String hello(String name); } 总结 RPC是一个远程过程调用。 client调用服务端的方法,意味着调用服务端的对象中的方法。 假设服务端的对象同意client调用,那么这个对象必须实现接口。 假设client可以调用到服务端对象的方法。那么这些方法一定位于对象的接口中。 链接 https://en.wikipedia.org/wiki/Remote_procedure_call 本文转自mfrbuaa博客园博客,原文链接:http://www.cnblogs.com/mfrbuaa/p/5381688.html,如需转载请自行联系原作者

优秀的个人博客,低调大师

MapReduce原理

1.什么是MapReduce? MapReduce是由Google公司的Jeffrey Dean和Sanjay Ghemawat开发的一个针对大规模群组中的海量数据处理的分布式编程模型。MapReduce实现了两个功能。Map把一个函数应用于集合中的所有成员,然后返回一个基于这个处理的结果集。而Reduce是把从两个或更多个Map中,通过多个线程,进程或者独立系统并行执行处理的结果集进行分类和归纳。Map()和Reduce()两个函数可能会并行运行,即使不是在同一的系统的同一时刻。 Google用MapReduce来索引每个抓取过来的Web页面。它取代了2004开始试探的最初索引算法,它已经证明在处理大量和非结构化数据集时更有效。用不同程序设计语言实现了多个MapReduce,包括Java, C++, Python, Perl, Ruby和C,其它语言。在某些范例里,如Lisp或者Python, Map()和Reduce()已经集成到语言自身的结构里面。通常,这些函数可能会如下定义: Map()函数把大数据集进行分解操作到两个或更多的小“桶”。而一个“桶”则是包含松散定义的逻辑记录或者文本行的集合。每个线程,处理器或者系统在独立的“桶”上执行Map()函数,去计算基于每个逻辑记录处理的一系列中间值。合并的结果值就会如同是单个Map()函数在单个“桶”上完全一致。Map()函数的通常形式是: Reduce()函数把从内存,磁盘或者网络介质提取过来的一个或多个中间结果列表,对列表中的每个元素逐一执行一个函数。完成操作的最终结果是通过对所有运行reduce()操作的处理结果进行分类和解释。Reduce()函数的通常形式是: MapReduce的实现把业务逻辑从多个处理逻辑中分离出来了,map()和reduce()函数跨越多个系统,通过共享池和部分RPC的形式来达到彼此之间的同步和通信。这里的业务逻辑是由用户自定义的函数子实现,并且这些函数子只能用在逻辑记录处理的工作上,而不用关心多个处理操作的问题。这样一旦MapReduce框架就位,就能通过大量的处理器快速的转变为应用系统的并行处理。因为开发人员可以把精力花在写函数子上面了。MapReduce簇可以通过替换函数子和提供新的数据源来重新使用,而无需每次都对整个应用进行编译,测试和部署。 2.实现MapReduce MapReduce()的目的是为了大型集群的系统能在大数据集上进行并行工作。 图1显示了一个运行在一个主系统上的主程序,协调其它实例进行map()或者reduce()操作,然后从每个reduce操作中收集结果。 【图1】 主应用程序负责把基础的数据集分解到“桶”中。桶的最佳大小依赖于应用,结点的数量和可用的I/O带宽。这些“桶”通常存储在磁盘,但有必要也可能分散到主存中,这依赖于具体的应用。“桶”将作为map()函数的输入。 主应用程序也负责调度和分散几个MapReduce的核心备份,除了控制者给空闲的处理器或线程分配了调整map()和reduce()任务之外,它们是完全相致的。控制者会持续跟踪每个map()和reduce()任务的状态,并且可以作为map()和reduce()任务之间路由中间结果的管道。每个map()任务处理器完全指派给“桶”,然后产生一个存到共享存储区域的中间结果集。共享存储可以设计成分布缓存,磁盘或其它设备等形式。当一个新的中间结果写入共享存储区域后,任务就向控制者发出通知,并提供指向其共享存储位置的句柄。 当新的中间结果可用时,控制者分配reduce()任务。这个任务通过应用独立的中间键值来实现排序,使相同的数据能聚集在一起,以提供更快的检索。大块的结果集可以进行外部排序,reduce()任务遍历整个排序的数据,把每个唯一的键和分类的结果传递到用户的reduce()函数子进行处理。 通过map()和reduce()实例终端的处理,当所有的“桶”都用完,然后全部的reduce()任务就通知控制者,以说明它们的结果已经产生了。控制者就向主应用程序发出检索这个结果的信号。主应用程序可能就直接操作这些结果,或者重新分配到不同的MapReduce控制者和任务进行进一步的处理, 显示情况下MapReduce的实现可能通常分配给控制者,map()和reduce()任务分配给单独的系统。Google操作模型是基于跨越大量的廉价硬件设备上组成的集群或者白盒子上面部署MapReduce应用。为了处理它自己的桶的需要,每个白盒子都有本地存储装置,一个合理数量的私有内存(2到4GB RAM)和至少两个处理内核。白盒子是可互相交换的,主应用程序可能把集群中的任何机器指派为控制者,而这个机器就把map()和reduce()任务分派给其它连接的白盒子。 3.基于Java的MapReduce实现 Google的环境是为它自己的需求定制和适应它们的操作环境。比如,为了它的MapReduce实现更好的执行这种类型的操作,使其更优化,Google使用了专有的文件系统用来存储文件。相反,企业应用系统都是建立在Java或类似的技术上面的,它们依赖于已有的文件系统,通信协议和应用栈。 一个基于Java的MapReduce实现应该考虑到已存在的数据存储设备,将来部署到的结构里面支持那种协议,有哪些内部API和支持部署那种第三方产品(开源的或商业的)。图2显示了通常的架构是如何通过映射到已有的、健壮的Java开源架构来实现的。 【图2】 这个架构采用了已有的工具,比如Terracotta和Mule,它们经常出现在很多企业系统的组织里面。已物理或虚拟系统形成存在的白盒子通过有效简单的配置和部署,设计成MapReduce群组中的一部分。为了效率,一个很大的系统可以分解到几个虚拟机器上,如果需要可以分配更多的结点。可以根据容量的问题和处理器的有效利用赖决定是否在群集中使用物理“白盒子”,虚拟机或者它们两者的结合。 Terracotta集群技术是map()和reduce()任务之间共享数据的很好选择,因为它把map()和reduce()之间的通信过程,包括共享文件或者使用RPC调用已初始处理结构都做了抽象。 从前面章节的描述知道,Map()和reduce()任务是在同一个核心应用中实现的。用来共享中间结构集的数据结构可以保持在内存的数据结构中,通过Terracotta透明的共享交换。 由跨域集群的MapReduce产生的进程内通信问题,自从Terracotta运行时掌管着这些共享数据结构后就不存在了。不同于实现一个复杂的信号系统,所有的map()任务需要标记内存中的中间结构集,然后reduce()任务就直接提取它们。 控制者和主应用程序都会在同时处在等待状态一段时间,即使是MapReduce集群有大量可用的并行处理能力。这两个组件之间以及当归并完成后的reduce()任务和控制者之间,都是通过Mule的ESB传递信号的。通过这种方式,为了其它应用的处理,输出结构可以排到队列,或者像前面章节讲的一样,为了其他MapReduced的处理,一个Mule服务对象(or UMO)可以把这些输出结果分解到“桶”中。 通过主流的企业应用协议或者完全的原始TCP/IP Sockets,Mule支持在内存中进行同步和异步的数据传输. Mule可以用于在同一台机器执行的应用系统,跨域不同的数据中心或者在完全不同地方且被程序员分开标识的本地终端结点互相传递输出结构集。其它基于Java的实现可以通过Hadoop,是一个用于运行应用程序在大型集群的廉价硬件设备上的框架,它是基于lucene框架。Hadoop是一个开源,点对点,通用的MapReduce实现。 4.结论 不管使用什么技术,索引大量非结构化数据是一件很艰难的任务。应用传统的算法和启发式方法很难维护,因为随着时间的推移,系统的性能下降使系统变得难以控制。RDBMS能有效的用于索引和检索大量的结构化数据集合,但不适合用于非结构化的数据。MapReduce为并行系统的数据处理,提供了一个简单,优雅的解决方案,优势有: l归并成本 l程序员的高产出,因为用并行的代码独立实现了业务逻辑 l比传统RDBMS技术更好的性能和更优的结果。 l使用Java企业框架和开发人员都熟悉的已有的技术和工具更易部署 用MapReduce, Google有令人印象深刻的跟踪记录,而且每天出现的工具都能轻易的融入到这个体系中。在企业级的应用系统中,如果你准备开始一个快速,简单的任务,例如根据IP地址分析请求的拥堵模型到你的web集群中,或者类似的东西。一个这样的练习将会很大程度上提高你对关键系统面临的问题和挑战的认识,MapReduce则就是为这些而准备的。

优秀的个人博客,低调大师

Spring MVC原理

摘要: Spring MVC工作流程图 springMVC工作流程图 图一 图二 开发工具 1.Eclipse IDE:采用Maven项目管理,模块化。 2.代码生成:通过界面方式简单配置,自动生成相应代码,目前包括三种生成方式(增删改查):单表、一对多、树结构。生成后的代码如果不需要注意美观程度,生成后即可用。 技术选型(只列了一部分技术) 1、后端 服务框架:Dubbo、zookeeper、Rest服务 缓存:Redis、ehcache 消息中间件:ActiveMQ 负载均衡:Nginx 分布式文件:FastDFS 数据库连接池:Alibaba Druid 1.0 核心框架:Spring framework 安全框架:Apache Shiro 1.2 视图框架:Spring MVC 4.0 服务端验证:hibernateValidator 5.1 布局框架:SiteMesh 2.4 工作流引擎:Activiti 5.15 任务调度:quartz 1.8.5 持久层框架:MyBatis 3.2 日志管理:SLF4J 1.7、Log4j 工具类:Apache Commons、Jackson 2.2、Xstream 1.4、Dozer 5.3、POI 2、前端 js框架:jQuery1.9。 CSS框架: Bootstrap 4 metronic 客户端验证:jqueryValidation Plugin。 富文本:CKEcitor 文件管理:CKFinder 动态页签:Jerichotab 数据表格:jqGrid 对话框:jQuery jBox 树结构控件:jQuery zTree 其他组件:Bootstrap 4 metronic 3、支持 服务器中间件:Tomcat 6、7、Jboss 7、WebLogic 10、WebSphere 8 数据库支持:目前仅提供MySQL数据库的支持,但不限于数据库,下个版本升级多数据源切换和数据库读写分离: 如:Oracle、SqlServer、H2等 支持开发环境:Eclipse、MyEclipse、Ras、Idea等 经典介绍: 源码结构 Spring工作流程描述 用户向服务器发送请求,请求被Spring 前端控制Servelt DispatcherServlet捕获; DispatcherServlet对请求URL进行解析,得到请求资源标识符(URI)。然后根据该URI,调用HandlerMapping获得该Handler配置的所有相关的对象(包括Handler对象以及Handler对象对应的拦截器),最后以HandlerExecutionChain对象的形式返回; DispatcherServlet 根据获得的Handler,选择一个合适的HandlerAdapter。(附注:如果成功获得HandlerAdapter后,此时将开始执行拦截器的preHandler(...)方法) 提取Request中的模型数据,填充Handler入参,开始执行Handler(Controller)。 在填充Handler的入参过程中,根据你的配置,Spring将帮你做一些额外的工作: HttpMessageConveter: 将请求消息(如Json、xml等数据)转换成一个对象,将对象转换为指定的响应信息 数据转换:对请求消息进行数据转换。如String转换成Integer、Double等 数据根式化:对请求消息进行数据格式化。 如将字符串转换成格式化数字或格式化日期等 数据验证: 验证数据的有效性(长度、格式等),验证结果存储到BindingResult或Error中 Handler执行完成后,向DispatcherServlet 返回一个ModelAndView对象; 根据返回的ModelAndView,选择一个适合的ViewResolver(必须是已经注册到Spring容器中的ViewResolver)返回给DispatcherServlet ; ViewResolver 结合Model和View,来渲染视图 将渲染结果返回给客户端。 Spring工作流程描述 为什么Spring只使用一个Servlet(DispatcherServlet)来处理所有请求? 详细见J2EE设计模式-前端控制模式 Spring为什么要结合使用HandlerMapping以及HandlerAdapter来处理Handler? 符合面向对象中的单一职责原则,代码架构清晰,便于维护,最重要的是代码可复用性高。如HandlerAdapter可能会被用于处理多种Handler。

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册