hdfs客户端及元数据

本文详细介绍了HDFS客户端与NameNode之间的交互过程,包括创建目录、写数据的操作流程。涉及到的类和方法如DFSClient、DFSOutputStream、FSNamesystem、FSDirectory等。同时,文章讨论了NameNode的RPC服务器处理请求的方式,以及元数据的管理,特别是Lease管理和契约检查。此外,还提及了Standby NameNode的检查点机制和数据同步。
摘要由CSDN通过智能技术生成

元数据:

  先看下方提供的,结构图,了解元数据的结构,以及相关的同步操作;

客户端事件请求:

客户端:DFSClient类可以和namenode通信,也可以和datanode通信读写block数据,使用者要获取DistributedFileSystem实例,即基类FileSystem;

创建目录:

  1. 先看FileSystem类是个抽象类,本地实现看LocalFileSystem,分布式实现看DistributedFileSystem,我们看分布式的;
  2. mkdirs-》mkdirs-》primitiveMkdir-》namenode.mkdirs,namenode是客户端代理,接下来看namenode rpc server;

写数据:

  1. FileSystem-》create-》DistributedFileSystem实现了create,DFSClient.create-》DFSOutputStream.newStreamForCreate,若捕获异常重试多次-》dfsClient.namenode.create

  2. out = new DFSOutputStream-》computePacketChunkSize,数据组成,dir->file->block(128M)->package(64k)->chunk(512byte)+chunk sum(4byte)

  3. out.start-》启动线程,查看run方法,dataQueue为空则wait,直到超时;

  4. 接下来看namenode rpc server的create方法-》向目录树添加文件,添加契约

  5. beginFileLease,每隔一段时间进行续约,LeaseRenewer.run-》namenode.renewLease,查看namenode rpc的处理方法;

  6. 最终返回dfs.createWrappedOutputStream-》HdfsDataOutputStream

  7. 接着调用,write-》DFSOutputStream-》FSOutputSummer.write-》flushBuffer-》writeChecksumChunks-》writeChunkImpl-》waitAndQueueCurrentPacket-》queueCurrentPacket,添加数据到dataQueue,然后,notifyAll(),唤醒等待的dataQueue;即run方法;

  8. nextBlockOutputStream,建立数据管道,向namenode申请block-》locateFollowingBlock,namenode.addBlock,看namenode rpc;

    1. createBlockOutputStream-》createSocketForPipeline创建socket连接server,创建输入/输出流-》writeBlock-》send-》out.flush(),目的是,各个datanode建立管道,接下来看datanode DataXceiverServer

    2. 如果建立管道不成功,放弃block,把datanode节点放入excludeNodes然后,重新申请block,并排除excludeNodes中的datanode;

  9. initDataStreaming-》new ResponseProcessor(nodes),看run方法,readFields读取下游处理结果,处理成功的话
    ackQueue.removeFirst();
    dataQueue.notifyAll();
  10. 写数据的时候,把数据从dataqueue拿出来放到ackqueue,然后,发送数据到datanode,one.writeTo(blockStream),接下来看datanode的DataXceiverServer;
  11. 写数据出问题,异常处理,关闭responseProcessor服务 /socket/输入输出流,把ackqueue添加到dataqueue,清空ackqueue,如果出问题的datanonde不多,会切换datanode进行写入,如果出问题的datanode多,向namenode重新发请求申请block,重新建立数据管道;

namenode rpc server:

