有时需要花些力气去思考。 这对每个开发人员都是一个好习惯,即使您仅花费10%的时间,并使用新的和值得注意的技术,您也将获得经验并扩大您的知识。 从那以后我一直想研究Scala和Akka。 在许多会议议程上,这两个众所周知的老熟人。 但老实说,我从来没有觉得需要重新审视。 当我开始更深入地研究微服务及其相关概念时,这种情况发生了很大变化。 让我们开始,看看里面有什么。
为什么使用Scala?
但是首先是关于什么是Akka的句子。 AKKA是演员内核中字母A和K的回文。
“ Akka是一个工具包和运行时,用于在JVM上构建高度并发,分布式和弹性消息驱动的应用程序。”
它的构想就是使编写并发,容错和可扩展的应用程序变得更加容易。 在所谓的“ Actor ”模型的帮助下,这些应用程序的抽象级别已被重新定义,并且通过采用“让它崩溃”的概念,您可以构建具有自我修复能力的应用程序和承受很高工作负载的系统。 Akka是开放源代码,可在Apache 2许可下获得,可以从http://akka.io/downloads下载。 在Akka官方文档中了解有关它的更多信息。 Akka有两种风格:Java和Scala API。 因此,您基本上可以自由选择要在项目中使用的版本。 我在此博客文章中选择了Scala,因为我在那里找不到足够的Akka Java示例。
为什么Java开发人员应该关心?
我对您不太了解,但是我对此感到很好奇,并开始浏览一些文档。 “ 强制性的Hello World ”并没有带我到任何地方。 也许是因为我仍然对Maven和Java进行过多思考,但是我们在这里稍加开放,所以现在该改变一下了。 弹性和消息驱动的系统似乎是设计基于微服务的应用程序的最有前途的方法。 即使Java开发人员可以更轻松地访问诸如Vert.x之类的东西,也可以尝试新的东西。 因为没有找到我想要的文档,我给了Konrad` @ktosopl`Malawsk一个ping命令,并寻求帮助。 他提出了一个很好的Akka-HTTP小示例,供我分解和学习。 谢谢你的帮助!
Akka,Scala以及现在的Akka-HTTP?
另一个新名字。 Akka HTTP模块在akka-actor和akka-stream之上实现了完整的服务器和客户端HTTP堆栈。 它不是Web框架,而是提供和使用基于HTTP的服务的更通用的工具包。 这就是我想看看的。 生病了吗? 让我们开始吧:
克隆和编译–冒烟测试
Git将Konrad的示例克隆到选择的文件夹中,并开始编译和运行它:
git clone https://github.com/ktoso/example-akka-http.git
mvn exec:java
下载互联网后,将浏览器指向http://127.0.0.1:8080/并尝试“ ping”链接。 您会得到一个很好的“ PONG!” 回答。
恭喜你 现在让我们看一下代码。
示例代码
查看pom.xml和exec-maven-plugin配置会将我们指向com.example。 ExampleServer.scala类。 它扩展了ExampleRoutes.scala,并且显然定义了一些路由。 毫不奇怪,这些映射到您可以从索引页面使用的链接。 即使您不了解Scala,这也是有道理的。 对于我们中间的Java开发人员来说,Konrad很友好,可以添加一个Java Akka示例( JavaExampleServer.java )。 如果将两者进行比较,我仍然会更喜欢Java示例,但是它可能还会更长一些。 只需选择最喜欢的东西即可。
该示例中有一件很酷的事情 ,您可能想检一下。 这条线正在发出一个Reactive Streams数据源,该数据源的推送速度与客户端可以使用的速度完全相同,并且仅“按需”生成。 比较http://www.reactive-streams.org/了解更多详细信息。
该示例的主要优势显然是,它为两种语言都提供了完整的基于Maven的构建,并且可以轻松地用来学习有关Akka的更多信息。 一个很好的起点。 而且从功能角度来看,此示例中没有更多内容,因此让我们看看是否可以在云中运行它。
在容器中部署Akka
根据文档,有三种不同的部署Akka应用程序的方式:
- 作为库:在类路径和/或Web应用程序中用作常规JAR,放入WEB-INF / lib
- 带有sbt-native-packager的软件包,它能够构建准备运行您的应用程序的* .deb,*。rpm或docker映像。
- 使用Typesafe ConductR打包和部署。
我对sbt和ConductR一无所知,所以我认为无论如何我还是跟着我最近玩的东西一起去的:在一个容器中。 如果它是从Maven构建中运行的,那么我可以轻松地将其打包为映像。 我们走吧。 第一步是将Maven Shade插件添加到pom.xml中:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.4.1</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<shadedArtifactAttached>true</shadedArtifactAttached>
<shadedClassifierName>allinone</shadedClassifierName>
<artifactSet>
<includes>
<include>*:*</include>
</includes>
</artifactSet>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
<resource>reference.conf</resource>
</transformer>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<main-Class>com.example.ExampleServer</main-Class>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
阴影插件会创建一个Uber jar,正是这种情况下我想要的。 在配置中有三种特殊情况。 我们要:
- 附加阴影的工件以从Docker Maven插件访问它
- 使用AppendingTransformer,因为配置文件是连接在一起的,而不是在构建过程中“挑一个”的东西 。
- 定义我们要运行的主类。
完成后,就该相应地配置我们的Docker Maven插件了:
<plugin>
<groupId>org.jolokia</groupId>
<artifactId>docker-maven-plugin</artifactId>
<version>0.13.5</version>
<configuration>
<images>
<image>
<name>myfear/akka-sample:latest</name>
<build>
<from>jboss/base-jdk:8</from>
<maintainer>markus@jboss.org</maintainer>
<ports>
<port>8080</port>
</ports>
<entryPoint>
<exec>
<arg>java</arg>
<arg>-jar</arg>
<arg>/opt/akka-http/akka-http-service.jar</arg>
</exec>
</entryPoint>
<assembly>
<inline>
<dependencySets>
<dependencySet>
<useProjectAttachments>true</useProjectAttachments>
<includes>
<include>com.example:akka-http-example:jar:allinone</include>
</includes>
<outputFileNameMapping>akka-http-service.jar</outputFileNameMapping>
</dependencySet>
</dependencySets>
</inline>
<user>jboss:jboss:jboss</user>
<basedir>/opt/akka-http</basedir>
</assembly>
</build>
<run>
<ports>
<port>${swarm.port}:8080</port>
</ports>
<wait>
<http>
<url>http://${docker.host.address}:${swarm.port}</url>
<status>200</status>
</http>
<time>30000</time>
</wait>
<log>
<color>yellow</color>
<prefix>AKKA</prefix>
</log>
</run>
</image>
</images>
</configuration>
</plugin>
需要注意的几件事:
- 输出文件映射,在入口点参数中必须相同。
- 项目附件包括我们在Maven阴影插件中定义的“ allinone”。
- 映像程序集中的用户(需要是在基本映像中定义的用户。在这种情况下,jboss / base-jdk仅知道用户jboss。)
在进行此操作时,我们需要对示例进行一些调整。 在容器化环境中,将Akka-Http服务器绑定到localhost并没有真正的帮助。 因此,我们使用java.net库来查找有关容器的实际IP。 而当我们:注释掉启动后的过程。 新的ExampleServer如下所示:
package com.example
import akka.actor.ActorSystem
import akka.http.scaladsl.Http
import akka.stream.ActorMaterializer
import java.net._
object ExampleServer extends ExampleRoutes {
implicit val system = ActorSystem("ExampleServer")
import system.dispatcher
implicit val materializer = ActorMaterializer()
// settings about bind host/port
// could be read from application.conf (via system.settings):
val localhost = InetAddress.getLocalHost
val interface = localhost.getHostAddress
val port = 8080
def main(args: Array[String]): Unit = {
// Start the Akka HTTP server!
// Using the mixed-in testRoutes (we could mix in more routes here)
val bindingFuture = Http().bindAndHandle(testRoutes, interface, port)
println(s"Server online at http://$interface:$port/\nON Docker...")
}
}
让我们通过执行以下命令来构建Akka应用程序和Dockerfile:
mvn package docker:build
并进行测试运行:
docker run myfear/akka-sample
将浏览器重定向到http://192.168.99.100:32773/(注意:您的环境中的IP和端口将有所不同。请确保列出与docker ps对应的容器端口,并获取boot2docker或docker-machine实例的ip )将再次显示您的工作示例。
最后的想法
将这个小小的Akka示例带到云中的下一步是将其部署在PaaS上。 以OpenShift为例(将这篇文章比较如何做 )。 作为肥罐应用程序,它可以很容易地包装到一个不变的容器中。 我不会将Akka与Java领域中的其他任何事物进行比较,而是希望为您提供自己的第一步的起点,并鼓励您始终保持好奇心,并对那里的一些技术进行自我教育。
进一步的阅读和信息: