非易失性記憶體在阿里生產環境的首次應用:Tair NVM最佳實踐總結

趙鈺瑩發表於2018-08-17

本文介紹了非易失性記憶體在阿里巴巴集團生產環境的首次應用:線上執行的情況;使用NVM遇到的問題和最佳化的過程;最後,總結性地給出了基於NVM構建快取服務的設計要點,希望這些實踐總結能對大家的工作有所啟發。

簡介

Tair MDB是阿里巴巴生態系統內廣泛使用的快取服務,它採用非易失性記憶體 Non-volatile memory (NVM)作為DRAM的補充,輔助DRAM作為後端儲存介質,從天貓618購物節開始在生產環境上線灰度,經歷了2次全鏈路壓測,至今執行穩定。在使用NVM的過程中,Tair MDB遇到了寫不均衡、鎖開銷等問題,經過最佳化之後取得了非常顯著的效果。

透過這一系列最佳化工作和生產環境的實踐,Tair工程團隊總結出了一些在Non-volatile memory (NVM) / Persistent memory (PMEM)上實現快取服務的設計準則,相信這些準則對其它有意願使用Non-volatile memory來進行最佳化的產品會非常有指導意義。

背景

Tair Mdb主要服務於快取場景,在阿里巴巴集團內部有著大量的部署和使用。隨著使用者態網路協議棧、無鎖資料結構等特性的引入,單機QPS極限能力已經達到了1000w+的級別。Tair Mdb所有的資料都是儲存在記憶體中,隨著單機QPS極限能力的上升,記憶體容量逐漸成為限制叢集規模的主要因素。

NVM產品單根DIMM的容量相對於DRAM DIMM要大很多,價格相對於DRAM更有優勢,將Tair Mdb的資料存放在NVM上,是突破單機記憶體容量的限制的一個方向。

生產環境

效果

端到端,讀寫平均延時和相同軟體版本下使用DRAM的節點資料持平;服務行為表現正常。生產環境的壓力並沒有達到Tair MDB節點的極限,後面的章節會介紹壓測時我們遇到的問題和解決方案。

成本

前面提到了單根NVM DIMM最大容量比DRAM DIMM要高,相同容量的價格會比DRAM便宜。Tair MDB容量型的叢集,如果採用NVM來補充記憶體容量的不足,規模可以大幅減少。算上機器價格、電費、機架等因素,成本大約可以降低30% ~ 50%左右 。

原理

使用方式

Tair MDB使用NVM裝置的方式,是把NVM以塊裝置的形式使用Pmem-Aware File System掛載(DAX掛載模式)。分配NVM空間對應的操作是在對應的檔案系統路徑上建立並開啟檔案,使用posix_fallocate分配空間。

記憶體分配器

NVM本身具備非易失的特性,對於快取服務Tair MDB,是把NVM當作易失性裝置,不需要去考慮操作的原子性和crash之後的recovery操作,也不需要顯式地呼叫clflush/clwb等命令將CPU Cache中的內容強制刷回介質。

使用DRAM空間時,有tcmalloc/jemalloc等記憶體分配器可供選擇,現在NVM的空間暴露給上層的是一個檔案(或者是一個字元裝置),所以如何使用記憶體分配器是首先需要考慮的事情。開源專案pmem[1]中維護了易失性的記憶體管理庫libmemkind,有易用的類malloc/free的API,大部分應用接入時可以考慮這種方式。

Tair MDB在實現時並沒有使用libmemkind[2]。下面介紹Tair MDB的記憶體佈局,說明做出這種選擇的原因。

記憶體佈局

Tair MDB在記憶體管理上使用了slab機制,不是在使用時動態地分配匿名記憶體,而是在系統啟動時先分配一大塊記憶體,內建的記憶體管理模組會把後設資料、資料頁等在這一大塊記憶體上連續分佈,如下圖所示:

Tair MDB使用的記憶體主要分為以下幾部分:

  • Cache Meta,存放了一些最大分片數之類的後設資料資訊,還有Slab Manager的索引資訊。

  • Slab Manager,每個Slab Manager中管理固定大小的Slab。

  • Hashmap,全域性雜湊表索引,使用線性衝突鏈的方式處理雜湊衝突,所有key的訪問都需要經過Hashmap。

  • Page pool,記憶體池,啟動之後會將記憶體劃分成以1M為單位的頁,Slab Manager會從Page pool中申請頁,並格式化成指定的slab大小。

Tair Mdb會在啟動時對所有可用的記憶體進行初始化,後續資料儲存部分不需要動態地從作業系統分配記憶體了。

