hadoop hdfs 性能调优

说明

  • 其实hdfs 并不适合作为小文件的分布式存储系统 . 前人埋下的坑....

背景

  • 一次线上环境的hdfs namenode 进程打满cpu. 一直在百分之6 7百 . namenode 一直在做 full gc, 此时hdfs基本处于不可用状态 , 此时系统可用内存又不足,而且cpu负载很高. 由于这个环境第一次接手维护 . 这篇文章主要总结下如何做的优化.

环境:

  • hadoop 版本:Hadoop 2.6.0-cdh5.5.0
  • 服务器 : CentOS release 5.6 (Final) , 32G 内存 , 8核cpu , 12块盘
  • 内核版本: Linux version 2.6.18-308.13.1.el5
  • hadoop 集群一共三台机器 , namenode 做了自动HA , datanode 也都在这三台机器上.

正文

  这个hadoop 环境是通过CDH 的Unmanaged Deployment方式来安装的 . 可以参考这里 ,没有管理端 没有监控. (个人还是偏好社区版本 , 灵活可控. ) . 那没有监控自然是先加监控呗

指标收集

  • 采集工具
      没有监控首先考虑的是加个监控上去 . 由于我们线上有opentsdb , grafana . 缺了个采集工具 , 网上找了把 , 找了个tcollector可以作为指标采集的工具. 参考这里. 而且tcollector自带了hadoop 的采集脚本.这个采集脚本使用了python语言通过采集hadoop 提供的 restapi接口来实现的. 具体hadoop指标参考这里
  • 兼容性的适配
       例如: 1. 在hadoop_namenode.py这个采集脚本里面连接的本地是localhost地址. 由于我们hdfs没有监听localhost ip所以连不上. 2. 在procstats.py这个采集系统状态的脚本里面会用到/proc/softirqs这个系统状态文件.然而在Linux version 2.6.18这个版本里面没有这个文件.
  • 定制化监控
      在tcollector这个程序里添加一个定制化监控还是非常简单的. 只要在它指定的文件夹中添加一个采集脚本 在程序里按照它的格式输出就可以 . 用python ,shell 实现都可以. 例如
#!/bin/bash
. "/etc/profile"
etc_path="$(cd "`dirname "$0"`"/../etc; pwd)"
run_day=$(date "+%Y-%m-%d")
time=$(date '+%H%M')
for i in `cat ${etc_path}/dir.txt` ;
 do
 meta_array=($(hadoop fs -count $i 2> /dev/null))
 echo "hadoop.hdfs.dir.count.dirs $(date +"%s") ${meta_array[0]:-0} dir=$i "
 echo "hadoop.hdfs.dir.count.files $(date +"%s") ${meta_array[1]:-0} dir=$i "
 echo "hadoop.hdfs.dir.count.size $(date +"%s") ${meta_array[2]:-0} dir=$i "
done ;

这里实现的是对重点目录的增长趋势做一个监控. 输出的第一列是指标名称. 第二列是时间戳, 第三列是指标值 后面是tags键值对. tcollector在读取到脚本输出后会自动将指标输出到opentsdb中去.

  • 启动tcollector
sh tcollector start -L opentsdb_host1,opentsdb_host2 -v -D

指标分析

  • 下图展示了张系统的内存的指标 (其实想精确统计系统可用内存还是很困难的这个后面会提到) 从这张图看系统可用内存还是挺紧张的. 而且系统已经用了一部分swap. 我们系统的swappiness 设置的是0(可以通过命令cat /proc/sys/vm/swappiness 查看) . 这表示只有物理内存已经快用尽了才会使用swap.(ps , 好像最新的内核如果设置为0 , 表示never swap .)


    系统内存

系统swap

但是系统内存都用到哪里去了呢 , 统计所有进程总共占用多少内存可以用下面的命令进行统计

[root@XXX scripts]#  grep Pss /proc/[1-9]*/smaps | awk '{total+=$2}; END {print total}'

结果是进程占用的内存才十多个G 远没到30多G那剩下的内存去哪里了呢,

