Java 應用壓測效能問題定位經驗分享

阿里巴巴雲原生 發表於 2022-06-23
Java

作者:凡勇

什麼是壓測

壓測,即壓力測試,是確立系統穩定性的一種測試方法,通常在系統正常運作範圍之外進行,以考察其功能極限和和可能存在的隱患。

壓測主要用於檢測伺服器的承受能力,包括使用者承受能力,即多少使用者同時使用系統時基本不影響質量、流量承受等。另外,通過諸如疲勞測試還能發現系統一些穩定性的問題,比如是否存在連線池中的連線被耗盡,記憶體被耗盡,執行緒池被耗盡,這些只能通過疲勞測試來進行發現定位。

為什麼要壓測

壓測的目的就是通過模擬真實使用者的行為,測算出機器的效能(單臺機器的 QPS、TPS),從而推算出系統在承受指定使用者數(100 W)時,需要多少機器能支撐得住。因此在進行壓測時一定要事先設定壓測目標值,這個值不能太小,也不能太大,按照目前業務預估的增長量來做一個合理的評估。壓測是在上線前為了應對未來可能達到的使用者數量的一次預估(提前演練),壓測以後通過優化程式的效能或準備充足的機器,來保證使用者的體驗。壓測還能探測應用系統在出現交易洪峰時穩定性情況,以及可能出現的一些問題,發現應用系統薄弱一環,從而更有針對性地進行加強。

壓測分類

 title=

這幾種測試可以穿插進行,一般會在壓力測試效能指標達標後,再安排耐久性測試。

壓測名詞解釋

 title=

常見的壓測工具

ab

ApacheBench 是 Apache 伺服器自帶的一個 web 壓力測試工具,簡稱 ab。ab 又是一個命令列工具,對發起負載的本機要求很低,根據 ab 命令可以建立很多的併發訪問執行緒,模擬多個訪問者同時對某一 URL 地址進行訪問,因此可以用來測試目標伺服器的負載壓力。總的來說 ab 工具小巧簡單,上手學習較快,可以提供需要的基本效能指標,但是沒有圖形化結果,不能監控。

Jmeter

Apache JMeter 是 Apache 組織開發的基於 Java 的壓力測試工具。用於對軟體做壓力測試,它最初被設計用於 Web 應用測試,但後來擴充套件到其他測試領域。

JMeter 能夠對應用程式做功能/迴歸測試,通過建立帶有斷言的指令碼來驗證你的程式返回了你期望的結果。

JMeter 的功能過於強大,這裡暫時不介紹用法,可以查詢相關文件使用(參考文獻中有推薦的教程文件)

LoadRunner

LoadRunner 是 HP(Mercury)公司出品的一個效能測試工具,功能非常強大,很多企業級客戶都在使用,具體請參考官網連結。

阿里雲PTS

效能測試 PTS(Performance Testing Service)是一款效能測試工具。支援按需發起壓測任務,可提供百萬併發、千萬 TPS 流量發起能力,100% 相容 JMeter。提供的場景編排、API 除錯、流量定製、流量錄製等功能,可快速建立業務壓測指令碼,精準模擬不同量級使用者訪問業務系統,幫助業務快速提升系統效能和穩定性。

作為阿里內部使用多年的效能測試工具,PTS 具備如下特性:

  1. 免運維、開箱即用。SaaS化施壓、最大支援百萬級併發、千萬級TPS流量自助發起能力。
  2. 支援多協議HTTP1.1/HTTP2/JDBC/MQTT/Kafka/RokectMq/Redis/Websocket/RMTP/HLS/TCP/UDP/SpringCloud/Dubbo/Grpc 等主流協議。
  3. 支援流量定製。全球施壓地域定製/運營商流量定製/IPv6 流量定製。
  4. 穩定、安全。阿里自研引擎、多年雙十一場景打磨、支援 VPC 網路壓測。
  5. 效能壓測一站式解決方案。** 0 編碼構建複雜壓測場景,覆蓋壓測場景構建、壓測模型設定、發起壓力、分析定位問題、出壓測報告完整的壓測生命週期。
  6. 100% 相容開源 JMeter。
  7. 提供安全、無侵入的生產環境寫壓測解決方案。

壓測工具的比較

 title=

如何選擇壓測工具

