天天看點

一個簡單的程式來使用WiredTiger 存儲引擎

前言

WiredTiger 自 mongodb3.0 內建進來之後為mongodb拉回了大量的口碑,進而在mongodb-3.2 版本直接代替了in-memory存儲引擎,作為了mongodb的預設存儲引擎。其 通過支援Append-only btree + lsm-tree 以及 針對磁盤/記憶體資料結構上的多核和無鎖優化,進而擁有了極高的性能,同時支援mongodb基本的事務/備份/time-based 等需求,成為mongodb 的核心動力。

研究wiredtiger 能夠對基本的B-tree/LSM-tree 資料結構的工業實作有極為深刻的了解,而且我們實際測試wired-tiger 能夠提供超過 rocksdb 2-3 倍的讀性能,這裡的測試是有cache和沒有cache場景測的,都有同樣的性能提升(b-tree的查找本身就是比較高效) 和 不弱于rocksdb 的寫性能(append-only btree 也是順序寫,是以仍然需要類似LSM-tree的compact操作)。

當然,在不了解内部核心鍊路的基本流程之前直接看源代碼基本難度很大(百萬級的行數),比rocksdb大一個量級。不過還是貼上源碼位址吧:​​https://github.com/wiredtiger/wiredtiger​​

基本接口

關于 wiredtiger 的編譯和安裝 :

  • on-linux 可以參考​​wiredtiger 編譯安裝​​
  • on-mac 可以直接 brew install wiredtiger

了解整個引擎之前還是先将整個引擎跑一跑,看看運作之後的db資料狀态;跑跑bench-mark,看看性能什麼的,後續梳理出一個roadmap 再進行源碼層級的深入。

如下測試代碼,涵蓋了wiredtiger的基礎db操作的接口:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wiredtiger.h>
static const char *home;

void
CheckOp(const int ret, const char* funcname, const char* home) {
  if (ret != 0) {
    fprintf(stderr, "%s -- Error connecting to %s: %s\n",
          funcname, home, wiredtiger_strerror(ret));
  }
}

int
main(void)
{
  WT_CONNECTION *conn;
  WT_SESSION *session;
  WT_CURSOR *cursor;
  int ret;

  /* 打開一個wiredtiger要操作的db目錄*/
  if (getenv("WIREDTIGER_HOME") == NULL) {
    home = "WT_HOME";
    ret = system("rm -rf WT_HOME && mkdir WT_HOME");
  } else {
    home = NULL;
  }

  /* 打開或者建立資料庫 */
  CheckOp(wiredtiger_open(home, NULL, "create", &conn), "wiredtiger_open", home);
  /* 打開1個資料庫連接配接 */
  CheckOp(conn->open_session(conn, NULL, NULL, &session), "open_session", home);
  /* 建立一張名字為access的表,後續的db檔案會以表的名字來命名 */
  CheckOp(session->create(session, "table:access", "key_format=S,value_format=S"), "create", home);
  /* 建立一個cursor,所有的請求都通過cursor來通路 */
  CheckOp(session->open_cursor(session, "table:access", NULL, NULL, &cursor), "open_cursor", home);

  /* 向一個cursor 插入一個KV */
  cursor->set_key(cursor, "key1");
  cursor->set_value(cursor, "value1");

  char* key = NULL;
  /* 擷取key , 當然,擷取value也是同樣的方式,通過get_value即可*/
  CheckOp(ret = cursor->get_key(cursor, &key),"get_key", home);
  printf("wt key is : %s", key);

  CheckOp(ret = conn->close(conn, NULL),"close", home);
  return (ret);
}      

我是在mac上編譯的: ​

​gcc test_wt.c -o test_wt -lwiredtiger​

​​,如果是linux,直接連結編譯好的​

​libwiredtiger.so​

​​就可以了。

運作之後會生成一個​​

​WT_HOME​

​的db目錄:

╰─$ tree WT_HOME
WT_HOME
├── WiredTiger
├── WiredTiger.basecfg
├── WiredTiger.lock
├── WiredTiger.turtle
├── WiredTiger.wt
├── WiredTigerLAS.wt
└── access.wt      
  1. ​wiredTiger​

    ​ 是wiredTiger的版本資訊或者編譯時間
  2. ​WiredTiger.basecfg​

    ​ wiredTiger的配置資訊
  3. ​WiredTiger.lock​

    ​ lock檔案,防止多個程序連結同一個資料庫(rocksdb的LOCK檔案),單進場獨享的
  4. ​WiredTiger.turtle​

    ​​存儲​

    ​WiredTiger.wt​

    ​檔案的中繼資料資訊
  5. ​access.wt​

    ​ 是實際的表資料,我們在代碼中建立了一個access命名的表
  6. ​WiredTiger.wt​

    ​ 特殊的table,用于存儲其他表資料的中繼資料資訊
  7. ​WiredTigerLAS.wt​

    ​ 這個是與wiredtiger的cache evict 相關的資料檔案,主要是當記憶體使用率高時用于臨時存放不能被逐出到使用者表檔案中的資料,表WiredTigerLAS中的資料會被高優先級逐出到磁盤檔案WiredTigerLAS.wt中。