Node.js的最快、非内存型、多进程键值存储是什么?

37

什么是Node.js支持多进程的最快的非内存键值存储?

我需要存储简单的键值字符串/字符串对(不是文档或JSON,只是字符串)。
以下是一些示例(会有数百万个这样的示例):

  • 12345678 – abcdefghijklmnopabcdefghijklmnop
  • 86358098 – ahijklmnopbcdefgahijklmnopbcdefg
  • abcdefghijklmnopabcdefghijklmnop - 12345678
  • ahijklmnopbcdefgahijklmnopbcdefg - 86358098

我已经尝试过:

  • Redis:它非常快并且满足我所有需求,但消耗太多RAM。
  • LevelDB:它速度很快,而且对RAM使用不太严重,但只支持单进程。

LevelDB 的一个解决方法是使用multilevel通过HTTP暴露一个单独的 LevelDB 进程。
但这当然是有代价的;我需要更快的东西。

有没有任何键值存储满足以下条件:

  • 支持 Node.js 或其绑定;
  • 存储字符串/字符串对;
  • 支持多进程;
  • 不完全驻留在内存中;
  • 速度快?

我只关心阅读。 快速的多进程阅读是必要的,但不需要写入。
我对 LevelDB 的当前速度感到满意,但不满意它只支持单个进程。


