最近在项目中集成hbase1.0.0和ElasticSearch2.3.3时出现了问题,今天我把其中一个比较尴尬的问题写下来,log中错误:
org.apache.hadoop.hbase.DoNotRetryIOException: java.lang.IllegalAccessError: tried to access method com.google.common.base.Stopwatch.<init>()V from class org.apache.hadoop.hbase.zookeeper.MetaTableLocator
之前我在集成ES时,引入了架包com.google.guava(18.0版本),程序得以顺利执行。后来在集成HBase时发现它也用到了guava,且是12.0版本的。这时候问题来了,如果将原来的guava 18.0版本修改为16.0版本以下(HBase中用到的guava版本需在16.0以下版本,具体原因请看guava包中StopWatch的改变),因此HBase中就是因为版本太高而报错。如果改变guava版本使用16.0版本那么ES的javaAPI就会因为guava的版本太低而报错。怎么办呢?再次困扰我好久。
于是乎查询了一下资料,发现在ES的官网上有一篇关于jar包冲突的blog。所以参考修改了一下,折腾一天终于搞定。这里提供两种解决方案:
方案一:
1、造成我出现上述的原因是由于我采用了ES较为常规的连接请求方式,如下:
Settings settings = Settings.settingsBuilder().put("cluster.name", "rube-es").put("client.transport.sniff", true).build();
TransportClient tClient = TransportClient.builder().settings(settings).build();
Client client = null;
String host = "";
client = tClient.addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName(host), 9300));
SearchResponse searchResponse = client.prepareSearch()
.setSearchType(SearchType.DEFAULT)
.setScroll(new TimeValue(60000))
.setIndices("indices")
.setTypes("type")
.setQuery(QueryBuilders.matchAllQuery())
.setFrom(0)
.setSize(500)
.execute()
.actionGet();
因此造成以上问题,这里我们可以绕过此种方法去进行ES的请求,采用如下Http请求的方法:
AsyncHttpClientConfig.Builder builder = new AsyncHttpClientConfig.Builder();
builder.setCompressionEnabled(true).setAllowPoolingConnection(true);
builder.setRequestTimeoutInMs((int) TimeUnit.MINUTES.toMillis(1));
builder.setIdleConnectionTimeoutInMs((int) TimeUnit.MINUTES.toMillis(1));
AsyncHttpClient client = new AsyncHttpClient(builder.build());
ListenableFuture<Response> future = client.preparePost(url).addHeader("content-type", "application/json").setBody(queryStr.getBytes("UTF-8")).execute();
这样就绕过了guava版本的问题,可以修改项目中的guava版本为16.0以下,暂且解决这个问题,但是如果绕不过去怎么办,请看下面的方案二。
方案二:
1、首先是参考es官网blog:https://www.elastic.co/blog/to-shade-or-not-to-shade ,新建一个maven项目进行如下配置:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>my.elasticsearch</groupId>
<artifactId>es-shaded</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<elasticsearch.version>2.2.0</elasticsearch.version>
</properties>
<dependencies>
<dependency>
<groupId>org.elasticsearch</groupId>
<artifactId>elasticsearch</artifactId>
<version>${elasticsearch.version}</version>
</dependency>
<dependency>
<groupId>org.elasticsearch.plugin</groupId>
<artifactId>shield</artifactId>
<version>${elasticsearch.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.4.1</version>
<configuration>
<createDependencyReducedPom>false</createDependencyReducedPom>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<relocations>
<relocation>
<pattern>com.google.guava</pattern>
<shadedPattern>my.elasticsearch.guava</shadedPattern>
</relocation>
<relocation>
<pattern>org.joda</pattern>
<shadedPattern>my.elasticsearch.joda</shadedPattern>
</relocation>
<relocation>
<pattern>com.google.common</pattern>
<shadedPattern>my.elasticsearch.common</shadedPattern>
</relocation>
</relocations>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer" />
</transformers>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>elasticsearch-releases</id>
<url>http://maven.elasticsearch.org/releases</url>
<releases>
<enabled>true</enabled>
<updatePolicy>daily</updatePolicy>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
</project>
如上配置完成后,其实就是将org.joda等4个可能有冲突的jar包通过maven-shade-plugin插件迁移后重新打个jar包从而使得在引入这个jar包时能够使用该jar包自己的依赖而不是使用外部依赖。
2、然后install项目,看到build success的话表示打包成功,新的依赖包会在.m2文件的仓库中。下面回到原来的集成项目的pom文件中。引入该jar包: (注意这里需要排除掉ES 2.3.3的jar包,不然maven会将2.3.3的jar包打进去,造成冲突)
<dependency>
<groupId>my.elasticsearch</groupId>
<artifactId>es-shaded</artifactId>
<version>1.0-SNAPSHOT</version>
<exclusions>
<exclusion>
<groupId>org.elasticsearch</groupId>
<artifactId>elasticsearch</artifactId>
</exclusion>
</exclusions>
</dependency>