譯文:ovs+dpdk中的“vHost User NUMA感知”特性

張浮生發表於2017-06-28
  本文描述了“vHost User NUMA感知”的概念,該特性的測試表現,以及該特性為ovs+dpdk帶來的效能提升。本文的目標受眾是那些希望瞭解ovs+dpdk底層細節的人,如果你正在使用ovs+dpdk在NUMA host上配置虛擬化平臺,使用vHost User型別的port作為guest的虛擬網路配置,那麼本文或許會給你一些優化效能的靈感。
 
  注意:在本文成文之際,vHost User NUMA感知這個特性僅在OVS master分支上可用。要下載OVS master分支,請戳這裡。要獲取ovs+dpdk的配置步驟,請戳這裡
 

vHost User NUMA感知

  vHost User NUMA感知特性在DPDK 2.2版本時引入,該特性的引入是為了解決DPDK中的一個拖後腿的地方:在多NUMA節點的環境中使用DPDK,vHost的記憶體分配效率比較低。為了瞭解這個拖後腿的點,我們先必須瞭解vHost User裝置使用的三種記憶體:
  • 由DPDK分配管理的記憶體,Device tracking memory
  • 由OVS分配管理的記憶體,mbufs
  • 由QEMU管理分配的記憶體,Guest memory(device and memory buffers)
  在多NUMA節點環境中,顯然如果要優化效能,這三種記憶體應當分配在同一個NUMA節點上。但就這個小小的要求,在DPDK 2.2版本之前都是不可能達到的,因為在2.2版本之前,所有由DPDK分配管理的Device tracking memory記憶體,都來自同一個NUMA節點,即便使用這些記憶體的vHost User裝置被其它NUMA節點上跑著的虛擬機器使用著。這就會有一種尷尬的場景出現:一臺虛擬機器,QEMU為它分配的guest memory在節點A上,而DPDK的device tracking memory在另外一個節點B上。這種尷尬的場景會直接導致Intel QuickPath Interconnect(QPI)堵車,顯然也會有其它方面潛在的效能損耗。這個場景的示意圖如下:

 

 
  在DPDK 2.2版本之後,DPDK中的vHost結構被優化成了動態的與QEMU管理的guest memory貼在一起。這時,當一個vHost裝置出生的時候,DPDK為它分配的記憶體不再固定,變得有點像一個臨時記憶體區,這個vHost裝置將在這個臨時記憶體區開心的活著,直到QEMU通知DPDK:“嘿,小同志,我需要一個vHost裝置”。當QEMU向DPDK索取一個vHost裝置的時候,顯然QEMU需要向DPDK傳送訊息,而DPDK就可以利用這個訊息去確定這個索要vHost裝置的虛擬機器位於哪個NUMA節點,之後,這個vHost裝置的記憶體也將遷移至這個NUMA節點上。
  換句話說,vHost裝置出生時居住在一個臨時住所,直至QEMU前來領養它,之後它才有一個穩定的家。
 
  現在我們解決了2/3的問題,還有一部分記憶體上文沒有提到,那就是由OVS分配管理的mbufs。這些記憶體由OVS分配管理,旨在提高datapath的執行效率,為了優化效能,顯然它們也應當與QEMU及DPDK管理分配的記憶體位於內一個NUMA節點上。目前,這個功能由DPDK向OVS傳送訊息實現,DPDK會向OVS傳送有關虛擬機器依存的NUMA節點資訊的訊息,之後OVS將把mbufs使用的記憶體分配在正確的NUMA節點上。在DPDK向OVS傳送這些訊息之前,mbufs的記憶體始終分配在DPDK master lcore所在的NUMA節點上。
 
  現在三部分記憶體都位於同一個NUMA節點了,還剩下最後一個問題:PMD輪詢執行緒(poll mode driver threads)。
  PMD輪詢執行緒是一些比較苦逼的執行緒,它們日夜不停馬不停蹄的輪詢input ports,對收到的包進行分類,並對包執行相應的actions。在“vHost User NUMA感知”特性出現之前,所有OVS中的PMD輪詢執行緒都住在同一個NUMA節點上,即是DPDK的master lcore所在的NUMA節點。終於,現在,社會解放了,好日子來了,PMD輪詢執行緒和mbufs、guest memory、device tracking memory呆在同一個NUMA節點了。
  下圖展示了三塊記憶體及PMD輪詢執行緒位於同一個NUMA節點時的場景:

 

 
