Linux中國

優化 Kubernetes 中的 Java 無伺服器函數

由於運行上千個應用程序 容器莢 Pod 所耗費的資源多,令它實現較少工作節點和資源佔用所需成本也較高,所以在使用 Kubernetes 時,快速啟動和較少的內存佔用是至關重要的。在 Kubernetes 平台運行容器化微服務時,內存佔用是比吞吐量更重要的考量因素,這是因為:

  • 由於需要持續運行,所以耗費資源更多(不同於 CPU 佔用)
  • 微服務令開銷成本成倍增加
  • 一個單體應用程序變為若干個微服務的情況(例如 20 個微服務佔用的存儲空間約有 20GB)

這些情況極大影響了無伺服器函數的發展和 Java 部署模型。到目前為止,許多企業開發人員選擇 Go、Python 或 Node.js 這些替代方案來解決性能瓶頸,直到出現了 Quarkus 這種基於 kubernetes 的原生 Java 堆棧,才有所改觀。本文介紹如何在使用了 Quarkus 的 kubernetes 平台上進行性能優化,以便運行無伺服器函數。

容器優先的設計理念

由於 Java 生態系統中傳統的框架都要進行框架的初始化,包括配置文件的處理、classpath 的掃描、類載入、註解的處理以及構建元模型,這些過程都是必不可少的,所以它們都比較耗費資源。如果使用了幾種不同的框架,所耗費的資源也是成倍增加。

Quarkus 通過「 左移 shifting left 」,把所有的資源開銷大的操作都轉移到構建階段,解決了這些 Java 性能問題。在構建階段進行代碼和框架分析、位元組碼轉換和動態元模型生成,而且只有一次,結果是:運行時可執行文件經過高度優化,啟動非常快,不需要經過那些傳統的啟動過程,全過程只在構建階段執行一次。

![Quarkus Build phase](/data/attachment/album/202210/26/151634r3l3gzbp27bkke0f.png "Quarkus Build phase")

更重要的是:Quarkus 支持構建原生可執行文件,它具有良好性能,包括快速啟動和極小的 駐留集大小 resident set size (RSS)內存佔用,跟傳統的雲原生 Java 棧相比,具備即時擴展的能力和高密度的內存利用。

![Quarkus RSS and Boot Time Metrics](/data/attachment/album/202210/26/151635p95d33596ilju4rd.png "Quarkus RSS and Boot Time Metrics")

這裡有個例子,展示如何使用 Quarkus 將一個 Java 無伺服器 項目構建為本地可執行文件。

1、使用 Quarkus 創建無伺服器 Maven 項目

以下命令生成一個 Quarkus 項目,(例如 quarkus-serverless-native)以此創建一個簡單的函數:

$ mvn io.quarkus:quarkus-maven-plugin:1.13.4.Final:create 
       -DprojectGroupId=org.acme 
       -DprojectArtifactId=quarkus-serverless-native 
       -DclassName="org.acme.getting.started.GreetingResource"

2、構建一個本地可執行文件

你需要使用 GraalVM 為 Java 程序構建一個本地可執行文件。你可以選擇 GraalVM 的任何發行版,例如 Oracle GraalVM Community Edition (CE)Mandrel(Oracle GraalVM CE 的下游發行版)。Mandrel 是為支持 OpenJDK 11 上的 Quarkus-native 可執行文件的構建而設計的。

打開 pom.xml,你將發現其中的 native 設置。你將使用它來構建本地可執行文件。

<profiles>
    <profile>
        <id>native</id>
        <properties>
            <quarkus.package.type>native</quarkus.package.type>
        </properties>
    </profile>
</profiles>

注意: 你可以在本地安裝 GraalVM 或 Mandrel 發行版。你也可以下載 Mandrel 容器映像來構建它(像我那樣),因此你還需要在本地運行一個容器引擎(例如 Docker)。

假設你已經打開了容器運行時,此時需要運行一下 Maven 命令:

使用 Docker 作為容器引擎:

$ ./mvnw package -Pnative 
  -Dquarkus.native.container-build=true 
  -Dquarkus.native.container-runtime=docker

使用 Podman 作為容器引擎:

$ ./mvnw package -Pnative 
  -Dquarkus.native.container-build=true 
  -Dquarkus.native.container-runtime=podman

輸出信息結尾應當是 BUILD SUCCESS

![Native Build Logs](/data/attachment/album/202210/26/151635iuy2m9l5zul5zu5i.png "Native Build Logs")

不藉助 JVM 直接運行本地可執行文件:

$ target/quarkus-serverless-native-1.0.0-SNAPSHOT-runner

輸出信息類似於:

__  ____  __  _____   ___  __ ____  ______
 --/ __ / / / / _ | / _ / //_/ / / / __/
 -/ /_/ / /_/ / __ |/ , _/ ,< / /_/ /   
