內存管理和性能

7 月 16

在Raima,我們始終致力於提高產品性能。最近,我與一位客戶一起解決了數據庫性能相關的問題,並發現了一些有趣的事實。解決數據庫性能問題的方法可能不只是添加更多以更高速度運行的內存。

優化方法

在數據管理中,有無數種方法可以優化數據存儲和檢索中涉及的不同操作。很多時候,一個領域的優化可能需要權衡其他領域。一個常見的示例是通過在事務處理中放寬ACID(原子性,一致性,隔離性,耐久性)屬性來提高插入性能。從正面看,您可以大大增加每秒的插入次數。不利的一面是您現在有更大的數據丟失風險。

While most attempts to increase performance need some sacrifices, I had always thought that there was one tried and true method to increase database performance across the board – throw hardware at the problem. However, this case has shown me that, in certain situations, adding resources can cut performance – perhaps even dramatically.

 

內存管理詳細信息

我指的客戶有一個應用程序 需要處理大量的記錄插入 – perhaps 10 million new records inserted into the database at a time. The application requires persistent storage so 單純的內存數據庫是不夠的 甚至將數據寫到速度最快的驅動器也無法始終滿足性能要求。在與我們的工程團隊進行了分析之後,我們決定該問題的短期解決方案是在具有足夠RAM的服務器上運行該應用程序,以便在提交事務並將其寫入磁盤之前,將最大的預期插入突發緩存到緩存。通過增加高速緩存頁面的總數和每個頁面的大小,它們可以將最大的預期事務塊放入約40 GB的RAM中。

有了這些知識,他們為服務器配備了128 GB的RAM和16個處理器內核。當他們在新服務器上運行應用程序時,結果是 絕對不知所措。與其通過利用計算機上的可用資源來提高性能,實際上數據庫的性能下降了。實際上,第一次測試花費了很長時間,他們最終放棄並終止了該過程。

為了幫助客戶理解正在發生的事情,並確定我們的代碼中是否包含任何內容或可以改善我們的情況,我們進行了許多測試。

 

我們要虛擬化嗎?

我們首先看的是磁盤I / O。我從客戶群中看到的一個常見錯誤是,請求的數據庫緩存頁面超出了可用的物理內存量所能解決的範圍。這可能會導致極大的性能下降,因為操作系統將通過將其寫出到磁盤來開始虛擬內存進程。儘管此測試用例中的服務器是專門為處理應用程序的預期負載而設計的,但我們希望確保操作系統按預期方式處理了緩存。我們的分析表明,除了應用程序請求的操作所期望的之外,沒有其他I / O被執行。正在使用可用的永久內存,並且未對進程進行虛擬化。

 

我們可以處理大量頁面嗎?

接下來要看的是我們如何處理內部數據庫緩存。在 RDM服務器 數據庫緩存用於保存數據庫的已修改部分,直到提交事務並將更改寫入磁盤為止。一個令人擔心的問題是,我們用於查找緩存頁面的算法無法很好地擴展,無法處理此應用程序請求的非常多的緩存頁面。分析確實證明,用於查找頁面的哈希算法對於大量頁面與在更典型的場景中使用的中等數量的頁面一樣有效。

 

為什麼關機需要這麼長時間?

繼續進行的分析表明,測試運行中的插入處理正在按預期的時間進行。但是,一旦插入處理完成,該應用程序將花費數小時(而不是幾秒鐘)關閉。分析和調試表明,在完成插入之後,花費了意外的時間來釋放為高速緩存頁面分配的內存。每次免費操作平均大約需要13毫秒。計算出分配了超過2,621,440個緩存頁後,計算出要完全釋放所有內存將花費5個小時以上。出於比較目的,在僅使用12 GB緩存(1,572,864個8K頁面)的開發機上,整個緩存在3.48秒(每次釋放2微秒)中被釋放。

為了隔離行為,創建了一個非常簡單的應用程序,該應用程序分配了內存,然後以不同大小的塊將其釋放。我們進行了此測試,為各種塊大小分配了不同的內存量,並繪製了結果圖表。

 

Windows Server 2008 R2數據中心上的內存分配

內存分配圖表看起來像預期的那樣。使用較小的塊大小時,內存分配會花費更多時間,因為需要更多的分配,但是對於不同的塊大小,圖形都是線性的。運行/繪製釋放內存的結果時,我們發現了一個截然不同的故事。
 
Windows Server 2008 R2數據中心上的內存分配

 

Windows Server 2008 R2數據中心上的可用內存不足

What isn’t very easy to see on the chart is that memory free operations are linear for 1K, 2K, 4K, and 8K block sizes. What is very easy to see is that when using a block size of 16K (actually any block larger than 16,343 bytes) freeing memory is not a linear operation, particularly if you are allocating more than 6GB. This behavior was causing the degradation in performance.
 
Window Server 2008 R2數據中心上的無內存

 

完整性檢查

