Flume-WAL日志机制源码分析

一、WAL

WAL 的全称是 Write-Ahead Logging,中文称预写式日志,是一种数据安全写入机制,记录变更操作。就是先写日志,然后在写入磁盘,这样保证数据的安全性。WAL在关系型数据库中非常常见,Mysql中的Redo Log就是采用WAL机制。

二、Put

// org.apache.flume.channel.file.Log.java
FlumeEventPointer put(long transactionID, Event event)
      throws IOException {
   
   
    Preconditions.checkState(open, "Log is closed");
    FlumeEvent flumeEvent = new FlumeEvent(
        event.getHeaders(), event.getBody());
    //封装Put操作,WAL日志会记录四种操作,分别是Put,Take,Commit和Rollback
    //Put操作,全局写顺序ID加1
    Put put = new Put(transactionID, WriteOrderOracle.next(), flumeEvent);
    ByteBuffer buffer = TransactionEventRecord.toByteBuffer(put);
    //选择数据目录的数据文件,比如log-1
    int logFileIndex = nextLogWriter(transactionID);
    long usableSpace = logFiles.get(logFileIndex).getUsableSpace();
    long requiredSpace = minimumRequiredSpace + buffer.limit();
    if (usableSpace <= requiredSpace) {
   
   
      throw new IOException("Usable space exhausted, only " + usableSpace +
          " bytes remaining, required " + requiredSpace + " bytes");
    }
    boolean error = true;
    try {
   
   
      try {
   
   
        // Put事件写入WAL日志文件,Event也就持久化到文件了
        // logFileIndex就是数据文件ID,比如log-1文件
        // 需要注意的是,这里并不意味着数据立即被物理写入到磁盘上,数据被写到了操作系统缓冲区
        // 最终由操作系统决定何时物理写入到磁盘。
        // 如果你需要确保数据已经物理写入到磁盘,可以调用FileChannel的force()方法进行强刷
        FlumeEventPointer ptr = logFiles.get(logFileIndex).put(buffer);
        error = false;
        return ptr;
      } catch (LogFileRetryableIOException e) {
   
   
        if (!open) {
   
   
          throw e;
        }
        roll(logFileIndex, buffer);
        FlumeEventPointer ptr = logFiles.get(logFileIndex).put(buffer);
        error = false;
        return ptr;
      }
    } finally {
   
   
      if (error && open) {
   
   
        roll(logFileIndex);
      }
    }
  }
//org.apache.flume.channel.file.LogFile.Writer
synchronized FlumeEventPointer put(ByteBuffer buffer) throws IOException {
   
   
      if (encryptor != null) {
   
   
        buffer = ByteBuffer.wrap(encryptor.encrypt(buffer.array()));
      }
      //往fileChannel写入数据
      Pair<Integer, Integer> pair = write(buffer);
      return new FlumeEventPointer(pair.getLeft(), pair.getRight());
    }

write(buffer)是一个公共方法,put、take、commit、rollback操作都通过该方法进行持久化。

private Pair<Integer, Integer> write(ByteBuffer buffer)
        throws IOException {
   
   
      if (!isOpen()) {
   
   
        throw new LogFileRetryableIOException("File closed " + file);
      }
      long length = position();
      long expectedLength = length + (long) buffer.limit();
      //如果一个log写不下了,将会抛出LogFileRetryableIOException,外面捕获到这个异常会创建一个新的log并进行重写,log默认大小是1.6G
      if (expectedLength > maxFileSize) {
   
   
        throw new LogFileRetryableIOException(expectedLength + " > " +
            maxFileSize);
      }
      int offset = (int) length;
      Preconditions.checkState(offset >= 0, String.valueOf(offset));
      // OP_RECORD + size + buffer
      int recordLength = 1 + (int)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值