--________/_/ |_/_/|_/_/|_|____/___/  
INFO  [io.quarkus] (main) quarkus-serverless-native 1.0.0-SNAPSHOT native
(powered by Quarkus xx.xx.xx.) Started in 0.019s. Listening on: http://0.0.0.0:8080
INFO [io.quarkus] (main) Profile prod activated.
INFO [io.quarkus] (main) Installed features: [cdi, kubernetes, resteasy]

簡直是超音速!啟動只花了 19 毫秒。你的運行時間可能稍有不同。

使用 Linux 的 ps 工具檢測一下,結果內存佔用還是很低。檢測的方法是:在應用程序運行期間,另外打開一個終端,運行如下命令:

$ ps -o pid,rss,command -p $(pgrep -f runner)

輸出結果類似於:

  PID    RSS COMMAND
10246  11360 target/quarkus-serverless-native-1.0.0-SNAPSHOT-runner

該進程只佔 11MB 內存。非常小!

注意: 各種應用程序(包括 Quarkus)的駐留集大小和內存佔用,都因運行環境而異,並隨著應用程序載入而上升。

你也可以使用 REST API 訪問這個函數。輸出結果應該是 Hello RESTEasy:

$ curl localhost:8080/hello
Hello RESTEasy

3、把函數部署到 Knative 服務

如果你還沒有創建命名空間,現在就在 OKD(OpenShift Kubernetes 發行版)創建一個命名空間(例如 quarkus-serverless-native),進而把這個本地可執行文件部署為無伺服器函數。然後添加 quarkus-openshift 擴展:

$ ./mvnw -q quarkus:add-extension -Dextensions="openshift"

src/main/resources/application.properties 文件中添加以下內容,配置 Knative 和 Kubernetes 的相關資源:

quarkus.container-image.group=quarkus-serverless-native
quarkus.container-image.registry=image-registry.openshift-image-registry.svc:5000
quarkus.native.container-build=true
quarkus.kubernetes-client.trust-certs=true
quarkus.kubernetes.deployment-target=knative
quarkus.kubernetes.deploy=true
quarkus.openshift.build-strategy=docker

構建本地可執行文件,並把它直接部署到 OKD 集群:

$ ./mvnw clean package -Pnative

注意: 提前使用 oc login 命令,確保登錄的是正確的項目(例如 quarkus-serverless-native)。

輸出信息結尾應當是 BUILD SUCCESS。完成一個本地二進位文件的構建並部署為 Knative 服務需要花費幾分鐘。成功創建服務後,使用 kubectloc 命令工具,可以查看 Knative 服務和版本信息:

$ kubectl get ksvc
NAME                        URL   [...]
quarkus-serverless-native   http://quarkus-serverless-native-[...].SUBDOMAIN  True

$ kubectl get rev
NAME                              CONFIG NAME                 K8S SERVICE NAME                  GENERATION   READY   REASON
quarkus-serverless-native-00001   quarkus-serverless-native   quarkus-serverless-native-00001   1            True

4、訪問本地可執行函數

運行 kubectl 命令,搜索無伺服器函數的節點:

$ kubectl get rt/quarkus-serverless-native

輸出信息類似於:

NAME                         URL                                                                                                          READY   REASON
quarkus-serverless-native   http://quarkus-serverless-restapi-quarkus-serverless-native.SUBDOMAIN   True

curl 命令訪問上述信息中的 URL 欄位:

$ curl http://quarkus-serverless-restapi-quarkus-serverless-native.SUBDOMAIN/hello

過了不超過一秒鐘,你也會得到跟本地操作一樣的結果:

Hello RESTEasy

當你在 OKD 群集中訪問 Quarkus 運行中的節點的日誌,你會發現本地可執行文件正在以 Knative 服務的形式運行。

![Native Quarkus Log](/data/attachment/album/202210/26/151635hrov9o2fwvfwlrwl.png "Native Quarkus Log")

下一步呢?

你可以藉助 GraalVM 發行版優化 Java 無伺服器函數,從而在 Knative 中使用 Kubernetes 將它們部署為無伺服器函數。Quarkus 支持在普通的微服務中使用簡易配置進行性能優化。

本系列的下一篇文章將指導你在不更改代碼的情況下跨多個無伺服器平台實現可移植函數。

(Daniel Oh, CC BY-SA 4.0)

via: https://opensource.com/article/21/6/java-serverless-functions-kubernetes

作者:Daniel Oh 選題:lujun9972 譯者:cool-summer-021 校對:wxy

本文由 LCTT 原創編譯,Linux中國 榮譽推出


本文轉載來自 Linux 中國: https://github.com/Linux-CN/archive

對這篇文章感覺如何?

太棒了
0
不錯
0
愛死了
0
不太好
0
感覺很糟
0
雨落清風。心向陽

    You may also like

    Leave a reply

    您的郵箱地址不會被公開。 必填項已用 * 標註

    此站點使用Akismet來減少垃圾評論。了解我們如何處理您的評論數據

    More in:Linux中國