挑戰(zhàn)Redis單實例內(nèi)存最大極限,“遭遇”NUMA陷阱庇忌!

我們公司的基礎(chǔ)架構(gòu)部有個云Redis平臺舞箍,其中Redis實例在申請的時候可以自由選擇需要的內(nèi)存的大小。然后就引發(fā)了我的一個思考皆疹,Redis單實例內(nèi)存最大申請到多大比較合適疏橄?假設(shè)母機是64GB內(nèi)存的物理機,如果不考慮CPU資源的的浪費,我是否可以開一個50G的Redis實例捎迫?

于是我在Google上各種搜索晃酒,討論這個問題的人似乎不多。找到唯一感覺靠譜點的答案窄绒,那就是單進程分配的內(nèi)存最好不要超過一個node里的內(nèi)存總量贝次,否則linux當該node里的內(nèi)存分配光了的時候,會在自己node里動用硬盤swap彰导,而不是其它node里申請蛔翅。這即使所謂的numa陷阱,當Redis進入這種狀態(tài)后會導致性能急劇下降(不只是redis位谋,所有的內(nèi)存密集型應(yīng)用如mysql山析,mongo等都會有類似問題)。

看起來這個解釋非常有說服力倔幼。于是乎盖腿,我就想親手捕捉一次NUMA陷阱,看看這個家伙究竟什么樣损同。

先聊聊QPI與NUMA

最早在CPU都是單核的時候翩腐,用的總線都是FSB總線。經(jīng)典結(jié)構(gòu)如下圖:

FSB總線

到來后來CPU的開發(fā)者們發(fā)現(xiàn)CPU的頻率已經(jīng)接近物理極限了膏燃,沒法再有更大程度的提高了茂卦。在2003年的時候,CPU的頻率就已經(jīng)達到2個多GB组哩,甚至3個G了〉攘現(xiàn)在你再來看今天的CPU,基本也還是這個頻率伶贰,沒進步多少蛛砰。摩爾定律失效了,或者說是向另外一個方向發(fā)展了黍衙。那就是多核化泥畅、多CPU化。

多CP化畫

剛開始核不多的時候琅翻,F(xiàn)SB總線勉強還可以支撐位仁。但是隨著CPU越來越多,所有的數(shù)據(jù)IO都通過這一條總線和內(nèi)存叫喚數(shù)據(jù)方椎,這條FSB就成為了整個計算機系統(tǒng)的瓶頸聂抢。舉個北京的例子,這就好比進回龍觀的京藏高速棠众,剛開始回龍觀人口不多的時候琳疏,這條高速承載沒問題。但是現(xiàn)在回龍觀聚集了幾十萬人了,“總線”還僅有這一條空盼,未免效率太低疮薇。

CPU的設(shè)計者們很快改變了自己的設(shè)計,引入了QPI總線我注,相應(yīng)的CPU的結(jié)構(gòu)就叫NMUA架構(gòu)。下圖直觀理解

NUMA架構(gòu)

話說NUMA陷阱

NUMA陷阱指的是引入QPI總線后迟隅,在計算機系統(tǒng)里可能會存在的一個坑但骨。大致的意思就是如果你的機器打開了numa,那么你的內(nèi)存即使在充足的情況下智袭,也會使用磁盤上的swap奔缠,導致性能低下。原因就是NUMA為了高效吼野,會僅僅只從你的當前node里分配內(nèi)存校哎,只要當前node里用光了(即使其它node還有),也仍然會啟用硬盤swap瞳步。

當我第一次聽說到這個概念的時候闷哆,不禁感嘆我運氣好,我的Redis實例貌似從來沒有掉進這個陷阱里過单起。那為了以后也別栽坑抱怔,趕緊去了解了下我的機器的numa狀態(tài):

# numactl --hardware
available: 2 nodes (0-1)
node 0 cpus: 0 1 2 3 4 5 12 13 14 15 16 17
node 0 size: 32756 MB
node 0 free: 19642 MB
node 1 cpus: 6 7 8 9 10 11 18 19 20 21 22 23
node 1 size: 32768 MB
node 1 free: 18652 MB
node distances:
node   0   1
  0:  10  21
  1:  21  10

上面結(jié)果說明我們有兩個node,node0和node1嘀倒,分別有12個核心屈留,各有32GB的內(nèi)存。
再看zone_reclaim_mode测蘑,它用來管理當一個內(nèi)存區(qū)域(zone)內(nèi)部的內(nèi)存耗盡時灌危,是從其內(nèi)部進行內(nèi)存回收還是可以從其他zone進行回收的選項:

  • 0 關(guān)閉zone_reclaim模式,可以從其他zone或NUMA節(jié)點回收內(nèi)存
  • 1 打開zone_reclaim模式碳胳,這樣內(nèi)存回收只會發(fā)生在本地節(jié)點內(nèi)
  • 2 在本地回收內(nèi)存時勇蝙,可以將cache中的臟數(shù)據(jù)寫回硬盤,以回收內(nèi)存
  • 4 在本地回收內(nèi)存時固逗,表示可以用Swap 方式回收內(nèi)存
