問(wèn)題
在初用spark streaming 1.5.2 自帶的low level 連接kafka例子(JavaDirectKafkaWordCount)時(shí),出現(xiàn)如下錯(cuò)誤:
java.lang.NoSuchMethodError: net.jpountz.util.Utils.checkRange([BII)V
at org.apache.kafka.common.message.KafkaLZ4BlockInputStream.read(KafkaLZ4BlockInputStream.java:176)
根據(jù)網(wǎng)上的解答,這是因?yàn)閗afka用了1.2版本lz4,? 但是程序運(yùn)行時(shí)使用了1.3版的lz4。 由于兩個(gè)版本中的checkRange方法差異大,1.3版的Utils類沒(méi)有checkRange方法了,所以報(bào)NoSuchMethodError。參見(jiàn)這里。
修改lz4版本
查看項(xiàng)目依賴了哪個(gè)版本的lz4: mvn dependency:tree

發(fā)現(xiàn)程序用了spark-core中的net.jpountz.lz4, 是1.3版的,而不是kafka對(duì)應(yīng)的1.2版,所以出錯(cuò)。
于是我將net.jpountz.lz4 從spark-core中去除:

重新查看lz4的依賴關(guān)系:mvn dependency:tree

上圖可以看出已經(jīng)使用了1.2版的lz4。
問(wèn)題依舊
修改版本號(hào)后重新在yarn中運(yùn)行,發(fā)現(xiàn)還是報(bào)“java.lang.NoSuchMethodError: net.jpountz.util.Utils.checkRange([BII)V” 這個(gè)錯(cuò)。
這說(shuō)明程序還是用的1.3版lz4, 這是什么原因呢?
問(wèn)題解決 spark.yarn.user.classpath.first=true
我從這篇博客得到啟發(fā),很可能1.2版的lz4被yarn自帶hadoop jar包中的1.3版lz4覆蓋了。于是我參照那篇博客,在spark-submit 命令中設(shè)置spark.yarn.user.classpath.first=true :
--conf spark.yarn.user.classpath.first=true \
--jars /your path/spark-streaming-kafka_2.10-1.5.2.jar \
這樣設(shè)置后yarn中優(yōu)先使用用戶傳上去的jar包,保證了lz1.2不被覆蓋。yarn中的environment UI可以看到優(yōu)先使用了spark-streaming-kafka_2.10-1.5.2.jar:

結(jié)論
解決本問(wèn)題的需要兩步:
1.在pom.xml中盡量去除1.3版的lz4, 可以使用maven的<exclusion>去除。
2.在yarn上運(yùn)行是設(shè)置“spark.yarn.user.classpath.first=true”參數(shù),保證1.2版的lz4優(yōu)先被使用, 不被hadoop相關(guān)jar包中的lz4覆蓋。