使用 Micronaut和OpenFaaS 構建無伺服器Java 應用程式 - openvalue

banq發表於2020-06-23

在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函式。

 
package bookstore.service.store;

    import io.Micronaut.http.annotation.Controller;
    import io.Micronaut.http.annotation.Get;
    import io.Micronaut.http.annotation.PathVariable;

    @Controller("books")
    public class BookstoreController {

        @Get("/{author}")
        public Book retrieveBooksByAuthor() {
            return new Book("1000 new things", "John Doe");
        }

    }


這看起來很像Spring Controller,對嗎?除了使用Micronaut軟體包中的註釋外。
這裡引人注目的是BookDTO 的實現:

 
@Introspected
    public class Book implements Serializable {

        private String title;
        private String author;

        public Book(String title, String author) {
            this.title  = title;
            this.author = author;
        }

        // some getters
    }

@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="java -Dcom.sun.management.jmxremote -noverify -XX:TieredStopAtLevel=1 -XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap -jar Handler.jar"


-noverify和-XX:+UseCGroupMemoryLimitForHeapJDK 13中已棄用,因此不需要。程式碼行將變為:

ENV fprocess="java -Dcom.sun.management.jmxremote -XX:TieredStopAtLevel=1 -XX:+UnlockExperimentalVMOptions -jar Handler.jar"


接下來,我們需要新增log4j2.xml作為log4日誌記錄的配置。
此外,還必須為jar中的日誌新增以下內容:

   <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
        <mainClass>${exec.mainClass}</mainClass>
        <manifestEntries>
            <Multi-Release>true</Multi-Release>
        </manifestEntries>
    </transformer>


現在,為方便起見,僅透過在Dockerfile中進一步更改fprocess命令,將日誌記錄級別設定為ERROR:

ENV fprocess="java -Dorg.apache.logging.log4j.simplelog.StatusLogger.level=ERROR -Dcom.sun.management.jmxremote -XX:TieredStopAtLevel=1 -XX:+UnlockExperimentalVMOptions -jar Handler.jar"


為了使函式儘可能簡單,函式類不會擴充套件 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://dl.get-arkade.dev/ | sudo sh


現在,您終於可以在本地Kubernetes叢集上安裝OpenFaaS了:

arkade install openfaas


現在的訣竅是不要忽略安裝中出現的所有日誌記錄行,那裡有一些有用的說明可以幫助您完成安裝。首先要檢查所有部署是否都成功:

 kubectl -n openfaas get deployments -l "release=openfaas, app=openfaas"


成功的部署應該是:

 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="{.data.basic-auth-password}" | base64 --decode; echo)
    echo -n $PASSWORD | faas-cli login --username admin --password-stdin
                

OpenFaaS現在應該已經啟動並執行!

部署Micronaut函式:在OpenFaaS上測試功能:OpenFaaS需要登錄檔來推送和部署功能。對於本地開發,可以在docker容器中啟動登錄檔:

 sudo docker run -d -p 5000:5000 --name registry registry:2


在提供者描述(僅指定閘道器的端點)之後, 更仔細地看看function.yml,該功能被描述為必須執行的docker映像:

    provider:
        name: openfaas
        gateway: http://127.0.0.1:8080
    functions:
        get-books-by-author:
            lang: dockerfile
            handler: .
            image: localhost:5000/get-books-by-author:latest


在此示例中,該映像的字首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://127.0.0.1:8080/function/get-books-by-author -H 'Content-Type: application/json' -d $'{"name":"Piet"}'


要驗證該功能正在執行:

kubectl -n openfaas-fn get pods


現在,此函式已經有執行的Pod,一旦對端點進行REST呼叫後,pod將啟動應用程式。這是透過看門狗完成的 。

資源:
本文中的所有內容都是在以下環境下開發的:
  • Mac OSX Catalina
  • Docker桌面(Engine v.19.03.5,Kubernetes v1.15.5)
  • OpenJDK的13.0.2

參考文獻:



 

相關文章