后面曾经差不多把执行的流程都讲完了,这篇讲讲每个 Task 执行的后果是如何存储和读取的。
BlockManager
BlockManager 是 SparkEnv 中的组件之一,存储体系的所有组件和性能都是依赖着 BlockManager,包含之前提到的 ShuffleManager、DiskBlockManager、MapOutputTracker 等,这篇会的流程也会再解说一次。
BlockManagerMaster
BlockManager 是 SparkEnv 的一部分,那 Driver 和 Executor 启动的时候,都会对 BlockManager 进行实例化。而 Driver 和 Executor 之间的 BlockManager 通信,包含注册 BlockManager、更新 Block 信息、获取 Block 的地位(即 Block 所在的 BlockManager)、删除 Executor 等,都是通过 BlockManagerMaster。
Driver 启动的时候,BlockManagerMaster 会创立 BlockManagerMasterEndpoint 并注册到 Driver 的 RpcEnv 中,而 Executor 启动的时候,会创立 BlockManagerMasterEndpointRef,指向 Driver 的 BlockManagerMasterEndpoint。
BlockManagerMasterEndpoint 中保护着一个 HashMap,key 为 BlockManagerId,value 为 BlockManagerInfo。BlockManagerId 是惟一的,就是通过 BlockManagerMasterEndpoint 来治理的。
当 Driver 和 Executor 初始化 BlockManager 的时候,都会向 BlockManagerMasterEndpoint 发动 RegisterBlockManager 申请。Driver 是发送给本人的,Executor 通过 BlockManagerMasterEndpointRef 发送给 BlockManagerMasterEndpoint。
BlockManagerMasterEndpoint 收到申请后,就会更新 map 里的值,所以 BlockManagerMasterEndpoint 治理着所有的 BlockManagerId。并且把 BlockManagerId 返回给申请方。那 BlockManagerId 是什么?
BlockManagerId
不同节点和实例上的 BlockManager 进行互相通信的时候,就须要有一个惟一的身份标识 -BlockManagerId。
BlockManagerId 包含 host、port、executorId 等信息。如果实例是 Driver,那么 executorId 为 driver,否则由 Master 负责给各个 Executor 调配,ID 格局为 app- 日期格局字符串 - 数字。
上图中,第一个是的 Driver 的 BlockManager,她的 executorId 为 driver。第二个是 Executor 的 BlockManager,她的 executorId 略过日期格局,简写为 app-0。第三个 Executor 的 BlockManager,她的 executorId 略过日期格局,简写为 app-1。
DiskBlockManager
BlockManager 中有一个用来对磁盘上的文件及目录的读写操作进行治理,叫做磁盘块管理器 DiskBlockManager。
当要写入磁盘的时候(这里能够看之前 Task 的执行过程),DiskBlockManager 就会创立惟一的 BlockId 和文件,用来存储 Shuffle 两头后果。
DiskBlockManager 保护着本地目录的数组 localDirs 以及本地子目录的二维数组 subDirs。localDirs 为 blockmgr-
为前缀,前面加 UUID。subDirs 记录本地子目录的数量,默认是 64,所以创立文件的时候,就会依据判断二级目录是否存在,如果不存在则创立二级目录。
整个树形构造如下:
比方创立 TempShuffleBlock,文件门路如下:
DiskBlockObjectWriter
DiskBlockManager 创立文件后,对文件的写入操作是由 DiskBlockObjectWriter 来实现的(这里能够看之前 Task 的执行过程),最初合并后,就有了 data 数据文件和 index 索引文件。而后告知 Driver 文件的信息,此步骤具体见 Task 执行后果的解决。
BlockTransferService
Executor 执行的过程中,会创立很多个块,块的传输都是通过块传输服务 BlockTransferService,次要用于不同阶段的工作之间的 Block 数据的传输与读写。默认为 NettyBlockTransferService,每个 BlockTransferService 都有 netty 对应的 server 用于提供服务和 clientFactory 用于创立 client。
假如 Executor1 执行的时候,通过 trackerEndpoint 向 Driver 的 MapOutputTrackerMasterEndpoint 获取到了她须要的 block 信息(此步骤具体见 Task 执行后果的解决)在 Executor0,与是通过 NettyBlockTransferService 向 Executor0 获取 block 信息。
Executor0 接管到信息后,就会通过 DiskBlockManager 把 data 文件和 index 文件取出来,依据起始偏移量返回数据给 Executor1。