這個世界上沒有最好的工具,只有最適合的工具,工具千千萬,選擇一款適合你的才是最重要的,在實際使用中有各種場景,讀者可以結合壓測步驟來確定適合自己的工具:

  1. 確定效能壓測目標:效能壓測目標可能源於專案計劃、業務方需求等
  2. 確定效能壓測環境:為了儘可能發揮效能壓測作用,效能壓測環境應當儘可能同線上環境一致
  3. 確定效能壓測通過標準:針對效能壓測目標以及選取的效能壓測環境,制定效能壓測通過標準,對於不同於線上環境的效能壓測環境,通過標準也應當適度放寬
  4. 設計效能壓測:編排壓測鏈路,構造效能壓測資料,儘可能模擬真實的請求鏈路以及請求負載
  5. 執行效能壓測:藉助效能壓測工具,按照設計執行效能壓測
  6. 分析效能壓測結果報告:分析解讀效能壓測結果報告,判定效能壓測是否達到預期目標,若不滿足,要基於效能壓測結果報告分析原因

由上述步驟可知,一次成功的效能壓測涉及到多個環節,從場景設計到施壓再到分析,缺一不可。工欲善其事,必先利其器,而一款合適的效能工具意味著我們能夠在儘可能短的時間內完成一次合理的效能壓測,達到事半功倍的效果。

JAVA 應用效能問題排查指南

問題分類

問題形形色色,各種各樣的問題都會有。對其進行抽象和分類是非常必要的。這裡將從兩個維度來對效能問題進行分類。第一個維度是資源維度,第二個維度是頻率維度。

資源維度類的問題:CPU 衝高,記憶體使用不當,網路過載。

頻率維度類的問題:交易持續性緩慢,交易偶發性緩慢。

對於每一類問題都有相應的解決辦法,方法或者工具使用不當,會導致不能快速而且精準地排查定位問題。

壓測效能問題定位調優是一門需要多方面綜合能力結合的一種技術工作,需要憑藉個人的技術能力、經驗、有時候還需要一些直覺和靈感,還需要一定的溝通能力,因為有時候問題並不是由定位問題的人發現的,所以需要通過不斷地溝通來發現一些蛛絲馬跡。涉及的技術知識面遠不僅限於程式語言本身,還可能需要紮實的技術基本功,比如作業系統原理、網路、編譯原理、JVM 等知識,決不只是簡單的瞭解,而是真正的掌握,比如 TCP/IP,必須得深入掌握。JVM 得深入掌握記憶體組成,記憶體模型,深入掌握 GC 的一些演算法等。這也是一些初中級技術人員在一遇到效能問題就傻眼,完全不知道如何從哪裡下手。如果擁有紮實的技術基本功,再加上一些實戰經驗然後形成一套屬於自己的打法,在遇到問題後才能心中不亂,快速撥開迷霧,最終找到問題的癥結。

本文筆者還帶來了實際工作中定位和排查出來的一些典型的效能問題的案例,每個案例都會介紹問題發生的相關背景,一線人員提供的問題現象和初步排查定位結論,且在筆者介入後看到的問題現象,再配合一些常用的問題定位工具,介紹發現和定位問題的整個過程,問題發生的根本原因等。

分析思路框架

遇到一個效能問題,首先要從各種表象和一些簡單工具將問題進行定義和分類,然後再做進一步的定位分析,可以參考一下圖 1 作者總結出來的一個決策圖,這張圖是筆者從近幾個金融行業 ToB 專案中做效能定位調優過程的一個總結提練,不一定適合所有的問題,但至少覆蓋到了近幾個專案中遇到的效能問題的排查過程。在接下來的大篇幅中將對每一類問題進行展開,並附上一些真實的經典案例,這些案例都是真真實實發生的,有一定的代表性,且很多都是客戶定位了很長時間都沒發現問題根本原因的問題。其中 GC 類問題在此文不做過多分析,對於 GC 這一類問題後續有空寫一篇專門的文章來進行展開。

 title=

記憶體溢位

記憶體溢位問題按照問題發生頻率又可進一步分為堆記憶體溢位、棧記憶體溢位、Metaspace 記憶體溢位以及 Native 記憶體溢位,下面對每種溢位情況進行詳細分析。

  • 堆記憶體溢位