其他详细信息:

  • 我要处理大约 5000 万个键值对,键和值的长度在 8 到 500 个字符之间。
  • 代码将在常规 Linux 服务器上运行。
  • 内存使用应限制在几个 GB(4GB 可接受,8GB 更好)。
  • 阅读比写作更加重要;实际上,如果没有写作也能完成。
  • 速度比任何东西都更加重要(前提是遵守内存和多进程限制)。

  • 你所说的非内存型是什么意思?你是指持久化吗? - Aliostad
    MongoDB实际上会根据可用内存在内存和磁盘存储之间进行交换。它不仅仅是您想要的键值,但可以用于类似的东西,并且表现非常出色。 - Zaptree
    @Aliostad 我的意思是除了 Redis 之外的任何东西,因为 Redis 需要将整个数据库存储在内存中。 - Ruben Verborgh
    是的,Redis很快,但它会尝试将所有内容加载到内存中,如果您的数据库很大,这可能会成为一个问题。然而,加载到内存部分正是它如此快速的原因 ;)。 - AlexGad
    @Zaptree 我担心MongoDB可能比技术上可能的要慢,因为它带有比简单键/值更多的功能。不过我应该试一下。 - Ruben Verborgh
    5个回答

    28

    这看起来非常相关,我会查一下! - Ruben Verborgh
    1
    @RubenVerborgh,LMDB工作正常吗?你最终选择了LMDB还是其他什么东西? - JP Richardson

    8
    你可以尝试使用ssdb,这是一个基于leveldb构建的与redis协议兼容的数据库。

    https://github.com/ideawu/ssdb

    你可以使用现有的node-redis客户端,但某些命令可能会有所不同。

    基准测试

                      Redis (100.000x)
          13,540 op/s ⨠ set small
          13,289 op/s ⨠ set medium
          13,279 op/s ⨠ set large
          13,651 op/s ⨠ get large
          13,681 op/s ⨠ get medium
          14,428 op/s ⨠ get small
    
                      SSDB (100.000x)
          12,252 op/s ⨠ set small
          11,824 op/s ⨠ set medium
          11,720 op/s ⨠ set large
          13,810 op/s ⨠ get large
          13,593 op/s ⨠ get medium
          12,696 op/s ⨠ get small
    
    
                      lmdb (100.000x)
           4,616 op/s ⨠ set small
          11,104 op/s ⨠ set medium
          17,283 op/s ⨠ set large
          13,778 op/s ⨠ get large
          16,002 op/s ⨠ get medium
          50,562 op/s ⨠ get small
    
                      multilevel (100.000x)
           6,124 op/s ⨠ set small
           5,900 op/s ⨠ set medium
           5,944 op/s ⨠ set large
           6,215 op/s ⨠ get large
           6,125 op/s ⨠ get medium
           6,310 op/s ⨠ get small
    

    正如您所看到的,ssdb 几乎和 redis 一样快,并且它专为持久性存储而设计。@didier-spezia提到的 lmdb 在获取小数据方面超级快,但设置一个则较慢。

    对于lmdb,由于它使用mmap,如果机器的内存足够大,则所有数据都将在内存中,永远不会被交换出去。 - yinqiwen
    所有的键都是序列号。我会尝试使用随机键来实现它。还可以问一下,“从不交换”是什么意思? - Polor Beer
    每个测试的30000次迭代不足够。而且,测试数据集中只有90000个键,这对于基准测试来说太小了。leveldb/lmdb可能会在您的测试中将所有数据缓存在内存中。(对于leveldb,在“set”测试之后,所有数据仍可能在memtable中,仍然在内存中)。我建议每个测试至少应迭代1000万次。 - yinqiwen
    由于leveldb/lmdb使用树状结构存储数据,其复杂度为O(log n),这意味着理论上存储的数据越多,速度越慢。而Redis使用哈希映射将数据存储在内存中,其复杂度为O(1)。 - yinqiwen
    1
    一旦哈希映射和数据变得足够大,它就不再是O(1)了,性能会急剧下降,比O(log n)还要糟糕。哈希在空间上极其低效且不友好于缓存。 - hyc
    显示剩余3条评论

    5

    这里有FaceBook的RocksDB,它应该很快(特别是在SSD存储上),还有其他一些,如LMDB(已经提到)和WiredTiger

    你提到了Redis - 如果您想使用Redis API,但是希望使用以上其中之一的键/值数据库作为存储而不是RAM,则我知道两个项目(尽管我没有测试过它们):LedisDB(用Go编写)和ardb(用C++编写)。

    我最近开始测试一个非常有前途但鲜为人知(虽然我相信这将会改变)的键值数据库库,名为CuttDB。它具有非常快的性能,并且专为处理大量数据而构建。它甚至包括Memcached服务器接口。


    3
    你可能会遇到的问题是,“闪电般快速”的性能和硬盘不相容,尤其是在键值系统中需要进行随机访问读取时。你需要尽可能地将数据存储在内存中,因为从内存读取比从硬盘读取要快得多。
    如果你想要最小化内存使用的原因是因为这是一个嵌入式数据库吗?如果是这样,你可以考虑使用Empress - http://www.empress.com。我在几个项目中使用过它,你可以配置加载多少数据,但它有一个关系型数据库系统的开销,所以不确定它是否足够精简。
    你也可以考虑使用MySQL和Memcache插件。这允许你将MySQL用作键值存储。比普通MySQL快得多,因为跳过了SQL层处理。此外,使用MySQL,你可以调整内存使用量。
    Firebird是另一个低内存使用的数据库 - http://www.firebirdnews.org/docs/fb2min.html
    希望这可以帮助你。如果没有更深入地解释你的需求(例如,这是嵌入式系统,为什么需要节省内存,如果内存宝贵,你认为低内存消耗是多少,你需要原子性、冗余,你认为闪电般快速的速度是多快等),那么就很难提供更详细的分析。

    好的,“闪电般快速”可能有点夸张(从问题中删除了这句话)。我对LevelDB很满意,但遗憾的是它只能支持单进程。我想要最小化的原因是因为我们要处理数百万条记录,其中一些记录非常长。我之前尝试过使用MySQL作为键值存储引擎,但速度非常慢,不过我从未尝试过Memcache。现在我会尝试一下,并将更新问题以提供更多细节。 - Ruben Verborgh
    Memcache难道不也只是另一种内存存储吗? - Pavel S.
    实际上是指InnoDB memcache插件。它使MySQL能够高效地作为键值存储操作。它并没有使读取变得更加高效,因此回顾起来,如果要求绝对快速的话,不确定它是否能满足问题的需求。 - AlexGad

    2
    为什么不使用MySQL(或MariaDB)进行主从复制呢? 根据您的需求,MySQL的主从架构非常适合您。 基本上,NoSQL需要很多服务器。 例如,MongoDB的最小设置需要三个服务器,HBase需要四个服务器。 从这个角度来看,如果需要更高的读性能,则可以在MySQL架构中添加新的从服务器。 我们假设MySQL的读性能为2k TPS。 那么4个MySQL节点的读性能为8k TPS。 这取决于您的测试结果和服务使用情况(读写比例)。 请查看下面的链接,这是“Marco Cecconi-StackOverflow的架构”。 http://www.youtube.com/watch?v=t6kM2EM6so4

    2
    我尝试过使用MySQL处理一张有1000万个键值对的表格,但是读取数值非常缓慢(即使键只是数字),即使使用了适当的索引。请注意,我不需要复制。 - Ruben Verborgh

    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接