복붙노트

[HADOOP] build.sbt에서 구아바가 제대로 음영 처리되지 않는 이유는 무엇입니까?

HADOOP

build.sbt에서 구아바가 제대로 음영 처리되지 않는 이유는 무엇입니까?

카산드라와 HDFS는 내부적으로 구아바를 사용하지만 여러 가지 이유로 의존성을 가리지 않습니다. 구아바 버전은 이진 호환되지 않기 때문에 런타임에 NoSuchMethodErrors를 찾고 있습니다.

내 build.sbt에서 구아바를 직접 음영 처리하려고했습니다.

val HadoopVersion =  "2.6.0-cdh5.11.0"

// ...

val hadoopHdfs = "org.apache.hadoop" % "hadoop-hdfs" % HadoopVersion
val hadoopCommon = "org.apache.hadoop" % "hadoop-common" % HadoopVersion
val hadoopHdfsTest = "org.apache.hadoop" % "hadoop-hdfs" % HadoopVersion % "test" classifier "tests"
val hadoopCommonTest = "org.apache.hadoop" % "hadoop-common" % HadoopVersion % "test" classifier "tests"
val hadoopMiniDFSCluster = "org.apache.hadoop" % "hadoop-minicluster" % HadoopVersion % Test

// ...

assemblyShadeRules in assembly := Seq(
  ShadeRule.rename("com.google.common.**" -> "shade.com.google.common.@1").inLibrary(hadoopHdfs).inProject,
  ShadeRule.rename("com.google.common.**" -> "shade.com.google.common.@1").inLibrary(hadoopCommon).inProject,
  ShadeRule.rename("com.google.common.**" -> "shade.com.google.common.@1").inLibrary(hadoopHdfsTest).inProject,
  ShadeRule.rename("com.google.common.**" -> "shade.com.google.common.@1").inLibrary(hadoopCommonTest).inProject,
  ShadeRule.rename("com.google.common.**" -> "shade.com.google.common.@1").inLibrary(hadoopMiniDFSCluster).inProject
)

assemblyJarName in assembly := s"${name.value}-${version.value}.jar"

assemblyMergeStrategy in assembly := {
  case PathList("META-INF", "MANIFEST.MF") => MergeStrategy.discard
  case _ => MergeStrategy.first
}

그러나 런타임 예외는 지속됩니다 (ha-사람들은 카산드라 농담입니다).

구체적인 예외는

[info] HdfsEntitySpec *** ABORTED ***
[info]   java.lang.NoSuchMethodError: com.google.common.base.Objects.toStringHelper(Ljava/lang/Object;)Lcom/google/common/base/Objects$ToStringHelper;
[info]   at org.apache.hadoop.metrics2.lib.MetricsRegistry.toString(MetricsRegistry.java:406)
[info]   at java.lang.String.valueOf(String.java:2994)
[info]   at java.lang.StringBuilder.append(StringBuilder.java:131)
[info]   at org.apache.hadoop.ipc.metrics.RetryCacheMetrics.<init>(RetryCacheMetrics.java:46)
[info]   at org.apache.hadoop.ipc.metrics.RetryCacheMetrics.create(RetryCacheMetrics.java:53)
[info]   at org.apache.hadoop.ipc.RetryCache.<init>(RetryCache.java:202)
[info]   at org.apache.hadoop.hdfs.server.namenode.FSNamesystem.initRetryCache(FSNamesystem.java:1038)
[info]   at org.apache.hadoop.hdfs.server.namenode.FSNamesystem.<init>(FSNamesystem.java:949)
[info]   at org.apache.hadoop.hdfs.server.namenode.FSNamesystem.<init>(FSNamesystem.java:796)
[info]   at org.apache.hadoop.hdfs.server.namenode.NameNode.format(NameNode.java:1040)
[info]   ...

런타임 오류를 막기 위해 구아바를 올바르게 음영 처리하려면 어떻게합니까?

해결법

  1. ==============================

    1.음영 처리 규칙은 뚱뚱한 항아리를 만들 때만 적용됩니다. 다른 sbt 작업 중에는 적용되지 않습니다.

    음영 처리 규칙은 뚱뚱한 항아리를 만들 때만 적용됩니다. 다른 sbt 작업 중에는 적용되지 않습니다.

    hadoop 종속성 내부에서 일부 라이브러리를 음영 처리하려면 hadoop 종속성 만있는 새 프로젝트를 만들고 라이브러리를 음영 처리하고 음영 처리 된 모든 hadoop 종속성이있는 팻 jar를 게시 할 수 있습니다.

    새로운 hadoop jar의 모든 종속 항목을 사용하는 사람은 "알 수 없음"이므로 충돌을 수동으로 처리해야하므로 이는 완벽한 솔루션이 아닙니다.

    다음은 fat hadoop jar를 게시하기 위해 build.sbt에 필요한 코드입니다. (코드 및 sbt 어셈블리 문서 사용) :

    val HadoopVersion =  "2.6.0-cdh5.11.0"
    
    val hadoopHdfs = "org.apache.hadoop" % "hadoop-hdfs" % HadoopVersion
    val hadoopCommon = "org.apache.hadoop" % "hadoop-common" % HadoopVersion
    val hadoopHdfsTest = "org.apache.hadoop" % "hadoop-hdfs" % HadoopVersion classifier "tests"
    val hadoopCommonTest = "org.apache.hadoop" % "hadoop-common" % HadoopVersion %  classifier "tests"
    val hadoopMiniDFSCluster = "org.apache.hadoop" % "hadoop-minicluster" % HadoopVersion 
    
    lazy val fatJar = project
      .enablePlugins(AssemblyPlugin)
      .settings(
        libraryDependencies ++= Seq(
            hadoopHdfs,
            hadoopCommon,
            hadoopHdfsTest,
            hadoopCommonTest,
            hadoopMiniDFSCluster
        ),
          assemblyShadeRules in assembly := Seq(
          ShadeRule.rename("com.google.common.**" -> "shade.@0").inAll
        ),
        assemblyMergeStrategy in assembly := {
          case PathList("META-INF", "MANIFEST.MF") => MergeStrategy.discard
          case _ => MergeStrategy.first
        },
        artifact in (Compile, assembly) := {
          val art = (artifact in (Compile, assembly)).value
          art.withClassifier(Some("assembly"))
        },
        addArtifact(artifact in (Compile, assembly), assembly),
        crossPaths := false, // Do not append Scala versions to the generated artifacts
        autoScalaLibrary := false, // This forbids including Scala related libraries into the dependency
        skip in publish := true
      )
    
    lazy val shaded_hadoop = project
      .settings(
        name := "shaded-hadoop",
        packageBin in Compile := (assembly in (fatJar, Compile)).value
      )
    

    나는 그것을 테스트하지는 않았지만 그것이 핵심입니다.

    파일에 다른 전략을 적용하고 싶기 때문에 병합 전략으로 인해 문제가 발생할 수 있다는 또 다른 문제를 지적하고자합니다. 기본 전략을 참조하십시오. 중복되지 않는 모든 것에 대한 원래 전략을 유지하기 위해 이와 같은 것을 사용하는 것이 좋습니다.

    assemblyMergeStrategy in assembly := {
              entry: String => {
                val strategy = (assemblyMergeStrategy in assembly).value(entry)
                if (strategy == MergeStrategy.deduplicate) MergeStrategy.first
                else strategy
              }
          }
    
  2. from https://stackoverflow.com/questions/47907446/why-isnt-guava-being-shaded-properly-in-my-build-sbt by cc-by-sa and MIT license