--------------------------------
原文链接:http://blog.csdn.net/amuseme_lu/article/details/5616198
Overview
* 为什么要用Mapreduce?
* 什么是Mapreduce?
* Hadoop的分布式文件系统
How MapReduce is Structured:
* 函数式程式满足了分布式计算的要求
* 大批量的数据处理系统
* 在应用逻辑层面上把很多可靠的因素考虑进来了
MapReduce Provides:
* 自动化的平行&数据分布
* 高可用性
* 状态与监控工具
* 为程序员提供了一种清晰的抽象
Programming Model:
* 来看一下什么是函数式编程
* 用可实现了下面两个方法
- map (in_key, in_value) -> (out_key, intermediate_value) list
- reduce (out_key, intermediate_value list) -> out_value list
Map:
* 从数据源中读取一条条记录来用做为Map函数的key和value对,如filename, line, etc..
* map()产生了一个或多个中间的value值,这些值是由input的输出key来提供的。
[c-sharp] view plain copy print ?
- map (in_key , in_value) -> (out_key, intermediate_value) list
- Example: Upper-case Mapper:
- let map(key ,v ) = emit(k.toUpper(), v.toUpper())
- ("foo","bar") -> ("FOO","BAR")
- ("Foo","other") -> ("FOO","OTHER")
- ("key2","data") -> ("KEY2","DATA")
map (in_key , in_value) -> (out_key, intermediate_value) list Example: Upper-case Mapper: let map(key ,v ) = emit(k.toUpper(), v.toUpper()) ("foo","bar") -> ("FOO","BAR") ("Foo","other") -> ("FOO","OTHER") ("key2","data") -> ("KEY2","DATA")
Explode Mapper:
[c-sharp] view plain copy print ?
- let map(k, v) = foreachchar c in v: emit(k,v)
- ("A","cats") -> ("A","c"), ("A","a"),("A","t"),("A","s")
- ("B","hi") -> ("B","h"), ("B","i")
let map(k, v) = foreach char c in v: emit(k,v) ("A","cats") -> ("A","c"), ("A","a"),("A","t"),("A","s") ("B","hi") -> ("B","h"), ("B","i")
Filter Mapper:
[c-sharp] view plain copy print ?
- let map(k, v) = if (isPrime(v)) then emit(k,v)
- ("foo",7) -> ("foo",7)
- ("test",10) -> (nothin)
let map(k, v) = if (isPrime(v)) then emit(k,v) ("foo",7) -> ("foo",7) ("test",10) -> (nothin)
Changing Keyspaces:
[c-sharp] view plain copy print ?
- let map(k, v) = emit(v.length(), v)
- ("hi","test") -> (4,"test")
- ("x","quux") -> (4,"quux")
- ("y","abracadabra") -> (10,"abracadabra")
let map(k, v) = emit(v.length(), v) ("hi","test") -> (4,"test") ("x","quux") -> (4,"quux") ("y","abracadabra") -> (10,"abracadabra")
reduce:
* 当map过程结束后,所有的中间值都会通过唯一的输出key聚合在一起,来作为reduce的输出值
* reudce()方法把这些有相同输出key的中间值组合成一个或多个最终的值(final values)
* 在实际中,一般一个Key只有一个value
[c-sharp] view plain copy print ?
- reduce (out_key, intermediate_value list) -> out_value list
- Example: Sum Reducer
- let reduce(k, vals) =
- sum = 0
- foreach int vin vals:
- sum += v
- emit(k, sum)
-
- ("A",[42,100,312]) -> ("A",454)
- ("B",[12,6,-2]) -> ("B",16)
- Identity Reducer:
- let reduce(k, vals) =
- foreach v in vals:
- emit(k, v)
-
- ("A", [ 42, 100, 312]) -> ("A",42),("A",100),("A",312)
- ("B",[12,6,-2]) -> ("B",12),("B",6),("B",-2)
reduce (out_key, intermediate_value list) -> out_value list Example: Sum Reducer let reduce(k, vals) = sum = 0 foreach int v in vals: sum += v emit(k, sum) ("A",[42,100,312]) -> ("A",454) ("B",[12,6,-2]) -> ("B",16) Identity Reducer: let reduce(k, vals) = foreach v in vals: emit(k, v) ("A", [ 42, 100, 312]) -> ("A",42),("A",100),("A",312) ("B",[12,6,-2]) -> ("B",12),("B",6),("B",-2)
Parallelism
* map() 函数是可以并行运行的,它从不同的输入数据集中创建了不同的中间值
* reduce() 函数也是并行运行的,各个执行者都有不同的输出key
* 所有的值都是相互独立(independently)处理的,也就是说并行处理的节点之间没有数据上的关联
* Bottleneck: reduce方法要等map方法完全处理完了才能够开始运行
[c-sharp] view plain copy print ?
- Example: Count word occurrences
- map(String input_key, String input_value):
-
-
- for each word w in input_value:
- emit(w,1);
-
- reduce(String output_key, Iterator<int> intermediate_values):
-
-
- int result = 0;
- for each v in intermediate_values:
- result += v;
- emit(output_key, result);
Example: Count word occurrences map(String input_key, String input_value): // input_key: document name // input_value: document contents for each word w in input_value: emit(w,1); reduce(String output_key, Iterator<int> intermediate_values): // output_key: a word // output_values: a list of counts int result = 0; for each v in intermediate_values: result += v; emit(output_key, result);
Combing Phase:
* 在Mapper节点上运行
* "Mini-reduce",只针对map的本地输出
* 在把数据发到reducer之前减少带宽的占用量
* reducer可以被组合,如果它是交互的或有关联的,如SumReducer。(不明白??)
[c-sharp] view plain copy print ?
- WordCountRedux:
- map(String input_key, String input_value):
-
-
- for each word w in input_value:
- emit(w, 1);
- reduce(String output_key, Iterator<int>
- intermediate_values):
-
-
- int result = 0;
- for each v in intermediate_values:
- result += v;
- emit(output_key, result);
WordCountRedux: map(String input_key, String input_value): // input_key: document name // input_value: document contents for each word w in input_value: emit(w, 1); reduce(String output_key, Iterator<int> intermediate_values): // output_key: a word // output_values: a list of counts int result = 0; for each v in intermediate_values: result += v; emit(output_key, result);
MapReduce Conclusions
* Maprduce在某些场合被证明是非常有用的抽象
* 很大程度上简化了大规模计算的复杂度
* 函数式编程的范例被证明可以用来处理大规模应用
* 你可以专心的解决实际问题,其它的事让library来帮你做吧
-=========================
HDFS
HDFS: Motivation
* 基于Google的GFS
* 大量的冗余数据分布式廉价的和不可靠的计算机上
* 为什么不使用现有的计算机文件系统呢?
- 不同的数据负载量和设计的优先级
- 不同与其它文件系统的大数据量处理能力
Assumptions
* 组件节点的高失效率
- 廉价的商用组件随时随地都可以失效
* "适当" 数量的大(HUGE)文件
- 数量只有几百万
- 每一个只有100MB或更大;一般都是几GB的文件
* 文件大者是写一次,append很多次
- 大概这些都是并行发生的
* 大量的数据流读操作
* 大量持久的吞吐量
HDFS Design Decisions
* 文件是以块的方式进行存储
- 块的大小都比一般的文件系统大,一般为64MB
* 通用复制数据块来得到高可用性
- 一般每一个数据块被复制成三份放在不同的数据节点上(DataNodes)
* 单个主节点(NameNode)管理对元数据的读写操作
- 简单的集中式管理
* 没有数据caching
- 有一点点得利于大规模数据集和流读取
* 熟悉的和可扩展的API
- 简化问题;集成分布式应用
HDFS Architecture
Picture::
Metadata
* 单个NameNode管理所有的元数据
- 文件名,每个文件在DataNodes上的地址
* 这些都存储在RAM中以提高访问速度
* 每一个DataNode以"block"为对象在本地文件系统对文件内容进行存储和管理
HDFS Conclusions
* HDFS支持在商用硬件平台上对大规模数据进行处理
- 设计用于支持使用的频繁失效
- 对于大文件的append和read进行了优化
- 文件系统接口为不同的工作而定制,但是又对开发者而言保持相对熟悉
- 简单的解决方案也可以工作,如单个master
* 在单个clusters上可靠的存储数TB的数据