相信這類問題大家多多少少都接觸過,問題發生的根本原因就是應用申請的堆記憶體超過了 Xmx 引數設定的值,進而導致 JVM 基本處於一個不可用的狀態。如圖 2 所示,示例程式碼模擬了堆記憶體溢位,執行時設定堆大小為 1MB,執行後結果如圖3所示,丟擲了一個 OutOfMemoryError 的錯誤異常,相應的 Message 是 Java heap space,代表溢位的部分是堆記憶體。

  • 棧記憶體溢位

這類問題主要是由於方法呼叫深度太深,或者不正確的遞迴方法呼叫,又或者是 Xss 引數設定不當都會引發這個問題,如圖 4 所示,一個簡單的無限遞迴呼叫就會引發棧記憶體溢位,出錯結果如圖5所示,將會拋一個 StackOverflowError 的錯誤異常。Xss 引數可以設定每個執行緒棧記憶體最大大小,JDK8 的預設大小為 1MB,正常情況下一般不需要去修改該引數,如果遇到 StackOverflowError 的報錯,那麼就需要留意了,需要查證是程式的問題還是引數設定的問題,如果確實是方法呼叫深度很深,預設的 1MB 不夠用,那麼就需要調高 Xss 引數。

  • Native記憶體溢位

這種溢位發生在 JVM 使用堆外記憶體時,且超過一個程式所支援的最大的記憶體上限,或者堆外記憶體超過 MaxDirectMemorySize 引數指定的值時即會引發 Native 記憶體溢位。如圖 6 所示,需要配置 MaxDirectMemorySize 引數,如果不配置這個引數估計很難模擬出這個問題,作者的機器的 64 位的機器,堆外記憶體的大小可想而知了。執行該程式得到的執行結果如圖 7 所示,丟擲來的異常也是 OutOfMemoryError,這個跟堆記憶體異常類似,但是 Message 是 Direct buffer memory,這個跟堆記憶體溢位的 Message 是不一樣的,請特別留意這條 Message,這對精準定位問題是非常重要的。

  • Metaspace記憶體溢位

Metaspace 是在 JDK8 中才出現的,之前的版本中都叫 Perm 空間,大概用途都相差不大。模擬 Metaspace 溢位的方式很簡單,如圖 8 所示通過 cglib 不斷動態建立類並載入到 JVM,這些類資訊就是儲存在 Metaspace 記憶體裡面的,在這裡為了快速模擬出問題,將 MaxMetaspaceSize 設定為 10MB。執行結果如圖 9 所示,依然是丟擲 OutOfMemoryError 的錯誤異常,但是 Message 變成了 Metaspace。

JVM 的記憶體溢位最常見的就這四種,如果能知道每一種記憶體溢位出現的原因,那麼就能快速而精準地進行定位。下面對一些遇到的真實的經典案例進行分析。

  • 案例:堆外記憶體溢位

這種問題也比較好查,前提是在堆記憶體發生溢位時必須自動轉儲堆記憶體到檔案中,如果壓測過程中通過 kill -3 或者 jmap 命令觸發堆記憶體轉儲。然後通過一些堆記憶體分析工具比如 IBM 的 Heap Analyzer 等工具找出是哪種物件佔用記憶體最多,最終可以把問題原因揪出來。

如果需要在發生 OOM 時自動轉儲堆記憶體,那麼需要在啟動引數中加入如下引數:

-XX:+HeapDumpOnOutOfMemoryError  

-XX:HeapDumpPath=/usr/local/oom

如果需要手工獲取執行緒轉儲或者記憶體轉儲,那麼請使用 kill -3 命令,或者使用 jstack 和 jmap 命令。

jstack -l pid > stackinfo,這條命令可以把執行緒資訊轉儲到文字檔案,把檔案下載到本地然後用諸如 IBM Core file analyze 工具進行分析。

jmap -dump:format=b,file=./jmap.hprof pid,這條命令可以把堆記憶體資訊到當前目錄的 jmap.hprof 檔案中,下載到本地,然後用諸如 IBM Heap Analyze 等堆記憶體分析工具進行分析,根據二八定律,找準最耗記憶體的物件就可以解決 80% 的問題。