效能測試環境
測試環境需要一個至少有兩個NUMA節點的host。上面跑著ovs+dpdk,ovs-bridge上有兩個vHost User裝置,我們稱之分別為vhost0與vhost1。兩個虛擬機器跑在不同的NUMA節點上,分別稱之為vm0與vm1。vhost0與vm0是一對,vhost1與vm1是一對。
下面是測試環境的規格:
Processor          E5-2695 v3
Kernel             4.2.8-200
OS                 Fedora* 22
QEMU*              2.6.0
DPDK               16.04
OVS                914403294be2
 
測試環境配置過程
  在安裝DPDK與OVS之前,確保NUMA庫已安裝
sudo yum install numactl-libs
sudo yum install numactl-devel

  確保編譯DPDK時開啟了以下的配置項

CONFIG_RTE_LIBRTE_VHOST_NUMA=y

  編譯DPDK

  連結DPDK庫,編譯OVS
  這些都沒啥可說的,畢竟裝了幾百回了,閉著眼睛也會做了。
  配置ovs-bridge,就像上面說的那樣:建立一個ovs-bridge,在下面建立兩個ovs-port,型別為dpdkvhostuser或dpdkvhostuserclient。設定ovs的other_config:pmd-cpu-mask掩碼時,為兩個NUMA節點雨露均沾,平均分配。比如,在一個28個邏輯核心的機器上,0~13號核心在NUMA節點0上,14~17號核心在NUMA節點1上,那麼如下設定就是雨露均沾:
ovs-vsctl set Open_vSwitch . other_config:pmd-cpu-mask=10001
# 10001是16進位制,翻譯成二進位制是10000000000000001,即PMD輪詢執行緒的核心親合設定為0號核心與16號核心兩個核心,其中0號核心位於NUMA節點0,1號核心位於NUMA節點1
# 這篇文章比較奇怪,只有一個cpu socket,這個cpu型號,即E5 2695 v3是14核心28執行緒的,按理來說應該只有一個numa節點啊。難道用一個cpu socket也能組兩個numa節點?

  在啟動虛擬機器之前,使用如下命令檢查一個pmd設定

ovs-appctl dpif-netdev/pmd-rxq-show

  在啟動虛擬機器之前,QEMU還沒有分配記憶體,也肯定談不上發訊息給DPDK,DPDK就更談不上發訊息給OVS了,所以此時這時PMD執行緒將落在同一個NUMA節點上,顯示如下:

pmd thread numa_id 0 core_id 0:
        port: dpdkvhostuser1    queue-id: 0
        port: dpdkvhostuser0    queue-id: 0
  然後啟動虛擬機器,在兩個NUMA節點上分別啟動vm0與vm1,下面以qemu為例,為了確保兩個虛擬機器分別跑在兩個NUMA節點上,使用taskset命令,如下:
sudo taskset 0x2 qemu-system-x86_64 -name vm0 -cpu ...
sudo taskset 0x2000 qemu-system-x86_64 -name vm1 -cpu ...

  這時檢視虛擬機器的log,vm1會列印出如下的log:

VHOST_CONFIG: read message VHOST_USER_SET_VRING_ADDR
VHOST_CONFIG: reallocate vq from 0 to 1 node
VHOST_CONFIG: reallocate dev from 0 to 1 node

  出現上面這樣的log就意味著DPDK的device tracking memory被從臨時住所挪到了正確的NUMA節點上

  另外一個驗證方法是使用pmd-rxq-show工具,顯示如下:
pmd thread numa_id 1 core_id 20:
        port: dpdkvhostuser1    queue-id: 0
pmd thread numa_id 0 core_id 0:
        port: dpdkvhostuser0    queue-id: 0
  dpdkvhostuser1現在被一個位於NUMA節點1上的執行緒服務著,這也正是vm1所在的NUMA節點
 
 
 
 
 
 
 
 
 
 

相關文章