前言
最近准备对数据质量进行监控,选定的工具是开源的Apache Griffin,由于文档稀缺,加上griffin本身使用的组件众多,期间采坑不少,我们将打好的包measure-0.6.0-SNAPSHOT.jar放到集群中,通过livy调用spark命令执行任务,过程还是相对繁琐的。本文就spark任务结果写入elasticsearch遇到异常做个小结。
异常
Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/http/impl/client/HttpClients
这个好解决,加上httpClient
依赖就好。
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.2</version>
</dependency>
接下来又遇到了。
java.lang.NoSuchFieldError: INSTANCE
at org.apache.http.conn.ssl.SSLConnectionSocketFactory.<clinit>(SSLConnectionSocketFactory.java:144)
at org.apache.http.impl.client.HttpClientBuilder.build(HttpClientBuilder.java:966)
at org.apache.griffin.measure.utils.HttpUtil$.doHttpRequest(HttpUtil.scala:50)
at org.apache.griffin.measure.sink.ElasticSearchSink$$anonfun$org$apache$griffin$measure$sink$ElasticSearchSink$$func$1$1.apply$mcZ$sp(ElasticSearchSink.scala:69)
at org.apache.griffin.measure.sink.ElasticSearchSink$$anonfun$org$apache$griffin$measure$sink$ElasticSearchSink$$func$1$1.apply(ElasticSearchSink.scala:69)
at org.apache.griffin.measure.sink.ElasticSearchSink$$anonfun$org$apache$griffin$measure$sink$ElasticSearchSink$$func$1$1.apply(ElasticSearchSink.scala:69)
at scala.concurrent.impl.Future$PromiseCompletingRunnable.liftedTree1$1(Future.scala:24)
at scala.concurrent.impl.Future$PromiseCompletingRunnable.run(Future.scala:24)
at scala.concurrent.impl.ExecutionContextImpl$AdaptedForkJoinTask.exec(ExecutionContextImpl.scala:121)
at scala.concurrent.forkjoin.ForkJoinTask.doExec(ForkJoinTask.java:260)
at scala.concurrent.forkjoin.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1339)
at scala.concurrent.forkjoin.ForkJoinPool.runWorker(ForkJoinPool.java:1979)
at scala.concurrent.forkjoin.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:107)
19/07/09 19:59:26 ERROR yarn.ApplicationMaster: RECEIVED SIGNAL TERM
根据java.lang.NoSuchFieldError: INSTANCE
搜索,很多会文章会提升你更换httpclient
和 httpcore
这两个包,然后我从最新版本往下换,换到4.3的版本,确实HttpClientBuilder.build
异常的行数变了,最开始是966,说明更换的jar包是被使用了,这个让我欣喜也迷惑了我很久。因为无论哪个版本NoSuchFieldError: INSTANCE
这个问题都存在。
只有另外想办法了,之后考虑换个环境,远程集群不行,本地调用下这个httpclient测试下试试,然后写了个简单的测试用例。
def httpResult(): Unit = {
// 集群的异常就client的创建中
val client = HttpClientBuilder.create.build
val dataMap = Map[String, String](("name","test2"));
val data = JsonUtil.toJson(dataMap)
// http request
val params = Map[String, Object]()
val header = Map[String, Object](("Content-Type", "application/json"))
// HttpUtil工具就是创建并执行一个HttpPost
val result = HttpUtil.doHttpRequest("http://sit-01:9200/griffin/accuracy","post", params, header, data)
print(result)
}
执行发现client的创建并没有异常,并且result返回true,在远程es中也能查到这条name的记录。于是排除es本身的问题和jar包版本的问题。百思不得其解,但是能肯定是jar包出了问题。如果集群没有采用httpclient的jar包,那么异常行数为什么会变,如果采用了为什么一直是那个异常。spark集群会不会有自带低级的httpclient版本导致冲突了。想到这,果断看了下spark2目录下的jars。
[root@sit-01 jars]# ls |grep http
commons-httpclient-3.1.jar
httpcore-4.4.8.jar
集群中spark2是cdh安装的2.3.1的版本,发现里面没有httpclient的包。于是突发奇想的在集群中添加一个httpclient-4.5.2.jar
wget https://repo1.maven.org/maven2/org/apache/httpcomponents/httpclient/4.5.2/httpclient-4.5.2.jar
果然,查看yarn管理界面,job能够正常执行,结果写入es了。
小结
如果学习或者工作中有使用一些新的东西,期间会经常遇到各类环境,版本问题,语法的问题。个人觉得还是要珍惜这些机会,如果能做出点东西是很有成就感的。找点有挑战的事情,这个过程也能加快自己的成长,毕竟搬砖多了也没意思。