一些零散的知识点。
symlink
社区本来计划在2.2.0加入对symlink的支持,但发现各种问题推迟了。
2.2.0的代码:
|
|
|
|
相关jira:
https://issues.apache.org/jira/browse/HADOOP-10020
https://issues.apache.org/jira/browse/HADOOP-10019
一直到2.5.2,也还是不支持的。
2.5.2的代码:
|
|
CDH与官方版本的对应关系
CDH的版本有点混乱
CDH版本 | 官方版本 |
---|---|
5.3.x、5.2.x | 2.5.0 |
5.1.x、5.0.x | 2.3.0 |
4.x | 2.2.0 |
3.x版本不是基于hadoop2的,不列了。
log-aggression删除服务
发现一个奇怪的问题,log-aggression相关的服务是在NM里面的,见LogAggregationService类。
但删除过期日志的服务是在history server里面的,见AggregatedLogDeletionService类。
意味着如果不启动history server,则hdfs上的日志不会删除。
这个设计有点奇怪。
https://issues.apache.org/jira/browse/YARN-2985
2.5.2代码导入eclipse
前提:maven、protoc.exe 2.5.0、avro
按BUILDING.txt的说明:
|
|
补充:在JDK8的情况下导入步骤似乎又不太一样。环境:JDK8、macOS 10.12、hadoop-2.6.0-cdh5.6.1。
- 需要修改根pom.xml中的
<javaVersion>1.7</javaVersion>
属性为1.8,否则maven-enforcer-plugin插件会报错。 - 直接
mvn eclipse:eclipse -DskipTests
似乎有些问题,据说是eclipse插件的bug,需要用mvn org.apache.maven.plugins:maven-eclipse-plugin:2.6:eclipse -DskipTests
- eclipse插件执行过程中出现了一个非常诡异的
missing tools.jar
错误,参考这个帖子解决即可。
导入eclipse后还是会报一些奇怪的error,有些error要手动修改build path引入jar包,有些error要手动修改项目编译级别到1.7(参考这个)。也可能是eclipse本身的bug。
不管怎样,最终完成后,所有error都可以消除。
顺便说下hive代码的导入。环境:JDK8、macOS 10.12、hive-1.1.0-cdh5.6.1。
参照这篇文章依次执行以下命令即可:
mvn clean install -DskipTests -Phadoop-2
mvn eclipse:clean
mvn eclipse:eclipse -DdownloadSources -DdownloadJavadocs -Phadoop-2
(虽然我觉得这两个-D参数可以不要)
然后导入eclipse,也是会报一些奇怪的error,一般都是build path有问题。我碰到的是报一个scala-compiler-2.10.0.jar
有错误,手动将有问题的项目的build path中的这个jar删除,就可以去除error。
如何开启客户端DEBUG日志
设置环境变量即可
|
|
这种方法适合临时debug。如果要长期开启DEBUG日志,可以将这个变量写到etc/hadoop/hadoop-env.sh中。
如果用的log4j.properties文件是hadoop自带的那个,还可以设置JVM属性-Dhadoop.root.logger=DEBUG,console。一样的效果。
因为log4j本身加载配置文件时支持对JVM变量的替换。
消除客户端的warn
客户端执行fs -ls /
之类的命令时出现warn,不影响使用,但看着比较烦。
常出现的warn有两种:
|
|
客户端完全不需要short-circuit read功能。在hdfs-site.xml注释掉short-circuit相关配置,warn就会消失。
|
|
hadoop客户端启动时会去java.library.path中尝试加载libhadoop,加载失败的话就会出现warn。具体为什么失败,要开debug日志看下,根据特定问题去找解决办法。
修改etc/hadoop/hadoop-env.sh,修改HADOOP_ROOT_LOGGER为DEBUG,console,再次运行命令观察输出。一个例子:
|
|
这个是由于编译时所用的glibc版本大于当前系统的glibc版本。解决方法:1.在当前系统下重新编译一次libhadoop;2.升级glibc到指定版本(未测试)。
如何查看hive-cli的日志
使用hive命令行时错误一般不会输出到stdout。而是写到文件/tmp/${user.name}/hive.log中。
另外,如果想开启DEBUG日志,可以修改$HIVE_HOME/conf/hive-log4j.properties将hive.root.logger改成DEBUG,console。
如果hive-log4j.properties不存在就将hive-log4j.properties.template重命名下。
相关配置:
|
|
DN/NM挂掉后多长时间会标记为dead?
一个DN挂掉后,要过一段时间才会被判断为dead,在这段时间内NN还是会把这个DN返回给客户端,客户端尝试读取数据时就会报错。
于是想到一个问题,DN/NM挂掉后多长时间才会被认为dead?
对DN而言,有两个参数共同作用:dfs.heartbeat.interval
(心跳间隔,默认3秒)、dfs.namenode.heartbeat.recheck-interval
(默认5分钟)。
超时时间是2*dfs.namenode.heartbeat.recheck-interval + 10*dfs.heartbeat.interval
。也就是说,默认超过10分30秒都没收到心跳,就认为DN挂掉了。
在我们的集群中,心跳是10秒,超时时间就是11分40秒。
这个逻辑见DatanodeManager类。
NM就简单很多了,心跳的超时时间是yarn.nm.liveness-monitor.expiry-interval-ms
参数,默认10分钟。
这个逻辑见NMLivelinessMonitor类。
顺便说一句,NM的心跳间隔是yarn.resourcemanager.nodemanagers.heartbeat-interval-ms
,默认1秒。不要随便增大NM的心跳,会降低集群的吞吐量,因为只有NM发来心跳时才能分配container。
在google的过程中,发现一个jira:HDFS-3703。社区对这种问题已经有了方案,当一个DN超过30秒没有发送心跳时,会被标记为stale状态,NN在向客户端返回时会将stale的节点放到最后一个,尽量减少出错的概率。但这个特性默认是关闭的。
关于HADOOP_CLASSPATH
仅针对MR而言。
对于MR任务需要关注两个classpath:1.客户端的classpath;2.NM端的classpath。
HADOOP_CLASSPATH变量就是用于设置客户端的classpath的,格式跟java -cp
的一样:stackoverflow。注意这里的jar包不会被传到NM节点。
要将相关的jar分发到所有节点,有几种方式
- 实现Tool接口。用-libjars参数分发。
- 在代码中手动调用DistributedCache的相关方法添加lib。
- 导出jar包时生成一个fat jar,将所有额外的lib放到jar包的lib目录里。
hadoop jar xxx.jar
命令会自动将jar解压,并将lib目录里的文件同时加入客户端和NM端的classpath。
最好保证分发的文件都是777权限,那样可以在不同用户间共享,减小上传文件的消耗。
以上3种方式其实都是同样的原理,实现方式不同而已,具体的逻辑去看NM的localize过程。
如何解决jar包冲突
接上条,如果自己用的jar和hadoop自带的冲突了如何解决?
对于客户端classpath,可以export HADOOP_USER_CLASSPATH_FIRST=true
,会优先加载HADOOP_CLASSPATH中指定的jar。
对于NM端classpath,可以
|
|
P.S.: JVM的类加载原则就是按classpath中出现的顺序加载。包名、类名都相同的话,后面的加载不会生效。
自定义JAVA_HOME
最近打算升级JDK7。
其实JDK的兼容性就一个原则:高版本的jdk可以运行低版本jdk编译的class文件,反过来不行。
如果服务端是JDK7,用hadoop jar执行一个JDK6编译的class,可以直接运行。
如果服务端是JDK6,但要执行一个JDK7编译的jar,可以手动设置JAVA_HOME,前提是服务端有对应的目录:
|
|
除了JAVA_HOME,还有其他一些属性可以自定义,见yarn-default.xml中的yarn.nodemanager.env-whitelist
属性。
xml配置文件中的坑
之前配置的snappy压缩没有生效,后来发现是core-site.xml中io.compression.codecs
最后多一个换行。。。
这个属性是逗号分隔的,而SnappyCodec是最后一个,所以没生效。
注意所有xml配置项中都不要有换行,hadoop的Configuration类似乎没有做trim操作。
0.0.0.0
在hadoop的很多配置中,都要配一个网络地址,可能是RPC,可能是web。
我们一般是直接写域名,比如hadoop0.photo.163.org:8020
。
但最近碰到一些虚拟机有2个IP,客户端的IP和机房的IP不一样。而直接写域名的话,服务绑定到机房IP上,客户端无法访问。
这时就要写0.0.0.0:8020
。0.0.0.0可以代表本机的所有IP地址。
2.2.0和2.5.2的container executor
升级过程中突然想到个问题,2.2.0和2.5.2的cotainer executor是否兼容?
实际测试是不兼容的:
|
|
注意参数个数的变化。如果升级时不替换container executor,NM执行任务会报错:
|
|
替换container executor后就正常了。NM进程不需要重启。
其实不光是container executor,升级过程中所有的native lib都应该替换。
jdk7编译的tar包是否可用于jdk6
升级2.5.2的过程中,我们也将服务端的jdk升级到7。在编译、打包的过程中,也是用的jdk7。
那这样编译出的tar包,是否可以用于jdk6?
答案是可以的,因为hadoop的pom文件中,限定了编译级别是1.6,即使是用jdk7编译:
|
|
用UltraEdit查看编译出来的class文件,major.minor版本也能证明确实是jdk6的class文件。