Tair mdb 存儲引擎的實現

BriBailey 8年前發布 | 17K 次閱讀 分布式/云計算/大數據

來自: http://www.0xffffff.org/2015/03/28/35-Tair-mdb-analyse/


Tair是一個高性能、分布式、可擴展、高可靠的NoSQL存儲系統。本文基于Tair v3.1.2.43版本,探究其mdb存儲引擎的實現。

Tair目前有mdb、ldb和rdb等存儲引擎。其中mdb是Tair最早的一款內存型產品,也是在公司內部應用最廣泛的集中式緩存。特別適用容量小(一般在M級別,50G之內),讀寫QPS高(萬級別)的應用場景。由于是內存型產品,因此無法保證數據的安全性,對數據安全有要求的應用建議在后端加持久化數據源(例如MySQL)。本文接下來詳細討論Tair mdb存儲引擎的實現。

Tair的存儲引擎接口是src\storage\storage_manager.hpp里的虛基類storage_manager。所有的Tair存儲引擎均繼承實現了storage_manager這個虛基類。src\dataserver\tair_manager.cpp文件中的tair_manager::initialize函數根據配置文件中storage_engine的設置初始化相應的存儲引擎。

mdb引擎默認使用POSIX共享內存的方式進行內存的分配和管理。mdb引擎會在初始化的時候創建或者使用已存在的共享內存。其配置使用內存的方式和共享內存命名的前綴均在其配置文件中進行設置。如圖所示:

src\storage\mdb目錄是mdb存儲引擎的實現,這里的實現、測試和接口文件都放在同一個目錄中。其中有關mdb存儲實現的文件如下:

◇ db_define.{hpp,cpp} —— mdb引擎相關的配置信息和定義。
◇ mdb_factory.{hpp,cpp} —— mdb引擎初始化工廠類的實現。
◇ mdb_manager.{hpp,cpp} —— mdb引擎管理結構的實現。
◇ mdb_instance.{hpp,cpp} —— mdb實例相關的實現。
◇ mem_cache.{hpp,cpp}  —— MemCache結構的實現。
◇ mem_pool.{hpp,cpp} —— MemPool結構的實現。
◇ cache_hashmap.{hpp,cpp} —— 全局緩存KV結構映射的Hash表的實現。
◇ mdb_stat_manager.{hpp,cpp} —— mdb引擎狀態管理相關實現。
◇ mdb_stat.hpp —— mdb引擎讀取寫入統計的相關數據結構的定義和實現。
◇ lock_guard.hpp —— pthread_mutex_t的簡單RAII封裝。

其中mdb_define.{hpp,cpp}里定義了mdb引擎的配置變量,打開共享內存的操作函數以及獲取時間、判斷當前時間的hour是否在給定區間等函數。

mdb_factory.{hpp,cpp}用于創建mdb引擎,mdb_factory.hpp中定義的接口如下:

create_mdb_manager讀取配置文件中的配置信息,然后創建mdb_manager對象并返回。這個函數在src\dataserver\tair_manager.cpp文件中的tair_manager::initialize函數中被調用。

mdb_manager.{hpp,cpp}定義了mdb引擎管理類mdb_manager的實現,mdb_manager類繼承自storage_manager虛基類,實現了相關的虛函數接口。其定義std::vector<mdb_instance*>結構保存所有的mdb實例。mdb_instance類在mdb_instance.{hpp,cpp}中定義和實現。mdb_manager類的initialize函數會調用init_area_stat函數創建/打開名為mdb_param::mdb_path+".stat這個存儲mdb引擎狀態信息的共享內存塊,其大小為TAIR_MAX_AREA_COUNT * sizeof(mdb_area_stat)。然后會根據配置文件里的實例個數信息創建mdb_instance實例。配置如下:

mdb_instance創建時會創建名為mdb_param::mdb_path+".000"開始計數的共享內存塊。創建的實例中bucket的個數由以下配置決定:

mdb_instancemem_cachemem_poolcache_hashmap這幾個類構成了mdb存儲引擎的核心。創建完成后,其包含指向關系如下:

對應的內存結構圖大致如下:

其中MemPool以頁的形式管理通過共享內存分配的內存,分配或者釋放一個內存頁。其定義了uint8_t page_bitmap[BITMAP_SIZE],以位的形式來管理內存頁;MemCache比頁低一級,采用slab算法將內存分配給具體的item;HashTable以一個巨大的Hash表存儲key的映射關系。下面闡述對共享內存具體的分配情況。內存布局如圖所示:

cache meta的結構如下:

hash buckets的結構如下:

slab use這里,當前的代碼實際上僅放置了一個mdb_cache_info:

下面是內存管理結構中的一些定義:

mdb_id的定義:

其中item_id的圖示如下:

一些換算關系如下:

page_addr = S0 + (page_id * page_size) item_addr = S0 + (page_id * page_size) + sizeof(page_info) + (slab_size * offset_in_page)

最后是slab分配器和K/V存儲相關的細節。mem_cache類使用slab_manager類對從mem_pool中申請到的內存頁進行管理。頁信息的結構定義如下:

mem_cache里的pages被放置在三個鏈表中,分別是Free頁鏈表、Full頁鏈表和Partial頁鏈表。Free頁鏈表、Full頁鏈表是簡單的雙向鏈表,用于鏈接空頁和滿頁。Partial頁鏈表如下圖:

下圖是不同的Area里放置item的圖示:

最后剩下的mdb_stat_manager.{hpp,cpp}mdb_stat.hpp定義和實現了訪問統計相關的功能,其創建的共享內存塊為相應的mdb實例的名稱+”mdbstat”,此處不再贅述。

 本文由用戶 BriBailey 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!