MapReduce/Hadoop
编程模型
- 思路:程序员写串行程序,由系统完成并行分布式地执行
- MapReduce的数据模型:<key, value>
- Map(ik, iv) -> {<mk, mv>}
- Reduce(mk, {mv}) -> {<ok, ov>}
系统实现
- 用户提交作业,Split切分数据
- 每个Map读取一份数据,Map函数执行后,输出结果再哈希分区映射到Reduce节点
- Master接收Map运行结果与输出文件列表,当所有Map完成,启动Reduce任务
- 节点并发执行Reduce任务
- Combiner:Map输出很多冗余数据,Maper运行Combiner相当于局部Reduce操作
- 容错:心跳,宕机节点任务移交给其他节点
典型算法
- Grep:找到符合特定模式的文本
-
Sorting
- 利用MapReduce系统的shuffle/sort功能完成sorting
- identity指将输入拷贝到输出,无操作
-
Join
-
一组Mapper处理R,一组Mapper处理S
-
利用shuffle/group by把匹配的record放到一起
-
Reduce调用时,{mv}包含对应同一个join key的所有匹配的R和S记录,于是产生每一对R记录和S记录的组合(笛卡尔积),并输出
-
需要传输整个R与S会产生比较大的代价
-
Microsoft Dryad
对MapReduce模型的一种扩展
-
组成单元不仅是Map和Reduce,可以是多种节点
-
节点之间形成一个有向无环图DAG(Directed Acyclic Graph) ,以表达所需要的计算
-
节点之间的数据传输模式更加多样
- 可以是类似Map/Reduce中的shuffle
- 也可以是直接1:1、1:多、多:1传输
-
比MapReduce更加灵活,但也更复杂
-
需要程序员规定计算的DAG
同步图计算系统
图算法:PageRank
-
模拟用户的访问过程:
- 有85%的可能性点击网页中的超链、有15%的可能性转向任意的网页
- 结果为访问这个网页的概率
计算方法
- 初始化:所有的顶点的PageRank为1/N
- 迭代:用上述公式迭代直至收敛
N非常大时,数据精度可能不够?
初始化:所有的顶点的PageRank为1
同步图计算
-
Pregel模型
-
开源实现: Apache Giraph, Apache Hama,我们的实现:GraphLite
-
运算流程:超步内,并行执行每个顶点,超步间数据同步
- 每个顶点:接收上个超步发出的in‐neighbor的消息,计算当前顶点的值,向out‐neighbor发消息
-
BSP模型:Bulk Synchronous Processing
- 全部计算分成多个超步,超步内部全部并行
- 超步之间进行全局同步
- 相邻的超步之间存在依赖关系,上一个超步的运算产生下一个超步的输入
-
基于顶点的编程模型
- 每个顶点有一个value
- 顶点为中心的运算
-
顶点的两种状态
- 活跃态Active:图系统只对活跃顶点调用compute
- 非活跃态Inactive:compute调用Volt to halt时,顶点变为非活跃态
- 当所有的顶点都处于非活跃状态时,图系统结束本次图运算
-
Pregel模型
分布式计算流程:每个worker进行本地的计算,为本partition的每个顶点调用compute,收集顶点发送的信息,并发向对应的worker
GraphLite 架构
-
消息格式:Message: (source ID, target ID, message value, ptr)
-
Vertex array:顶点数组(按顶点ID从小到大存),包含:
- 应用程序定义的Vertex Type
- 边指针、消息队列指针等
-
Out-edge array:出边数组(按顶点ID从小到大存),包含:
- 应用程序定义的Edge Type
- 边的src、dest顶点ID等
-
In-message list:In‐message消息队列,包含:
- 每个顶点在上一超步收到的消息
- 形成Compute(调用参数)
-
Received message list:全局收到消息队列,包含:
- 在超步进行中,收到的消息
-
Free list:空闲消息队列,用于支持消息空间的快速分配释放
计算流程:
-
超步开始:分发message
- 把 Received message list 中的消息放入接收顶点的 in‐message list
-
超步计算中:依次访问Vertex, 调用Compute
- 在超步中可能收到消息
-
超步结束时:收到的上一超步的消息都在 Received message list 之中
Aggregator全局统计量,计算过程:
-
每个超步内
- 每个Worker分别进行本地的统计:accumulate()
-
超步间,全局同步时
- Worker把本地的统计值发给master
- Master进行汇总,计算全局的统计结果
- Master把全局的统计结果发给每个Worker
-
下一个超步内
-
Worker从Master处得到了上个超步的全局统计结果
- Compute就可以访问上一超步的全局统计信息了
- getAggregate()
-
-
继续计算本超步的本地统计量
GAS模型
Why?
图符合Power‐Law分布:部分节点边特别多
Pregel模型中可能引起大量的消息传递代价
How?
把单个大度顶点分裂成为了多个顶点,多跨边变为少数顶点与其镜像的边
GAS模型:把Pregel compute分为三个函数
- Gather:收消息求局部和,再计算全局和
- Apply:在主顶点更新PageRank
- Scatter: Copy顶点状态减少跨机器的消息
MapReduce + SQL系统
Hive
-
功能:
- 存储关系表到HDFS
- 存储元信息
- 支持SQL为MapReduce操作
-
数据存储在HDFS上
-
Table: 一个单独的hdfs目录,进一步划分为Partition目录,Partition可以进一步划分为Bucket目录
- /usr/hive/warehouse/
- Table:/user/hive/warehouse/表名
- Partition:/user/hive/warehouse/表名/pkey=value
- Bucket:/user/hive/warehouse/表名/pkey=value/bkey=value
-
-
MetaStore:存储表的定义信息等
- 默认在本地${HIVE_HOME}/metastore_db中
-
Hive QL:类似SQL,部分SQL和扩展,MapReduce执行
数据流处理
-
数据流概念:数据流过系统,在流动的数据上完成处理,只看到一次数据,看到数据的顺序确定
-
无状态运算:可以对流过的单条记录进行计算,例如,选择(过滤),投影,Map
-
有状态运算:需要对多条记录进行计算,例如,groupby + aggregation, join
- 在所有记录上计算:数据流运算算子上记录状态信息,对每条记录都处理更新状态信息
- 基于Window的计算:对一个窗口内的所有记录完成计算,设置窗口长度:时间、记录数,设置相邻两个窗口之间的距离:步长
数据流系统Storm
Storm 系统结构
-
前端master: Nimbus
-
后端worker: Supervisor,每个Supervisor运行多个线程
- 每个线程只会负责一个Spout/Bolt
- 一个Spout/Bolt可以对应多个Supervisor和多个线程
-
通过ZooKeeper通信
Storm程序概念
-
计算任务形成一个有向无环图DAG
- DAG用一个Topolopy数据结构表示
- 每个job有一个Topology
- 对应于数据流处理运算关系的一张图
-
Topology中的每个顶点代表一个运算
- Spout:产生数据流,没有输入,有输出
- Bolt:对数据流进行某种运算,有输入,有输出
-
Topology中两个顶点之间的边代表数据流动的关系
上游节点的输出如何分发到下游顶点?
-
Shuffle grouping: 随机
-
Fields grouping:group‐by shuffle
-
根据tuple中指定域的取值,相同取值的tuple发给固定的下游实例
-
消息日志系统Kafka
Why?
N-N的消息发送:复杂,难以管理、维护,容易出错
How?
N‐1‐N:降低复杂度,隔离consumer和producer之间处理速度的差异
Kafka基本模型
-
角色
- Producer:消息生产者
- Consumer:消费者,主动去读(Pull模型)
- Broker:Kafka服务器存储Producer发来的消息,为Consumer提供消息读取服务
-
消息的组织,Producer发布消息时需要指明topic和partition
-
Topic:每个Topic对应一个Log/Queue
-
Partition:相当于水平扩展
- 每个topic可以划分为多个partition
- 每个partition内部消息有序
- Partition之间消息无序
-
Kafka系统结构
容错:
-
At least once delivery
-
Message order in a topic partition
-
备份
-
Topic partition是备份的基本单位
-
Primary‐backup主从备份
-
内存计算
内存数据库
-
MonetDB:内存列式存储, 数据在类似数组的结构中
-
SAP HANA
内存键值系统
-
Memcached
-
数据在内存中以hash table的形式存储
-
组成:
-
Communication & Protocol:实现自定义的协议,支持GET/PUT等请求和响应
-
Slab based Memory Management:采用多个链表管理内存
- 每个链表中的内存块大小相同,只分配和释放整个内存块
- 第k个链表的内存块大小是2^kBase字节
-
Hash Table:Key‐Value采用一个全局的Hash Table进行索引,多线程并发互斥访问
-
Key Value Storage:每个Key‐Value存储在一个内存块中
- Hash link:chained hash table
- LRU link: 相同大小的已分配内存块在一个LRU链表上
- 内存不够时,可以丢弃LRU项
-
-
-
Redis
-
分布式内存键值对系统
-
提供更加丰富的类型,例如hashes, lists, sets 和sorted sets
-
支持副本和集群
-
Spark:面向大数据分析的内存系统
Hadoop的问题:通过HDFS进行作业间数据共享,代价太高
How?
可以从HDFS读数据,但是运算中数据放在内存中,不使用Hadoop,而是新实现了分布式的处理,目标是低延迟的分析操作。
基础数据结构:RDD
-
Resilient Distributed Data sets
-
一个数据集
-
只读,整个数据集创建后不能修改
-
通常进行整个数据集的运算
-
优点
-
并发控制被简化了
-
可以记录lineage(数据集上的运算序列),可以重新计算
- 并不需要把RDD存储在stable storage上
-
-
-
RDD产生方式:
- 从输入文件产生RDD
- 程序产生RDD
-
RDD的两类运算
- Transformation:输入RDD,输出RDD
- Action:输入是RDD,输出是可以返回给driver程序的结果
-
运算过程:
- 读入内存一次,在内存中可以多次处理
- Transformation:仅记录,不运算,Lazy execution
- 当遇到Action时,需要返回结果,才真正执行已经记录的前面的运算
-
容错/内存缓冲替换:当内存缓冲的RDD丢失时
-
可以重新执行记录的运算,重新计算这个RDD
-
Spark Streaming
- 把输入的数据流转化为一个个minibatch
- 然后在minibatch上运行计算