标签为 Hadoop 的文章

分享一个Oozie Job Debug脚本

参考资料:
https://oozie.apache.org/docs/4.0.0/WebServicesAPI.html

背景介绍:
在我们的线上Hadoop集群中,采用了Oozie来作为Workflow的管理,而平时有不少Workflow在执行过程中会因为各种问题而失败。
于是,我们通常都会通过Oozie Web Console去Troubleshooting,但是整个过程并不方便,在研究了Oozie API之后,我写了一个脚本来自动化的帮我们完成绝大部分的Troubleshooting步骤。

具体配置:
整个脚本需要模拟的Troubleshooting思路如下:
1. 获取整个Workflow所有步骤的信息,通常的状态有:OK,RUNNING,FAILED,KILLED,ERROR
2. 对FAILED,KILLED,ERROR状态的步骤,首先获取其consoleUrl,然后进一步获取更有价值的logsLinks,同时打印相关的调试信息,并导出该步骤的相关XML配置文件

脚本地址:https://github.com/mcsrainbow/python-demos/blob/master/demos/debug_oozie_job.py

执行示例:

, ,

No Comments

分享一个 RAID磁盘健康状态 监控脚本

参考资料
http://blog.irq1.com/megacli-commands-to-storcli-command-conversion/
https://github.com/mcsrainbow/shell-scripts/blob/master/scripts/MegaRAID_SUM

背景介绍:
在我们的线上环境中,有大量的物理实体服务器,主要用于对配置要求很高的Hadoop集群。
通常在这些服务器中,都配置了RAID卡并且挂载有16块大小至少为3T的硬盘,由于Hadoop集群的IO密集型特征,不少硬盘经常不堪重负而损坏,因此对RAID磁盘健康状态的检查,非常有必要。

具体配置:
整个脚本的思路如下:
1. 通过MegaCli64分别获取异常状态的信息,通常有Degrade,Offline,Critical,Failed等状态
2. 将获取到的异常状态汇总,并提取出有问题的磁盘槽位信息

脚本地址:https://github.com/mcsrainbow/shell-scripts/blob/master/scripts/check_megaraid_status

执行示例:

, ,

2 Comments

Hadoop运维笔记 之 CDH5.0.0升级到CDH5.3.0

参考资料:
Hadoop: http://www.cloudera.com/content/cloudera/en/documentation/core/v5-3-x/topics/cdh_ig_earlier_cdh5_upgrade.html?scroll=topic_8
Oozie: http://www.cloudera.com/content/cloudera/en/documentation/core/v5-3-x/topics/cdh_ig_oozie_upgrade.html
Hive: http://www.cloudera.com/content/cloudera/en/documentation/core/v5-3-x/topics/cdh_ig_hive_upgrade.html
Pig: http://www.cloudera.com/content/cloudera/en/documentation/core/v5-3-x/topics/cdh_ig_pig_upgrade.html

1. 在所有Hadoop服务器上停止Monit(我们线上使用了Monit来监听进程)
登录idc2-admin1(我们线上使用了idc2-admin1作为管理机以及Yum repo服务器)
# mkdir /root/cdh530_upgrade_from_500
# cd /root/cdh530_upgrade_from_500
# pssh -i -h idc2-hnn-rm-hive 'service monit stop'
# pssh -i -h idc2-hmr.active 'service monit stop'

2. 确认本地的CDH5.3.0的Yum repo服务器已经就绪
http://idc2-admin1/repo/cdh/5.3.0/
http://idc2-admin1/repo/cloudera-gplextras5.3.0/

3. 在Ansible中更新相应的repo模板(我们线上使用了Ansible作为配置管理工具)

{% if "idc2" in group_names %}

...

{% if "cdh5-all" in group_names %}
[heylinux.el6.cloudera-cdh5.3.0]
name= el6 yum cloudera cdh5.3.0
baseurl=http://idc2-admin1/repo/cdh/5.3.0
enabled=1
gpgcheck=0

[heylinux.el6.cloudera-gplextras5.3.0]
name= el6 yum cloudera gplextras5.3.0
baseurl=http://idc2-admin1/repo/cloudera-gplextras5.3.0
enabled=1
gpgcheck=0
{% else %}

...

{% endif %}

4. 更新所有Hadoop服务器的repo文件(/etc/yum.repos.d/heylinux.repo)
# ansible-playbook --private-key /path/to/key_root -u root --vault-password-file=/path/to/vault_passwd.file base.yml -i hosts.idc2 --tags localrepos --limit cdh5-all

5. 升级HDFS相关内容
5.1. 获取当前的Activie Namenode(我们在线上的DNS服务器中创建了一个始终检查并指向Active Namenode的CNAME)
# host active-idc2-hnn
active-idc2-hnn.heylinux.com is an alias for idc2-hnn2.heylinux.com
idc2-hnn2.heylinux.com has address 172.16.2.12

5.2. 在Active NameNode上进入safe mode并生成新的fsimage,并等待整个过程结束。
# sudo -u hdfs hdfs dfsadmin -safemode enter
# sudo -u hdfs hdfs dfsadmin -saveNamespace

5.3 关闭所有的Hadoop服务
回到idc2-admin1上的工作目录
# cd /root/cdh530_upgrade_from_500

首先通过pssh批量关闭Namenode,ResourceManager以及Hive服务器上的Hadoop相关进程(将对应的服务器地址或主机名列表写入到idc2-hnn-rm-hive与idc2-hmr.active)
# pssh -i -h idc2-hnn-rm-hive 'for x in `cd /etc/init.d ; ls hadoop-*` ; do sudo service $x status ; done'
# pssh -i -h idc2-hmr.active 'for x in `cd /etc/init.d ; ls hadoop-*` ; do sudo service $x status ; done'