mkdirs:

  1. FSNamesystem.mkdirs,检查是否安全模式,是的话创建不了-》FSDirMkdirOp.mkdirs
    1. getFSDirectory获取目录树,FSDirectory(内存目录树),相比较,FSNamesystem持久化操作到磁盘;
    2. 获取请求目录的inode把信息存入INodesInPath,获取最后一个inode,如果为空继续处理;
    3. createChildrenDirectories,循环,创建目录-》createSingleDirectory-》unprotectedMkdir-》创建INodeDirectory然后添加inode,FSDirectory.addLastINode;
    4. FSDirectory.getEditLog(),即FSEditLog-》logMkDir-》logEdit-》
    5. 创建txid,editLogStream.write(op)-》遍历journalSet包含的JournalAndStream,获取包含的流然后写入,jas.getCurrentStream().write(op);即EditLogFileOutputStrem、QuorumOutputStream;
    6. 通过双缓冲,选取当前buffer,写入TxnBuffer;
    7. logSync-》临时变量获取editLogStream,然后调用flush,然后分两条线(鱼和熊掌不可兼得,想要性能高,就要损失安全性,问题来了,假如出现元数据丢失怎么办?)
      1. EditLogFileOutputStrem的实现 flushAndSync-》调用双缓冲的readybuffer写入文件,doubleBuf.flushTo(fp);
      2. QuorumOutputStream含有AsyncLoggerSet,里面包含了多个AsyncLogger,遍历,调用sendEdits-》getProxy().journal,这里使用rpc调用,接下来可用看journalrpc的处理方法,journal协议;

create:

  1. checkNNStartup检查namenode启动状态,FSNamesystem.startFile
  2. startFileInternal-》addFile-》newINodeFile,创建INodeFile-》addINode-》addLastINode-》addChild契约
  3. startFileInternal-》addLease-》类似全局锁,防止一个文件多个节点写入,因此,写入时,获取一个文件的契约;

addBlock:

  1. getAdditionalBlock-》chooseTarget4NewBlock负载均衡,选择存放block的多台主机-》saveAllocatedBlock修改内存目录树-》addBlock-》addBlockCollection,fileINode.addBlock
  2. persistNewBlock-》logAddBlock-》logEdit

renewLease:

  1. 更新契约时间
  2. 这里额外说下契约检查,LeaseManager,看监控线程-》FSNamesystem 非安全模式下,checkLeases,检查过期契约,过期解除契约;

涉及的类:

FSNamesystem:

  • loadFromDisk
  1. 创建FSImage,创建FSNamesystem,如果启动模式时RECOVER,则进入安全模式;
  2. loadFSImage-》如果启动模式时FORMAT,fsimage format处理;
  3. 获取storage的image目录,editslog的目录,若空则异常;
  4. recoverStorageDirs
  5. storage获取getLayoutVersion,小于-3则checkVersionUpgradable
  6. loadFSImage-》readAndInspectDirs,获取imageFiles
  7. initEditLog
  8. 遍历imageFiles,loadFSImageFile,通过不同部署版本不同处理
  9. loadFSImage读文件
    1. FSNamesystem.getBlockIdManager,设置数据
    2. 如果支持snapshot,FSNamesystem.getSnapshotManager,设置数据;
    3. loadLocalNameINodesWithSnapshot,loadLocalNameINodes,loadFullNameINodes-》loadINode,然后添加到FSNamesystem.dir
  10. loadEdits

FSDirectory:

  • INodeDirectory 根目录
  1. List<INode> children,存储节点;
  2. INode实现有INodeDirectory,INodeFile等,表示目录和文件;

standby namenode:

  1. startStandbyServices-》
    1. new StandbyCheckpointer(初始化,CheckpointerThread),start,启动线程;
    2. CheckpointerThread 满足条件(100W条日志,或者1小时没checkpoint)会把内存中的image数据写入到磁盘,替换fsimage;
    3. 向namenode发起http请求,"/imagetransfer",同步fsimage;namenode servlet处理,写磁盘,替换fsimage;疑问?(为什么namenode不自己更新fsimage呢?)
    4. 第一种方式namenode可以直接写磁盘更新fsimage,但是会不可用;第二种,快照,再写磁盘,但耗内存;第三种,如何加载editlog更新fsimage,难;
    5. 因此,当前的方式可能效果更好,但也有几个问题,比如同步故障问题等;

DataXceiverServer:

  1. writeblock下建立管道操作
    1. 看run方法-》DataXceiver.create-》看run方法-》readOp读取操作类型,processOp处理操作-》
    2. opWriteBlock-》writeBlock-》启动BlockReceiver-》PIPELINE_SETUP_CREATE创建管道-》createRbw(写文件时会放到rbw目录,完成后放到finalized目录),获取volume,然后createRbwFile
    3. 连接到下游机器,new Sender(mirrorOut).writeBlock,发送数据到下游的datanode;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

MyObject-C

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值