Ozone数据写入过程分析

前言


上篇文章Ozone Datanode的分布式元数据管理,笔者阐述了关于Ozone Datanode的分布式元数据相关的内容以及Datanode上的数据layout。既然我们了解了Datanode上元数据的结构,那么一个很自然的问题:Datanode如何进行数据的写入的呢?里面的数据一致性是怎么做的?中间写数据发生错误,Datanode这边怎么来处理?本文我们来细聊Ozone数据写入的内部过程。

Ozone Key(文件)数据的写入


我们知道,Ozone作为对象存储系统,支持K-V模式的键值对存储,文件的数据的put操作实质上代表的key的写入。Ozone在这边是通过OM返回给客户端KeyOutputStream对象,来进行后续数据的写入的。换句话说,client是通过向OM服务申请获取目标key的KeyOutputStream,样例代码如下:

  private void writeKey(String key1, OzoneBucket bucket) throws IOException {
   
    OzoneOutputStream out = bucket.createKey(key1, 1024, STAND_ALONE,
        ONE, new HashMap<>());
    out.write(RandomStringUtils.random(1024).getBytes());
    out.close();
  }

OzoneOutputStream内部包装的OutputStream对象即为KeyOutputStream。

KeyOutputStream代表一个key下的数据文件,如果目标key对应要写的数据文件比较大,就可能会出现需要多block存储的情况。类似于HDFS大文件,需要多个block来存储,每个block根据offset来分隔开。在Ozone中,每个block又对应有独自的BlockOutputStream,这里每个专属的BlockOutputStream全程控制对应词block的数据写操作。

在前篇文章也提到了,Block在Ozone中是虚拟的概念,实际存储的文件叫chunk文件,一个Block由1个或多个chunk文件组成。因此BlockOutputStream的数据写出实质上是chunk文件的数据写出。BlockOutputStream内部维护了一个Chunk Buffer池做临时数据缓存,等数据达到flush触发阈值,BlockOutputStream再进行chunk文件的数据写Datanode操作。

然后执行client向Datanode发起putBlock的元数据更新操作,更新其Container db文件。此操作结束,意味着这个block数据成功地被写出Datanode中了。然后BlockOutputStream内部对应的Chunk Buffer空间也能被释放了。

上述数据的写出过程如下图所示:

在这里插入图片描述

KeyOutputStream的write方法代码如下,通过Block池创建多个BlockOutputStream进行数据的写入,

  private void handleWrite(byte[] b, int off, long len, boolean retry)
      throws IOException {
   
    while (len > 0) {
   
      // 如果当前剩余写入长度还未减少为0,则意为数据还未完全写出到Block,则继续进行循环内的数据写出
      try {
   
    	// 1.Block Pool新申请块进行数据的写入,返回的BlockOutputStream包装对象
        BlockOutputStreamEntry current =
            blockOutputStreamEntryPool.allocateBlockIfNeeded();
        // length(len) will be in int range if the call is happening through
        // write API of blockOutputStream. Length can be in long range if it
        // comes via Exception path.
        // 2.计算得到应写出的len数据长度,取当前BlockOutputStream和目标写入长度的最小值
        int writeLen = Math.min((int) len, (int) current.getRemaining());
        long currentPos = current.getWrittenDataLength();
        
        // 3.写出字节数据到BlockOutputStream,数据范围为字节b从offset位置后的writeLen长度
        // 此过程如果达到内部buffer触发阈值,会进行chunk的flush写出。
        writeToOutputStream(current, retry, len, b, writeLen, off, currentPos);
        // 4.如果写完这批数据后,此BlockOutputStream达到最大写入length限制,无剩余,则close此stream
        // close操作会flush出最后一个block chunk文件。
        if (current.getRemaining() <= 0) {
   
          // since the current block is already written close the stream.
          handleFlushOrClose(StreamAction.FULL);
        }
        // 5.更新offset和len长度值
        len -= writeLen;
        off += writeLen;
      } catch (Exception e) {
   
    	// 6.如果发生异常,关闭当前在写的stream
        markStreamClosed();
        throw new IOException("Allocate any more blocks for write failed"
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值