圖 10 就是一個真實發生的案例,該問題的發生現象是這樣的,壓測開始後,前十分鐘一切正常,但是在經歷大約十分鐘後,TPS 逐漸下降,直到後面客戶端的 TCP 連線都建不上去,客戶一度認為是服務端Linux的網路棧的引數設定有問題,導致 TCP 無法建連,給出的證據是,服務端存在大量的 TIME_WAIT 狀態的連線,然後要求調整Linux核心網路引數,減少 TIME_WAIT 狀態的連線數。什麼是 TIME_WAIT?在這個時候就不得不祭出祖傳 TCP 狀態機的那張圖了,如圖 11 所示。對照這個圖就能知道 TIME_WAIT 的來朧去脈了,TIME_WAIT 主要出現在主動關閉連線方,當然了,如果雙方剛好同時關閉連線的時候,那麼雙方都會出現 TIME_WAIT 狀態。在進行關閉連線四路握手協議時,最後的 ACK 是由主動關閉端發出的,如果這個最終的 ACK 丟失,伺服器將重發最終的 FIN,因此客戶端必須維護狀態資訊以允許它重發最終的 ACK。如果不維持這個狀態資訊,那麼客戶端將響應 RST 分節,伺服器將此分節解釋成一個錯誤(在 java 中會丟擲 connection reset的SocketException)。因而,要實現 TCP 全雙工連線的正常終止,必須處理終止序列四個分節中任何一個分節的丟失情況,主動關閉的客戶端必須維持狀態資訊進入 TIME_WAIT 狀態。

 title=

圖 10 真實堆記憶體溢位案例一

 title=

圖 11 TCP 狀態機

順著客戶提供的這些資訊,查了一下壓測客戶端,採用的是 HTTP 協議,keep-alive 為開,而且採用的是連線池的方式與服務端進行互動,理論上在伺服器端不應該出現如此之多的 TIME_WAIT 連線,猜測一種可能性是由於客戶側剛開始壓測的時候 TPS 比較高,佔用連線數多,後續效能下來後,連線數空閒且來不及跟服務端進行保活處理,導致連線被服務端給主動關閉掉了,但這也僅限於是猜測了。

為了更精準地定位問題,決定去一線現場看下情況,在 TPS 嚴重往下掉的時候,通過 top、vmstat 等命令進行初步探測,發現 cpu 佔比並不十分高,大約 70% 左右。但是 JVM 佔用的記憶體已經快接近 Xmx 引數配置的值了,然後用 jstat -gcutil -h10 pid 5s 100 命令看一下 GC 情況,不查不知道一查嚇一跳,如圖 12 所示,初看這就是一份不太正常的 GC 資料,首先老年代佔比直逼 100%,然後 5 秒內居然進行了 7 次 FullGC,eden 區佔比 100%,因為老年代已經滿了,年輕代的 GC 都已經停滯了,這明顯不正常,趁 JVM 還活著,趕緊執行 jmap -dump:format=b,file=./jmap.hprof pid,把整個堆檔案快照拿下來,整整 5 個 G。取下來後通過 IBM 的 HeapAnalyzer 工具分析堆檔案,結果如圖 10 所示,經過一番查詢,發現某個物件佔位元別大,佔比達 98%,繼續追蹤持有物件,最終定位出問題,申請了某個資源,但是一直沒有釋放,修改後問題得到完美解決,後續再經過長達 8 個小時的耐久性測,沒能再發現問題,TPS 一直非常穩定。

 title=

圖 12 GC 情況統計分析

再來看看為何會出現那麼多的 TIME_WAIT 連線,跟開始的猜測是一致的,由於大量的閒置連線被服務端主動關閉掉,所以才會出現那麼多的 TIME_WAIT 狀態的連線。

CPU高

  • 案例

某金融銀行客戶在壓測過程中發現一個問題,導致 TPS 極低,交易響應時長甚至接近驚人的 30S,嚴重不達票,服務響應時間如圖 23 所示,這是應用打的 tracer log,顯示的耗時很不樂觀。應用採用 SOFA 構建,部署在專有云容器上面,容器規格為 4C8G,使用 OceanBase 資料庫。交易緩慢過程中客戶在相應容器裡面用 top、vmstat 命令獲取 OS 資訊,發現記憶體使用正常,但是 CPU 接近 100%,通過 jstack 命令取執行緒轉儲檔案,如圖 22 所示,客戶發現大量的執行緒都卡在了獲取資料庫連線上面,再上應用日誌中也報了大量的獲取 DB 連線失敗的錯誤日誌,這讓客戶以為是連線池中的連線數不夠,所以不斷繼續加大 MaxActive 這個引數,DB 連線池使用的是 Druid,在加大引數後,效能沒有任何改善,且獲取不到連線的問題依舊。客戶在排查該問題大概兩週且沒有任何實質性進展後,開始向阿里 GTS 的同學求助。

