Hadoop DataNode IO高问题排查

最近,有个客户反应,他通过Flume写入HDFS的数据经常超时,写入失败等。我看了一下他的集群,使用的是Aliyun D1机型,即本地盘,写入速度单盘一般都是100MB+,所以在磁盘性能上应该不存在太多问题。
登录集群后,看了一下基本的IO,CPU等信息,发现有大量的磁盘IO Util到达了100%,通过iotop查看io较多的进程,发现是Hadoop DataNode进场占用较多,进而查看到DataNode的一个du -sk 占用了大量的IO。
默认的DataNode会定期10分钟对磁盘空间进行扫描,使用的是DU命令,但是如果目录存在大量文件,并且文件经常变化,会导致DU需要大量的随机读,并引发IO使用率飙升。
至于这个客户的情况是,他通过flume写入了大量的小文件,每个6TB磁盘写入了150万个文件,一次DU将近了5分钟以上,这样子他大部分的时间都在进行无意义的IO操作,从而有效的IO写入操作延迟,甚至中断连接。
针对这一问题,有两种方式解决:
1.https://issues.apache.org/jira/browse/HADOOP-9884
这个jira基本上是希望通过df来代替du
2.修改fs.du.interval参数
修改这个参数,比如每个小时进行一次磁盘空间大小检查操作

最后用户是通过了第二种方式,将磁盘空间检查时间从10分钟提升到了1小时,基本上解决了写入问题。

TensorFlow Session restore checkpoint

最近写了一些TensorFlow的小程序,遇到了一个session无法restore checkpoint的问题,写法非常简单,使用的是

with tf.train.MonitoredTrainingSession(master = server.target,
                                           is_chief = task_index == 0,
                                           checkpoint_dir= checkpoint_dir,
                                           save_checkpoint_secs=20) as sess:

按理说,tf.train.MonitoredTrainingSession能够save和restore checkpoint,经过测试发现,save是没问题的,但是每次训练都是新的模型,没有持续训练。
经过多次查找,才发现正确的写法。
根据TF官网,save 和restore只需要使用tf.train.Saver()就可以解决问题。但是我根据官网去实现,却报了很多错误,最后发现,通过以下方法才可以,首先要获取latest checkpoint文件,就是最近的checkpoint文件,包括模型参数。
然后将模型restore出来,但是别忘了之前要reset这次训练的graph。
代码如下:

checkpoint_dir = "hdfs://emr-header-1:9000/movie"
saver = tf.train.Saver()
epoch = 0

with tf.train.MonitoredTrainingSession(master = server.target,
                                           is_chief = task_index == 0,
                                           checkpoint_dir= checkpoint_dir,
                                           save_checkpoint_secs=20) as sess:
     tf.reset_default_graph()
     sess.run(init)
     latest_path = tf.train.latest_checkpoint(checkpoint_dir=checkpoint_dir)
     saver.restore(sess, latest_path)

Hadoop CGroup 设置

hadoop 2.8 CGroup的设置,CentOS7 默认的CGroup位置在/sys/fs/cgroup/cpu 等,如果Hadoop不设置自动mount,而是使用默认mount位置的话,会mount到/sys/fs/cgroup/cpu/hadoop-yarn,所以如果要在Hadoop2.8版本请做以下操作:

假设以Hadoop用户启动YARN:
mkdir -p /sys/fs/cgroup/cpu/hadoop-yarn
chown -R hadoop:hadoop /sys/fs/cgroup/cpu/hadoop-yarn

修改如下配置:
yarn.nodemanager.container-executor.class   org.apache.hadoop.yarn.server.nodemanager.LinuxContainerExecutor
yarn.nodemanager.linux-container-executor.resources-handler.class  org.apache.hadoop.yarn.server.nodemanager.util.CgroupsLCEResourcesHandler
yarn.nodemanager.linux-container-executor.group hadoop

然后重启Node Manager就可以了

解决Docker容器中 mpi 日志丢失问题

最近使用Docker跑Tensorflow的时候,经常发现通过docker java api获取不到Tensorflow的日志获取日志的代码如下:

  private class DockerLogReader extends LogContainerResultCallback {
    @Override
    public void onStart(Closeable stream) {
      System.out.println("start");
    }

    @Override
    public void onNext(Frame item) {
      System.out.print(new String(item.getPayload()));
    }

    @Override
    public void onError(Throwable throwable) {
      System.out.print(throwable.getMessage());
    }

    @Override
    public void onComplete() {
      super.onComplete();
      System.out.println("Docker exit.");
    }
  }

正常情况下,代码会走到onNext中,从而收集到Docker中正在运行的TensorFlow的日志,由于使用的是Horovod,所以底层使用的是MPI去运行程序。然后在运行过程中,只打印了Python程序中的日志,而TensorFlow中的日志全部丢失了。
为了解决这一问题,单独起了两个Docker container,然后手动启动mpi,mpi的命令为:

mpirun  --allow-run-as-root -np 2 ***** >stdout 2>stderr

将命令重定向后发现stdout,stderr就是 docker java获取的日志,但是console能够打出日志,查询了mpi的文档,发现了一个选项-tag-output,同时将stderr重定向的stdout中

mpirun -tag-output --allow-run-as-root -np 2 ***** 2>&1

经过修改后,日志全部打印出来。成功解决这一问题。

pyspark with jupyter

首先配置jupyter config文件。

jupyter-notebook --generate-config

修改jupyter config文件

c.NotebookApp.port = 18888
c.NotebookApp.ip = '0.0.0.0'
c.NotebookApp.allow_root = True