# cat /proc/sys/vm/zone_reclaim_mode
1

額浅蚪,好吧。我的這臺機器上的zone_reclaim_mode還真是1烫罩,只會在本地節(jié)點回收內(nèi)存惜傲。

實踐捕捉numa陷阱未遂

那我的好奇心就來了,既然我的單個node節(jié)點只有32G贝攒,那我部署一個50G的Redis盗誊,給它填滿數(shù)據(jù)試試到底會不會發(fā)生swap。

實驗開始,我先查看了本地總內(nèi)存哈踱,以及各個node的內(nèi)存剩余狀況荒适。

# top
......
Mem:  65961428k total, 26748124k used, 39213304k free,   632832k buffers
Swap:  8388600k total,        0k used,  8388600k free,  1408376k cached

# cat /proc/zoneinfo"
  ......
Node 0, zone   Normal
  pages free     4651908
Node 1, zone   Normal
  pages free     4773314

總內(nèi)存不用解釋,/proc/zoneinfo里包含了node可供應(yīng)用程序申請的free pages开镣。node1有4651908個頁面刀诬,4651908*4K=18G的可用內(nèi)存。

接下來讓我們啟動redis實例邪财,把其內(nèi)存上限設(shè)置到超過單個node里的內(nèi)存大小陕壹。我這里單node內(nèi)存大小是32G,我把redis設(shè)置成了50G树埠。開始灌入數(shù)據(jù)糠馆。最終數(shù)據(jù)全部灌完之后,

# top
Mem:  65961428k total, 53140400k used, 12821028k free,   637112k buffers
Swap:  8388600k total,        0k used,  8388600k free,  1072524k cached
  PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND
 8356 root      20   0 62.8g  46g 1292 S  0.0 74.5   3:45.34 redis-server
 
# cat /proc/zoneinfo | grep "pages free"
  pages free     3935
  pages free     347180
  pages free     1402744
  pages free     1501670

實驗證明怎憋,在zone_reclaim_mode為1的情況下又碌,Redis是平均在兩個node里申請節(jié)點的,并沒有固定在某一個cpu里绊袋。

莫非是大佬們的忠告錯了嗎毕匀?其實不是,如果不綁定親和性的話癌别,分配內(nèi)存是當進程在哪個node上的CPU發(fā)起內(nèi)存申請期揪,就優(yōu)先在哪個node里分配內(nèi)存。之所以是平均分配在兩個node里规个,是因為redis-server進程實驗中經(jīng)常會進入主動睡眠狀態(tài)凤薛,醒來后可能CPU就換了。所以基本上诞仓,最后看起來內(nèi)存是平均分配的缤苫。如下圖,CPU進行了500萬次的上下文切換墅拭,用top命令看到cpu也是在node0和node1跳來跳去活玲。

# grep ctxt /proc/8356/status
voluntary_ctxt_switches:        5259503
nonvoluntary_ctxt_switches:     1449

改進方法,成功抓獲numa陷阱

殺死進程谍婉,內(nèi)存歸位

# cat /proc/zoneinfo 
Node 0, zone   Normal
  pages free     7597369
Node 1, zone   Normal
  pages free     7686732

綁定CPU和內(nèi)存的親和性舒憾,然后再啟動。

numactl --cpunodebind=0 --membind=0 /search/odin/daemon/redis/bin/redis-server /search/odin/daemon/redis/conf/redis.conf 

top命令觀察到CPU確實一直在node0的節(jié)點里穗熬。node里的內(nèi)存也在快速消耗镀迂。

# cat /proc/zoneinfo 
Node 0, zone   Normal
  pages free     10697
Node 1, zone   Normal
  pages free     7686732

看,內(nèi)存很快就消耗光了唤蔗。我們再看top命令觀察到的swap探遵,很激動地發(fā)現(xiàn)窟赏,我終于陷入到傳說中的numa陷阱了。

Tasks: 603 total,   2 running, 601 sleeping,   0 stopped,   0 zombie
Cpu(s):  0.7%us,  5.4%sy,  0.0%ni, 85.6%id,  8.2%wa,  0.0%hi,  0.1%si,  0.0%st
Mem:  65961428k total, 34530000k used, 31431428k free,   319156k buffers
Swap:  8388600k total,  6000792k used,  2387808k free,   777584k cached

  PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND
  258 root      20   0     0    0    0 R 72.3  0.0   0:17.18 kswapd0
25934 root      20   0 37.5g  30g 1224 D 71.6 48.7   1:06.09 redis-server

這時候箱季,Redis實際使用的物理內(nèi)存RES定格到了30g不再上漲涯穷,而是開始消耗Swap。

又過了一會兒藏雏,Redis被oom給kill了拷况。

結(jié)論

