测试环境简单说明

Windows下测试

硬件环境如下:
处理器:Intel(R) Core(TM) i5-4460 CPU @ 3.20GHz
内 存:8GB
硬 盘:希捷 ST1000DM003
操作系统:Windows 10 企业版
编译说明:
两个都是使用VS2015编译的64位Release版本。运行时库采用动态多线程版本(MD)

Linux下测试

硬件环境如下:
处理器:Intel(R) Core(TM) i7-4500U CPU @ 1.80GHz
内 存:8GB
硬 盘:金士顿64G SSD
操作系统:ArchLinux (Linux version 4.8.13-1-ARCH)
编译说明:
两个都是使用Gcc 6.2.1编译的x64版本,使用-O2参数优化。

测试结果

LevelDBForestDB进行简单的性能测试。
两个都在单线程下进行10000次的增删查改测试,共测试5次。(这里测试的次数有点少,应该测试十万次以上的)
测试的时候可以发现(设置断点),Forest每次操作都将数据缓存在内存了,内存占用比较大。而LevelDB在添加的时候并没有缓存,但是在数据获取和修改的时候内存会变大。
总体上LevelDB占用内存小一点,但是linux下速度不及ForestDB(非常接近)。易用程度上,LevelB简单得多。磁盘占用的情况的话,Forest对磁盘使用比较少,这10000条数据占了13MB左右,而LevelDB则占了120MB左右。

Windows下测试结果

测试结果平均值对比直方图:
【20180701】LevelDB和ForestDB简单性能测试(含代码) - 图1

LevelDB 测试结果截图
【20180701】LevelDB和ForestDB简单性能测试(含代码) - 图2

ForestDB 测试结果截图
【20180701】LevelDB和ForestDB简单性能测试(含代码) - 图3

Linux下测试结果

测试结果平均值对比直方图:
【20180701】LevelDB和ForestDB简单性能测试(含代码) - 图4

LevelDB 测试结果截图
【20180701】LevelDB和ForestDB简单性能测试(含代码) - 图5

ForestDB 测试结果截图
【20180701】LevelDB和ForestDB简单性能测试(含代码) - 图6

测试代码

LevelDB测试代码

  1. #include <cassert>
  2. #include <string>
  3. #include <iostream>
  4. #include <chrono>
  5. #include "leveldb/db.h"
  6. #define TEST_FREQUENCY (10000)
  7. char* randomstr()
  8. {
  9. static char buf[1024];
  10. int len = rand() % 768 + 255;
  11. for (int i = 0; i < len; ++i) {
  12. buf[i] = 'A' + rand() % 26;
  13. }
  14. buf[len] = '\0';
  15. return buf;
  16. }
  17. int main()
  18. {
  19. leveldb::DB* db;
  20. leveldb::Options options;
  21. options.create_if_missing = true;
  22. // 打开数据库
  23. leveldb::Status status = leveldb::DB::Open(options, "./testdb", &db);
  24. assert(status.ok());
  25. srand(2017);
  26. std::string k[TEST_FREQUENCY];
  27. for (int i = 0; i < TEST_FREQUENCY; ++i) {
  28. k[i] = (randomstr());
  29. }
  30. std::string v("壹贰叁肆伍陆柒捌玖拾");
  31. v.append(v).append(v).append(v).append(v).append(v);
  32. // 测试添加
  33. {
  34. auto start = std::chrono::system_clock::now();
  35. for (int i = 0; i < TEST_FREQUENCY; ++i) {
  36. status = db->Put(leveldb::WriteOptions(), k[i], v);
  37. assert(status.ok());
  38. }
  39. auto end = std::chrono::system_clock::now();
  40. auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start);
  41. std::cout << TEST_FREQUENCY <<"次添加耗时: "
  42. << double(duration.count()) * std::chrono::microseconds::period::num / std::chrono::microseconds::period::den
  43. << "秒" << std::endl;
  44. }
  45. // 测试获取
  46. {
  47. auto start = std::chrono::system_clock::now();
  48. std::string v2[TEST_FREQUENCY];
  49. for (int i = 0; i < TEST_FREQUENCY; ++i) {
  50. status = db->Get(leveldb::ReadOptions(), k[i], &v2[i]);
  51. assert(status.ok());
  52. }
  53. auto end = std::chrono::system_clock::now();
  54. auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start);
  55. std::cout << TEST_FREQUENCY <<"次获取耗时: "
  56. << double(duration.count()) * std::chrono::microseconds::period::num / std::chrono::microseconds::period::den
  57. << "秒" << std::endl;
  58. // 验证获取结果是否正确
  59. std::string ss;
  60. for (int i = 0; i < TEST_FREQUENCY; ++i) {
  61. if (v2[i] != v) {
  62. std::cout << "第 " << i << " 个结果不正确" << std::endl;
  63. std::cout << v2[i] << std::endl;
  64. }
  65. }
  66. }
  67. // 测试修改
  68. {
  69. auto start = std::chrono::system_clock::now();
  70. v.append(v);
  71. for (int i = 0; i < TEST_FREQUENCY; ++i) {
  72. status = db->Put(leveldb::WriteOptions(), k[i], v);
  73. assert(status.ok());
  74. }
  75. auto end = std::chrono::system_clock::now();
  76. auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start);
  77. std::cout << TEST_FREQUENCY <<"次修改耗时: "
  78. << double(duration.count()) * std::chrono::microseconds::period::num / std::chrono::microseconds::period::den
  79. << "秒" << std::endl;
  80. }
  81. // 测试删除
  82. {
  83. auto start = std::chrono::system_clock::now();
  84. for (int i = 0; i < TEST_FREQUENCY; ++i) {
  85. status = db->Delete(leveldb::WriteOptions(), k[i]);
  86. assert(status.ok());
  87. }
  88. auto end = std::chrono::system_clock::now();
  89. auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start);
  90. std::cout << TEST_FREQUENCY <<"次删除耗时: "
  91. << double(duration.count()) * std::chrono::microseconds::period::num / std::chrono::microseconds::period::den
  92. << "秒" << std::endl;
  93. }
  94. delete db;
  95. return 0;
  96. }