当然要配置好spark,emr环境spark已经完全配置正确。配置pyspark参数

export PYSPARK_DRIVER_PYTHON=jupyter
export PYSPARK_DRIVER_PYTHON_OPTS='notebook'

启动pyspark即可。

pyspark --master yarn

Hadoop NameNode元数据恢复

最近在为用户解决问题的时候发现的,个别用户删除了namenode standby的所有元数据,为了恢复数据可以做以下操作:

1.停止任务
2.namenode 进入safemode

hdfs dfsadmin -safemode enter

3.nameonde存储元数据

hdfs dfsadmin -saveNamespace

4.备份active元数据

备份 /mnt/disk1/hdfs 下所有数据

5.拷贝active数据到standby
将/mnt/disk1/hdfs 数据拷贝到standby
6.重启standby
7.重启成功后,退出safemode

hdfs dfsadmin -safemode leave

8.恢复任务

gperftool安装及使用说明

安装方法
1.从github上下载代码到服务器上
2../autogen.sh
需要提前安装autoconf,libtool,gcc-c++,libunwind。先安装libunwind,下载源码包:

./configure && make && make install
yum install -y autoconf libtool gcc-c++

使用方法

export LD_PRELOAD=/usr/lib/libtcmalloc.so:/usr/lib/libprofiler.so
CPUPROFILE=/tmp/cpu java ****
HEAPPROFILE=/tmp/heap java ****

查看结果:
pprof --text /bin/java /tmp/cpu
pprof --text /bin/java /tmp/heap

解决Mac Os X ssh LC_CTYPE警告问题

自从Mac升级以后,登录到linux服务器上,总会报如下的错误:

warning: setlocale: LC_CTYPE: cannot change locale (UTF-8): No such file or directory

并且中文显示全是乱码,google了一下发现是由于mac ssh过去的时候把LANG环境变量也传递了过去,与服务器的不match导致的。解决方法也很简单,去掉LANG环境变量传输:

sudo vi /etc/ssh/ssh_config
注释掉   SendEnv LANG LC_*

创建gpu挂载/dev/nvidia开机启动进程

由于GPU机器重启后gpu的device并不会主动挂载,所以需要开机后执行一个脚本,开机自动挂载,以便于后面Docker进行挂载。执行的脚本gpu-service如下:

#!/bin/bash

/sbin/modprobe nvidia

if [ "$?" -eq 0 ]; then
  # Count the number of NVIDIA controllers found.
  NVDEVS=`lspci | grep -i NVIDIA`
  N3D=`echo "$NVDEVS" | grep "3D controller" | wc -l`
  NVGA=`echo "$NVDEVS" | grep "VGA compatible controller" | wc -l`

  N=`expr $N3D + $NVGA - 1`
  for i in `seq 0 $N`; do
    mknod -m 666 /dev/nvidia$i c 195 $i
  done

  mknod -m 666 /dev/nvidiactl c 195 255

else
  exit 1
fi

/sbin/modprobe nvidia-uvm

if [ "$?" -eq 0 ]; then
  # Find out the major device number used by the nvidia-uvm driver
  D=`grep nvidia-uvm /proc/devices | awk '{print $1}'`

  mknod -m 666 /dev/nvidia-uvm c $D 0
else
  exit 1
fi

需要加入新的system服务,方法为

touch /etc/systemd/system/gpu.service
chmod 664 /etc/systemd/system/gpu.service

修改gpu.service文件为

[Unit]
Description=auto run gpu construct
[Service]
Type=simple
ExecStart=/usr/sbin/gpu-service
[Install]
WantedBy=multi-user.target

将gpu-service脚本拷贝到/usr/sbin/gpu-service

mv gpu-service usr/sbin/
chmod 554 /usr/sbin/gpu-service

通过systemctl命令,将gpu-service作为开机自启动命令

systemctl daemon-reload
systemctl enable gpu.service

TensorFlow源码编译问题汇总

根据官网指南,按照官网说明,首先要安装protobuf 3.0+的版本。在configure过程中,按照说明,一步步点击需要的部分。然后通过bazel编译,当然bazel版本要使用0.6以下的版本。
通过bazel编译

bazel build --config=opt --config=cuda //tensorflow/tools/pip_package:build_pip_package

然后报错

ERROR: /mnt/disk1/taokelu/tensorflow-1.3.0/tensorflow/tools/pip_package/BUILD:134:1: error loading package 'tensorflow/contrib/session_bundle': Encountered error while reading extension file 'protobuf.bzl': no such package '@protobuf//': java.io.IOException: Error downloading [https://github.com/google/protobuf/archive/0b059a3d8a8f8aa40dde7bea55edca4ec5dfea66.tar.gz, http://mirror.bazel.build/github.com/google/protobuf/archive/0b059a3d8a8f8aa40dde7bea55edca4ec5dfea66.tar.gz] to /root/.cache/bazel/_bazel_root/d3cc9e5e7119c18dd166b716d8b55c4b/external/protobuf/0b059a3d8a8f8aa40dde7bea55edca4ec5dfea66.tar.gz: Checksum was e5fdeee6b28cf6c38d61243adff06628baa434a22b5ebb7432d2a7fbabbdb13d but wanted 6d43b9d223ce09e5d4ce8b0060cb8a7513577a35a64c7e3dad10f0703bf3ad93 and referenced by '//tensorflow/tools/pip_package:build_pip_package'.

这个错误是sha错误,解决方法是去掉sha比较。

sed -i '@https://github.com/google/protobuf/archive/0b059a3d8a8f8aa40dde7bea55edca4ec5dfea66.tar.gz@d' tensorflow/workspace.bzl