版本兼容性问题的来源
在迁移新机房的过程中,我决定将各种软件升级到最新的稳定版,最常用的三个软件都用到了Guava,具体如下表:
名称 | 版本 | Guava依赖版本 |
---|---|---|
Hadoop | 2.7.1 | 11.0.2 |
Hbase | 1.1.2 | 12.0.1 |
Spark | 1.5.2 | 14.0.1 |
ElasticSearch | 2.1.0 | 18.0 |
Guava的11和18版本的API更改很大,比如StopWatch
的创建和时间获取,比如com.google.common.util.concurrent.Service
的基本函数,在hbase-client
和hbase-server
中都有使用。ElasticSearch中也有大量的使用Guava,正在计划将Guava移除出去,但并未合并到Release中(参见这里)。
我们的MR程序需要从各种数据源中读取数据,按照知识图谱中的schema定义生成混合数据,然后写入到Hbase和ES中。为了加速任务的执行,我们正在向Spark迁移,这样就导致了4个不同版本的Guava依赖。下面我来简要介绍一下为解决这个问题所做的努力。
Hbase Client 依赖升级
官方Jira中一通搜索只有没发现社区有人讨论这个问题,稍微看了一下代码,发现Client和Common中对Guava的使用并不多,仅有几处,遂手动修改并部署到公司内部的maven仓库中。值得注意的是,为了防止其他人用错,我更改了Guava 18.0版本的Hbase的artifactId。
这样编译出来的assembly包依然无法直接在Hadoop上执行,因为Hadoop自己的安装目录中还有个11.0.2版本的Guava,我们必须在执行Hadoop命令前将assembly的路径放到java的classpath的前面。有如下的三个环境变量可以使用(具体参见Hadoop的各种启动脚本如bin/hadoop、etc/hadoop/hadoop-env.sh、hadoop-config.sh等,以及mapreduce的参数):
HADOOP_CLASSPATH
: Hadoop用户可以将额外的jar包的路径写到这个环境变量里面。HADOOP_USER_CLASSPATH_FIRST
: 默认情况下HADOOP_CLASSPATH
会放到classpath的最后面,如果设置了这个环境变量,HADOOP_CLASSPATH
会放到classpath的最前面。- 参数
mapreduce.user.classpath.first
: 启动MR任务的时候,将这个参数设置成true
,那么在启动子进程执行任务的时候,用户的jar包会放到classpath的最前端。
Hbase Server 依赖升级
Hadoop 依赖升级
Hadoop的Guava升级较为简单,社区中有现成的patch,但是并未release,可以自行打补丁并编译安装。
Spark 依赖升级
Spark的对Guava的依赖并没有涉及到变动的那部分API,直接在pom.xml
里面把Guava的版本升级到18.0就能编译,之后的部署暂且不表。
结论
没事别随便改API,真有必要的话,也请换个名字,要不会给使用方带来巨大的麻烦。