Forest 测试代码

  1. #include <cassert>
  2. #include <string>
  3. #include <iostream>
  4. #include <chrono>
  5. #include "libforestdb/forestdb.h"
  6. #define TEST_FREQUENCY (10000)
  7. char* randomstr()
  8. {
  9. static char buf[1024];
  10. int len = rand() % 768 + 255;
  11. for (int i = 0; i < len; ++i) {
  12. buf[i] = 'A' + rand() % 26;
  13. }
  14. buf[len] = '\0';
  15. return buf;
  16. }
  17. int main()
  18. {
  19. fdb_file_handle* fdbFileHandle = nullptr;
  20. fdb_kvs_handle* fdbKvsHandle = nullptr;
  21. fdb_status status;
  22. // 初始化ForestDB
  23. // 1、文件配置设置配置
  24. fdb_config fileConfig = fdb_get_default_config();
  25. {// WAL阈值4K
  26. fileConfig.wal_threshold = 4096;
  27. // 缓存大小64MB
  28. fileConfig.buffercache_size = 64 * 1024 * 1024;
  29. // 设置使用默认的kvs
  30. fileConfig.multi_kv_instances = false;
  31. // 关闭循环块复用
  32. fileConfig.block_reusing_threshold = 100;
  33. // 使用序列树
  34. fileConfig.seqtree_opt = FDB_SEQTREE_USE;
  35. }
  36. // 2、使用设置的配置进行初始化
  37. status = fdb_init(&fileConfig);
  38. assert(status == FDB_RESULT_SUCCESS);
  39. // 打开数据库
  40. status = fdb_open(&fdbFileHandle, "./testdb", &fileConfig);
  41. assert(status == FDB_RESULT_SUCCESS);
  42. // 打开kvs
  43. fdb_kvs_config kvsConfig = fdb_get_default_kvs_config();
  44. status = fdb_kvs_open_default(fdbFileHandle, &fdbKvsHandle, &kvsConfig);
  45. assert(status == FDB_RESULT_SUCCESS);
  46. srand(2017);
  47. std::string k[TEST_FREQUENCY];
  48. for (int i = 0; i < TEST_FREQUENCY; ++i) {
  49. k[i] = (randomstr());
  50. }
  51. std::string v("壹贰叁肆伍陆柒捌玖拾");
  52. v.append(v).append(v).append(v).append(v).append(v);
  53. // 测试添加
  54. {
  55. auto start = std::chrono::system_clock::now();
  56. for (int i = 0; i < TEST_FREQUENCY; ++i) {
  57. status = fdb_set_kv(fdbKvsHandle, k[i].data(), k[i].size(), v.data(), v.size());
  58. assert(status == FDB_RESULT_SUCCESS);
  59. }
  60. // 提交操作到磁盘(这里必须commit才能实际写入到磁盘)
  61. fdb_commit(fdbFileHandle, FDB_COMMIT_NORMAL);
  62. auto end = std::chrono::system_clock::now();
  63. auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start);
  64. std::cout << TEST_FREQUENCY <<"次添加耗时: "
  65. << double(duration.count()) * std::chrono::microseconds::period::num / std::chrono::microseconds::period::den
  66. << "秒" << std::endl;
  67. }
  68. // 测试获取
  69. {
  70. auto start = std::chrono::system_clock::now();
  71. void* v2[TEST_FREQUENCY]; size_t v2len[TEST_FREQUENCY];
  72. for (int i = 0; i < TEST_FREQUENCY; ++i) {
  73. status = fdb_get_kv(fdbKvsHandle, k[i].data(), k[i].size(), &v2[i], &v2len[i]);
  74. assert(status == FDB_RESULT_SUCCESS);
  75. }
  76. auto end = std::chrono::system_clock::now();
  77. auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start);
  78. std::cout << TEST_FREQUENCY <<"次获取耗时: "
  79. << double(duration.count()) * std::chrono::microseconds::period::num / std::chrono::microseconds::period::den
  80. << "秒" << std::endl;
  81. // 验证获取结果是否正确
  82. std::string ss;
  83. for (int i = 0; i < TEST_FREQUENCY; ++i) {
  84. ss.assign((const char*)v2[i], v2len[i]);
  85. if (ss != v) {
  86. std::cout << "第 " << i << " 个结果不正确" << std::endl;
  87. std::cout << ss << std::endl;
  88. }
  89. free(v2[i]);
  90. }
  91. }
  92. // 测试修改
  93. {
  94. auto start = std::chrono::system_clock::now();
  95. v.append(v);
  96. for (int i = 0; i < TEST_FREQUENCY; ++i) {
  97. status = fdb_set_kv(fdbKvsHandle, k[i].data(), k[i].size(), v.data(), v.size());
  98. assert(status == FDB_RESULT_SUCCESS);
  99. }
  100. // 提交操作到磁盘(这里必须commit才能实际写入到磁盘)
  101. fdb_commit(fdbFileHandle, FDB_COMMIT_NORMAL);
  102. auto end = std::chrono::system_clock::now();
  103. auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start);
  104. std::cout << TEST_FREQUENCY <<"次修改耗时: "
  105. << double(duration.count()) * std::chrono::microseconds::period::num / std::chrono::microseconds::period::den
  106. << "秒" << std::endl;
  107. }
  108. // 测试删除
  109. {
  110. auto start = std::chrono::system_clock::now();
  111. for (int i = 0; i < TEST_FREQUENCY; ++i) {
  112. status = fdb_del_kv(fdbKvsHandle, k[i].data(), k[i].size());
  113. assert(status == FDB_RESULT_SUCCESS);
  114. }
  115. // 提交操作到磁盘(这里必须commit才能实际写入到磁盘)
  116. fdb_commit(fdbFileHandle, FDB_COMMIT_NORMAL);
  117. auto end = std::chrono::system_clock::now();
  118. auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start);
  119. std::cout << TEST_FREQUENCY <<"次删除耗时: "
  120. << double(duration.count()) * std::chrono::microseconds::period::num / std::chrono::microseconds::period::den
  121. << "秒" << std::endl;
  122. }
  123. // 关闭数据库
  124. status = fdb_kvs_close(fdbKvsHandle);
  125. assert(status == FDB_RESULT_SUCCESS);
  126. status = fdb_close(fdbFileHandle);
  127. assert(status == FDB_RESULT_SUCCESS);
  128. status = fdb_shutdown();
  129. assert(status == FDB_RESULT_SUCCESS);
  130. return 0;
  131. }

参考资料