筆者剛好在客戶現場,介入該效能問題的定位工作。跟客戶一番溝通,並查閱了了歷史定位資訊記錄後,根據以往的經驗,這個問題肯定不是由於連線池中的最大連線數不夠的原因導致的,因為這個時候客戶已經把 MaxActive 的引數已經調到了恐怖的 500,但問題依舊,在圖 22 中還能看到一些有用的資訊,比如正在 Waiting 的執行緒高達 908 個,Runnable 的執行緒高達 295 個,都是很恐怖的數字,大量的執行緒處於 Runnable 狀態,CPU 忙著進行執行緒上下文的切換,CPU 呼呼地轉,但實際並沒有幹多少有實際有意義的事。後經詢問,客戶將 SOFA 的業務處理執行緒數調到了 1000,預設是 200。

 title=

圖 22 執行緒卡在獲取 DB 連線池中的連線

 title=

圖 23 交易緩慢截圖

查到這裡基本可以斷定客戶陷入了“頭痛醫頭,腳痛醫腳”,“治標不治本”的窘境,進一步跟客戶溝通後,果然如此。剛開始的時候,是由於 SOFA 報了執行緒池滿的錯誤,然後客戶不斷加碼 SOFA 業務執行緒池中最大執行緒數,最後加到了 1000,效能提升不明顯,然後報了一個獲取不到資料庫連線的錯誤,客戶又認為這是資料庫連線不夠了,調高 Druid 的 MaxActive 引數,最後無論怎麼調效能也都上不來,甚至到後面把記憶體都快要壓爆了,如圖 24 所示,記憶體中被一些業務 DO 物件給填滿了,後面客戶一度以為存在記憶體洩露。對於這類問題,只要像是出現了資料庫連線池不夠用、或者從連線池中獲取連線超時,又或者是執行緒池耗盡這類問題,只要引數設定是在合理的範圍,那麼十有八九就是交易本身處理太慢了。後面經過進一步的排查最終定位是某個 SQL 語句和內部的一些處理不當導致的交易緩慢。修正後,TPS 正常,最後把執行緒池最大大小引數、DB 連線池的引數都往回撥成最佳實踐中推薦的值,再次壓測後,TPS 依然保持正常水平,問題得到最終解決。

 title=

圖 24 記憶體填滿了業務領域物件

這個案例一雖說是因為 CPU 衝高且交易持續緩慢的這一類典型問題,但其實就這個案例所述的那樣,在定位和調優的時候很容易陷進一種治標不治本的困境,很容易被一些表象所迷惑。如何撥開雲霧見月明,筆者的看法是 5 分看經驗,1 分看靈感和運氣,還有 4 分得靠不斷分析。如果沒經驗怎麼辦?那就只能沉下心來分析相關效能檔案,無論是執行緒轉儲檔案還是 JFR,又或者其他採集工具採集到效能資訊,反正不要放過任何蛛絲馬跡,最後實在沒轍了再請求經驗豐富的專家的協助排查解決。

  • 使用 JMC+JFR 定位問題

如果超長問題偶然發生,這裡介紹一個比較簡單且非常實用的方法,使用 JMC+JFR,可以參考連結進行使用。但是使用前必須開啟 JMX 和 JFR 特性,需要在啟動修改啟動引數,具體引數如下,該引數不要帶入生產,另外如果將容器所屬宿主機的埠也暴露成跟 jmxremote.port 一樣的埠,如下示例為 32433,那麼還可以使用 JConsole 或者 JVisualvm 工具實時觀察虛擬機器的狀況,這裡不再做詳細介紹。

-Dcom.sun.management.jmxremote.port=32433

-Dcom.sun.management.jmxremote.ssl=false

-Dcom.sun.management.jmxremote.

authenticate=false

-XX:+UnlockCommercialFeatures -XX:+FlightRecorder

下面以一個實際的 JFR 例項為例。

首先要開啟 JMX 和 JFR 功能,需要在啟動引數中加 JMX 開啟引數和 JFR 開啟引數,如上面所述,然後在容器裡面執行下述命令,執行後顯示“Started recording pid. The result will be written to xxxx”,即表示已經開始錄製,這個時候開始進行壓測,下述命令中的 duration 是 90 秒,也就表示會錄製 90S 後才會停止錄製,錄製完後將檔案下載到本地,用 jmc 工具進行分析,如果沒有這個工具,也可以使用 IDEA 進行分析。