在使用NVM時,把對應的檔案mmap到記憶體,獲取虛擬地址空間,內建的記憶體管理模組就可以透明地利用這塊空間了。所以在這個過程中,並不需要再呼叫malloc/free來管理NVM裝置上的空間。

壓測

Tair MDB在使用NVM作為DRAM的補充,輔助DRAM作為後端儲存之後,在壓測過程中遇到了一些問題,在這一章節會介紹這些問題的具體表現和最佳化的方法。

問題

使用了NVM之後,使用100 bytes的條目對Tair MDB進行了壓測,得到如下的資料:

引擎內延遲

客戶端觀測QPS

基於NVM的Read QPS /latency和DRAM相當,Write TPS大概是DRAM的1/3。

分析

寫效能的損耗從perf的結果上看都在鎖上,這個鎖管理的臨界區包含的是對上文記憶體佈局中提到的Page的寫操作。懷疑這種情況是NVM上的寫延遲比DRAM上高導致的。

在壓測的過程中,使用pcm[3]檢視NVM DIMMS的頻寬統計,觀察到在某一根DIMM上的寫非常不均衡,穩定情況下大約是其它DIMM的兩倍。

具體情況如下圖所示:

這裡先大概介紹下NVM DIMM的放置策略。

放置策略

現在使用單socket放置了4根 NVM DIMM,具體分佈類似下圖:

這種放置策略被稱為2-2-1。每一個socket有4根 DIMM,分別屬於四個不同的通道。在使用多個通道時,為了有效利用記憶體頻寬CPU會進行interleave。當前放置策略和配置下,CPU以4K為單位,按照DIMM順序進行interleave。

不均衡原因

從memory interleaving的策略,可以推斷每次都會寫同一個區域,而這片區域位於那根不均衡的DIMM上,導致這根DIMM的寫入量會明顯高於其它的DIMM。

那麼接下來需要解決的問題就是找到導致寫熱點的處理邏輯。trivial的方法就是找些可疑的點,然後一個個排除下去,下面介紹下Tair工程團隊使用的方法。

最佳化

上面提到了,寫熱點導致NVM DIMM訪問不均衡,所以最佳化的第一步是先把寫熱點找出來,進行一些處理,比如說打散熱點訪問,或者把熱點訪問的區域放到DRAM中。

查詢寫熱點

對於寫熱點的查詢,Tair工程團隊使用了Pin[4]。上面提到Tair MDB是對檔案進行mmap獲取邏輯地址來操作記憶體。於是我們可以使用Pin抓取mmap的返回值,進而得到NVM在程式記憶體空間中的邏輯地址。之後我們繼續使用Pin對所有操作記憶體的程式指令進行插樁,統計對NVM對映到的地址空間中的每個位元組的寫入次數。

最終,發現寫熱點的確存在,相應的區域是Page的後設資料。解決寫熱點的方案考慮過:加padding把熱點交錯到各個DIMM上、基本一樣熱的資料分DIMM存放、將熱點移回DRAM等,最終選擇將slab_manager和page_info移回DRAM。修改後結構如下:

至此,不均衡問題解決,TPS從85w提升至140w,此時引擎內寫延遲從40us降低到12us。

鎖開銷過大

當TPS在140w時,注意到上面提到過的pthread_spin_lock的開銷依然非常大。透過perf record的結果可以看到,pthread_spin_lock消耗的呼叫棧是:

透過分析batch_alloc_item發現臨界區內對page中item的初始化操作會對NVM產生大量寫入。由於NVM的寫入速度比DRAM慢,所以這裡成為一個很耗時的地方。

其實按照Tair MDB的邏輯,只有將page link進slab_manager的時候才需要加鎖。因此這裡將對item的初始化操作移出臨界區。之後又對Tair MDB程式碼中臨界區內所有對NVM的寫入操作進行了排查,並進行了相應的最佳化。

最佳化之後pthread_spin_lock開銷降低到正常範圍內,TPS提升至170w,此時引擎內寫延遲為9us。

最佳化結果

均衡寫負載、鎖粒度細化等最佳化有效地降低了Latency,TPS上升到了170w,相較之前的資料,TPS提高了100%。由於介質的差異,和DRAM的寫效能相比依然有30%左右的差距,但是對於快取服務讀多寫少的場景,這個差距對整體的效能並不會有太大的影響。

設計指引

基於上述的最佳化工作和生產環境的實踐,Tair工程團隊總結了基於NVM實現快取服務的設計準則,這些準則是和使用的硬體特性有緊密聯絡的。

硬體特性

對快取服務設計有影響的特有的NVM硬體特性:

  • 相對於DRAM密度更高,更便宜

  • 延遲相較DRAM高,頻寬比DRAM低

  • 讀寫不均衡,寫延遲相較讀高

  • 硬體有磨損,頻繁寫單一位置會加大磨損