[root@XXX scripts]# free -m
             total       used       free     shared    buffers     cached
Mem:         32176      32026        150          0        801         76
-/+ buffers/cache:      31148       1028
Swap:        18041       1643      16398

那系统内存被谁给用去了呢 而且此时的cpu负载一直很高


系统cpu负载
slab_info

为了看了更直观,这里的slab用了负值表示.这里可以看出系统内存波动和slab完全一致. 那slab又被谁给用去了呢


slabtop

使用slabtop命令看到slab绝大部分被ext3_inode_cache和dentry_cache 用去了. 而ext3_inode_cache是被谁用去了呢. 在top 查看进程时 ,经常看到du -sk /data1/hdfs/data/current/BP-xx.xx.xx.xx 在运行. 我们有12块盘,所以经常看到很多du -sk 在运行. 这个统计脚本的父进程是datanode, datanode 会定期(默认10分钟)统计BP的大小.我们每块盘都有大量的小文件. 其中一块盘就有差不多块200万的文件. 12块盘那就是2000多万的文件.

##统计一个目录下的文件个数
[root@XXXX  hdfs]# ls -lR| grep "^-" | wc -l
1885296

这时使用du -sk是非常耗时的.它会递归文件所以会导致slab cache一直很高.基本都超过10分钟.du -sk 这个命令在2.8的版本已经可以被替换了 详情见这里
这里提到可以用df 替换du的一个方案具体实现是这样的

mv /usr/bin/du /usr/bin/du_bak
vim /usr/bin/du

#!/bin/sh
if [[ $2 == */current/BP-* ]] && [ $1 == -sk ]
then
    used=`df -k $2 | grep -vE 'Used|可用' | awk '{print $3}'`
    echo -e "$used\t$2"
else
    echo -e "$(du_bak $@)"
fi
chmod +x /usr/bin/du

方案参考这里
由于df是基于硬盘统计的所以很快, 而du是基于文件统计的. 这种方案在datanode的目录分别在不同的硬盘上问题不大.
而且调整后的效果很明显(红框是调整后的效果)

meminfo

上图可以看到slab里用到的cache明显减少 . 用于系统的cache明显增多.而且系统的cpu负载也明显降低
红框是调整后的效果

细心的同学可能还会问,为什么还是每隔6个小时slab还是会去增长呢. 这是由于datanode 的directoryscan会每隔6小时扫描一次目录这里也是递归,会去检查文件是否有坏块, 丢失块或者不一致的情况.

这里可以调整/proc/sys/vm/vfs_cache_pressure的值让操作系统更加积极的回收slab里面的cache . 默认是100 可以被调整500或1000.这里调整到500 . 下面这张图可以看到调整前后的变化.


vfs_cache_pressure调整前后比较

总结

说明

  • 不同linux版本的free看到的统计方式不一样.参考这里

    当我们考虑有多少cache可供回收的时候,首先要知道的是:不同版本的”free”命令计算cache值的算法不同,据不完全统计举例如下:
    版本:procps-3.2.8-36
    cache值等于/proc/meminfo中的”Cached”;
    版本:procps-3.3.9-10.1
    cache值等于/proc/meminfo的 [Cached + SReclaimable];
    版本:procps-ng-3.3.10-3
    cache值等于/proc/meminfo的 [Cached + Slab]。

  • 系统可用内存的计算方式 参考这里
      如果/proc/meminfo中有MemAvailable时取MemAvailable
    /proc/meminfo中无MemAvailable时取 free+cache+ SReclaimable 当然cache 里面还有一分部可能不能被回收.
      总的来说 很难精确估计系统剩余可用内存.

海量小文件优化方案

  • 使用df替换du去统计
  • 修改vfs_cache_pressure的值让系统内核更加积极回收slab里的cache
  • 减少数据存储的现有目录层级[HDFS-8791]参考这里
  • 控制扫描的速度 参考这里 . hadoop2.8 提供了控制Allow the directoryScanner to be rate-limited
  • 使用文件归档 Archives 参考这里 可以将多个文件合并成一个文件.

你可能感兴趣的:(hadoop hdfs 性能调优)