我們決定在不同的操作系統上運行測試以確認我們的結果。我們編譯了相同的源代碼,並在相同的硬件上運行了二進製文件(雙引導到Linux而不是Windows),並且得到了截然不同的結果。

 

Linux上的內存分配

Linux上的內存分配也有一個很好的線性圖,在Linux上分配內存要比Windows花費更長的時間,但是結果是相似的。
 
Linux上的內存分配

 

Linux上的無內存

Free memory on Linux was vastly different from what we saw on Windows. The free operations on Linux were much faster and more predictable than what happened on the Windows platform. Linux’s implementation in this respect was more robust and provided better scalability.
 
Linux上的無內存

 

可以做什麼?

One of the most challenging things about “something that should be fast but isn’t” is figuring out how to make it fast as it should be. We were unable to find much information about this issue through web searches, but we did make one minor change to the test that proved to have good results. The original test allocated memory in the same order it was freed. By modifying the test to free memory in the reverse order, stack instead of a queue, performance was greatly improved on Windows.

 

Windows Server 2008 R2數據中心上的反向內存可用

儘管圖形不是完全線性的,但在Windows上以相反的順序釋放內存時,如果使用大於16K的頁面大小,則可以在幾秒鐘而不是幾小時內完成。
 
Windows Server 2008 R2數據中心上的反向內存

 

在Linux上免費反向存儲

與分配內存的方式相反,Linux還通過可用內存提高了性能,結果仍然是線性的。
 
在Linux上免費反向存儲

從圖表中可以看出,以相反的順序釋放內存可以顯著提高性能。儘管它仍然不及Linux上所見的數據庫性能,但至少是可以容忍的。對於在Windows上運行的客戶來說,這是一個完美的短期解決方案,但我們仍然認為它應該運行得更快。

 

我們可以用更好的東西代替Malloc / Free嗎?

在與我們的客戶確認以相反的順序更改自由數據允許他們運行他們的應用程序之後,我們決定查看Microsoft提供的一些備用malloc實現。有幾種選擇,但其中許多是16位時代遺留下來的遺留實現。 VirtualAlloc / VirtualFree函數似乎是malloc / free的唯一可行選擇。這些虛擬內存功能提供的功能超出了基本malloc / free所提供的功能,但是通過正確的選項,您可以將這些功能用作malloc / free的可行替代品。

我們修改了測試代碼,以將對malloc的調用替換為以下內容:

p =(MEM_CHUNK *)VirtualAlloc(NULL,chunk_size,MEM_COMMIT | MEM_RESERVE,PAGE_READWRITE);

免費通話已被替換為:

VirtualFree(p,0,MEM_RELEASE);

We then ran the test application to allocate 24GB of memory in 1K chunks and the results were…not very good.

我們運行測試的計算機具有64 GB的內存,而我們期望在測試運行中分配的最大內存量是24 GB。但是,在我們的測試運行在幾個小時內未能完成之後,我們注意到性能監視器顯示我們的測試過程中所有的64GB內存都在使用中。仔細閱讀VirtualAlloc文檔可以輕鬆地解釋這一點。 VirtualAlloc的最小分配大小是單個內存頁。在我們的計算機上,內存頁面的大小為4K,因此我們所有的1K內存請求實際上都保留了4K。在測試的最高限制下,我們將在只有64 GB可用空間的系統上請求96 GB的內存。進行了一些測試修改,以刪除頁面大小小於4K的測試運行,從而為我們提供了希望的結果。

 

Windows Server 2008 R2數據中心上的VirtualAlloc

對於較小的頁面大小,VirtualAlloc的性能不如malloc,但是對於大於16K的頁面大小,它執行malloc的性能。
 
Windows Server 2008 R2數據中心上的VirtualAlloc

 

Windows Server 2008 R2數據中心上的VirtualFree

VirtualFree的性能全面優於FreeFree,尤其是頁面大小大於16K的情況。
 
Windows Server 2008 R2數據中心上的VirtualFree

 

在Windows Server 2008 R2數據中心上反向VirtualFree

VirtualAlloc具有類似的性能,而與釋放訂單內存無關。對於大於8K的頁面,它的性能優於malloc。
 
在Windows Server 2008 R2數據中心上反向VirtualFree

VirtualAlloc / VirtualFree結果的好處是,數據庫的性能保持一致,而與釋放內存的順序無關。通過修改代碼以使用VirtualAlloc分配大於16K的緩衝區,我們可以提高基於Windows的系統的性能和可預測性。

 

結論

如果您的應用程序使用相對較小的塊分配大量內存,則可能需要考慮在基於Windows的系統上使用malloc / free的替代方法。儘管VirtualAlloc / VirtualFree不適合分配少於一個內存頁面,但是當以單個頁面的倍數分配內存時,它們可以極大地提高數據庫性能和可預測性。

實際上應該很快的事情總是很不錯。

Get notified about new RDM updates

Be the first to know about new Raima Database Manager updates when they go live, use cases, industry trends and more.