NightPxy 个人技术博客

Spark-存储体系

Posted on By NightPxy

概述

Spark 通过BlockManager,在Driver和Executor之间构建出一个类似HDFS的小型分布式文件存储.

Block

Spark抽象的最小存储单位为Block(不存在半块).一个Block等价于RDD一个分区,每一个Block都会有一个唯一ID

分布式存储网络

Spark的分布式存储类似HDFS中NN和DN架构
在Spark启动时会在SparkContext中通过BlockManager分别在Driver启动BlockManagerMaster,在Executor启动BlockManagerSlaver

  • Master负责管理Block元数据并对外暴露元数据服务
  • Slave通过Netty在Master完成注册并维持心跳,并对外暴露本节点的数据传输服务.

元数据管理

BlockManagerMaster类似NN,负责管理Block元数据.
其中是通过BlockManagerMasterEndpoint内存维护的三个HashMap来负责存储元数据

  • ExecutorId与BlockManagerId (某一个Executor对应的BlockManager是谁)
  • BlockManagerId与BlockManagerInfo(BlockManager的已存储块信息,目标传输服务引用等)
  • BlockId与BlockManagerId集合(表示块被存储在哪些BlockManager节点上,多个表示副本情况)

读取过程

  • 首先客户端根据BlockId,请求BlockManagerMaster中的元数据服务接口
    获取到Block的存储方式(内存&磁盘&序列化),节点地址(包括副本地址)等等
  • 通过元数据感知到Block的位置,确定是本地读取还是请求远程服务远程读取
  • 如果是本地读取则直接走getLocalValue,通过元数据获知是内存(走MemStore)还是磁盘(走DiskStore).内存读取就类似直接读取,因为MemStore中内存载体是LinkHashMap,如果是DiskStore则通过存储目录+文件名计算出二层文件目录+文件名从磁盘中读取
  • 如果是远程读取,则通过元数据获知Block所在节点位置,通过getRemoteValues向其节点数据服务发起请求,节点数据服务获知请求后按照本地读取后发回数据

写入

对某一个Block的写入流程如下

  • 首先通过BlockId联系BlockManagerMaster元数据服务
    获取到Block的存储方式(内存&磁盘&序列化),节点地址(包括副本地址)等等
  • 通过元数据获知Block需要写入的位置(可能有多个,考虑到副本的存在)
  • 如果是内存写入,则写入MemStore的LinkHashMap中
    这个写入是逐步展开的,每一Block都会判断内存标量是否足够,足够则直接写入,不够则会尝试扩容直到超过Executor的存储内存限制后弹出,之后再决定是否溢写
  • 如果是磁盘写入,则会通过文件名两次Hash计算出二级目录位置(第一层为UUID16位,第二层会64)后将文件块写入到磁盘文件
  • 如果远程写入,则通过目标节点数据服务将Block数据写入(同上)
  • 如果是多副本情况,则根据副本节点位置依次写入
  • 所有写入完成后,再次通知BlockManagerMaster全部写入成功