Scala + SBT - 如何为着色的Akka库配置reference.conf

Joh*_*sch 4 akka sbt-assembly apache-spark cloudera-cdh shading

TL; DR

我试图遮蔽akka库的一个版本并将其与我的应用程序捆绑在一起(以便能够spray-canCDH 5.7版本上运行服务器Spark 1.6).着色过程混淆了akka默认配置,并且在为阴影手动提供单独版本的akkas之后,看起来仍然看起来两个版本以某种方式混淆了.reference.confakka

是否akka已知阴影版本会导致问题?我究竟做错了什么?

背景

我有一个Scala/ Spark应用程序当前在Spark 1.6.1独立运行.应用程序使用spray-canhttp服务器运行spray 1.3.3,这需要akka 2.3.9(Spark 1.6.1独立包括兼容akka 2.3.11).

我正在尝试将应用程序迁移到运行该版本的新的Cloudera基于Spark群集的群集.问题是,在与捆绑这是不足够的正常工作.CDH 5.7Spark 1.6Spark 1.6CDH 5.7akka 2.2.3spray 1.3.3

试图解决方案

根据这篇文章中的建议,我决定将akka 2.3.9它与我的应用程序一起进行着色并捆绑.虽然这次我偶然发现了一个新问题 - akka它是否在reference.conf文件中定义了默认配置,该文件应该位于应用程序的类路径中.由于着色功能中的已知问题,sbt-assembly阴影akka库似乎需要单独的配置.

所以,我最终akka使用以下阴影规则进行着色:

ShadeRule.rename("akka.**" -> "akka_2_3_9_shade.@1")
    .inLibrary("com.typesafe.akka" % "akka-actor_2.10" % "2.3.9")
    .inAll
Run Code Online (Sandbox Code Playgroud)

reference.conf在我的项目中包含一个附加文件,该文件与akka原始文件相同reference.conf,但所有出现的"akka"都替换为"akka_2_3_9_shade".

但现在,似乎Spark-provided akka被莫名其妙地夹杂了阴影akka,因为我发现了以下错误:

Exception in thread "main" java.lang.IllegalArgumentException: Cannot instantiate MailboxType [akka.dispatch.UnboundedMailbox], defined in [akka.actor.default-mailbox], make sure it has a public constructor with [akka.actor.ActorSystem.Settings, com.typesafe.config.Config] parameters
    at akka_2_3_9_shade.dispatch.Mailboxes$$anonfun$1.applyOrElse(Mailboxes.scala:197)
    at akka_2_3_9_shade.dispatch.Mailboxes$$anonfun$1.applyOrElse(Mailboxes.scala:195)
    at scala.runtime.AbstractPartialFunction.apply(AbstractPartialFunction.scala:33)
    at scala.util.Failure$$anonfun$recover$1.apply(Try.scala:185)
    at scala.util.Try$.apply(Try.scala:161)
    at scala.util.Failure.recover(Try.scala:185)
    at akka_2_3_9_shade.dispatch.Mailboxes.lookupConfiguration(Mailboxes.scala:195)
    at akka_2_3_9_shade.dispatch.Mailboxes.lookup(Mailboxes.scala:78)
    at akka_2_3_9_shade.actor.LocalActorRefProvider.akka$actor$LocalActorRefProvider$$defaultMailbox$lzycompute(ActorRefProvider.scala:561)
    at akka_2_3_9_shade.actor.LocalActorRefProvider.akka$actor$LocalActorRefProvider$$defaultMailbox(ActorRefProvider.scala:561)
    at akka_2_3_9_shade.actor.LocalActorRefProvider$$anon$1.<init>(ActorRefProvider.scala:568)
    at akka_2_3_9_shade.actor.LocalActorRefProvider.rootGuardian$lzycompute(ActorRefProvider.scala:564)
    at akka_2_3_9_shade.actor.LocalActorRefProvider.rootGuardian(ActorRefProvider.scala:563)
    at akka_2_3_9_shade.actor.LocalActorRefProvider.init(ActorRefProvider.scala:618)
    at akka_2_3_9_shade.actor.ActorSystemImpl.liftedTree2$1(ActorSystem.scala:619)
    at akka_2_3_9_shade.actor.ActorSystemImpl._start$lzycompute(ActorSystem.scala:616)
    at akka_2_3_9_shade.actor.ActorSystemImpl._start(ActorSystem.scala:616)
    at akka_2_3_9_shade.actor.ActorSystemImpl.start(ActorSystem.scala:633)
    at akka_2_3_9_shade.actor.ActorSystem$.apply(ActorSystem.scala:142)
    at akka_2_3_9_shade.actor.ActorSystem$.apply(ActorSystem.scala:109)
    at akka_2_3_9_shade.actor.ActorSystem$.apply(ActorSystem.scala:100)
    at MyApp.api.Boot$delayedInit$body.apply(Boot.scala:45)
    at scala.Function0$class.apply$mcV$sp(Function0.scala:40)
    at scala.runtime.AbstractFunction0.apply$mcV$sp(AbstractFunction0.scala:12)
    at scala.App$$anonfun$main$1.apply(App.scala:71)
    at scala.App$$anonfun$main$1.apply(App.scala:71)
    at scala.collection.immutable.List.foreach(List.scala:318)
    at scala.collection.generic.TraversableForwarder$class.foreach(TraversableForwarder.scala:32)
    at scala.App$class.main(App.scala:71)
    at MyApp.api.Boot$.main(Boot.scala:28)
    at MyApp.api.Boot.main(Boot.scala)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:601)
    at org.apache.spark.deploy.SparkSubmit$.org$apache$spark$deploy$SparkSubmit$$runMain(SparkSubmit.scala:731)
    at org.apache.spark.deploy.SparkSubmit$.doRunMain$1(SparkSubmit.scala:181)
    at org.apache.spark.deploy.SparkSubmit$.submit(SparkSubmit.scala:206)
    at org.apache.spark.deploy.SparkSubmit$.main(SparkSubmit.scala:121)
    at org.apache.spark.deploy.SparkSubmit.main(SparkSubmit.scala)
