在Java生态系统中的微服务上工作时,尤其是使用Spring(Boot)时,您会注意到应用程序会有很长的启动时间,更不用说它们将拥有高内存消耗了。每个微服务的开销最终将在系统上承担其成本。而诸如Micronaut之类的框架可以帮助减少这种开销,而又不损失任何开发人员的生产力。使用Micronaut不仅可以构建“经典”应用程序,而且可以使用OpenFaaS在云环境或Kubernetes上构建和部署无服务器应用程序和功能。让我们开始吧!
小注释:在本文中,对Spring进行了一些参考和比较。因此,有关Spring的一些知识可能会很有用。
隆重介绍Micronaut
Micronaut是一个基于JVM的框架,旨在构建模块化微服务。当您打开Micronaut项目时,乍看之下不会感到惊讶,它的外观和感觉与Java世界中常见的Spring(引导)项目相同。但是,差异远远很小或微妙,在开始将此类项目投入生产之前,应该很好地理解它们。另一方面,开始发现Micronaut世界的过程将非常顺利,并且随着您逐步探索Micronaut世界,对它的理解也会随之增长。
注释和Micronaut
众所周知,在运行时Spring会使用大量反射,而Micronaut所做的这些工作却是编译时已经完成。一个示例是运行时生成的Spring Data查询,Micronaut将在编译时生成相同的查询,从而在运行时最大程度地减少使用的内存。创建的每个Bean都会在编译时得到充实,从而创建一个所谓的BeanDefinition 类,其中包含Bean的需求及其构造函数。所有这些类都使用进行处理BeanDefinitionInjectProcessor。
而且,Micronaut依赖于Java EE依赖注入,因此可以使用@Singleton和使用@Inject对Bean进行注释 。这些bean的生命周期将由Micronaut自己管理。
构建一个Micronaut组件
对于与Micronaut有关的所有事情,都可以使用CLI(命令行界面)工具。只需按照官方 文档中 的步骤安装即可 。
对于使用Micronaut的任何项目,CLI工具都是一个很好的起点,它将生成项目的主干结构以及一些有用的开发文件。它为您完成整个脚手架。对于每种应用程序类型,可以设置功能列表以生成这些功能所需的所有必要配置。CLI工具支持三种JVM语言:Java,Kotlin和Groovy,以及两种构建工具:Maven和Gradle。如果是Maven项目,则将生成Maven包装器以及pom.xml。
紧接着,CLI工具将生成一个Micronaut-cli.yml,这将是CLI工具进行任何进一步操作的输入,并将包含项目的名称和配置文件。
如果你来自Spring世界,会在Spring 的main / resources目录中找到:application.yml。就像在Spring应用程序中一样,此文件包含该应用程序的所有配置设置。
示例
一个简单的应用程序将为作者提供一本书。为此,它将调用一个返回作者所有书籍的函数。
在此示例中,应用程序将包含一个REST端点,以询问特定作者的书。该端点必须调用一个函数来检索此信息。因此,该应用程序将是一个http服务器以及一个http客户端,并将部署在Kubernetes上。
因此,生成应用程序基础的命令将是:
mn create-app bookstore-service --build=Maven --lang=java --features=Kubernetes,netflix-hystrix,http-server,http-client
由于该服务调用一个函数,因此需要netflix-hystrix。一个函数需要一些时间才能启动(预热时间)。这并不意味着会花费很多时间,但是HTTP调用肯定会花费一些时间。为避免该函数直接返回状态为500的HTTP响应,需要一种重试机制以确保在答案可用后立即对其进行检索。
由于该应用程序将按函数指示部署在Kubernetes上Kubernetes,因此该create-app命令还将生成一个k8s.yml,它将作为部署的基础。当然,必须根据部署环境的要求对其进行调整。该Kubernetes配置将具有部署和服务。
默认情况下,此应用程序将在端口8080上运行。要更改application.yml中的以下属性,可以将其设置为首选值:
micronaut: server: port: 8081
现在是时候添加一个端点来检索给定作者的所有书籍。为此,将使用Micronaut的HTTP函数。
<b>package</b> bookstore.service.store; <b>import</b> io.Micronaut.http.annotation.Controller; <b>import</b> io.Micronaut.http.annotation.Get; <b>import</b> io.Micronaut.http.annotation.PathVariable; @Controller(<font>"books"</font><font>) <b>public</b> <b>class</b> BookstoreController { @Get(</font><font>"/{author}"</font><font>) <b>public</b> Book retrieveBooksByAuthor() { <b>return</b> <b>new</b> Book(</font><font>"1000 new things"</font><font>, </font><font>"John Doe"</font><font>); } } </font>
这看起来很像Spring Controller,对吗?除了使用Micronaut软件包中的注释外。
这里引人注目的是BookDTO 的实现:
@Introspected <b>public</b> <b>class</b> Book implements Serializable { <b>private</b> String title; <b>private</b> String author; <b>public</b> Book(String title, String author) { <b>this</b>.title = title; <b>this</b>.author = author; } <font><i>// some getters</i></font><font> } </font>
@Introspected是反射DTO所需的注释。在编译时,将执行检查以查看是否可以为DTO初始化所有属性。
构建一个函数来服务需要快速提供给我们应用程序的数据,而无需使用大量逻辑。在我们的示例中,该函数将返回给定作者姓名的书籍清单。让我们从最简单的情况开始:
mn create-function get-books-by-author --build=Maven --features=openfaas
为了使该函数可构建,必须删除一个AWS依赖项(在本示例中,将不使用任何AWS功能,并且它将返回类路径错误),我们是为在OpenFaaS上构建运行的函数。:
<dependency> <groupId>com.amazonaws</groupId> <artifactId>aws-lambda-java-log4j2</artifactId> <version>1.0.0</version> <scope>runtime</scope> </dependency>
在撰写本文时,Dockerfile仍将存在一个错误。Dockerfile基于OpenJDK 8映像,但它应基于OpenJDK 13映像,以免遇到任何运行时/编译问题。
在Dockerfile中的以下代码行中,必须删除两个标志:
ENV fprocess=<font>"java -Dcom.sun.management.jmxremote -noverify -XX:TieredStopAtLevel=1 -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap -jar Handler.jar"</font><font> </font>
-noverify和-XX:+UseCGroupMemoryLimitForHeapJDK 13中已弃用,因此不需要。代码行将变为:
ENV fprocess=<font>"java -Dcom.sun.management.jmxremote -XX:TieredStopAtLevel=1 -XX:+UnlockExperimentalVMOptions -jar Handler.jar"</font><font> </font>
接下来,我们需要添加log4j2.xml作为log4日志记录的配置。
此外,还必须为jar中的日志添加以下内容:
<transformer implementation=<font>"org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"</font><font>> <mainClass>${exec.mainClass}</mainClass> <manifestEntries> <Multi-Release><b>true</b></Multi-Release> </manifestEntries> </transformer> </font>
现在,为方便起见,仅通过在Dockerfile中进一步更改fprocess命令,将日志记录级别设置为ERROR:
ENV fprocess=<font>"java -Dorg.apache.logging.log4j.simplelog.StatusLogger.level=ERROR -Dcom.sun.management.jmxremote -XX:TieredStopAtLevel=1 -XX:+UnlockExperimentalVMOptions -jar Handler.jar"</font><font> </font>
为了使函数尽可能简单,函数类不会扩展 FunctionInitializer.
部署Micronaut
现在需要一个环境来部署它。OpenFaaS是在Kubernetes上部署应用程序或功能的不错选择。对于Micronaut功能,OpenFaaS将部署一个Pod。在此Pod上,直到调用终结点之前,任何内容都不会运行。届时,应用程序将开始运行并返回端点调用。
安装OpenFaaS非常容易,不应花费太多时间。在执行项目时,我想探索Micronaut功能。但是,不能选择部署到AWS,而我的好奇心是由OpenFaaS触发的。在本地安装OpenFaaS非常容易。OpenFaaS使在现有Kubernetes集群上轻松部署功能和应用程序变得容易。
此处 列出了安装说明 。
简而言之,从安装CLI开始:
brew install faas-cli
然后在安装OpenFaaS之前,安装Arkade(这是以后安装OpenFaaS的最快选择):
curl -SLsf https:<font><i>//dl.get-arkade.dev/ | sudo sh</i></font><font> </font>
现在,您终于可以在本地Kubernetes集群上安装OpenFaaS了:
arkade install openfaas
现在的诀窍是不要忽略安装中出现的所有日志记录行,那里有一些有用的说明可以帮助您完成安装。首先要检查所有部署是否都成功:
kubectl -n openfaas get deployments -l <font>"release=openfaas, app=openfaas"</font><font> </font>
成功的部署应该是:
NAME READY UP-TO-DATE AVAILABLE AGE alertmanager 1/1 1 1 6d21h basic-auth-plugin 1/1 1 1 6d21h faas-idler 1/1 1 1 6d21h gateway 1/1 1 1 6d21h nats 1/1 1 1 6d21h prometheus 1/1 1 1 6d21h queue-worker 1/1 1 1 6d21h
现在必须采取最后一步。OpenFaaS使用的网关应转发:
kubectl -n openfaas rollout status deploy/gateway kubectl -n openfaas port-foward svc/gateway 8080:8080
不要忘记设置登录名:
PASSWORD=$(kubectl get secret -n openfaas basic-auth -o jsonpath=<font>"{.data.basic-auth-password}"</font><font> | base64 --decode; echo) echo -n $PASSWORD | faas-cli login --username admin --password-stdin </font>
OpenFaaS现在应该已经启动并运行!
部署Micronaut函数:在OpenFaaS上测试功能:OpenFaaS需要注册表来推送和部署功能。对于本地开发,可以在docker容器中启动注册表:
sudo docker run -d -p 5000:5000 --name registry registry:2
在提供者描述(仅指定网关的端点)之后, 更仔细地看看function.yml,该功能被描述为必须运行的docker映像:
provider: name: openfaas gateway: http:<font><i>//127.0.0.1:8080</i></font><font> functions: get-books-by-author: lang: dockerfile handler: . image: localhost:5000/get-books-by-author:latest </font>
在此示例中,该映像的前缀localhost:5000/是前一个bash命令启动的本地注册表。
现在,让我们使用的神奇命令faas-cli来部署和运行该函数:
faas-cli build -f function.yml faas-cli push -f function.yml faas-cli deploy -f function.yml
现在通过OpenFaaS网关调用该函数:
curl -X GET http:<font><i>//127.0.0.1:8080/function/get-books-by-author -H 'Content-Type: application/json' -d $'{"name":"Piet"}'</i></font><font> </font>
要验证该功能正在运行:
kubectl -n openfaas-fn get pods
现在,此函数已经有运行的Pod,一旦对端点进行REST调用后,pod将启动应用程序。这是通过 看门狗 完成的 。
资源:
本文中的所有内容都是在以下环境下开发的:
参考文献: