我不確定 serverfault 是否是問這個問題的正確位置,但我想知道如果您必須為 Java Web 應用程式選擇新的 CPU 類型,您會做出什麼選擇:
a) 32 核心、時脈速度 2.5 Ghz 的 CPU
或者
b) 8 核心但時脈速度為 3.8 Ghz 的 CPU
鑑於每個 Web 應用程式傳入的 HTTP 請求都由一個空閒的 Java 執行緒提供服務,選擇 a) 可能是有意義的,因為您可以同時處理四倍以上的 HTTP 請求。然而,另一方面,CPU b) 可以更快地完成單一 HTTP 請求的處理...
你怎麼認為?
附註:
- 它必須是實體機,在這種情況下不能選擇虛擬機或雲端解決方案
- RAM並不重要,伺服器最終將擁有512GB RAM
- 快取:Java Web 應用程式具有廣泛的快取框架,因此選擇實際上取決於 CPU。
答案1
太棒了;真正的答案可能是“更多內存”,但正如您所問的那樣,答案當然是,這取決於情況。話又說回來,32 個核心 @2.5Ghz 幾乎肯定會擊敗 8 個核心 @3.8Ghz - 它的核心數多了 4 倍,時脈速度快了 1.5 倍。這不是一場非常公平的戰鬥。
您應該考慮的幾個因素是交易回應時間、並髮使用者和應用程式架構。
交易回應時間 如果您的 Java 應用程式在幾毫秒內回應大多數請求,那麼擁有更多核心來處理更多並發請求可能是正確的選擇。但是,如果您的應用程式主要處理運行時間更長、更複雜的事務,那麼它可能會受益於更快的核心。 (或者可能不會 - 見下文)
並髮用戶和請求 如果您的 Java 應用程式收到大量並發請求,那麼更多核心可能會有所幫助。如果您沒有那麼多並發請求,那麼您可能只需為一堆額外的空閒核心付費。
應用架構 如果應用程式伺服器花費大部分事務時間等待來自 Web 服務、資料庫、kafaka/mq/等的回應,那麼我提到的那些長時間運行的請求不會從更快的核心中受益匪淺。我見過很多事務處理時間為 20-30 秒的應用程序,它們僅將一小部分響應時間用於應用程式本身的處理,其餘時間則等待資料庫和 Web 服務的回應。
您還必須確保應用程式的不同部分能夠很好地配合在一起。讓 32 或 64 個執行緒分別處理一個請求,所有執行緒都排隊等待 JDBC 池中的 10 個連線之一,這對您沒有多大好處,也稱為 Python 問題中的豬。現在進行一些規劃和設計將為您在以後的效能故障排除中節省大量時間。
最後一件事 - 您可能會比較哪些 CPU?我能找到的最便宜的 32 核心 2.5 GHz CPU 的成本至少是任何 8 核心 3.8 Ghz CPU 的 3 到 4 倍。
答案2
假設您的 Java Web 伺服器已正確配置,您應該選擇更多核心。
仍然存在依賴關係,例如信號量、並發訪問,無論核心數量或速度如何,仍然會有一些線程等待。但由 CPU(核心)管理比由作業系統(多執行緒)管理好。
無論如何,32 核心 @2.5Ghz 將處理更多線程,並且比 8 核心 @3.8Ghz 更好。
此外,CPU 產生的熱量取決於頻率(除其他外),並且這不是線性的。這意味著,3.8Ghz 會產生比 3.8/2.5 x 更多的熱量(必須根據您的確切 CPU 類型/品牌進行確認......許多網站都提供詳細資訊)。
答案3
您告訴我們,執行一個請求大約需要 100-200 毫秒,並且主要是處理時間(儘管很難將實際的 CPU 執行與實際的記憶體存取分開),很少的 I/O,等待資料庫等
您必須對兩個CPU 中的每一個CPU 實際花費的時間進行基準測試,但我們假設較慢的CPU(具有32 個核心)需要150 毫秒,而較快的CPU(只有8 個核心)需要100 毫秒。
那麼第一個 CPU 每秒最多能夠處理 32/0.15 = 213 個請求。
第二個 CPU 每秒最多能夠處理 8/0.1 = 80 個請求。
所以最大的問題是:您預計每秒有多少個請求?如果每秒處理的請求遠不及幾十個,那麼您不需要第一個 CPU,第二個 CPU 將為您提供每個請求的更快執行時間。如果您每秒確實需要超過 100 個請求,那麼第一個請求就有意義(或者擁有多個伺服器可能更有意義)。
請注意,這是非常粗略的估計。唯一確定的方法是用實際負載對每台伺服器進行基準測試。如上所述,快速 CPU 或具有大量核心的 CPU 很快就會變得缺乏記憶體存取。各種CPU快取的大小在這裡非常重要,還有每個請求的「工作集」。這是考慮真正受 CPU 限制的工作,沒有系統呼叫、沒有共享資源、沒有 I/O...
答案4
太棒了;真正的答案可能是“更多內存”
尤其是這一點。
警告
本身並不是一個管理員。
也許更多的是從軟體工程的角度來看。
除了測量之外別無選擇
我們所知道的
所以,機器是
- 將運行某種(企業?)基於 Java 的後端應用程式
- 公開(無論如何,在一些相當大的上下文中)公開處理客戶端請求的 HTTP API
- 大概附加了某種形式的資料庫
- 否則被描述為不太受 I/O 限制
- 不依賴第三方服務的可用性、延遲或吞吐量
並不是那麼模糊的畫面,OP正在繪畫。但同時還遠遠沒有足夠的數據來給出答案關於OP的個人狀況。
當然,32 個核心,時脈速度的 2/3可能以相對較小的速度優勢執行優於 1/4 核心的效能。當然,當時脈速度高於 4GHz 閾值時,產生的熱量就無法很好地擴展。當然,如果我必須盲目地把雞蛋放在一個籃子裡,我會在一周中的任何一天挑選 32 個核心。
我們不知道什麼
仍然太多了。
然而,除了這些簡單的事實之外,我對尋求更具體和客觀答案的假設嘗試非常懷疑。 伊夫這是可能的(並且您有充分的理由仍然相信單位時間的操作是一個有效的關注點),掌握您打算運行系統的硬件,端到端地測量和測試。
一個明智的決定涉及相關的和可信的數據。
OP 寫道: 記憶體並不重要
在絕大多數情況下,記憶是瓶頸。
當然,OP主要是詢問CPU 核心與時脈速度因此,記憶就出現在偏離主題的邊緣。
但我不認為是這樣。對我來說,如果這個問題是基於錯誤的前提,那麼這個問題的可能性就更大。現在,不要誤會我的意思,@OP,你的問題切中主題,措辭得當,你的擔憂顯然是真實的。我只是不相信哪個 CPU 在您的用例中表現「更好」的答案與(對您而言)完全相關。
為什麼記憶體很重要(對於 CPU)
主記憶體是極其緩慢。
從歷史上看,與硬碟相比,我們傾向於將 RAM 視為「快速儲存類型」。在這種比較的背景下,它仍然成立。然而,在近幾十年來,處理器速度的成長速度始終快於 DRAM 的效能。隨著時間的推移,這種發展導致了通常所說的“處理器-內存-間隙”。
處理器和記憶體速度之間的差距(來源:Carlos Carvalho,Departamento de Informatica,Universidade do Minho)
取得快取行從主存到 CPU 暫存器大約佔用約 100 個時脈週期的時間。在此期間,您的作業系統會將 x86 架構的 4 個(?)核心之一中的兩個硬體執行緒之一報告為忙碌的。
就可用性就這個硬體線程而言,你的作業系統沒有說謊,它正忙著等待。然而,處理單元本身,不考慮正在爬向它的快取線,事實上閒置。
在此期間沒有執行任何指令/操作/計算。
+----------+---------------+---------------------------------------------------------------------------------------------------+
| Type of | size of | Latency due to fetching a cache line |
| mem / op | cache +--------+--------+------------+--------------------------------------------------------------------+
| | (register) | clock | real | normalized | now I feel it |
| | | cycles | time | | |
+----------+---------------+--------+--------+------------+--------------------------------------------------------------------+
| tick | 16KB | 1 | 0.25ns | 1s | Dinner is already served. Sit down, enjoy. |
| | *the* 64 Bits | | | | |
+----------+---------------+--------+--------+------------+--------------------------------------------------------------------+
| L1 | 64KB | 4 | 1ns | 4s | Preparations are done, food's cooking. |
| | | | | | Want a cold one to bridge the gap? |
+----------+---------------+--------+--------+------------+--------------------------------------------------------------------+
| L2 | 2048KB | 11 | ~3ns | 12s | Would you be so kind as to help me dice the broccoli? |
| | | | | | If you want a beer, you will have to go to the corner store. |
+----------+---------------+--------+--------+------------+--------------------------------------------------------------------+
| L3 | 8192KB | 39 | ~10ns | 40s | The car is in the shop, you'll have to get groceries by bike. |
| | | | | | Also, food ain't gonna cook itself, buddy. |
+----------+---------------+--------+--------+------------+--------------------------------------------------------------------+
| DRAM | ~20GB | 107 | ~30ns | 2min | First year of college. First day of the holiday weekend. |
| | | | | | Snow storm. The roommate's are with their families. |
| | | | | | You have a piece of toast, two cigarettes and 3 days ahead of you. |
+----------+---------------+--------+--------+------------+--------------------------------------------------------------------+
該系列晶片的延遲數據
Core-i7-9XX
(資料來源:斯科特·邁耶斯,2010)
底線 如果無法進行適當的測量,那麼與其爭論內核與時脈速度,不如超額硬體預算的最安全投資是 CPU 快取大小。
因此,如果記憶體定期保持各個硬體線程空閒,那麼更多的“牛鈴”核心肯定是解決方案嗎?
理論上,如果軟體準備好了,多線程/超線程可以快點
假設您正在查看過去幾年的報稅表(例如),總共 8 年的資料。您每年(行)持有 12 個每月值(列)。
現在,一個位元組可以容納 256 個單獨的值(因為它的 8 個單獨的二進制數字,每個數字可能有 2 個狀態,這會導致8^2 = 256
不同狀態的排列。無論採用哪種貨幣,256 感覺有點低端,無法代表此外,為了便於討論,我們假設最小面額(“美分”)無關緊要(每個人都賺取主要面額的整數值)。保留在完全不同的會計系統中。
因此,在這個簡化的場景中,我們假設上述記憶體空間量的兩倍,即 2 個位元組(或「半字」),以unsigned
形式使用時,即表示從 的範圍[0, 2^16 = 65536)
,足以表示所有員工的月薪值。
因此,在您選擇的語言/RDBS/作業系統中,您現在持有一個矩陣(某種二維資料結構,「清單的清單」),其值具有統一的資料大小(2 位元組/16 位元) 。
在 C++ 中,這將是一個std::vector<std::vector<uint16_t>>
.我猜你也會在 Java 中使用vector
of vector
of short
。
現在,這是有獎問題:
假設您想根據通貨膨脹調整這 8 年的數值(或寫入位址空間的其他任意原因)。我們正在研究 16 位元值的均勻分佈。您需要存取矩陣中的每個值一次,讀取它,修改它,然後將其寫入位址空間。
如何遍歷數據重要嗎?
答案是:是的,非常如此。如果您先迭代行(內部資料結構),您將在並發執行環境中獲得近乎完美的可擴展性。在這裡,一個額外的線程,因此一個線程中的一半資料和另一個線程中的另一半將使您的作業運行速度提高兩倍。 4 個線程? 4 倍的性能增益。
但是,如果您選擇先做列,兩個執行緒將運行你的任務明顯慢一些。您將需要大約 10 個並行執行線程,以減輕(!)剛剛選擇主要遍歷方向所帶來的負面影響。只要您的程式碼在單一執行緒中運行,您就無法測量到差異。
+------+------+------+------+------+------+------+
| Year | Jan | Feb | Mar | Apr | ... | Dec |
+------+------+------+------+------+------+------+
| 2019 | 8500 | 9000 | 9000 | 9000 | 9000 | 9000 | <--- contiguous in memory
+------+------+------+------+------+------+------+
| 2018 | 8500 | 8500 | 8500 | 8500 | 8500 | 8500 | <--- 12 * 16Bit (2Byte)
+------+------+------+------+------+------+------+
| 2017 | 8500 | 8500 | 8500 | 8500 | 8500 | 8500 | <--- 3 * (4 * 16Bit = 64Bit (8Byte)
+------+------+------+------+------+------+------+
| ... | 8500 | 7500 | 7500 | 7500 | 7500 | 7500 | <--- 3 cache lines
+------+------+------+------+------+------+------+
| 2011 | 7500 | 7200 | 7200 | 7200 | 7200 | 7200 | <--- 3 lines, likely from the same
+------+------+------+------+------+------+------+ virtual memory page, described by
the same page block.
OP 寫道: a) 32 核心、時脈速度 2.5 Ghz 的 CPU
或
b) 8 核心、時脈速度 3.8 Ghz 的 CPU
在其他條件相同的情況下:
-->考慮快取大小、記憶體大小、硬體的推測預取功能以及實際上可以利用並行化的運行軟體,這些都比時脈速度更重要。
--> 即使不依賴第 3 方分散式系統,確保您在生產條件下確實不受 I/O 限制。如果您必須擁有內部硬體並且無法讓 AWS / GCloud / Azure / Heroku /Whatever-XaaS-IsHipNow 來處理這種痛苦,那麼請花在您放置資料庫的 SSD 上。當你這樣做時不是如果希望資料庫與應用程式位於同一台實體電腦上,請確保網路距離(也在此測量延遲)盡可能短。
--> 選擇一個著名的、經過審查的頂級「企業級」HTTP 伺服器庫(毫無疑問是為並發而構建的)還不夠。確保您在路線中運行的任何第三方庫都是。確保您的內部代碼也是如此。
在這種情況下,虛擬機器或雲端解決方案不是一個選擇
我明白了。
存在各種正當理由。
它一定要是A實體機 [...]
[...] 32 核心 CPU,時脈速度 2.5 Ghz
但這並沒有那麼多。
AWS 和 Azure 都沒有發明分散式系統、微叢集或負載平衡。在裸機硬體上設定並且沒有 MegaCorp 式資源會更加痛苦,但是您能在您自己的客廳中運行 K8 叢集的分散式網格。對於自託管專案來說,也存在用於定期運行狀況檢查和尖峰負載自動配置的工具。
OP 寫道: 記憶體並不重要
這是一個~假設的~可重現的場景:啟用 zram 作為交換空間,因為 RAM 很便宜而且並不重要等等。現在運行一個穩定的記憶體密集型任務,該任務不會導致頻繁的分頁。當你達到嚴重的 LRU 倒置點時,你的風扇會變得很吵,你的 CPU 核心也會很熱 - 因為它正忙於處理記憶體管理(將垃圾移入和移出交換區)。
OP 寫道: 記憶體並不重要
如果我表達得不夠清楚:我認為你應該重新考慮這個觀點。
長話;博士?
32 核。
更多的是更好的。