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

时间:2016-11-21 12:22:15

标签: apache-spark akka cloudera-cdh sbt-assembly shading

TL; DR

我正在尝试对akka库的版本进行着色并将其与我的应用程序捆绑在一起(以便能够在spray-canCDH 5.7版本上运行Spark 1.6服务器})。着色过程messes up akka's default configuration,在为着色akka手动提供reference.conf akka的单独版本后,它仍然看起来像2个版本混合以某种方式。

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

背景

我的Scala / Spark应用程序当前正在Spark 1.6.1独立运行。该应用程序使用spray 1.3.3运行spray-can http服务器,这需要akka 2.3.9Spark 1.6.1独立包含兼容的akka 2.3.11。)

我正在尝试将应用程序迁移到运行Spark CDH 5.7版本Spark 1.6的基于Cloudera的新Spark 1.6群集。问题是CDH 5.7中的akka 2.2.3spray 1.3.3捆绑在一起,这不足以让akka 2.3.9正常运作。

尝试解决方案

根据this post中的建议,我决定对akka进行着色并将其与我的应用程序捆绑在一起。虽然这次我偶然发现了一个新问题 - reference.confsbt-assembly文件中定义了默认配置,该文件应该位于应用程序的类路径中。由于akka的着色功能中的known issue,阴影akka库似乎需要单独配置。

所以,我最终使用以下阴影规则着色ShadeRule.rename("akka.**" -> "akka_2_3_9_shade.@1") .inLibrary("com.typesafe.akka" % "akka-actor_2.10" % "2.3.9") .inAll

reference.conf

并在我的项目中包含一个额外的akka文件,该文件与reference.conf的原始Spark相同,但所有出现的都是" akka&#34 ;替换为" akka_2_3_9_shade"。

现在,似乎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 混淆,因为我收到以下错误:

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) 文件中的相关代码如下:

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
pageEncoding="ISO-8859-1"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"             "http://www.w3.org/TR/html4/loose.dtd">

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Insert title here</title>


<script type="text/javascript">

function validateForm(){


var firstname=document.getElementById("fname").value;
firstname.trim();
var lastname=document.getElementById("lname").value;
lastname.trim();
var emailid=document.getElementById("email").value;
emailid.trim();
var conatctnumber=document.getElementById("cont").value;
cont.trim();
//alert(firstname+lastname+emailid+conatctnumber);

if(firstname_validation(firstname)){
if(lastname_validation(lastname)){
    if(emailid_validation(emailid)){
        if(contactnumber_validation(contactnumber)){
            return true;
        }
        else{
            return false;
        }
    }

}

}

}


function firstname_validation(firstname){
var letters = /^[A-Za-z]+$/;  
if(firstname.match(letters))  
{ 

return true;  
}  
else  
{  
alert('firstname must have alphabet characters only');  
fname.focus();    
return false;  
}
}

function lastname_validation(lastname){
var letters = /^[A-Za-z]+$/;  
if(lastname.match(letters))  
{ 

return true;  
}  
else  
{  
alert('lastname must have alphabet characters only');  
lastname.focus();  
return false;  
}
} 


function emailid_validation(emailid){
var mailformat=/^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$/;
if(emailid.match(mailformat)){
    return ture;
}
else{
    alert("Enter correct email address");
    emailid.focus();
    return false;
}

}

function contactnumber_validation(contactnumber){
var letters="/^\d{10}$/";
if(contactnumber.match(letters)){
    return true;
}
else{
    alert("enter valid contact number");
    contactnumber.focus();
    return false;
}

}


</script>

</head>

<body>

<form name="myform" action="UserServlet" method="post"  >
<input style="display: none;" type = "text" name="userid" value="<c:out      value="${update.userid} ">  </c:out>"><br>

First Name:<br>
<input type = "text" id="fname" name="firstname" value="<c:out    value="${update.firstname} "></c:out>" maxlength="40" required><br>

Last Name:<br>
<input type = "text" id="lname" name="lastname" value="<c:out   value="${update.lastname} "></c:out>" maxlength="40" required><br>
EmailId:<br>
<input type="text" id="email" name="emaild" value="<c:out  value="${update.emailid} "></c:out>" maxlength="50" required><br>

Contact Number:<br>
<input type="text" id="cont" name="contactnumber" value="<c:out          value="${update.contactnumber}"></c:out>"   maxlength="10"  required><br>

<input type="button" value="submit" onClick="return validateForm()">

</form>
</body>
</html>

3 个答案:

答案 0 :(得分:6)

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

使用定义为字符串文字的键从配置文件中加载akka个(部分)配置设置。例如,您可以在akka/actor/ActorSystem.scala中找到很多这样的内容。

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

此外,某些配置键 会被sbt-assembly的阴影更改。我还没有花时间在akka的源代码中找到它们的定义位置和方式,但是在ActorSystem初始化代码中抛出了以下异常,证明确实如此:

ConfigException$Missing: No configuration setting found for key 'akka_2_3_9_shade'

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

  • akka原始reference.conf的内容,但配置值中的akka前缀更改为akka_2_3_9_shade。 (这是硬编码字符串文字配置键所必需的)
  • akka原始reference.conf的内容,但配置值中的akka前缀更改为akka_2_3_9_shade 并拥有根配置密钥已更改akka更改为akka_2_3_9_shade。 (这是由sbt-assembly
  • 修改的配置键所必需的
  • spray原始reference.conf的内容,但配置值中的akka前缀更改为akka_2_3_9_shade。 (这是确保spray始终引用带阴影的akka
  • 所必需的

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

val akkaShadeConfig = ConfigFactory.load("akka_spray_shade")
implicit val system = ActorSystem("custom-actor-system-name", akkaShadeConfig)

答案 1 :(得分:1)

接受答案的一小部分。

没有必要将此配置放在自定义命名的文件中,如akka_spray_shade.conf。在没有明确指定自定义配置的情况下,可以在application.conf创建期间默认加载ActorSystem配置:ActorSystem("custom-actor-system-name")实际上意味着ActorSystem("custom-actor-system-name", ConfigFactory.load("application"))

答案 2 :(得分:0)

我也为此挣扎了很长时间。事实证明,sbt-assembly 中的默认合并策略排除了所有 reference.conf 文件。将此添加到 build.sbt 为我解决了这个问题:

assemblyMergeStrategy in assembly := {
  case PathList("reference.conf") => MergeStrategy.concat
}