大数据运算系统

27 阅读9分钟

MapReduce/Hadoop

编程模型

  • 思路:程序员写串行程序,由系统完成并行分布式地执行
  • MapReduce的数据模型:<key, value>
  • Map(ik, iv) -> {<mk, mv>}
  • Reduce(mk, {mv}) -> {<ok, ov>}

系统实现

  1. 用户提交作业,Split切分数据
  2. 每个Map读取一份数据,Map函数执行后,输出结果再哈希分区映射到Reduce节点
  3. Master接收Map运行结果与输出文件列表,当所有Map完成,启动Reduce任务
  4. 节点并发执行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%的可能性转向任意的网页
    • 结果为访问这个网页的概率

计算方法

  1. 初始化:所有的顶点的PageRank为1/N
  2. 迭代:用上述公式迭代直至收敛

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:空闲消息队列,用于支持消息空间的快速分配释放

计算流程:

  1. 超步开始:分发message

    1. 把 Received message list 中的消息放入接收顶点的 in‐message list
  2. 超步计算中:依次访问Vertex, 调用Compute

    1. 在超步中可能收到消息
  3. 超步结束时:收到的上一超步的消息都在 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上运行计算