<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          云原生時代的Java應(yīng)用優(yōu)化實踐

          共 9536字,需瀏覽 20分鐘

           ·

          2022-03-19 05:00

          點擊上方“服務(wù)端思維”,選擇“設(shè)為星標(biāo)

          回復(fù)”669“獲取獨(dú)家整理的精選資料集

          回復(fù)”加群“加入全國服務(wù)端高端社群「后端圈」


          作者 | 于善游
          出品?| 騰訊云中間件


          導(dǎo)語


          Java從誕生至今已經(jīng)走過了26年,在這26年的時間里,Java應(yīng)用從未停下腳步,從最開始的單機(jī)版到web應(yīng)用再到現(xiàn)在的微服務(wù)應(yīng)用,依靠其強(qiáng)大的生態(tài),它仍然占據(jù)著當(dāng)今語言之爭的“天下第一”的寶座。但在如今的云原生serverless時代,Java應(yīng)用卻遭遇到了前所未有的挑戰(zhàn)。


          在云原生時代,云原生技術(shù)利用各種公有云、私有云和混合云等新型動態(tài)環(huán)境,構(gòu)建和運(yùn)行可彈性擴(kuò)展的應(yīng)用。而我們應(yīng)用也越來越呈現(xiàn)出以下特點:


          • 基于容器鏡像構(gòu)建


          Java誕生之初,靠著“一次編譯,到處運(yùn)行”的口號,以語言層虛擬化的方式,在那個操作系統(tǒng)平臺尚不統(tǒng)一的年代,建立起了優(yōu)勢。但如今步入云原生時代,以Docker為首的容器技術(shù)同樣提出了“一次構(gòu)建,到處運(yùn)行”的口號,通過操作系統(tǒng)虛擬化的方式,為應(yīng)用程序提供了環(huán)境兼容性和平臺無關(guān)性。因此,在云原生時代的今天,Java“一次編譯,到處運(yùn)行”的優(yōu)勢,已經(jīng)被容器技術(shù)大幅度地削弱,不再是大多數(shù)服務(wù)端開發(fā)者技術(shù)選型的主要考慮因素了。此外,因為是基于鏡像,云原生時代對鏡像大小可以說是十分敏感,而包含了JDK的Java應(yīng)用動輒幾百兆的鏡像大小,無疑是越來越不符合時代的要求。


          • 生命周期縮短,并經(jīng)常需要彈性擴(kuò)縮容


          靈活和彈性可以說是云原生應(yīng)用的一個顯著特性,而這也意味著應(yīng)用需要具備更短的冷啟動時間,以應(yīng)對靈活彈性的要求。Java應(yīng)用往往面向長時間大規(guī)模程序而設(shè)計,JVM的JIT和分層編譯優(yōu)化技術(shù),會使得Java應(yīng)用在不斷的運(yùn)行中進(jìn)行自我優(yōu)化,并在一段時間后達(dá)到性能頂峰。但與運(yùn)行性能相反,Java應(yīng)用往往有著緩慢的啟動時間。流行的框架(例如Spring)中大量的類加載、字節(jié)碼增強(qiáng)和初始化邏輯,更是加重了這一問題。這無疑是與云原生時代的理念是相悖的。


          • 對計算資源用量敏感


          進(jìn)入公有云時代,應(yīng)用往往是按用量付費(fèi),這意味著應(yīng)用所需要的計算資源就變的十分重要。Java應(yīng)用固有的內(nèi)存占用多的劣勢,在云原生時代被放大,相對于其他語言,使用起來變得更加“昂貴”。


          由此可見,在云原生時代,Java應(yīng)用的優(yōu)勢正在不斷被蠶食,而劣勢卻在不斷的被放大。因此,如何讓我們的應(yīng)用更加順應(yīng)時代的發(fā)展,使Java語言能在云原生時代發(fā)揮更大的價值,就成了一個值得探討的話題。為此,筆者將嘗試跳出語言對比的固有思路,為大家從一個更全局的角度,來看看在云原生應(yīng)用發(fā)布的全流程中,我們都能夠做哪些優(yōu)化。


          鏡像構(gòu)建優(yōu)化


          Dockerfile


          從Dockerfile說起是因為它是最基礎(chǔ)的,也是最簡單的優(yōu)化,它可以簡單的加快我們的應(yīng)用構(gòu)建鏡像和拉取鏡像的時間。


          以一個Springboot應(yīng)用為例,我們通常會看到這種樣子的Dockerfile:


          FROM?openjdk:8-jdk-alpineCOPY app.jar /ENTRYPOINT?["java","-jar","/app.jar"]



          足夠簡單清晰,但很顯然,這并不是一個很好的Dockerfile,因為它沒有利用到Image layer去進(jìn)行效率更高的緩存。


          我們都知道,Docker擁有足夠高效的緩存機(jī)制,但如果不好好的應(yīng)用這一特性,而是簡單的將Jar包打成單一layer鏡像,就會導(dǎo)致,即使應(yīng)用只改動一行代碼,我們也需要重新構(gòu)建整個Springboot Jar包,而這其中Spring的龐大依賴類庫其實都沒有發(fā)生過更改,這無疑是一種得不償失的做法。因此,將應(yīng)用的所有依賴庫作為一個單獨(dú)的layer顯然是一個更好的方案。


          因此,一個更合理的Dockerfile應(yīng)該長這個樣子:


          FROM?openjdk:8-jdk-alpineARG DEPENDENCY=target/dependencyCOPY ${DEPENDENCY}/BOOT-INF/lib /app/libCOPY ${DEPENDENCY}/META-INF /app/META-INFCOPY ${DEPENDENCY}/BOOT-INF/classes /appENTRYPOINT?["java","-cp","app:app/lib/*","HelloApplication"]



          這樣,我們就可以充分利用Image layer cache來加快構(gòu)建鏡像和拉取鏡像的時間。


          構(gòu)建組件


          在Docker占有鏡像構(gòu)建的絕對話語權(quán)的今天,我們在實際開發(fā)過程中,往往會忽視構(gòu)建組件的選擇,但事實上,選擇一個高效的構(gòu)建組件,往往能使我們的構(gòu)建效率事半功倍。


          傳統(tǒng)的“docker build”存在哪些問題?


          在Docker v18.06之前的`docker build`會存在一些問題:


          • 改變Dockerfile中的任意一行,就會使之后的所有行的緩存失效

          #?假設(shè)只改變此Dockerfile中的EXPOSE端口號# 那么接下來的RUN命令的緩存就會失效FROM debianEXPOSE 80RUN?apt?update?&&?apt?install?–y?HEAVY-PACKAGES



          • 多階段并行構(gòu)建效率不佳


          # 即使stage0和stage1之間并沒有依賴# docker也無法并行構(gòu)建,而是選擇串行FROM openjdk:8-jdk AS stage0RUN ./gradlew clean build

          FROM openjdk:8-jdk AS stage1RUN ./gradlew clean build

          FROM openjdk:8-jdk-alpineCOPY --from=stage0 /app-0.jar /COPY?--from=stage1?/app-1.jar?/



          • 無法提供編譯歷史緩存

          #?單純的RUN命令無法提供編譯歷史緩存# 而RUN --mount的新語法在舊版本docker下無法支持RUN ./gradlew build# since Docker v18.06# syntax = docker/dockerfile:1.1-experimentalRUN?--mount=type=cache,target=/.cache?./gradlew?build



          • 鏡像push和pull的過程中存在壓縮和解壓的固有耗時

          如上圖所示,在傳統(tǒng)的docker pull push階段,存在著pack和unpack的耗時,而這一部分并非必須的。針對這些固有的弊病,業(yè)界也一直在積極的探討,并誕生了一些可以順應(yīng)新時代的構(gòu)建工具。


          新一代構(gòu)建組件:


          在最佳的新一代構(gòu)建工具選擇上,是一個沒有銀彈的話題,但通過一些簡單的對比,我們?nèi)阅苓x出一個最適合的構(gòu)建工具,我們認(rèn)為,一個適合云原生平臺的構(gòu)建工具應(yīng)該至少具備以下幾個特點:


          • 能夠支持完整的Dockerfile語法,以便應(yīng)用平順遷移;

          • 能夠彌補(bǔ)上述傳統(tǒng)Docker構(gòu)建的缺點;

          • 能夠在非root privilege模式下執(zhí)行(在基于Kubernetes的CICD環(huán)境中顯得尤為重要)。


          因此,Buildkit就脫穎而出,這個由Docker公司開發(fā),目前由社區(qū)和Docker公司合理維護(hù)的“含著金鑰匙出生”的新一代構(gòu)建工具,擁有良好的擴(kuò)展性、極大地提高了構(gòu)建速度,并提供了更好的安全性。Buildkit支持全部的Dockerfile語法,能更高效的命中構(gòu)建緩存,增量的轉(zhuǎn)發(fā)build context,多并發(fā)直接推送鏡像層至鏡像倉庫。

          Buildkit與其他構(gòu)建組件的對比

          Buildkit的構(gòu)建效率


          鏡像大小


          為了在拉取和推送鏡像過程中更高的控制耗時,我們通常會盡可能的減少鏡像的大小。


          Alpine Linux是許多Docker容器首選的基礎(chǔ)鏡像,因為它只有5 MB大小,比起其他Cent OS、Debain 等動輒一百多MB的發(fā)行版來說,更適合用于容器環(huán)境。不過Alpine Linux為了盡量瘦身,默認(rèn)是用musl作為C標(biāo)準(zhǔn)庫的,而非傳統(tǒng)的glibc(GNU C library),因此要以Alpine Linux為基礎(chǔ)制作OpenJDK鏡像,必須先安裝glibc,此時基礎(chǔ)鏡像大約有12 MB。


          在【JEP 386】(http://openjdk.java.net/jeps/386)中,OpenJDK將上游代碼移植到musl,并通過兼容性測試。這一特性已經(jīng)在Java 16中發(fā)布。這樣制作出來的鏡像僅有41MB,不僅遠(yuǎn)低于Cent OS的OpenJDK(大約 396 MB),也要比官方的slim版(約200MB)要小得多。


          應(yīng)用啟動加速


          讓我們首先來看一下,一個Java應(yīng)用在啟動過程中,會有哪些階段。

          這個圖代表了Java運(yùn)行時各個階段的生命周期,可以看到它要經(jīng)過五個階段,首先是VM init虛擬機(jī)的初始化階段,然后是App init應(yīng)用的初始化階段,再經(jīng)過App active(warmup)的應(yīng)用預(yù)熱時期,在預(yù)熱一段時間后進(jìn)入App active(steady)達(dá)到性能巔峰期,最后應(yīng)用結(jié)束完成整個生命周期。


          使用AppCDS

          從上面的圖中,我們不難發(fā)現(xiàn),藍(lán)色的CL(ClassLoad)部分,實際長占用了Java應(yīng)用啟動的階段的一大部分時間。而Java也一直在致力于減少應(yīng)用啟動的ClassLoad時間。


          從JDK 1.5開始,HotSpot就提供了CDS(Class Data Sharing)功能,很長一段時間以來,它的功能都非常有限,并且只有部分商業(yè)化。早期的CDS致力于,在同一主機(jī)上的JVM實例之間“共享”同樣需要加載一次的類,但是遺憾的是早期的CDS不能處理由AppClassloader加載的類,這使得它在實際開發(fā)實踐中,顯得比較“雞肋”。


          但在從OpenJDK 10 (2018) 開始,AppCDS【JEP 310】(https://openjdk.java.net/jeps/310)在CDS的基礎(chǔ)上,加入了對AppClassloader的適配,它的出現(xiàn),使得CDS技術(shù)變得廣泛可用并且更加適用。尤其是對于動輒需要加載數(shù)千個類的Spring Boot程序,因為JVM不需要在每個實例的每次啟動時加載(解析和驗證)這些類,因此,啟動應(yīng)該變得更快并且內(nèi)存占用應(yīng)該更小。看起來,AppCDS的一切都很美好,但實際使用也確實如此嗎?

          當(dāng)我們試圖使用AppCDS時,它應(yīng)該包含以下幾個步驟:


          • 使用`-XX:DumpLoadedClassList`參數(shù)來獲取我們希望在應(yīng)用程序?qū)嵗g共享的類;

          • 使用`-Xshare:dump`參數(shù)將類存儲到適合內(nèi)存映射的存檔(.jsa文件)中;

          • 使用`-Xshare:on`參數(shù)在啟動時將存檔附加到每個應(yīng)用程序?qū)嵗?/p>


          乍一看,使用AppCDS似乎很容易,只需3個簡單的步驟。但是,在實際使用過程中,你會發(fā)現(xiàn)每一步都可能變成一次帶有特定JVM Options的應(yīng)用啟動,我們無法簡單的通過一次啟動來獲得可重復(fù)使用的類加載存檔文件。盡管在JDK 13中,提供了新的動態(tài)CDS【JEP 350】(https://openjdk.java.net/jeps/350),來將上述步驟1和步驟2合并為一步。但在目前流行的JDK 11中,我們?nèi)匀惶硬婚_上述三個步驟(三次啟動)。因此,使用AppCDS往往意味著對應(yīng)用的啟動過程進(jìn)行復(fù)雜的改造,并伴隨著更為漫長的首次編譯和啟動時間。


          同時需要注意的是,在使用AppCDS時,許多應(yīng)用的類路徑將會變得更加混亂:它們既位于原來的位置(JAR包)中,同時又位于新的共享存檔(.jsa文件)中。在我們應(yīng)用開發(fā)的過程中,我們會不斷更改、刪除原來的類,而JVM會從新的類中進(jìn)行解析。這種情況所帶來的危險是顯而易見的:如果類歸檔文件保持不變,那么類不匹配是遲早的事,我們會遇到典型的“Classpath Hell”問題。


          JVM無法阻止類的變化,但它至少應(yīng)該能夠在適當(dāng)?shù)臅r候檢測到類不匹配。然而,在JVM的實現(xiàn)中,并沒有檢測每一個單獨(dú)的類,而是選擇去比較整個類路徑,因此,在AppCDS的官方描述中,我們可以找到這樣一句話:


          The classpath used with -Xshare:dump must be the same as, or be a prefix of, the classpath used with -Xshare:on. Otherwise, the JVM will print an error message


          即第二部步歸檔文件創(chuàng)建時使用的類路徑必須與運(yùn)行時使用的類路徑相同(或前者是后者的前綴)。


          但這是一個相當(dāng)含糊的陳述,因為類路徑可能以幾種不同的方式形成,例如:


          • 從帶有Jar包的目錄中直接加載.class文件,例如`java com.example.Main`;

          • 使用通配符,掃描帶有Jar包的目錄,例如`java -cp mydir/* com.example.Main`;

          • 使用明確的Jar包路徑,例如`java -cp lib1.jar:lib2.jar com.example.Main`。


          在這些方式中,AppCDS唯一支持的方式只有第三種,即是顯式列出Jar包路徑。這使得那些使用了大規(guī)模Jar包依賴的應(yīng)用的啟動語句變得十分繁瑣。


          同時,我們也要必須注意到,這種顯式列出Jar包路徑的方式并不會進(jìn)行遞歸查找,即它只會在包含所有class文件的FatJar中生效。這意味著使用SpringBoot框架的嵌套Jar包結(jié)構(gòu),將很難利用AppCDS技術(shù)所帶來的便利。


          因此,SpringBoot如果想在云原生環(huán)境中使用AppCDS,就必須進(jìn)行應(yīng)用侵入性的改造,不去使用SpringBoot默認(rèn)的嵌套Jar啟動結(jié)構(gòu),而是用類似【maven shade plugin】(https://maven.apache.org/plugins/maven-shade-plugin/)重新打FatJar,并在程序中顯示的聲明能讓程序自然關(guān)閉的接口或參數(shù),通過Volume掛載或者Dockerfile改造的方式,來存儲和加載類的歸檔文件。這里給出一個改造過的Dockerfile的示例:


          # 這里假設(shè)我們已經(jīng)做過FatJar改造,并且Jar包中包含應(yīng)用運(yùn)行所需的全部class文件FROM eclipse-temurin:11-jre as APPCDS

          COPY target/helloworld.jar /helloworld.jar

          # 運(yùn)行應(yīng)用,同時設(shè)置一個'--appcds'參數(shù)使程序在運(yùn)行后能夠停止RUN java -XX:DumpLoadedClassList=classes.lst -jar helloworld.jar --appcds=true

          # 使用上一步得到的class列表來生成類歸檔文件RUN java -Xshare:dump -XX:SharedClassListFile=classes.lst -XX:SharedArchiveFile=appcds.jsa --class-path helloworld.jar

          FROM eclipse-temurin:11-jre

          # 同時復(fù)制Jar包和類歸檔文件COPY --from=APPCDS /helloworld.jar /helloworld.jarCOPY --from=APPCDS /appcds.jsa /appcds.jsa

          # 使用-Xshare:on參數(shù)來啟動應(yīng)用ENTRYPOINT?java?-Xshare:on?-XX:SharedArchiveFile=appcds.jsa?-jar?helloworld.jar



          由此可見,使用AppCDS還是要付出相當(dāng)多的學(xué)習(xí)和改造成本的,并且許多改造都會對我們的應(yīng)用產(chǎn)生入侵。


          JVM優(yōu)化


          除了構(gòu)建階段和啟動階段,我們還可以從JVM本身入手,根據(jù)云原生環(huán)境的特點,進(jìn)行針對性的優(yōu)化。


          使用可以感知容器內(nèi)存資源的JDK


          在虛擬機(jī)和物理機(jī)中,對于 CPU 和內(nèi)存分配,JVM會從常見位置(例如,Linux 中的`/proc/cpuinfo`和`/proc/meminfo`)查找其可以使用的CPU和內(nèi)存。但是,在容器中運(yùn)行時,CPU和內(nèi)存限制條件存儲在`/proc/cgroups/...`中。較舊版本的JDK會繼續(xù)在`/proc`(而不是`/proc/cgroups`)中查找,這可能會導(dǎo)致CPU和內(nèi)存用量超出分配的上限,并因此引發(fā)多種嚴(yán)重的問題:


          • 線程過多,因為線程池大小由`Runtime.availableProcessors()`配置;

          • JVM的對內(nèi)存使用超出容器內(nèi)存上限。并導(dǎo)致容器被OOMKilled。


          JDK 8u131首先實現(xiàn)了`UseCGroupMemoryLimitForHeap`的參數(shù)。但這個參數(shù)存在缺陷,為應(yīng)用添加`UnlockExperimentalVMOptions`和`UseCGroupMemoryLimitForHeap`參數(shù)后,JVM確實可以感知到容器內(nèi)存,并控制應(yīng)用的實際堆大小。但是這并沒有充分利用我們?yōu)槿萜鞣峙涞膬?nèi)存。


          因此JVM提供`-XX:MaxRAMFraction`標(biāo)志來幫助更好的計算堆大小,`MaxRAMFraction`默認(rèn)值是4(即除以4),但它是一個分?jǐn)?shù),而不是一個百分比,因此很難設(shè)置一個能有效利用可用內(nèi)存的值。


          JDK 10附帶了對容器環(huán)境的更好支持。如果在Linux容器中運(yùn)行Java應(yīng)用程序,JVM將使用`UseContainerSupport`選項自動檢測內(nèi)存限制。然后,通過`InitialRAMPercentage`、`MaxRAMPercentage`和`MinRAMPercentage`來進(jìn)行對內(nèi)存控制。這時,我們使用的是百分比而不是分?jǐn)?shù),這將更加準(zhǔn)確。


          默認(rèn)情況下,`UseContainerSupport`參數(shù)是激活的,`MaxRAMPercentage`是25%,`MinRAMPercentage`是50%。


          需要注意的是,這里`MinRAMPercentage`并不是用來設(shè)置堆大小的最小值,而是僅當(dāng)物理服務(wù)器(或容器)中的總可用內(nèi)存小于250MB時,JVM將用此參數(shù)來限制堆的大小。


          同理,`MaxRAMPercentage`是當(dāng)物理服務(wù)器(或容器)中的總可用內(nèi)存大小超過250MB時,JVM將用此參數(shù)來限制堆的大小。


          這幾個參數(shù)已經(jīng)向下移植到JDK 8u191。UseContainerSupport默認(rèn)情況下是激活的。我們可以設(shè)置`-XX:InitialRAMPercentage=50.0 -XX:MaxRAMPercentage=80.0`來JVM感知并充分利用容器的可用內(nèi)存。需要注意的是,在指定`-Xms -Xmx`時,`InitialRAMPercentage`和`MaxRAMPercentage`將會失效。


          關(guān)閉優(yōu)化編譯器


          默認(rèn)情況下,JVM有多個階段的JIT編譯。雖然這些階段可以逐漸提高應(yīng)用的效率,但它們也會增加內(nèi)存使用的開銷,并增加啟動時間。


          對于短期運(yùn)行的云原生應(yīng)用,可以考慮使用以下參數(shù)來關(guān)閉優(yōu)化階段,以犧牲長期運(yùn)行效率來換取更短的啟動時間。


          `JAVA_TOOL_OPTIONS="-XX:+TieredCompilation -XX:TieredStopAtLevel=1"`


          關(guān)閉類驗證


          當(dāng)JVM將類加載到內(nèi)存中以供執(zhí)行時,它會驗證該類未被篡改并且沒有惡意修改或損壞。但在云原生環(huán)境,CI/CD流水線通常也由云原生平臺提供,這表示我們的應(yīng)用的編譯和部署是可信的,因此我們應(yīng)該考慮使用以下參數(shù)關(guān)閉驗證。如果在啟動時加載大量類,則關(guān)閉驗證可能會提高啟動速度。


          `JAVA_TOOL_OPTIONS="-noverify"`


          減小線程棧大小


          大多數(shù)Java Web應(yīng)用都是基于每個連接一個線程的模式。每個Java線程都會消耗本機(jī)內(nèi)存(而不是堆內(nèi)存)。這稱為線程棧,并且每個線程默認(rèn)為1 MB。如果您的應(yīng)用處理100個并發(fā)請求,則它可能至少有100個線程,這相當(dāng)于使用了100MB的線程棧空間。該內(nèi)存不計入堆大小。我們可以使用以下參數(shù)來減小線程棧大小。


          `JAVA_TOOL_OPTIONS="-Xss256k"`


          需要注意如果減小得太多,則將出現(xiàn)`java.lang.StackOverflowError`。您可以對應(yīng)用進(jìn)行分析,并找到要配置的最佳線程棧大小。


          使用TEM進(jìn)行零改造的Java應(yīng)用云原生優(yōu)化


          通過上面的分析,我們可以看出,如果想要讓我們的Java應(yīng)用能在云原生時代發(fā)揮出最大實力,是需要付出許多侵入性的改造和優(yōu)化操作的。那么有沒有一種方式能夠幫助我們零改造的開展Java應(yīng)用云原生優(yōu)化?


          騰訊云的TEM彈性微服務(wù)就為廣大Java開發(fā)者提供了一種應(yīng)用零改造的最佳實踐,幫助您的Java應(yīng)用以最優(yōu)姿態(tài)快速上云。使用TEM您可以享受的以下優(yōu)勢:


          • ?零構(gòu)建部署

          直接選擇使用Jar包/War包交付,無需自行構(gòu)建鏡像。TEM默認(rèn)提供能充分利用構(gòu)建緩存的構(gòu)建流程,使用新一代構(gòu)建利器Buildkit進(jìn)行高速構(gòu)建,構(gòu)建速度優(yōu)化50%以上,并且整個構(gòu)建流程可追溯,構(gòu)建日志可查,簡單高效。

          直接使用Jar包部署

          構(gòu)建日志可查

          構(gòu)建速度對比


          • 零改造加速

          直接使用KONA Jdk 11/Open Jdk 11進(jìn)行應(yīng)用加速,并且默認(rèn)支持SpringBoot應(yīng)用零改造加速。您無需改造原有的SpringBoot嵌套Jar包結(jié)構(gòu),TEM將直接提供Java應(yīng)用加速的最佳實踐,實例擴(kuò)容時的啟動時間將縮短至10%~40%。

          不使用應(yīng)用加速,規(guī)格1c2g

          使用應(yīng)用加速,規(guī)格1c2g

          應(yīng)用啟動速度對比

          以[spring petclinic](https://github.com/spring-projects/spring-petclinic)為例,規(guī)格1c2g


          • 零運(yùn)維監(jiān)控

          使用SkyWalking為您的Java應(yīng)用進(jìn)行應(yīng)用級別的監(jiān)控,您可以直觀的查看JVM堆內(nèi)存,GC次數(shù)/耗時,接口RT/QPS等關(guān)鍵參數(shù),幫助您即使找到應(yīng)用性能瓶頸。

          應(yīng)用JVM監(jiān)控

          • 極致彈性

          TEM默認(rèn)提供使用率較高的定時彈性策略和基于資源的彈性策略,為您的應(yīng)用提供秒級的彈性性能,幫助您應(yīng)對流量洪峰,并能在實例閑置時及時節(jié)省資源。

          指標(biāo)彈性策略

          定時彈性策略



          總結(jié)


          工欲善其事,必先利其器。在步入云原生時代的今天,如何讓您的Java應(yīng)用的部署效率和運(yùn)行性能最大化,這對所有開發(fā)者都是一個挑戰(zhàn)。而TEM作為一款面向微服務(wù)應(yīng)用的Serverless PaaS平臺,將成為您手中的“云端利器”,TEM將致力于為企業(yè)和開發(fā)者服務(wù),幫助您的業(yè)務(wù)以最快速、便捷、省心的姿態(tài),無憂上云,享受云原生時代的便利。



          — 本文結(jié)束 —


          ●?漫談設(shè)計模式在 Spring 框架中的良好實踐

          ●?顛覆微服務(wù)認(rèn)知:深入思考微服務(wù)的七個主流觀點

          ●?人人都是 API 設(shè)計者

          ●?一文講透微服務(wù)下如何保證事務(wù)的一致性

          ●?要黑盒測試微服務(wù)內(nèi)部服務(wù)間調(diào)用,我該如何實現(xiàn)?



          關(guān)注我,回復(fù) 「加群」 加入各種主題討論群。



          對「服務(wù)端思維」有期待,請在文末點個在看

          喜歡這篇文章,歡迎轉(zhuǎn)發(fā)、分享朋友圈


          在看點這里


          瀏覽 55
          點贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  www.日本特黄24小时免费 | 久久久影院 | 超碰自拍网| 夜色福利夜 | 天天爽夜夜 |