Caused by: java.lang.ClassCastException: interface akka_2_3_9_shade.dispatch.MailboxType is not assignable from class akka.dispatch.UnboundedMailbox
    at akka_2_3_9_shade.actor.ReflectiveDynamicAccess$$anonfun$getClassFor$1.apply(DynamicAccess.scala:69)
    at akka_2_3_9_shade.actor.ReflectiveDynamicAccess$$anonfun$getClassFor$1.apply(DynamicAccess.scala:66)
    at scala.util.Try$.apply(Try.scala:161)
    at akka_2_3_9_shade.actor.ReflectiveDynamicAccess.getClassFor(DynamicAccess.scala:66)
    at akka_2_3_9_shade.actor.ReflectiveDynamicAccess.CreateInstanceFor(DynamicAccess.scala:84)
    ... 34 more
Run Code Online (Sandbox Code Playgroud)

我的应用程序Boot.scala文件中的相关代码如下:

[45]    implicit val system = ActorSystem()
...
[48]    val service = system.actorOf(Props[MyAppApiActor], "MyApp.Api")
...
[52]    val port = config.getInt("MyApp.server.port")
[53]    IO(Http) ? Http.Bind(service, interface = "0.0.0.0", port = port)
Run Code Online (Sandbox Code Playgroud)

Joh*_*sch 6

好的,所以最终我设法解决了这个问题.

akka使用定义为字符串文字的键从配置文件中输出加载(某些)配置设置.例如,你可以找到很多这些akka/actor/ActorSystem.scala.

并且似乎sbt-assembly 不会更改字符串文字中对着色库/包名称的引用.

此外,一些配置键被改变sbt-assembly的阴影.我没有真正花时间在akka源代码中找到它们的定义位置和方式,但是在ActorSysteminit代码中抛出的以下异常证明了确实如此:

ConfigException$Missing: No configuration setting found for key 'akka_2_3_9_shade'
Run Code Online (Sandbox Code Playgroud)

因此,解决方案包括自定义配置文件(例如akka_spray_shade.conf,调用它),并在其中复制以下配置部分:

  • akka原始内容reference.conf,但akka配置值中的前缀更改为akka_2_3_9_shade.(这是硬编码字符串文字配置键所必需的)
  • 的内容akka的原始reference.conf的,但具有akka在配置值的前缀改变为akka_2_3_9_shade 和具有改变的根构造密钥akkaakka_2_3_9_shade.(这是需要修改的配置键所必需的sbt-assembly)
  • spray原始内容reference.conf,但akka配置值中的前缀更改为akka_2_3_9_shade.(这是确保spray始终引用阴影所必需的akka)

现在,必须在应用程序代码的初始化期间显式提供此自定义配置文件:ActorSystemBoot.scala

val akkaShadeConfig = ConfigFactory.load("akka_spray_shade")
implicit val system = ActorSystem("custom-actor-system-name", akkaShadeConfig)
Run Code Online (Sandbox Code Playgroud)