設計準則

準則A:避免寫熱點

Tair MDB在使用NVM的過程中遇到過寫熱點的問題,寫熱點會加大介質的磨損,而且會導致負載不均衡(寫壓力在某一根DIMM上,不能充分利用所有DIMM的頻寬)。除了記憶體佈局(後設資料和資料混合存放)會導致寫熱點外,業務的訪問行為也會導致寫熱點。

這裡,Tair工程團隊總結了幾種避免寫熱點的方法:

  • 分離後設資料和資料,將後設資料移到DRAM中。後設資料訪問頻率會相對於資料更高,前面提到的Tair MDB 中page_info屬於後設資料。這樣可以從上層緩解NVM寫延遲相較DRAM高的劣勢。

  • 上層實現Copy-On-Write的邏輯。這樣在一些場景下會減少對特定區域硬體的磨損,Tair MDB中更新一條資料時,並不會in-place update之前的條目,而是會新增條目新增到hashmap衝突鏈的頭部,非同步刪除之前的條目。

  • 常態檢測熱點寫,動態遷移到DRAM,執行寫合併。對於上面提到的業務訪問行為導致的熱點寫,Tair MDB會常態化檢測熱點寫,並把熱點寫進行合併,減少對下層介質的訪問。

準則B:減少臨界區訪問

由於NVM的寫延遲相較DRAM高,所以當臨界區中包含了對NVM的操作時,臨界區的影響會放大,導致上層的併發度降低。

前面提到的鎖開銷,Tair MDB執行在DRAM上時並沒有觀測到,原因是執行在DRAM上,假設了這個臨界區的開銷比較小,但是使用NVM時,這個假設不成立了。這也是在使用新介質時經常會遇到的問題,以往軟體流程中可能沒有意識到的一些假設,在新介質上不成立了,這時候就需要對原有的流程進行一些調整。

鑑於上面的原因,Tair工程團隊建議快取服務使用NVM時,應該儘量地結合資料儲存做無鎖化的設計,減少臨界區的訪問,規避延遲升高帶來的級聯影響。

Tair MDB引入了使用者態RCU,對大部分訪問路徑上的操作進行了無鎖化改造,極大地降低了NVM延遲對上層帶來的影響。準則C:實現合適的分配器

分配器是業務使用NVM裝置的基礎元件,分配器的併發度會直接影響軟體的效率,分配器的空間管理會決定空間利用率。設計實現或者選擇適合於軟體特性的分配器,是快取服務使用NVM的關鍵。

從Tair MDB的實踐上來看,適用於NVM的分配器應該具備以下功能和特性:

  • 碎片整理:由於NVM有密度更高、容量更大,所以在相同碎片率下,相較於DRAM會浪費更多的空間。由於碎片整理機制的存在,所以需要上層應用避免in-place update,而且儘量保證分配器分配的空間是fixed size。

  • 需要有Threadlocal的quota:和上面說的減小臨界區訪問類似,如果沒有Threadlocal的quota,從全域性的資源池中分配資源的延時會降低分配操作的併發度。

  • Capacity-aware,分配器需要感知所能管理的空間: 快取服務需要對管理的空間進行擴容或者縮容,分配器需要提供相應的功能以適配這個需求。

以上這些設計準則都是在實踐中檢驗過,切實可行,而且會對應用帶來有利的影響,相信對其它希望使用NVM的產品也會有非常大的幫助。

未來的工作

上面提到了Tair MDB使用NVM時還是當作易失性的裝置,利用了密度大價格低的優勢來降低整體服務的成本。未來Tair工程團隊會致力於更好地利用NVM的非易失特性,挖掘新硬體的紅利,賦能於業務和其它上層的服務。

本文是阿里巴巴集團儲存技術事業部Tair團隊關於NVM的系列分享的開篇,接下來會陸續推出我們在NVM領域的思考和成果。

分散式線上儲存系統Tair 專注於承擔超大流量下的線上訪問加速,阿里巴巴集團大規模使用,在每秒數億次訪問請求的背後,提供著超低延時的響應。場景包括各類線上快取,記憶體資料庫,高效能持久化NoSQL資料庫等,在高併發,快速響應和高可用上追求極致。在這裡,你會遇到億級別訪問的尖峰時刻,不同型別業務錯綜複雜的場景需求,萬臺規模伺服器叢集的運營支撐,業務全球化等各類技術挑戰。


本文作者

漠冰(付秋雷),阿里巴巴集團儲存技術事業部技術專家,主要關注於分散式快取、NoSQL資料庫。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/31077337/viewspace-2200254/,如需轉載,請註明出處,否則將追究法律責任。

相關文章