一、現代CPU模式
現代一個CPU中,可以有多個運行核心(稱之為物理核),每個物理核都有自己獨立的一級緩存(L1)和二級緩存(L2)。並且每個物理核一般會有兩個超線程(稱之為邏輯核);同一個物理核下的兩個邏輯核同享L1和L2緩存。並且現在機器主流都是多CPU處理器結構(CPU Socket),每個CPU擁有自己的L1和L2以及L3級緩存和自己所管理的內存空間;不同處理器之間通過總線進行連接。一台機器的cpu構造如下圖所示:
二、cpu多核對redis的影響
因為我們的cpu存在上下文切換(context switch),每個物理核有自己獨立的L1和L2級緩存,程序執行最頻繁的指令和數據會被緩存到L1和L2級緩存中,一旦我們的程序被切換到另一個物理核時,對應的指令和數據需要被重新刷到對應的(L1、L2)緩存中,所以頻繁進行上下文切換的話,程序就不能很好的利用L1和L2級緩存,就會增加程序的延時性。針對這個頻繁切換cpu核進行操作,我們可以采用綁核操作,將一個redis實例只在對應的物理核上執行,不會切換到其他物理核上。
taskset -c 0 ./redis-server
三、多cpu對redis的影響
我們的程序被cpu執行都是通過時間片,一台機器上有多個應用時,某一時刻是有一個程序可以獲取cpu去執行程序代碼,所以當一個程序在一個CPU socket運行時,如果此時發生了CPU切換,程序被切換到另一個CPU socket上運行,此時程序在運行時讀取內存數據時,需要讀取到之前的cpu socket所管理的內存,這種訪問屬於遠端內存訪問。這種訪問 Socket 直接連接的內存相比,遠端內存訪問會增加應用程序的延遲。
所以多cpu對redis的影響:
- 因為L1,L2緩存中的指令和數據可以提高訪問速度,一旦發生了cpu的切換,同樣的指令和數據需要重新加載到L1和L2緩存中,影響redis的性能。
- 應為每個cpu都有自身控制的內存,一旦發生cpu的切換,就會存在一個cpu需要訪問另一個cpu所管理的內存,出現遠端內存的訪問情況,影響redis的響應時間。
首先我們的redis實例需要很好的網絡性能,redis是如何和操作系統的網絡中斷程序進行交互的呢?
網絡中斷程序從網卡中讀取數據,並將數據寫入到操作系統的內核緩沖區中,內核會通過epoll機制觸發事件,通知到redis實例,redis就會從內核中拉取數據,復制到自己的內存空間中。這個時候就會存在一個潛在影響性能的點,到redis實例和網絡中斷處理程序,在不同的CPU Socket中運行時,redis讀取網絡數據時,就需要跨CPU Socket運行,影響其性能,其流程如下:
所以為了避免redis跨cpu訪問網絡數據,需要將redis實例和網絡中斷程序,綁定在同一個CPU Socket中:
四、綁核存在的風險點
當我們將redis實例綁在一個cpu核上時,redis其后台線程和fork的子進程等都會和redis主線程搶占cpu資源,導致redis主線程變慢,影響性能。
針對這個問題:主要的解決方法有兩種:
- 一個就是redis實例對應綁一個物理核,因為我們的cpu一個物理核有兩個邏輯核,這樣可以把我們的兩個邏輯核都給用上,可以在一定程度上緩解cpu的資源競爭。
- 修改redis源代碼,把子進程和后台線程綁到不同的CPU核上。