FB版本RaidNode线程分析——BlockIntegerMonitor


FB版本RaidNode线程分析——BlockIntegerMonitor

概述

RaidNode上的BlockIntegrityMonitor线程会通过DFSck工具检查系统中corrupt或decomission的数据,通过BlockCopier和BlockFixer线程周期行对出错的数据进行修复。local模式下,修复过程在RaidNode上之行,Dist模式下修复过程通过提交Job的方式提交给集群完成。

具体代码

线程的创建和启动

RaidNode.initialize方法

    // Create a block integrity monitor and start its thread(s)
    this.blockIntegrityMonitor = BlockIntegrityMonitor.createBlockIntegrityMonitor(conf);
    
    boolean useBlockFixer = 
      !conf.getBoolean(RAID_DISABLE_CORRUPT_BLOCK_FIXER_KEY, false);
    
    Runnable fixer = blockIntegrityMonitor.getCorruptionMonitor();
    if (useBlockFixer && (fixer != null)) {
      this.blockFixerThread = new Daemon(fixer);
      this.blockFixerThread.setName("Block Fixer");
      this.blockFixerThread.start();
    }

线程的实现代码(Dist模式)

image-20220325175254439

fixer的实现类是继承了Worker.class的CorruptionWorker.class

Worker.run :

   public void run() {
      while (running) {
        try {
          updateStatus();//更新状态,可以忽略
          checkAndReconstructBlocks();// important
        }
        try {
          Thread.sleep(blockCheckInterval);
        }
      }
    }

Worker.checkAndReconstructBlocks:

   void checkAndReconstructBlocks()
    throws IOException, InterruptedException, ClassNotFoundException {
      checkJobs();

      if (jobIndex.size() >= maxPendingJobs) {
        LOG.info("Waiting for " + jobIndex.size() + " pending jobs");
        return;
      }

      Map<String, Integer> lostFiles = getLostFiles();
      FileSystem fs = new Path("/").getFileSystem(getConf());
      Map<String, Priority> filePriorities =
        computePriorities(fs, lostFiles);

      LOG.info("Found " + filePriorities.size() + " new lost files");

      startJobs(filePriorities);
    }

checkJobs 方法:

1.检查Job是否完成,完成的话,从容器中进行移除

2.清楚 fileIndex容器中过期的文件,由raid.blockfix.max.time.for.file指定,默认是4hour。

3.删除不再运行job的in/out路径

getLostFiles 方法:

使用 hadoop fsck -list-corruptfileblocks命令得到 缺块的文件列表。

computePriorities 方法:

将待修复文件分为校验文件和源文件,文件的缺块大于1,Priority =High ,等于1,Priority = Low

startJobs 方法:

将之前的待修复文件按Priority进行变量,filesPerTask * TASKS_PER_JOB(默认是10*50)的待修复文件组成一个job,然后进行startJob

   private void startJobs(Map<String, Priority> filePriorities)
    throws IOException, InterruptedException, ClassNotFoundException {
      String startTimeStr = dateFormat.format(new Date());

      for (Priority pri : Priority.values()) {
        Set<String> jobFiles = new HashSet<String>();
        for (Map.Entry<String, Priority> entry: filePriorities.entrySet()) {
          // Check if file priority matches the current round.
          if (entry.getValue() != pri) {
            continue;
          }
          jobFiles.add(entry.getKey());
          // Check if we have hit the threshold for number of files in a job.
          if (jobFiles.size() == filesPerTask * TASKS_PER_JOB) {
            String jobName = JOB_NAME_PREFIX + "." + jobCounter +
            "." + pri + "-pri" + "." + startTimeStr;
            jobCounter++;
            startJob(jobName, jobFiles, pri);
            jobFiles.clear();
            if (jobIndex.size() > maxPendingJobs) return;
          }
        }
        if (jobFiles.size() > 0) {
          String jobName = JOB_NAME_PREFIX + "." + jobCounter +
          "." + pri + "-pri" + "." + startTimeStr;
          jobCounter++;
          startJob(jobName, jobFiles, pri);
          jobFiles.clear();
          if (jobIndex.size() > maxPendingJobs) return;
        }
      }
    }