jcmd pid JFR.start name=test duration=90s filename=output.jfr

 title=

通過分析火焰圖,具體怎麼看火焰圖請參考連結。通過這個圖可以看到主要的耗時是在哪個方法上面,給我們分析問題提供了很大的便利。

還可以檢視 call tree,也能看出耗時主要發生在哪裡。

 title=

JMC 工具下載地址:JDK Mission Control (JMC) 8 Downloads (oracle.com)

最後再介紹一款工具,阿里巴巴開源的 arthas,也是效能分析和定位的一把利器,具體使用就不在這裡介紹了,可以參考 arthas 官網。

  • 如何定位 CPU 耗時過高的執行緒及方法

首先找到 JAVA 程式的 PID,然後執行 top -H -p pid,這樣可以找到最耗時的執行緒,如下圖所示。然後使用 printf "%x\n" 17880,將執行緒號轉成 16 進位制,最終通過這個 16 進位制值去 jstack 執行緒轉儲檔案中去查詢是哪個執行緒佔用 CPU 最高。

 title=

其他問題案例

這類問題在發生的時候,JVM 表現得靜如止水,CPU 和記憶體的使用都在正常水位,但是交易就是緩慢,對於這一類問題可以參考 CPU 衝高類問題來進行解決,通過使用執行緒轉儲檔案或者使用JFR來錄製一段 JVM 執行記錄。這類問題大概率的原因是由於大部分執行緒卡在某個 IO 或者被某個鎖個 Block 住了,下面也帶來一個真實的案例。

  • 案例一

某金融保險頭部客戶,反應某個交易非常緩慢,經常響應時間在 10S 以上,應用部署在公有云的容器上,容器規格為 2C4G,資料庫是 OceanBase。問題每次都能重現,通過分散式鏈路工具只能定位到在某個服務上面慢,並不能精確定是卡在哪個方法上面。在交易緩慢期間,通過 top、vmstat 命令檢視 OS 的狀態,CPU 和記憶體資源都在正常水位。因此,需要看在交易期間的執行緒的狀態。在交易執行緩慢期間,將交易的執行緒給轉儲出來,如圖 29 所示,可以定位相應的執行緒卡在哪個方法上面,案例中的執行緒卡在了執行 socket 讀資料階段,從堆疊可以斷定是卡在了讀資料庫上面了。如果這個方法依然不好用,那麼還可以藉助抓包方式來進行定位。

 title=

圖 29 交易被 hang 住示例圖

  • 案例二

某金融銀行客戶壓測過程中發現 TPS 上不去,10TPS 不到,響應時間更是高到令人髮指,在經過一段時間的培訓賦能和磨合,該客戶已經具備些效能定位的能力。給反饋的資訊是 SQL 執行時間、CPU 和記憶體使用一切正常,客戶打了一份執行緒轉儲檔案,發現大多數執行緒都卡在了使用 RedissionLock 的分散式鎖上面,如圖 30 所示,後經查是客戶沒有合理使用分散式鎖導致的問題,解決後,TPS 翻了 20 倍。

 title=

圖 30 分散式鎖使用不當導致的問題示例

這兩個案例其實都不算複雜,也很容易進行排查,放到這裡只是想重述一下排查這類問題的一個整體的思路和方法。如果交易緩慢且資源使用都正常,可以通過分析執行緒轉儲檔案或者 JFR 檔案來定位問題,這類問題一般是由於 IO 存在瓶頸,又或者被鎖 Block 住的原因導致的。

總結

問題千千萬,但只要修練了足夠深厚的內功,形成一套屬於自己的排查問題思路和打法,再加上一套支撐問題排查的工具,憑藉已有的經驗還有偶發到來的那一絲絲靈感,相信所有的問題都會迎刃而解。

更多交流,歡迎進釘釘群溝通,PTS 使用者交流釘釘群號:11774967。

此外,PTS 近期對售賣方式做了全新升級,基礎版價格直降 50%!5W 併發價格只需 199,免去自運維壓測平臺煩惱!更有新使用者 0.99 體驗版、VPC 壓測專屬版,歡迎大家選購!

 title=

點選此處,前往官網檢視更多!

相關文章