# pssh -i -h idc2-hnn-rm-hive 'for x in `cd /etc/init.d ; ls hadoop-*` ; do sudo service $x stop ; done'
# pssh -i -h idc2-hmr.active 'for x in `cd /etc/init.d ; ls hadoop-*` ; do sudo service $x stop ; done'

# 检查如果存在与新版本相冲突的libhadoop.so文件,如果存在则删除(我们线上安装了Snappy,它会自己生成一个与CDH5.3.0自带的libhadoop.so相冲突的文件并放置到当前的JDK lib目录下面)。
# pssh -i -h idc2-hnn-rm-hive 'rm -f /usr/java/jdk1.7.0_45/jre/lib/amd64/libhadoop.so'
# pssh -i -h idc2-hmr.active 'rm -f /usr/java/jdk1.7.0_45/jre/lib/amd64/libhadoop.so'
Backup the HDFS metadata on the NameNodes

在Namenodes上备份metadata文件(我们线上有两个Namenode组成的HA,分别为idc2-hnn1与idc2-hnn2:
# mkdir /root/cdh530upgrade
# cd /root/cdh530upgrade
# tar -cf /root/nn_backup_data.data1.`date +%Y%m%d`.tar /data1/dfs/nn
# tar -cf /root/nn_backup_data.data2.`date +%Y%m%d`.tar /data2/dfs/nn

6. 升级Hadoop相关软件包
登录并升级Hive服务器idc2-hive1
# yum clean all; yum upgrade hadoop

登录并升级ResourceManager服务器idc2-rm1与idc2-rm2
# yum clean all; yum upgrade hadoop

回到idc2-admin1并升级所有的Datanode服务器idc2-hmr*
# pssh -i -h idc2-hmr.active 'yum clean all; yum upgrade hadoop hadoop-lzo -y'

登录并升级idc2-hnn1(Standby Namenode,由之前的host active-idc2-hnn命令判断得来)
# yum clean all; yum upgrade hadoop hadoop-lzo

登录并升级idc2-hnn2(Active Namenode,由之前的host active-idc2-hnn命令判断得来)
# yum clean all; yum upgrade hadoop hadoop-lzo

回到idc2-admin1并升级所有的Hadoop Clients
# pssh -i -h idc2-client 'yum clean all; yum upgrade hadoop -y'

7. 启动相关服务
登录并启动Journal Nodes服务(我们线上为idc2-hnn1, idc2-hnn2, idc2-rm1三台服务器)
# service hadoop-hdfs-journalnode start

登录所有的DataNode并启动服务(我们线上为idc2-hmr*服务器)
# service hadoop-hdfs-datanode start

登录Active NameNode并更新HDFS Metadata
# service hadoop-hdfs-namenode upgrade
# tailf /var/log/hadoop/hadoop-hdfs-namenode-`hostname -s`.heylinux.com.log

一直等待直到整个过程结束,例如在Log中出现如下类似内容:
/var/lib/hadoop-hdfs/cache/hadoop/dfs/<name> is complete.

等待直至NameNode退出Safe Mode,然后重启Standby NameNode

登录Standby NameNode并重启服务
# sudo -u hdfs hdfs namenode -bootstrapStandby
# service hadoop-hdfs-namenode start

登录所有的ResourceManager并启动服务
# service hadoop-yarn-resourcemanager start

登录所有的NodeManager并启动服务(我们线上为idc2-hmr*服务器)
# service hadoop-yarn-nodemanager start

在Active ResourceManager上启动HistoryServer(我们线上为idc2-rm1服务器)
# service hadoop-mapreduce-historyserver start

至此,整个Hadoop相关的升级就结束了,下面,将对Hive,Oozie和Pig的升级做相应的介绍。

8. 升级Hive与Oozie服务器(我们线上统一安装到了一台机器idc2-hive1)
8.1 升级Hive服务器
备份Metastore数据库
# mkdir -p /root/backupfiles/hive
# cd /root/backupfiles/hive
# mysqldump -uoozie -pheylinux metastore > metastore.sql.bak.`date +%Y%m%d`

更新hive-site.xml

Confirm the following settings are present in hive-site.xml
<property>
  <name>datanucleus.autoCreateSchema</name>
  <value>false</value>
</property>
  <property>
  <name>datanucleus.fixedDatastore</name>
  <value>true</value>
</property>

停止Hive相关服务
# service hive-server2 stop
# service hive-metastore stop

升级Hive相关软件包
# yum upgrade hive hive-metastore hive-server2 hive-jdbc
# yum install hive-hbase hive-hcatalog hive-webhcat

升级Hive的Metastore
# sudo -u oozie /usr/lib/hive/bin/schematool -dbType mysql -upgradeSchemaFrom 0.12.0

启动Hive服务
# service hive-metastore start
# service hive-server2 start

8.2 升级Oozie服务器
备份Oozie数据库
# mkdir -p /root/backupfiles/hive
# cd /root/backupfiles/hive
# mysqldump -uoozie -pheylinux oozie > oozie.sql.bak.`date +%Y%m%d`

备份Oozie配置文件
# tar cf oozie.conf.bak.`date +%Y%m%d` /etc/oozie/conf

停止Oozie
# service oozie stop

升级Oozie软件包
# yum upgrade oozie oozie-client

仔细校对新的配置文件中与原有配置文件中的参数,并将原有配置文件中的参数更新到新的配置文件

备份Oozie lib目录
# tar cf oozie.lib.bak.`date +%Y%m%d` /var/lib/oozie

升级Oozie数据库
# sudo -u oozie /usr/lib/oozie/bin/ooziedb.sh upgrade -run

升级Oozie Shared Library
# sudo -u oozie hadoop fs -mv /user/oozie/share /user/oozie/share.orig.`date +%Y%m%d`
# sudo oozie-setup sharelib create -fs hdfs://idc1-hnn2:8020 -locallib /usr/lib/oozie/oozie-sharelib-yarn.tar.gz

将所有的library从目录/user/oozie/share/lib/lib_<new_date_string>移动到/user/oozie/share/lib(<new_date_string>为目录生成后上面的时间戳)
# sudo -u oozie mv /user/oozie/share/lib/lib_<new_date_string>/* /user/oozie/share/lib/

检查HDFS中/user/oozie/share目录下的所有文件,并与备份后的share.orig.`date +%Y%m%d`中的文件进行一一对比,除了带有"cdh5"版本字样的软件包仅保留更新的以外,其它的都复制到新的lib目录下。

启动Oozie服务器
# service oozie start

9. 升级Pig
杀掉所有正在运行的Pig进程
# pkill -kill -f pig

更新Pig软件包
# yum upgrade pig

10. 在所有的软件包都升级完毕,并且HDFS也能正常工作的情况下,执行finalizeUpgrade命令做最后的收尾
登录Active Namenode并执行以下命令
# sudo -u hdfs hdfs dfsadmin -finalizeUpgrade

, , , , , ,

No Comments

Hadoop运维笔记 之 调整hdfs与yarn用户的进程nice优先级

最近,线上的CDH5集群增加了一批新的datanode,但是其中有一些datanode的负载明显比其它的要高。
通过Ganglia上的图形报告查看,发现这些datanode的CPU %ni很高,进一步查看进程,发现不少的hdfs与yarn进程运行在高优先级(<0 可通过 ps -lp pid 查看)上,这样会夺取一部分重要系统进程的资源,导致一些问题。 于是,我们通过在线调整的方式,将所有hdfs与yarn用户的进程优先级都设置为了0,将问题解决了。 具体步骤如下: vim /etc/security/limits.d/hdfs.conf 新增如下配置:

hdfs    hard    priority        20
hdfs    hard    nice            0

vim /etc/security/limits.d/yarn.conf
新增如下配置:

yarn    hard    priority  20
yarn    hard    nice    0

vim /etc/security/limits.d/mapred.conf
新增如下配置:

mapred    hard    priority  20
mapred    hard    nice    0

执行命令,在线调整hdfs,yarn与mapred用户的进程nice优先级:
renice 0 -u hdfs yarn mapred

ulimit -Hr 20 hdfs
ulimit -Hr 20 yarn
ulimit -Hr 20 mapred

ulimit -He 0 hdfs
ulimit -He 0 yarn
ulimit -He 0 mapred

,

2 Comments

Hadoop运维笔记 之 Datanode的Last Contact值异常增大导致频繁出现Deadnode

我们在线上采用的是CDH的Hadoop发行版,但从CDH3迁移到CDH5之后,Bug层出不穷。:(

CDH5.0.x版本没有什么严重的Bug,但是Namenode之间的状态同步却有问题。
具体表现为,在需要Decommission某个节点时,必须在Active Namenode上操作,如果在Standby Namenode上操作,其Decommissioning状态不会同步到Active Namenode上,也不会真正的Decommissioning。
而即使在Active Namenode上操作的话,Decommissioned状态也不会同步到Standby Namenode;
通过升级到CDH5.1.0之后,我们解决了这个问题,但没想到的是,后面版本的Bug会更加严重。

在CDH5.1.0版本中,有严重的snapshot操作导致edits记录紊乱使Namenode崩溃的问题,在定位到了其匹配的Bug后,我们只能继续通过升级到CDH5.2.0解决这个问题。

但CDH5.2.0又引入了一个新的Bug,就是Namenode与Datanode的心跳会因为正在运行的job而被block,虽然Datanode的负载并不高,但仍然会导致Last Contact值不断增大。
而默认的心跳超时时间是630秒,超过这个数值之后,Namenode就自动将Datanode列入Deadnodes当中。
我们所有的开发和运维花费了一周的时间做各种分析和调试,都没能解决这个问题,也没有找到与问题完全匹配的Bug。
最后,因为一个同行的哥们儿也遇到了相同的问题,他通过升级到CDH5.3.0将问题解决了。
于是,我们在无计可施的情况下,也升级到了CDH5.3.0,果然解决了Last Contact值增高的心跳问题。

于此,不得不感叹,CDH5的Bug真是多,有的还会导致非常严重的问题,但目前已经上了贼船,也就只能自求多福了。

从CDH5.2.0之前的旧版本直接升级到CDH5.3.0的文档:
http://www.cloudera.com/content/cloudera/en/documentation/core/latest/topics/cdh_ig_earlier_cdh5_upgrade.html

从CDH5.2.0升级到CDH5.3.0的文档:
http://www.cloudera.com/content/cloudera/en/documentation/core/latest/topics/cdh_ig_cdh5beta1_to_latest_upgrade.html

升级Hive与Oozie到CDH5.3.0对应版本的文档:
http://www.cloudera.com/content/cloudera/en/documentation/core/latest/topics/cdh_ig_hive_upgrade.html
http://www.cloudera.com/content/cloudera/en/documentation/core/latest/topics/cdh_ig_oozie_upgrade.html

, ,

No Comments

Hadoop运维笔记 之 更换du命令降低datanode磁盘IO

背景介绍:
近期,不少datanode节点的磁盘IO比较高,主要原因还是由于job数量的增多,以及规模的增大。
但任何可以降低磁盘IO消耗的手段,我们都可以尝试一下。

比如,我们经常可以看到hdfs用户在执行"du -sk"命令:
[root@idc1-server2 ~]# ps -ef| grep "du -sk"

hdfs     17119 10336  1 00:57 ?        00:00:04 du -sk /data1/dfs/dn/current/BP-1281416642-10.100.1.2-1407274717062
hdfs     17142 10336  1 00:57 ?        00:00:03 du -sk /data5/dfs/dn/current/BP-1281416642-10.100.1.2-1407274717062
hdfs     17151 10336  1 00:57 ?        00:00:05 du -sk /data6/dfs/dn/current/BP-1281416642-10.100.1.2-1407274717062
...

随着datanode上的数据不断增加,这样频繁的du操作,会耗时比较长,在CPU和磁盘IO很闲的时候,每次也都会耗时5秒左右,而在服务器负载比较高的时候,这样的操作就会耗时很长时间。

于是,我们便考虑通过将原有的du命令替换,并基于df命令来编写一个新的du命令来取而代之。

[root@idc1-server2 ~]# mv /usr/bin/du /usr/bin/du.orig
[root@idc1-server2 ~]# vim /usr/bin/du

#!/bin/sh

mydf=$(df -Pk $2 | grep -vE '^Filesystem|tmpfs|cdrom' | awk '{ print $3 }')
echo -e "$mydf\t$2"

[root@idc1-server2 ~]# chmod +x /usr/bin/du

不过这样的话,统计出来的结果不就不准确了吗?
但具体情况具体应对,一般来说,Hadoop的datanode都会采用不同的磁盘并划分分区来存储数据,那么使用df统计出来的结果,误差应该是很小的。

No Comments

Hadoop运维笔记 之 Snappy创建libhadoop.so导致datanode报错

为了解决上一篇文章中提到的Bug,我们将线上的CDH5升级到了目前最新的CDH5.2.0,但升级之后,有一部分服务器的datanode不能正常启动,报错如下:

2014-11-20 19:54:52,071 WARN org.apache.hadoop.hdfs.server.datanode.DataNode: Unexpected exception in block pool Block pool <registering> (Datanode Uuid unassigned) service to idc1-server1/10.100.1.100:8020
com.google.common.util.concurrent.ExecutionError: java.lang.UnsatisfiedLinkError: org.apache.hadoop.io.nativeio.NativeIO.link0(Ljava/lang/String;Ljava/lang/String;)V
	at com.google.common.util.concurrent.Futures.wrapAndThrowExceptionOrError(Futures.java:1126)
	at com.google.common.util.concurrent.Futures.get(Futures.java:1048)
	at org.apache.hadoop.hdfs.server.datanode.DataStorage.linkBlocks(DataStorage.java:870)
	at org.apache.hadoop.hdfs.server.datanode.BlockPoolSliceStorage.linkAllBlocks (BlockPoolSliceStorage.java:570)
	at org.apache.hadoop.hdfs.server.datanode.BlockPoolSliceStorage.doUpgrade (BlockPoolSliceStorage.java:379)
	at org.apache.hadoop.hdfs.server.datanode.BlockPoolSliceStorage.doTransition (BlockPoolSliceStorage.java:313)
	at org.apache.hadoop.hdfs.server.datanode.BlockPoolSliceStorage.recoverTransitionRead (BlockPoolSliceStorage.java:187)
	at org.apache.hadoop.hdfs.server.datanode.DataStorage.recoverTransitionRead (DataStorage.java:309)
	at org.apache.hadoop.hdfs.server.datanode.DataNode.initStorage(DataNode.java:1109)
	at org.apache.hadoop.hdfs.server.datanode.DataNode.initBlockPool(DataNode.java:1080)
	at org.apache.hadoop.hdfs.server.datanode.BPOfferService.verifyAndSetNamespaceInfo (BPOfferService.java:320)
	at org.apache.hadoop.hdfs.server.datanode.BPServiceActor.connectToNNAndHandshake (BPServiceActor.java:220)
	at org.apache.hadoop.hdfs.server.datanode.BPServiceActor.run(BPServiceActor.java:824)
	at java.lang.Thread.run(Thread.java:744)
Caused by: java.lang.UnsatisfiedLinkError: org.apache.hadoop.io.nativeio.NativeIO.link0 (Ljava/lang/String;Ljava/lang/String;)V
	at org.apache.hadoop.io.nativeio.NativeIO.link0(Native Method)
	at org.apache.hadoop.io.nativeio.NativeIO.link(NativeIO.java:838)
	at org.apache.hadoop.hdfs.server.datanode.DataStorage$2.call(DataStorage.java:862)
	at org.apache.hadoop.hdfs.server.datanode.DataStorage$2.call(DataStorage.java:855)
	at java.util.concurrent.FutureTask.run(FutureTask.java:262)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
	... 1 more
2014-11-20 19:54:52,073 WARN org.apache.hadoop.hdfs.server.datanode.DataNode: Ending block pool service for: Block pool <registering> (Datanode Uuid unassigned) service to idc1-server1/10.100.1.100:8020

但搜遍了Google也未能找到匹配的信息,唯一沾点边的都是一些在Windows平台上因为缺少lib导致的问题。
而在我们的环境中,只有一部分的服务器有以上问题,对比了所有Hadoop相关的软件包之后都没法发现有什么不同,这给我们分析问题带来了很大的干扰。

最后,我们尝试通过strace来跟踪datanode的进程。
yum install strace
strace -f -F -o /tmp/strace.output.txt /etc/init.d/hadoop-hdfs-datanode start
lsof | grep libhadoop.so

java 18527 hdfs mem REG 253,0 122832 270200 /usr/java/jdk1.7.0_45/jre/lib/amd64/libhadoop.so

发现它读取了一个lib文件:/usr/java/jdk1.7.0_45/jre/lib/amd64/libhadoop.so,而其它正常的服务器的datanode进程则是读取的/usr/lib/hadoop/lib/native/libhadoop.so。
经过验证发现/usr/java/jdk1.7.0_45/jre/lib/amd64/libhadoop.so是在安装Snappy软件包时创建的,在移走了它之后,datanode终于正常启动了。

看来,虽然datanode在启动时指定了 -Djava.library.path=/usr/lib/hadoop/lib/native,但jre中的lib被载入的优先级还是要高一些。

,

No Comments

Hadoop运维笔记 之 Namenode异常停止后无法正常启动

背景:
公司在线上使用了CDH5 HA模式,有两个Namenode节点,结果其中的Standby节点因为一些关于edits文件的报错异常停止了,并且在启动的过程中一直报告找不到各种文件。

刚开始怀疑问题可能只发生在Standby本身,因此尝试了bootstrapStandby来重新初始化Standby节点,但问题依旧。
而后来因为我尝试重启ZKFC(Zookeeper Failover)服务器,导致了Active节点进行自动切换,在切换失败后打算切换回去时,也无法启动服务了,报错跟Standby节点一模一样,于是整个Hadoop集群就挂了。

问题严重,在搜遍了整个Google都找不到任何有用的信息之后,只能求助于老大。最后,老大想到一个思路,就是将fsimage(元数据)文件与edits(编辑日志)文件都反编译成文本,查看里面具体有什么内容,为什么加载edits文件时会报错。

结果,这个思路给我们带来了曙光,并最终修复了整个集群。

环境介绍:
idc2-server1: namenode, journalnode, zkfc
idc2-server2: namenode, journalnode, zkfc
idc2-server3: journalnode, resourcemanager

具体过程:
首先,是Standby Namenode上出现以下错误,然后自动异常关闭了进程:

2014-11-11 02:12:54,057 FATAL org.apache.hadoop.hdfs.server.namenode.ha.EditLogTailer: Unknown error encountered while tailing edits. Shutting down standby NN.
java.io.FileNotFoundException: File does not exist: /user/dong/data/dpp/classification/gender/vw-output-train/2014-10-30-research-with-confict-fix-bug-rerun/_temporary/1/_temporary/attempt_1415171013961_37060_m_000015_0/part-00015
       at org.apache.hadoop.hdfs.server.namenode.INodeFile.valueOf(INodeFile.java:65)
       at org.apache.hadoop.hdfs.server.namenode.INodeFile.valueOf(INodeFile.java:55)
...

其中提到了"Unknown error encountered while tailing edits. Shutting down standby NN."

于是,我们尝试启动Standby Namenode服务,结果报告以下错误:

2014-11-12 04:26:28,860 INFO org.apache.hadoop.hdfs.server.namenode.EditLogInputStream: Fast-forwarding stream 'http://idc2-server10.heylinux.com:8480/getJournal?jid=idc2&segmentTxId=240823073&storageInfo=-55%3A1838233660%3A0%3ACID-d77ea84b-1b24-4bc2-ad27-7d2384d222d6' to transaction ID 240741256
2014-11-12 04:26:28,874 ERROR org.apache.hadoop.hdfs.server.namenode.FSEditLogLoader: Encountered exception on operation CloseOp [length=0, inodeId=0, path=/user/dong/data/dpp/classification/gender/vw-output-train/2014-10-30-research-with-confict-fix-bug-rerun/_temporary/1/_temporary/attempt_1415171013961_37060_m_000015_0/part-00015, replication=3, mtime=1415671845582, atime=1415670522749, blockSize=134217728, blocks=[], permissions=oozie:hdfs:rw-r--r--, aclEntries=null, clientName=, clientMachine=, opCode=OP_CLOSE, txid=240823292]
java.io.FileNotFoundException: File does not exist: /user/dong/data/dpp/classification/gender/vw-output-train/2014-10-30-research-with-confict-fix-bug-rerun/_temporary/1/_temporary/attempt_1415171013961_37060_m_000015_0/part-00015
        at org.apache.hadoop.hdfs.server.namenode.INodeFile.valueOf(INodeFile.java:65)
        at org.apache.hadoop.hdfs.server.namenode.INodeFile.valueOf(INodeFile.java:55)
...
2014-11-12 04:26:32,641 WARN org.apache.hadoop.hdfs.server.namenode.FSNamesystem: Encountered exception loading fsimage
java.io.FileNotFoundException: File does not exist: /user/dong/data/dpp/classification/gender/vw-output-train/2014-10-30-research-with-confict-fix-bug-rerun/_temporary/1/_temporary/attempt_1415171013961_37060_m_000015_0/part-00015
        at org.apache.hadoop.hdfs.server.namenode.INodeFile.valueOf(INodeFile.java:65)

说找不到"/user/dong/data/dpp/classification/gender/vw-output-train/2014-10-30-research-with-confict-fix-bug-rerun/_temporary/1/_temporary/attempt_1415171013961_37060_m_000015_0/part-00015"这个文件。
而事实上,这个文件是临时文件,不重要并且已经被删除了。
但在上面,却报告"ERROR org.apache.hadoop.hdfs.server.namenode.FSEditLogLoader: Encountered exception on operation CloseOp",可以看出是在加载edits文件,执行OP_CLOSE操作时提示找不到文件。

刚开始我们怀疑可能只是Standby上的fsimage文件或edits文件有问题,于是我们在Standby上执行了bootstrapStandby,改过程会自动从Active Namenode上获取最新的fsimage文件,并从Journalnode日志服务器上下载并执行新的edits文件。

sudo -u hdfs hadoop namenode -bootstrapStandby

但是,在初始化之后,加载edits时仍然遇到上面相同的报错。

而接下来,由于我尝试将ZKFC(Zookeeper Failover)服务重启,导致了Active Namenode自动切换到Standby,但由于Standby无法take over,所以Active Namenode切换回去的时候,也无法正常重启了,错误跟Standby启动时一样。

这样一来,整个Hadoop集群就挂了,在搜遍了整个Google都找不到任何有用的信息之后,我打电话给了老大,老大也通过上面的错误Google不到任何一条有用的信息。
于是老大尝试在edits文件中grep上面的路径,找到了一些相关的edits文件:

# cd /data1/dfs/nn/
# cp -rpa current current.backup.orig
# cd /data2/dfs/nn/
# cp -rpa current current.backup.orig
# cd /data1/dfs/nn/current
# grep attempt_1415171013961_37060_m_000015_0 *
Binary file edits_0000000000240687057-0000000000240698453 matches
Binary file edits_0000000000240823073-0000000000240838096 matches
Binary file edits_inprogress_0000000000244853266 matches

于是,我们思考能否从这些edits文件或fsimage文件中找到一些线索。
而下面的两篇文章中,提到了Hadoop自带的针对fsimage和edits文件的反编译工具:
http://hadoop.apache.org/docs/current/hadoop-project-dist/hadoop-hdfs/HdfsImageViewer.html
http://hadoop.apache.org/docs/current/hadoop-project-dist/hadoop-hdfs/HdfsEditsViewer.html

其中,关于edits文件的一些描述给我们带来了极大的希望:

In case there is some problem with hadoop cluster and the edits file is corrupted it is possible to save at least part of the edits file that is correct. This can be done by converting the binary edits to XML, edit it manually and then convert it back to binary.

通过以上描述,我们了解到edits文件可能会corrupted,而反编译之后手动修改,在编译回二进制格式进行替换,可以作为一种解决办法。
于是我们将上面找到的两个关联edits文件,将其复制出来并进行了反编译:

# mkdir /tmp2/
# cd /data1/dfs/nn
# cp edits_0000000000240687057-0000000000240698453 /tmp2/
# cp edits_0000000000240823073-0000000000240838096 /tmp2/
# cd /tmp2
# hdfs oev -i edits_0000000000240687057-0000000000240698453 -o edits_0000000000240687057-0000000000240698453.xml
# hdfs oev -i edits_0000000000240823073-0000000000240838096 -o edits_0000000000240823073-0000000000240838096.xml

反编译之后,生成了两个XML文件,我们在XML文件中搜索"/user/dong/data/dpp/classification/gender/vw-output-train/2014-10-30-research-with-confict-fix-bug-rerun/_temporary/1/_temporary/attempt_1415171013961_37060_m_000015_0/part-00015",找到了OP_CLOSE与OP_DELETE相关记录:

  <RECORD>
    <OPCODE>OP_DELETE</OPCODE>
    <DATA>
      <TXID>240818498</TXID>
      <LENGTH>0</LENGTH>
      <PATH>/user/dong/data/dpp/classification/gender/vw-output-train/2014-10-30-research-with-confict-fix-bug-rerun/_temporary/1/_temporary/attempt_1415171013961_37060_m_000015_0/part-00015</PATH>
      <TIMESTAMP>1415671972595</TIMESTAMP>
      <RPC_CLIENTID>4a38861d-3bee-40e6-abb6-d2b58f313781</RPC_CLIENTID>
      <RPC_CALLID>676</RPC_CALLID>
    </DATA>
  </RECORD>
  <RECORD>
    <OPCODE>OP_CLOSE</OPCODE>
    <DATA>
      <TXID>240823292</TXID>
      <LENGTH>0</LENGTH>
      <INODEID>0</INODEID>
      <PATH>/user/dong/data/dpp/classification/gender/vw-output-train/2014-10-30-research-with-confict-fix-bug-rerun/_temporary/1/_temporary/attempt_1415171013961_37060_m_000015_0/part-00015</PATH>
      <REPLICATION>3</REPLICATION>
      <MTIME>1415671845582</MTIME>
      <ATIME>1415670522749</ATIME>
      <BLOCKSIZE>134217728</BLOCKSIZE>
      <CLIENT_NAME></CLIENT_NAME>
      <CLIENT_MACHINE></CLIENT_MACHINE>
      <PERMISSION_STATUS>
        <USERNAME>oozie</USERNAME>
        <GROUPNAME>hdfs</GROUPNAME>
        <MODE>420</MODE>
      </PERMISSION_STATUS>
    </DATA>
  </RECORD>

可以看到,对于"/user/dong/data/dpp/classification/gender/vw-output-train/2014-10-30-research-with-confict-fix-bug-rerun/_temporary/1/_temporary/attempt_1415171013961_37060_m_000015_0/part-00015",OP_DELETE发生在了OP_CLOSE之前,因此执行OP_CLOSE时会提示"File does not exist"。

于是,我们尝试将OP_CLOSE这部分代码,替换成其它的内容,比如无关痛痒的修改一个现有文件的权限,并保留TXID 240823292以确保edits文件的完整性。

  <RECORD>
    <OPCODE>OP_SET_PERMISSIONS</OPCODE>
    <DATA>
      <TXID>240823292</TXID>
      <SRC>/user/oozie-heylinux/.staging/job_1415171013961_37194</SRC>
      <MODE>504</MODE>
    </DATA>
  </RECORD>

修改完成之后,再将XML文件反编译回binary格式。

# cd /tmp2/
# cp edits_0000000000240823073-0000000000240838096.xml edits_0000000000240823073-0000000000240838096.xml.orig
# vim edits_0000000000240823073-0000000000240838096.xml
# hdfs oev -i edits_0000000000240823073-0000000000240838096.xml -o edits_0000000000240823073-0000000000240838096 -p binary 

然后将binary文件同步到journalnode日志服务器中:

# cd /var/hadoop/data/dfs/jn/idc2prod/
# cp -rpa current current.backup.orig
# cd /tmp2/
# cp edits_0000000000240823073-0000000000240838096 /data1/dfs/nn/current/
# cp edits_0000000000240823073-0000000000240838096 /data2/dfs/nn/current/
# cp edits_0000000000240823073-0000000000240838096 /var/hadoop/data/dfs/jn/idc2prod/current/
# scp edits_0000000000240823073-0000000000240838096 root@idc2-server2:/var/hadoop/data/dfs/jn/idc2prod/current/
# scp edits_0000000000240823073-0000000000240838096 root@idc2-server3:/var/hadoop/data/dfs/jn/idc2prod/current/

然后启动namenode服务,可以发现,之间的错误已经不存在了,取而代之的已经变成了其它文件。

2014-11-12 08:57:13,053 INFO org.apache.hadoop.hdfs.server.namenode.EditLogInputStream: Fast-forwarding stream 'http://idc2-server1.heylinux.com:8480/getJournal?jid=idc2prod&segmentTxId=240823073&storageInfo=-55%3A1838233660%3A0%3ACID-d77ea84b-1b24-4bc2-ad27-7d2384d222d6' to transaction ID 240299210
2014-11-12 08:57:13,063 ERROR org.apache.hadoop.hdfs.server.namenode.FSEditLogLoader: Encountered exception on operation CloseOp [length=0, inodeId=0, path=/user/dong/data/dpp/classification/gender/vw-output-train/2014-10-30-research-with-confict-fix-bug-rerun/_temporary/1/_temporary/attempt_1415171013961_37060_m_000018_0/part-00018, replication=3, mtime=1415671845675, atime=1415670519537, blockSize=134217728, blocks=[], permissions=oozie:hdfs:rw-r--r--, aclEntries=null, clientName=, clientMachine=, opCode=OP_CLOSE, txid=240823337]
java.io.FileNotFoundException: File does not exist: /user/dong/data/dpp/classification/gender/vw-output-train/2014-10-30-research-with-confict-fix-bug-rerun/_temporary/1/_temporary/attempt_1415171013961_37060_m_000018_0/part-00018
        at org.apache.hadoop.hdfs.server.namenode.INodeFile.valueOf(INodeFile.java:65)
        at org.apache.hadoop.hdfs.server.namenode.INodeFile.valueOf(INodeFile.java:55)
...

2014-11-12 08:57:16,847 WARN org.apache.hadoop.hdfs.server.namenode.FSNamesystem: Encountered exception loading fsimage
java.io.FileNotFoundException: File does not exist: /user/dong/data/dpp/classification/gender/vw-output-train/2014-10-30-research-with-confict-fix-bug-rerun/_temporary/1/_temporary/attempt_1415171013961_37060_m_000018_0/part-00018
        at org.apache.hadoop.hdfs.server.namenode.INodeFile.valueOf(INodeFile.java:65)
...

那么,接下来,就是重复以上动作,其中有时候能找到一部分规律,可以批量将同一个目录下反复报错的文件的OP_CLOSE都替换掉。但更多的时候则是随机的文件,需要一次次修改XML文件,然后编译成binary,再启动namenode,进行针对性的修改,一直反复的进行下去,直到Namenode能够成功启动为止。

我们在具体的操作过程中,还遇到过关于OP_ADD_BLOCK的错误,造成问题的原因是由于最后一个edits文件在反编译回binary文件时出现一些关于OP_UPDATE_BLOCK的错误。
我将报错的部分通过以上方式进行了替换,才成功的将edits文件反编译回binary文件。
具体的解决办法,就是根据"Encountered exception on operation AddBlockOp"定位到OP_ADD_BLOCK相关配置并替换即可。

2014-11-12 18:07:39,070 ERROR org.apache.hadoop.hdfs.server.namenode.FSEditLogLoader: Encountered exception on operation AddBlockOp [path=/user/dong/data/dpp/classification/gender/vw-input/2014-10-30-research-with-no-confict-fix-bug-rerun/all_labelled/_temporary/1/_temporary/attempt_1415171013961_42350_m_001474_0/part-m-01474, penultimateBlock=NULL, lastBlock=blk_1109647729_35920089, RpcClientId=, RpcCallId=-2]
java.lang.IllegalStateException

最后,在Namenode启动成功后,会报告很多Block丢失,解决办法是通过fsck删除这些错误的Block。

# hadoop fsck / -files -blocks -locations | tee -a fsck.out

然后在fsck.out中获取所有Block的信息,执行"hadoop fsck / -move"加Block路径进行删除。

最后,退出safemode,生活再次变得美好起来。

# hadoop dfsadmin -safemode leave

PS: 在后来,上面的问题又再次出现了,通过分析我们发现是由于Hadoop的一个Bug导致的,从2.10-beta就开始存在了:
https://issues.apache.org/jira/browse/HDFS-6527
https://issues.apache.org/jira/browse/HDFS-6647
想要彻底避免这类问题的再次发生,必须将Hadoop升级到2.5以上版本,而对应的CDH版本则是5.2.0。

,

1 Comment

Hadoop运维笔记 之 Balancer难以在快速增长的集群上平衡大量的数据

背景:
公司在线上使用了CDH5集群,一开始由于疏忽,忘记了在计划任务中定期执行Balancer来平衡各节点的数据。
后来,在引入大量的Job之后,数据增长非常迅猛,有很多节点开始出现利用率超过99.9%的情况,部分Job甚至开始Failed。

于是我们便执行Balancer来清理数据,结果发现有26T的数据需要平衡,而Balancer每次只移动50G的数据,并且耗时30分钟,而集群每个小时新写入的数据会导致又有40-60G的数据需要平衡。这样一来,Balancer就根本无法胜任了。

14/10/14 20:31:11 INFO balancer.Balancer: Need to move 26.49 TB to make the cluster balanced.
14/10/14 20:31:11 INFO balancer.Balancer: Decided to move 10 GB bytes from 10.100.1.10:50010 to 10.100.1.60:50010
14/10/14 20:31:11 INFO balancer.Balancer: Decided to move 10 GB bytes from 10.100.1.20:50010 to 10.100.1.70:50010
14/10/14 20:31:11 INFO balancer.Balancer: Decided to move 10 GB bytes from 10.100.1.30:50010 to 10.100.1.80:50010
14/10/14 20:31:11 INFO balancer.Balancer: Decided to move 10 GB bytes from 10.100.1.40:50010 to 10.100.1.90:50010
14/10/14 20:31:11 INFO balancer.Balancer: Decided to move 10 GB bytes from 10.100.1.50:50010 to 10.100.1.100:50010
14/10/14 20:31:11 INFO balancer.Balancer: Will move 50 GB in this iteration
...

解决办法:
1. 增加Balancer可操作的带宽
我们思考,是否是因为Balancer的默认带宽太小,所以效率低下,于是我们尝试将Balancer的带宽扩容到了500M/s:

hadoop dfsadmin -setBalancerBandwidth 524288000

但问题并没有得到太大的改善。

2. 强行对节点进行Decommission
我们发现,当对一些节点进行Decommission操作时,上面的数据虽然有10-30T甚至更多,但总能在1天内全部Copy到其它的节点上,这里面由于默认集群副本数为3的原因,应该只有1/3的数据被复制了,但数据是完整的,并且被复制出去的数据也是平均分配到各个节点上的。那么我们何不使用它来作为一个类似Balancer的功能来解决一些磁盘用量超过99.9%的节点呢?
事实证明,这个方法非常可行,我们针对线上8个节点进行了Decommission操作(注意要尽量一台一台进行),在完成下线之后再立刻格式化数据磁盘,并重新添加回集群,新的数据也会非常快的平衡过来。比较完美的解决了之前头疼的问题,并且只花费了不到4天的时间。

3. Hadoop对LVM磁盘卷的支持问题
在解决Balancer的问题时,我们还发现,Hadoop对LVM磁盘卷的支持不是很好,表现在如果在一块磁盘上创建了逻辑卷/根分区等,再创建了逻辑卷/data1分区,Hadoop会一直将/data1写到100%,然后导致一些Job提示没有空间写入。我们猜想Hadoop应该是物理卷为单位来控制用量的。因此,我们不得不将这些包含了逻辑卷数据磁盘的主机重新安装,并分配单独的物理卷,如/dev/sda3作为/data1挂载,便再也没有以上问题。

,

No Comments

Hadoop集群(CHD4)实践之 (5) Sqoop安装

目录结构
Hadoop集群(CDH4)实践之 (0) 前言
Hadoop集群(CDH4)实践之 (1) Hadoop(HDFS)搭建
Hadoop集群(CDH4)实践之 (2) HBase&Zookeeper搭建
Hadoop集群(CDH4)实践之 (3) Hive搭建
Hadoop集群(CHD4)实践之 (4) Oozie搭建
Hadoop集群(CHD4)实践之 (5) Sqoop安装

本文内容
Hadoop集群(CHD4)实践之 (5) Sqoop安装

参考资料
http://www.cloudera.com/content/cloudera-content/cloudera-docs/CDH4/latest/CDH4-Installation-Guide/CDH4-Installation-Guide.html

环境准备
OS: CentOS 6.4 x86_64
Servers:
hadoop-master: 172.17.20.230 内存10G
- namenode
- hbase-master

hadoop-secondary: 172.17.20.234 内存10G
- secondarybackupnamenode,jobtracker
- hive-server,hive-metastore
- oozie
- sqoop

hadoop-node-1: 172.17.20.231 内存10G sudo yum install hbase-regionserver
- datanode,tasktracker
- hbase-regionserver,zookeeper-server

hadoop-node-2: 172.17.20.232 内存10G
- datanode,tasktracker
- hbase-regionserver,zookeeper-server

hadoop-node-3: 172.17.20.233 内存10G
- datanode,tasktracker
- hbase-regionserver,zookeeper-server

对以上角色做一些简单的介绍:
namenode - 整个HDFS的命名空间管理服务
secondarynamenode - 可以看做是namenode的冗余服务
jobtracker - 并行计算的job管理服务
datanode - HDFS的节点服务
tasktracker - 并行计算的job执行服务
hbase-master - Hbase的管理服务
hbase-regionServer - 对Client端插入,删除,查询数据等提供服务
zookeeper-server - Zookeeper协作与配置管理服务
hive-server - Hive的管理服务
hive-metastore - Hive的元存储,用于对元数据进行类型检查与语法分析
oozie - Oozie是一种Java Web应用程序,用于工作流的定义和管理
sqoop - Sqoop是一个转换工具,用于在关系型数据库与HDFS之间进行数据转换

本文定义的规范,避免在配置多台服务器上产生理解上的混乱:
以下操作都只需要在 Sqoop 所在主机,即 hadoop-secondary 上执行。

1. 安装前的准备
Hadoop集群(CHD4)实践之 (4) Oozie搭建

2. 安装Sqoop
$ sudo yum install sqoop sqoop-metastore

3. 启动Sqoop Metastore
$ sudo service sqoop-metastore start

4. 配置JDBC驱动
MySQL JDBC Driver:
$ sudo yum install mysql-connector-java
$ sudo ln -s /usr/share/java/mysql-connector-java.jar /usr/lib/sqoop/lib/mysql-connector-java.jar

Microsoft SQL Server JDBC Driver:
$ wget http://download.microsoft.com/download/0/2/A/02AAE597-3865-456C-AE7F-613F99F850A8/sqljdbc_4.0.2206.100_enu.tar.gz
$ tar xzvf sqljdbc_4.0.2206.100_enu.tar.gz
$ sudo cp sqljdbc_4.0/enu/sqljdbc4.jar /usr/lib/sqoop/lib/

5. 配置HCAT_HOME
$ sudo vim /etc/profile.d/sqoop.sh

 
export HCAT_HOME=/var/lib/sqoop

$ source /etc/profile

6. 至此,Sqoop的安装就已经完成。

,

4 Comments