startJob 方法:

在这里构建只有Map的job,指定job的in/out路径,将待修复的文件列表写入到in路径中,ReconstructionMapper.class作为job的实现类。

BlockIntegrityMonitor和RaidShell对文件的修复最终都通过BlockReconstructor来完成。 BlockReconstructor修复文件过程主要分为三类:Har parity文件,parity文件和源数据文件。

Har parity文件

  1. 获取har文件的基本信息及index
  2. 获取har文件中的lost block,对每个block进行如下处理:
  3. 在本地文件系统创建该block的临时文件,
  4. 对该block涉及的所有parity文件,获取对应的source文件,通过Encoder重新encode,在本地生成parity数。
  5. 将本地生成的block数据发送到一个datanode上,datanode的选取规则是从集群中除原block所属节点外随机选取一个。发送过程同时生成block的meta文件。

parity文件

parity文件的修复处理相对简单:

  1. 在本次创建lost block的临时文件
  2. 获取parity文件的源文件,通过Encoder重新encode,在本地生成parity文件的block
  3. 选取一个dn(选取规则和har parity文件修复一致),将block数据发送到该dn上,并同时生成meta文件

源数据文件

源文件的恢复与parity文件的修复相反,是一个decode过程:

  1. 对于file中丢失的每个block执行修复操作

  2. 在本地创建block的临时文件

  3. 通过Decoder恢复block数据

  4. 选取一个target dn,将block数据发送给target dn,并同时生成meta文件。

    Decoder的修复过程:即一个parity文件的decode过程:

    Decode

    1. 根据文件中出错的位置,计算出错的block,该block所在的stripe,以及在stripe中的位置,计算parity文件相应block的位置。
    2. 通过ParallelStreamReader读取源block数据和parity数据,读取方式与编码时类似
    3. 通过Erasured Code将源block和parity数据的进行解码,生成丢失的block数据
  private void startJob(String jobName, Set<String> lostFiles, Priority priority)
    throws IOException, InterruptedException, ClassNotFoundException {
      Path inDir = new Path(JOB_NAME_PREFIX + "/in/" + jobName);
      Path outDir = new Path("/user/work/"+JOB_NAME_PREFIX + "/out/" + jobName);
      List<String> filesInJob = createInputFile(
          jobName, inDir, lostFiles);
      if (filesInJob.isEmpty()) return;

      Configuration jobConf = new Configuration(getConf());
      if (jobpool != null){
    	  jobConf.set("mapred.fairscheduler.pool", jobpool);
      }
      
      RaidUtils.parseAndSetOptions(jobConf, priority.configOption);
      if (priority == priority.HIGH){
        jobConf.set("mapred.job.priority", "HIGH");
      }

      Job job = new Job(jobConf, jobName);
      configureJob(job, this.RECONSTRUCTOR_CLASS);
      job.setJarByClass(getClass());
      job.setMapperClass(ReconstructionMapper.class);
      job.setNumReduceTasks(0);
      job.setInputFormatClass(ReconstructionInputFormat.class);
      job.setOutputFormatClass(SequenceFileOutputFormat.class);
      job.setOutputKeyClass(Text.class);
      job.setOutputValueClass(Text.class);
      
      ReconstructionInputFormat.setInputPaths(job, inDir);
      SequenceFileOutputFormat.setOutputPath(job, outDir);
      submitJob(job, filesInJob, priority);
      List<LostFileInfo> fileInfos =
        updateFileIndex(jobName, filesInJob, priority);
      // The implementation of submitJob() need not update jobIndex.
      // So check if the job exists in jobIndex before updating jobInfos.
      if (jobIndex.containsKey(job)) {/// sumbit put job null
        jobIndex.put(job, fileInfos);
      }
      numJobsRunning++;
    }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值