近期在排查redis做rdb時會有部分請求逾時的case。初步推斷是我們redisserver上開啟了THP(Transparent Huge Pages)。
1) Linux本身的頁大小是固定的4KB,在2.6.38核心新增了THP,透明地支援huge page(2MB)的使用。而且預設開啟。開啟THP的優勢在于:
- 降低page fault。一次page fault能夠載入更大的記憶體塊。
- 更小的頁表。同樣的記憶體大小,須要更少的頁。
- 因為頁表更小,虛拟位址到實體位址的翻譯也更快。
劣勢在于:
- 降低配置設定記憶體效率。
須要大塊、連續記憶體塊。核心線程會比較激進的進行compaction。解決記憶體碎片。加劇鎖争用。
- 降低IO吞吐。因為swapable huge page,在swap時須要切分成原有的4K的頁。Oracle的測試資料顯示會降低30%的IO吞吐。
2) 對于redis而言,開啟THP的優勢在于:
- fork子程序的時間大幅降低。fork程序的主要開銷是拷貝頁表、fd清單等程序資料結構。因為頁表大幅較小(2MB / 4KB = 512倍),fork的耗時也會大幅降低。
劣勢在于:
- fork之後,父子程序間以copy-on-write方式共享位址空間。
假設父程序有大量寫操作,而且不具有locality。會有大量的頁被寫。并須要拷貝。同一時候,因為開啟THP,每一個頁2MB,會大幅添加記憶體拷貝。
3) 針對這個特性,我做了一個測試,分别在開啟和關閉THP的情況下,測試redis的fork、響應時間。
測試條件:
redis資料集大小:16G
rdb檔案大小:3.4G
./redis-benchmark -P 4 -t set -r 5000000 -n 1000000000
(1) fork時間對照
開啟THP後。fork大幅降低。

(2)逾時次數
使用redis-benchmark測試,單個kv僅僅有幾位元組,沒辦法模拟真實線上的延遲,這裡任務延遲超過300us的請求即為逾時,統計這些請求的個數。
開啟THP後,逾時次數明顯增多,可是每次逾時時間較短。而關閉THP後,僅僅有4次逾時,原因是與fork在同一事件循環的請求受到fork的影響,chu'l。
關閉THP影響的僅僅是零星幾個請求。而開啟後,盡管逾時時間短了,可是影響面擴大了。
4)檢視THP狀态
$ cat /sys/kernel/mm/transparent_hugepage/enabled
[always] madvise never
always表示總是開啟, madvise依據程式的配置開啟,never關閉。
關閉THP
sudo echo never > /sys/kernel/mm/transparent_hugepage/enabled
須要重新啟動程序
5) 結論
集合業界的經驗,建議關閉我們線上redis、mysql、mongodb等機器的THP。
6)references
各種坑:
<a target="_blank" href="https://blogs.oracle.com/linux/entry/performance_issues_with_transparent_huge">https://blogs.oracle.com/linux/entry/performance_issues_with_transparent_huge</a>
<a target="_blank" href="http://docs.splunk.com/Documentation/Splunk/6.2.3/ReleaseNotes/SplunkandTHP">http://docs.splunk.com/Documentation/Splunk/6.2.3/ReleaseNotes/SplunkandTHP</a>
<a target="_blank" href="http://structureddata.org/2012/06/18/linux-6-transparent-huge-pages-and-hadoop-workloads/">http://structureddata.org/2012/06/18/linux-6-transparent-huge-pages-and-hadoop-workloads/</a>
<a target="_blank" href="http://antirez.com/news/84">http://antirez.com/news/84</a>
本文轉自mfrbuaa部落格園部落格,原文連結:http://www.cnblogs.com/mfrbuaa/p/5093266.html,如需轉載請自行聯系原作者