通過今天的實驗,我們可以發(fā)現(xiàn)確實有NUMA陷阱這種東西存在掘殴。不過那是我手工通過numactl指令綁定cpu和mem的親和性后才遭遇的蝠嘉。相信國內(nèi)絕大部分的線上Redis沒有進行這個綁定,所以理論上來單Redis單實例可以使用到整個機器的物理內(nèi)存杯巨。(實踐中最好不要這么干,你的大部分內(nèi)存都綁定到一個redis進程里的話努酸,那其它CPU核就沒啥事干了服爷,浪費了CPU的多核計算能力)

擴展

當通過numactl綁定CPU和mem都在一個node里的時候,內(nèi)存IO不需要經(jīng)過總線获诈,性能會比較高仍源,你Redis的QPS能力也會上漲。和跨node的內(nèi)存IO性能對比舔涎,可以下面的實例笼踩,就是10:21的區(qū)別。

# numactl --hardware
......
node distances:
node   0   1
  0:  10  21
  1:  21  10

你要是對性能有極致的追求亡嫌,可以試著綁定numa的親和性玩玩嚎于。不過,no作no die挟冠,掉到numa陷阱里可別賴我于购,嘎嘎!

歡迎搜索微信公眾號:開發(fā)內(nèi)功修煉

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末知染,一起剝皮案震驚了整個濱河市肋僧,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌控淡,老刑警劉巖嫌吠,帶你破解...
    沈念sama閱讀 218,755評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異掺炭,居然都是意外死亡辫诅,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評論 3 395
  • 文/潘曉璐 我一進店門涧狮,熙熙樓的掌柜王于貴愁眉苦臉地迎上來泥栖,“玉大人簇宽,你說我怎么就攤上這事“上恚” “怎么了魏割?”我有些...
    開封第一講書人閱讀 165,138評論 0 355
  • 文/不壞的土叔 我叫張陵,是天一觀的道長钢颂。 經(jīng)常有香客問我钞它,道長,這世上最難降的妖魔是什么殊鞭? 我笑而不...
    開封第一講書人閱讀 58,791評論 1 295
  • 正文 為了忘掉前任遭垛,我火速辦了婚禮,結(jié)果婚禮上操灿,老公的妹妹穿的比我還像新娘锯仪。我一直安慰自己,他們只是感情好趾盐,可當我...
    茶點故事閱讀 67,794評論 6 392
  • 文/花漫 我一把揭開白布庶喜。 她就那樣靜靜地躺著,像睡著了一般救鲤。 火紅的嫁衣襯著肌膚如雪久窟。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,631評論 1 305
  • 那天本缠,我揣著相機與錄音斥扛,去河邊找鬼。 笑死丹锹,一個胖子當著我的面吹牛稀颁,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播楣黍,決...
    沈念sama閱讀 40,362評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼峻村,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了锡凝?” 一聲冷哼從身側(cè)響起粘昨,我...
    開封第一講書人閱讀 39,264評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎窜锯,沒想到半個月后张肾,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,724評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡锚扎,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年吞瞪,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片驾孔。...
    茶點故事閱讀 40,040評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡芍秆,死狀恐怖惯疙,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情妖啥,我是刑警寧澤霉颠,帶...
    沈念sama閱讀 35,742評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站荆虱,受9級特大地震影響蒿偎,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜怀读,卻給世界環(huán)境...
    茶點故事閱讀 41,364評論 3 330
  • 文/蒙蒙 一诉位、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧菜枷,春花似錦苍糠、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至坷衍,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間条舔,已是汗流浹背枫耳。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留孟抗,地道東北人迁杨。 一個月前我還...
    沈念sama閱讀 48,247評論 3 371
  • 正文 我出身青樓,卻偏偏與公主長得像凄硼,于是被迫代替她去往敵國和親铅协。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,979評論 2 355

推薦閱讀更多精彩內(nèi)容

  • SWAP/swappiness/kswapd原理摊沉,swap分區(qū)優(yōu)先級的妙用 概述 本文討論的swap基于Linux...
    xywzhen閱讀 5,206評論 1 5
  • 本文截取自:http://hbasefly.com/2017/05/24/hbase-linux/ swap是干嘛...
    博弈史密斯閱讀 27,280評論 0 14
  • 內(nèi)存管理 內(nèi)存管理包含: 物理內(nèi)存管理; 虛擬內(nèi)存管理; 兩者的映射 除了內(nèi)存管理模塊, 其他都使用虛擬地址(包括...
    西山薄涼閱讀 757評論 0 2
  • 內(nèi)存回收 當發(fā)生了內(nèi)存泄漏時狐史,或者運行了大內(nèi)存的應(yīng)用程序,導致系統(tǒng)的內(nèi)存資源緊張時说墨,系統(tǒng)又會如何應(yīng)對呢骏全? 這其實會...
    taj3991閱讀 2,661評論 0 0
  • 2016/01/25 內(nèi)存分配的過程 用戶態(tài)的程序調(diào)用 malloc 函數(shù)申請內(nèi)存. malloc 是一個庫函數(shù)...
    楊廣xiang閱讀 1,348評論 0 1