共计 4571 个字符,预计需要花费 12 分钟才能阅读完成。
前言
由于项目中,需要统计每个业务组使用的计算机资源,如 cpu,内存,io 读写,网络流量。所以需要阅读源码查看 Hadoop 的默认 counter。
MapReduce Counter 可以观察 MapReduce job 运行期的一些细节数据,Counter 有 ” 组 group” 的概念,用于表示逻辑上相同范围的所有数值。
cpu
如何衡量 mapreduce 的任务的计算量呢,如果按照任务的运行时间,有些任务的大部分时间可能卡在最后一个 reduce,或者运行期间有资源抢占问题,造成运行时间较高。如果按照任务的 map 数和 reduce 数,也是不准确的,因为有些 map 和 reduce 处理的数据量很少,运行时间很短。
hadoop 任务的运行使用的 cpu 时间,才是衡量任务的计算量,hadoop 提供的 counter:”Map-Reduce Framework:CPU time spent (ms)”, 就是任务运行耗费的 cpu 时间,这个 cpu 时间是如何统计出来的,是 hadoop 在运行期间,每个 task会从/proc/<pid>/stat 读取对应进程的用户 cpu 时间和内核 cpu 时间,他们的和就是 cpu 时间。
附:task 获取 cpu 时间的源码:org.apache.hadoop.mapred.Task.updateResourceCounters–> org.apache.hadoop.util.LinuxResourceCalculatorPlugin.getProcResourceValues(获取 cpu 和内存资源)–> org.apache.hadoop.util.ProcfsBasedProcessTree.getProcessTree.
内存
hadoop 默认 counter,获取内存信息,有以下参数:
“Map-Reduce Framework:Physical memory (bytes) snapshot” 每个 task 会从 /proc/<pid>/stat 读取对应进程的内存快照,这个是进程的当前物理内存使用大小。
“Map-Reduce Framework:Virtual memory (bytes) snapshot” 每个 task 会从 /proc/<pid>/stat 读取对应进程的虚拟内存快照,这个是进程的当前虚拟内存使用大小。
“Map-Reduce Framework:Total committed heap usage (bytes)” 每个 task 的 jvm 调用 Runtime.getRuntime().totalMemory()获取 jvm 的当前堆大小。
附:task 获取内存的源码:org.apache.hadoop.mapred.Task.updateResourceCounters
io 读写
hadoop 读写文件,都是使用 org.apache.hadoop.fs.FileSystem.open 一个文件,如果是 hdfs 文件,就有 hdfs:// 开头的文件 url,如果是本地文件,就是 file:// 开头的文件 url。所以每个 task 的文件读写情况,都可以从 FileSystem.getAllStatistics()获取,而 hadoop 使用FileSystemCounters 记录了 FileSystem 的一切 io 读写大小,FileSystemCounters 分析如下:
“FileSystemCounters:HDFS_BYTES_READ” job 执行过程中,只有 map 端运行时,才从 HDFS 读取数据,这些数据不限于源文件内容,还包括所有 map 的 split 元数据。所以这个值应该比 FileInputFormatCounters.BYTES_READ 要略大些。
“FileSystemCounters:HDFS_BYTES_WRITTEN” job 执行过程中,累计写入 HDFS 的数据大小,reduce 在执行完毕后,会写入到 HDFS(存在只有 map,没有 reduce 的情况,该情况是 map 执行完毕把结果写入到 HDFS)。
“FileSystemCounters:FILE_BYTES_READ” 累计读取本地磁盘的文件数据大小,map 和 reduce 端有排序,排序时需要读写本地文件。
“FileSystemCounters:FILE_BYTES_WRITTEN” 累计写入本地磁盘的文件数据大小,map 和 reduce 端有排序,排序时需要读写本地文件,还有 reduce 做 shuffle 时,需要从 map 端拉取数据,也存在写入本地磁盘文件的情况。
附:FileSystemCounters 相关代码:org.apache.hadoop.mapred.Task.updateResourceCounters–> org.apache.hadoop.mapred.Task.FileSystemStatisticUpdater.updateCounters
FileSystemCounters 的 counter 对于 io 读写的数据,已经很齐全,但是 hadoop 还有一些细微的 io 读写的 counter:
“File Input Format Counters:Bytes Read” job 执行过程中,Map 端从 HDFS 读取的输入的 split 的源文件内容大小,但是不包括 map 的 split 元数据,所以这个值和 ”FileSystemCounters:HDFS_BYTES_READ” 略小,但是很接近。如果 map 输入的源文件是压缩文件,它的值只是压缩文件解压前的大小 ( 附:代码位于 org.apache.hadoop.mapred.MapTask.TrackedRecordReader.fileInputByteCounter)。
“Map-Reduce Framework:Map input bytes” job 执行过程中,Map 端从 HDFS 读取的输入的 split 的源文件内容大小, 如果源文件是压缩文件,它的值是压缩文件解压后的大小 ( 附:代码位于 org.apache.hadoop.mapred.MapTask.TrackedRecordReader.inputByteCounter)。
“File Output Format Counters:Bytes Written” job 执行过程中, 会分为 map 和 reduce,但是也可能存在只有 map 的情况,但是 job 执行完毕后,一般都要把结果写入到 hdfs,该值是结果文件的大小,如果是压缩文件,它的值只是压缩文件解压前的大小 ( 附:代码位于 org.apache.hadoop.mapred.MapTask.DirectMapOutputCollector.fileOutputByteCounter 和 org.apache.hadoop.mapred.ReduceTask.NewTrackingRecordWriter.fileOutputByteCounter)。
但是这些细微的 counter,没有统计 map 和 reduce 排序时文件读写的情况,所以要衡量 job 任务的 io 读写情况,我觉得最合适的还是使用 FileSystemCounters 的 counter。
io 读写流量大致可以通过上述 FileSystemCounters 四个参数求和而得,存在不足就是:
“FileSystemCounters:HDFS_BYTES_WRITTEN”,它只是一个副本的 hdfs 的写入大小,而 hdfs 的块副本是可以调整的,所以 io 读写流量,还需要 ”FileSystemCounters:HDFS_BYTES_WRITTEN” * 副本数。
map 和 reduce 都是用户自定义的,存在可能是用户代码绕过 hadoop 框架,不使用 org.apache.hadoop.fs.FileSystem.open 文件,这部分 io 读写流量,是无法被统计的。
网络流量
hadoop 任务产生网络流量的阶段:map 输入从 hdfs 拉取数据,reduce shuffle 时从 map 端拉取数据,reduce 完成往 hdfs 写入结果(如果没有 reduce,就是 map 完成往 hdfs 写入结果)。
job 和 hdfs 交互产生的流量,可以通过 io 读写分析的两个 counter 获取:”FileSystemCounters:HDFS_BYTES_READ” 和 ”FileSystemCounters:HDFS_BYTES_WRITTEN”
而 reduce shuffle 时从 map 端拉取数据产生的流量,对应的 counter 是:
“Map-Reduce Framework:Reduce shuffle bytes” 它是 reduce 往 map 拉取中间结果的累计数据大小,如果 map 产生的中间结果是压缩文件,它的值是压缩文件解压前的大小(附:代码位于 org.apache.hadoop.mapred.ReduceTask.reduceShuffleBytes)。
网络流量大致可以通过上述三个参数求和而得,存在不足就是:
“FileSystemCounters:HDFS_BYTES_READ” 和 ”FileSystemCounters:HDFS_BYTES_WRITTEN”,它没有考虑 hadoop 对 hdfs 的本地化优化,hdfs 读写块时,如果发现客户端和目标块在同一个节点,会直接通过本地读写,有些块如果在本地,hadoop 会直接通过本地文件系统读写,不通过网络读写。
“FileSystemCounters:HDFS_BYTES_WRITTEN”,它只是一个副本的 hdfs 的写入大小,而 hdfs 的块副本是可以调整的,所以网络流量,还需要 ”FileSystemCounters:HDFS_BYTES_WRITTEN” * 副本数。
map 和 reduce 都是用户自定义的,存在可能是用户代码绕过 hadoop 框架,自行产生网络通信,这部分流量是无法被统计。
————————————– 分割线 ————————————–
Ubuntu 13.04 上搭建 Hadoop 环境 http://www.linuxidc.com/Linux/2013-06/86106.htm
Ubuntu 12.10 +Hadoop 1.2.1 版本集群配置 http://www.linuxidc.com/Linux/2013-09/90600.htm
Ubuntu 上搭建 Hadoop 环境(单机模式 + 伪分布模式)http://www.linuxidc.com/Linux/2013-01/77681.htm
Ubuntu 下 Hadoop 环境的配置 http://www.linuxidc.com/Linux/2012-11/74539.htm
单机版搭建 Hadoop 环境图文教程详解 http://www.linuxidc.com/Linux/2012-02/53927.htm
————————————– 分割线 ————————————–
更多 Hadoop 相关信息见Hadoop 专题页面 http://www.linuxidc.com/topicnews.aspx?tid=13