numSplits源码分析

本文详细解析了Hadoop MapReduce作业如何根据输入文件大小和预设的Map任务数,智能地将大文件拆分为多个小任务进行并行处理,以提高数据处理效率。
/** Splits files returned by {@link #listStatus(JobConf)} when
   * they're too big.*/ 
//numSplits:来自job.getNumMapTasks(),即在job启动时用org.apache.hadoop.mapred.JobConf.setNumMapTasks(int n)设置的值,给M-R框架的Map数量的提示
  public InputSplit[] getSplits(JobConf job, int numSplits)
    throws IOException {
      //一个简化的秒表实现,可以在纳秒内测量时间
    StopWatch sw = new StopWatch().start();
      //返回FileStatus对象数组-->getInputPaths获得输入目录列表
    FileStatus[] files = listStatus(job);
    
    // Save the number of input files for metrics/loadgen
    job.setLong(NUM_INPUT_FILES, files.length);
    long totalSize = 0;                           // compute total size
    for (FileStatus file: files) {                // check we have valid files
      if (file.isDirectory()) {
        throw new IOException("Not a file: "+ file.getPath());
      }
      //totalSize:是整个Map-Reduce job所有输入的总大小
      totalSize += file.getLen();
    }

    //goalSize为“InputFile大小”/“我们在配置文件中定义的mapred.map.tasks”值
      //如果不给默认初始化0
    long goalSize = totalSize / (numSplits == 0 ? 1 : numSplits); 
    //minSize:取的1和mapred.min.split.size中较大的一个。(getLong()方法,如果不设置 为null 返回defaultValue 1,如果设置后,返回设置数值对应的16进制(Long))
    long minSize = Math.max(job.getLong(org.apache.hadoop.mapreduce.lib.input.
      FileInputFormat.SPLIT_MINSIZE, 1), minSplitSize);

    // generate splits
    ArrayList<FileSplit> splits = new ArrayList<FileSplit>(numSplits);
    //这个类带有网络拓扑信息
    NetworkTopology clusterMap = new NetworkTopology();
    for (FileStatus file: files) {
      Path path = file.getPath();
      //得到文件的长度
      long length = file.getLen();
      if (length != 0) {//如果不为0
        //返回拥有此路径的文件系统
        FileSystem fs = path.getFileSystem(job);
        //该数组含有块的网络位置、主机信息包含块副本和其他块元数据(例如文件)与块、长度、是否损坏等相关的偏移量)
        BlockLocation[] blkLocations;
        //如果LocatedFileStatus是FileStatus的子类
        if (file instanceof LocatedFileStatus) {
          //类型强转后获得文件的块位置
          blkLocations = ((LocatedFileStatus) file).getBlockLocations();
        } else {
          //不能向下转型   返回一个包含主机名、偏移量和大小的数组
          blkLocations = fs.getFileBlockLocations(file, 0, length);
        }
        //如果可以切片,默认为true
        if (isSplitable(fs, path)) {
          //获取文件的块大小
          long blockSize = file.getBlockSize();
          //得到分片的大小
          long splitSize = computeSplitSize(goalSize, minSize, blockSize);
		
          //定义一个bytesRemaining(剩余文件的长度) 初始值等于文件的长度
          long bytesRemaining = length;
          //只要文件的长度除以分片的大小 大于 SPLIT_SLOP(默认为1.1D)
          while (((double) bytesRemaining)/splitSize > SPLIT_SLOP) {
              //返回两个数组——其中一个主机对这个分割贡献最大,和对这个分割贡献最大的主机之一,它拥有数据缓存到它们上---getSplitHostsAndCachedHosts函数识别并返回做出共享的主机(贡献大的优先机架上贡献少的)
            String[][] splitHosts = getSplitHostsAndCachedHosts(blkLocations,
                length-bytesRemaining, splitSize, clusterMap);
              //添加到List集合中
            splits.add(makeSplit(path, length-bytesRemaining, splitSize,
                splitHosts[0], splitHosts[1]));
              //剩余文件的长度
            bytesRemaining -= splitSize;
          }

            //如果相除后小于SPLIT_SLOP(默认的溢出值)且剩余文件长度不等于0
          if (bytesRemaining != 0) {
              //同样返回两个数组——其中一个主机对这个分割贡献最大,和对这个分割贡献最大的主机之一,它拥有数据缓存到它们上
            String[][] splitHosts = getSplitHostsAndCachedHosts(blkLocations, length - bytesRemaining, bytesRemaining, clusterMap);
            splits.add(makeSplit(path, length - bytesRemaining, bytesRemaining,
                splitHosts[0], splitHosts[1]));
          }
        } else {//如果设置为不能切分,则把整个文件及其主机信息等放入数组添加到集合
          String[][] splitHosts = getSplitHostsAndCachedHosts(blkLocations,0,length,clusterMap);
          splits.add(makeSplit(path, 0, length, splitHosts[0], splitHosts[1]));
        }
      } else { 
        //Create empty hosts array for zero length files
        splits.add(makeSplit(path, 0, length, new String[0]));
      }
    }
07-16 14:10:29.691 16109 16109 I A0FF00/wei.hmos.hiviewx:workScheduler/[HiViewX]: Signature, getSignatureString canonicalReq = /v2/getUploadInfo 07-16 14:10:29.694 16109 16109 I A0FF00/wei.hmos.hiviewx:workScheduler/[HiViewX]: RequestAction, post begin 07-16 14:10:29.697 16109 16109 I C015C5/wei.hmos.hiviewx:workScheduler/NETSTACK_RCP: Run request id: 34 07-16 14:10:29.706 16109 16109 I A0FF00/wei.hmos.hiviewx:workScheduler/[HiViewX]: ChargingStatusUtils, isCharging false 07-16 14:10:29.706 16109 16109 I A0FF00/wei.hmos.hiviewx:workScheduler/[HiViewX]: ChargingStatusUtils, battery changed usual.event.BATTERY_CHANGED 07-16 14:10:29.708 16109 16397 W C01719/wei.hmos.hiviewx:workScheduler/ffrt: 16:RecordSymbolAndBacktrace:263 Task_Sch_Timeout: process name:[com.huawei.hmos.hiviewx:workScheduler], Tid:[16299], Worker QoS Level:[3], Concurrent Worker Count:[3], Execution Worker Number:[2], Sleeping Worker Number:[1], Task Type:[0], occupies worker for more than [1]s 07-16 14:10:29.951 16109 16402 I C015C5/wei.hmos.hiviewx:workScheduler/NETSTACK_RCP: id=34, httpVer:1.1, method:POST, size:692, statusCode: 200. httpPhase:111111, dnsDur:0.61, tcpDur:55.82, tlsDur:99.00, sndDur:1.43, rcvDur:88.18, totDur:245.52, redDur:0.00, sptIP6:0, proxyType:none, uptProxyMs:0, lastOsIn:14:10:29.949, lastOsOut:14:10:29.761, srcAddr:192.168.*.***, srcPort:34432, dstAddr:36.150.***.**, dstPort:443, sock:142, dnsDur:0.61, tcpDur:55.82, tlsDur:99.00, sndDur:1.43, rcvDur:88.18, totDur:245.52, redDur:0.00, 07-16 14:10:29.956 16109 16109 I A0FF00/wei.hmos.hiviewx:workScheduler/[HiViewX]: UploadInfoRequestAction, result: Unsupported model 07-16 14:10:29.957 16109 16109 I C03F01/wei.hmos.hiviewx:workScheduler/NAPI: taskpool:: Task Allocation: 101368320, 1 07-16 14:10:29.958 16109 16370 I C03F01/wei.hmos.hiviewx:workScheduler/NAPI: taskpool:: Task Perform: q20, 101368320, runningLoop: 543380164608 07-16 14:10:29.959 16109 16370 I A0FF00/wei.hmos.hiviewx:workScheduler/[HiViewX]: FileUtils, splitFileBySize numSplits = 1.9082292020320892 07-16 14:10:29.960 16109 16371 I C04707/wei.hmos.hiviewx:workScheduler/HaAppEvent: OnEvent(api_diagnostic, 0, api_exec_end) 07-16 14:10:29.962 16109 16371 I C04707/wei.hmos.hiviewx:workScheduler/HaAppEvent: OnEvent(api_diagnostic, 0, api_exec_end) 07-16 14:10:30.610 16109 16299 I C02D11/DfxSignalHandler: crash processdump unwind finish, unwind success Flag 610839791, blockFlag 0 07-16 14:10:30.611 16109 16299 I C02D11/DfxSignalHandler: Finish handle signal(11) in 16109:16299. 07-16 14:10:30.611 16109 16299 E C03F00/MUSL-SIGCHAIN: signal_chain_handler SIG_DFL handler for signal: 11
最新发布
07-17
这段日志来自 **OpenHarmony(鸿蒙系统)** 的 `workScheduler` 模块,属于 **HiViewX 日志系统** 的一部分。整体来看,它记录了一个 **网络请求任务的执行过程**、**文件处理行为** 和 **一次崩溃(Segmentation Fault)事件**。 --- ## 🧾 日志结构解析 我们选取其中几行作为代表: ``` 07-16 14:10:29.691 16109 16109 I A0FF00/wei.hmos.hiviewx:workScheduler/[HiViewX]: Signature, getSignatureString canonicalReq = /v2/getUploadInfo 07-16 14:10:29.694 16109 16109 I A0FF00/wei.hmos.hiviewx:workScheduler/[HiViewX]: RequestAction, post begin 07-16 14:10:29.956 16109 16109 I A0FF00/wei.hmos.hiviewx:workScheduler/[HiViewX]: UploadInfoRequestAction, result: Unsupported model 07-16 14:10:30.610 16109 16299 I C02D11/DfxSignalHandler: crash processdump unwind finish, unwind success Flag 610839791, blockFlag 0 07-16 14:10:30.611 16109 16299 E C03F00/MUSL-SIGCHAIN: signal_chain_handler SIG_DFL handler for signal: 11 ``` ### ✅ 日志格式拆解: | 字段 | 内容 | 含义 | |------|------|------| | 时间戳 | `07-16 14:10:29.691` | 系统时间 | | PID | `16109` | 进程 ID | | TID | `16109` | 线程 ID | | 日志级别 | `I`(Info)、`E`(Error) | 日志严重程度 | | 标签 | `A0FF00/...`、`C02D11/...` | 日志标签,用于分类 | | 子模块 | `[HiViewX]`、`NETSTACK_RCP`、`NAPI` 等 | 表示日志来源子系统 | | 日志内容 | `Signature, getSignatureString ...` | 实际信息 | --- ## 🔍 关键字段分析 ### 1️⃣ 请求签名与发起 ```log Signature, getSignatureString canonicalReq = /v2/getUploadInfo RequestAction, post begin ``` - 表示正在为 `/v2/getUploadInfo` 接口生成签名并开始 POST 请求。 - 可能是上传数据前的身份认证或请求构造阶段。 --- ### 2️⃣ 网络请求详情 ```log id=34, httpVer:1.1, method:POST, size:692, statusCode: 200... ``` - HTTP 请求详细信息: - 方法:POST - 数据大小:692 bytes - 响应码:200(成功) - DNS、TCP、TLS、发送接收耗时等性能指标 - 目标地址和端口:`36.150.***.**:443` - 源地址和端口:`192.168.*.***:34432` 这表明这个请求是一个 HTTPS 请求,成功获取了服务器响应。 --- ### 3️⃣ 请求结果 ```log UploadInfoRequestAction, result: Unsupported model ``` - 虽然 HTTP 返回了 200 成功状态码,但服务器返回的业务逻辑错误是 `Unsupported model`。 - 可能是客户端使用的 API 版本不支持、设备型号不在白名单中、或者协议不兼容。 --- ### 4️⃣ 文件分片处理 ```log FileUtils, splitFileBySize numSplits = 1.9082292020320892 ``` - 表示尝试对一个文件进行按大小分片处理。 - `numSplits ≈ 1.908` 表示文件略大于单个分片限制,因此被分为 2 份。 --- ### 5️⃣ 异常崩溃日志 ```log crash processdump unwind finish, unwind success Flag 610839791, blockFlag 0 Finish handle signal(11) in 16109:16299. signal_chain_handler SIG_DFL handler for signal: 11 ``` - `signal: 11` 是 **SIGSEGV(Segmentation Fault)**,表示访问非法内存地址导致程序崩溃。 - `unwind success` 表示堆栈回溯成功,系统已经完成了崩溃现场保存。 - `DfxSignalHandler` 是 OpenHarmony 中负责异常信号处理的模块。 --- ## 📌 总结流程图 ```text [1] 构造请求签名 → [2] 发起 POST 请求到 /v2/getUploadInfo → [3] 成功建立 HTTPS 连接(DNS/TLS/TCP)→ [4] 收到响应 200 OK,但业务层返回 "Unsupported model" → [5] 尝试对本地文件进行分片处理 → [6] 在后续处理中发生 SIGSEGV(Segmentation Fault)崩溃 ``` --- ## 🛠 分析建议 | 问题点 | 建议 | |--------|------| | `Unsupported model` | 检查当前设备型号是否在服务端允许列表内;检查 API 协议版本是否一致 | | `FileUtils splitFileBySize` | 查看文件大小阈值配置是否合理,是否频繁触发分片 | | `SIGSEGV` | 查看 native 堆栈回溯(通常会紧随其后),定位哪个模块访问了非法内存地址 | --- ## ✅ 总结表格 | 模块 | 日志内容 | 含义 | |------|----------|------| | HiViewX | Signature, getSignatureString | 请求签名 | | HiViewX | RequestAction, post begin | 开始 POST 请求 | | NETSTACK_RCP | id=34, statusCode=200 | 成功的 HTTPS 请求 | | HiViewX | UploadInfoRequestAction, result: Unsupported model | 业务层错误 | | NAPI | FileUtils, splitFileBySize | 文件分片 | | DfxSignalHandler | Finish handle signal(11) | 段错误崩溃 | --- ###
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值