Java微服務:用Spark替代SpringBoot才是正確的方式 - Christian Lusardi

banq發表於2019-02-21

一個真正的微服務是一個非常輕薄的程式,只有一個函式具有自己的資料庫(如果有必要)和非常小的記憶體佔用......在Java中可能嗎?

問題
我已經使用Spring Framework多年了,現在和我的團隊一起開始質疑它,特別是Spring Boot:它是開發微服務的正確選擇嗎?不,因為根據我們的經驗,它太耗費記憶體了。
我發現在Spring Boot上執行的基本Java應用程式需要至少1GB的RAM才能執行,而且在開發中介軟體應用程式時也沒問題,但在微服務架構中這非常糟糕!
我們注意到部署在CloudFoundry上的Spring Boot應用程式或帶有k8s的OpenShift遭遇記憶體不足錯誤並且如果它們未設定為最小1GB則會崩潰。

我們正在尋找一種新工具來幫助我們使用這個技術規範開發真正的微服務:

  • 符合Java標準
  • 輕量級
  • 沒有無用的庫
  • 記憶體佔用少
  • 快速服務請求

正確的框架
下面是pom.xml的一小段摘錄

<dependencies>

    <!-- Spark dependencies (the core) -->
    <dependency>
        <groupId>com.sparkjava</groupId>
        <artifactId>spark-core</artifactId>
        <version>2.8.0</version>
    </dependency>

    <!-- Logback version (I hope you want to log!) -->
    <dependency>
        <groupId>ch.qos.logback</groupId>
        <artifactId>logback-classic</artifactId>
        <version>1.2.3</version>
    </dependency>


那麼,現在我們正確定義Docker檔案......

FROM openjdk:8-jre-alpine

LABEL maintainer="" \
      name="my-microservice" \
      description="my description" \
      myGroupId.myArtifactId="0.0.1-SNAPSHOT"

ARG JAR_NAME="service-name-version.jar"
ENV HTTP_PORT=4567 Default Spark port 
EXPOSE ${HTTP_PORT}
WORKDIR /usr/src/app


我們選擇了“ openjdk:8-jre-alpine ”,因為這個起始映象在記憶體和大小方面都是更小,更輕的。如果你想提高效能,你可以選擇Java 11 ...但是目前,不幸的是,可能不存在更小的映象,Java12釋出時,你可以在將來使用“ openjdk:12-jre-alpine ”。(您可以在此處檢視完整列表:https://hub.docker.com/_/openjdk/)。

結果
首先,Jar包大小:只有10MB的Jar!太棒了!使用SpringBoot,我們總是達到至少30MB ......不是那麼糟糕!

  • 啟動時間(開發):使用我們的MCU庫(這裡查詢資訊)和Spark的啟動時間非常簡約。你可以在1分鐘內完成“hello-world”GET方法......
  • 啟動時間:我們習慣等待將近30-40秒......現在我們的等待時間不到1秒。
  • 程式碼行:在微服務架構中,您應該建立一個非常小的程式,具有極簡主義配置,依賴性和僅一個功能......在這些前提下,我們假設程式碼行應該很少。在Spring Boot中,這並不總是正確的,因為框架往往是羅嗦的。使用Spark,LOC數量非常低。
  • 記憶體佔用:你可能知道Java是記憶體貪婪,但透過正確的配置和最佳化,你可以達到一個很好的目標!在帶有Spring Boot的Docker容器中,我們很沮喪,因為很難獲得低於500MB的RAM ......現在我們保持大約30~60MB的RAM。
  • 可維護性:簡單就是更好!微服務的目標之一是將主要問題領域切分成n個問題。沒有比較難的配置,沒有依賴關係,而且程式碼很小,可維護性非常簡單。
  • 可靠性:我們的壓力測試沒有任何問題......該框架非常強大且具有彈性。


基準測試

們建立了兩種型別的基準:

  • Hello World - 在JSON響應中序列化的簡單“hello world”訊息
  • 計算任務 - 具有JSON反序列化,ETL作業和物件序列化響應的中等複雜度級別計算任務

我們已經實現了這兩種基準型別:
  • 使用Undertow Application Server進行Spring Boot
  • Spring Boot Webflux
  • VertX
  • SparkJava

結果如下:
有框架都是差不多的,但隨著當代使用者數量的增加,Spark開始受到影響。那麼,關注點是記憶體佔用而不僅僅是吞吐量。
  • 使用此基準測試的Spark記憶體佔用無關緊要:60 MB的堆大小和35 MB的平均使用率,沒有任何型別的微調。

對於其他框架,堆大小是非常大,例如使用Spring Boot,我們有大約290-300 MB的堆(受-xmx JVM引數限制)
實際使用率約為100-150MB,比Spark重4-5倍。

結論
如果你必須做一個簡單的微服務,正確的選擇是Spark,因為:

  • 它真的很輕
  • 啟動時間太快了
  • 沒有任何無用的類/庫
  • 最後的罐子重量非常輕

現在,您只關注開發和可擴充套件性,將其留給Docker和Kubernetes而不考慮記憶體。
例如:2個Spark容器使用70MB或更少的記憶體,並且比1個Spring Boot容器提供更多的請求處理。

​​​​​​​我想強調並感謝我所有團隊的合作,特別是Luca Pompei是一位出色的團隊領導和開發人員。

相關文章