需要一个支持查询功能的内存key-value存储,Nodejs有没有什么好推荐的?

需要一个支持查询功能的内存key-value存储,Nodejs有没有什么好推荐的?

需求比较独特,就是要一个内存版的mongodb: 1、这个hash的key是有时序的,value是JSON格式的数据 2、JSON的读取支持类似mongodb的projection,只返回指定的数据 3、JSON的更新可以指定字段,类似mongodb的update 4、应该支持丰富的查询,包括按regexp查询一个或多个特定的key,或者查询特定字段是否存在,等等 5、API应该是异步的(对于大量数据来说,同步会卡住js进程) 6、占用内存只受配置或硬件限制,应该可以突破2G内存的局限。V8的BUG导致js对象占用空间无法突破2G,不论是不是64位系统。因此这个k-v必然是C++ Addon的实现。 7、不需要实现持久化功能,但是有持久化的event机制,用户可以自己接管事件,自己按需要做磁盘存储。 8、最好支持embedded模式运行。也就是以npm模块的方式在node内部运行,避免进程间通讯的序列化开销。因为频繁处理大批数据时,序列化的成本非常高。

我自己在断断续续做一个这样的东西,但是完成度还很低。大致上,就是用C++的map做保存,做了js的读写接口包装。查询上重点考虑了regexp的优化,测试之后选了速度最快的grep里的dfasearch模块,异步用的就是uv的工作队列。但是不知道怎么搞的,很多地方执行效率很低。。。如果不考虑这货能多线程的话,很多地方甚至不如纯js的速度。理想和现实相差太多。对v8的秉性不熟悉,对C++的优化毫无头绪。而且这货就算写成了也没法发出来了,直接把MIT GPL一堆柔和在一起,貌似法律上也违和了。如果有个现成的。。。真不想写下去了。

p.s. 请不要推荐类似 nedb 这样的纯 js 实现的库,这种库遇到大量数据的时候 node 进程就崩溃了,是 v8 陈年老 BUG 导致的。再说纯 js 实现的计算,量一大就会卡住js线程的,不可取。


9 回复

针对您的需求,我推荐使用 LevelDBRocksDB 结合 LevelUPRocksUP 来实现一个支持查询功能的内存 key-value 存储。虽然这些存储引擎本身是基于文件系统的,但它们可以通过配置来主要利用内存,从而满足您的需求。以下是一个简单的示例,展示如何使用 LevelUPLevelDOWN(LevelDB 的 Node.js 封装)来实现您的需求。

首先,确保安装必要的依赖包:

npm install level levelup leveldown

接下来,创建一个简单的数据库操作示例:

const level = require('level');
const levelup = require('levelup');

// 创建一个新的LevelDB实例,使用内存模式
const db = levelup(level('./mydb', { valueEncoding: 'json' }));

// 示例数据插入
async function insertData() {
    await db.put('key1', { timestamp: Date.now(), data: 'some data' });
    await db.put('key2', { timestamp: Date.now(), data: 'other data' });
}

// 查询数据,支持projection
async function queryData() {
    const iterator = db.iterator({ gte: 'key1', lte: 'key2' });
    for await (const [key, value] of iterator) {
        console.log(`Key: ${key}, Data: ${value.data}`); // projection 只返回 data 字段
    }
}

// 更新数据,只更新指定字段
async function updateData() {
    const key = 'key1';
    const newValue = { $set: { data: 'updated data' } };
    const currentData = await db.get(key);
    const updatedData = { ...currentData, ...newValue.$set };
    await db.put(key, updatedData);
}

// 使用正则表达式查询特定键
async function regexQuery() {
    const iterator = db.iterator({ gte: 'key', lte: 'key\x7F' });
    for await (const [key, value] of iterator) {
        if (key.match(/key\d/)) {
            console.log(`Matched Key: ${key}`);
        }
    }
}

// 运行示例
(async () => {
    await insertData();
    await queryData();
    await updateData();
    await regexQuery();
})();

此示例展示了如何插入、查询、更新数据以及通过正则表达式进行查询。请注意,LevelDBRocksDB 都是持久化的存储解决方案,但在配置为内存模式下,它们可以提供高性能的内存存储。此外,您可以根据需要调整配置,以更好地适应内存使用情况。

如果需要更高级的查询功能,可以考虑结合其他技术如 ElasticsearchRedis,但这些通常需要更多的配置和资源管理。希望这个示例能满足您的基本需求!


没听说过这样的内存数据库…

坐等大神…

memcached 这个应该可以满足吧,我感觉

占用内存只受配置或硬件限制,应该可以突破2G内存的局限。V8的BUG导致js对象占用空间无法突破2G,不论是不是64位系统。因此这个k-v必然是C++ Addon的实现。

nodejs 的 Buffer 是 V8 以外的内存,不受 2G 限制。所以不是非得用 C++ addon

有特殊的需求,很难直接在现有的系统里找到。有没有考虑在现有的系统基础上开发,比如 redis 是开源的。

自己回自己吧。我最後用 shm 解決了。數據都保存在 /run/shm 的json文件中。這樣,對數據的訪問就變成了對內存文件的訪問。拆分大的數據,放在多個json文件中,減少序列化成本。仿mongodb寫了個查詢和更新的接口。測試結果,多個node併發訪問的速度果然比redis快,解決了之前用redis會卡的問題。

mysql 内存表不行吗,用memory引擎

针对你的需求,可以考虑使用 nedb-pure 的增强版本 lowdb 或者 LevelDB 的封装 level,但这些方案可能不完全满足所有需求,尤其是关于复杂查询的支持。

这里推荐一个能满足部分需求的库——nanomongo。虽然它不是专门为内存设计的,但它提供了类似 MongoDB 的 API,并且可以很好地集成到 Node.js 应用中。以下是一个简单的示例代码:

const NanoMongo = require('nanomongo');
const nanoMongo = new NanoMongo();

(async () => {
    // 初始化数据库
    await nanoMongo.init(':memory:');

    // 插入数据
    await nanoMongo.db.insert({ name: 'John Doe', age: 30, city: 'New York' });
    await nanoMongo.db.insert({ name: 'Jane Doe', age: 25, city: 'San Francisco' });

    // 查询数据
    const result = await nanoMongo.db.find({ age: { $gt: 25 } });
    console.log(result);

    // 更新数据
    await nanoMongo.db.update({ name: 'John Doe' }, { $set: { city: 'Los Angeles' } });

    // 删除数据
    await nanoMongo.db.remove({ name: 'Jane Doe' });

    // 关闭数据库连接
    await nanoMongo.close();
})();

这段代码演示了如何初始化数据库、插入数据、查询数据、更新数据和删除数据。nanomongo 提供了一些基本的查询能力,如条件查询和更新操作,但复杂的查询(如正则表达式)可能需要自行实现。

如果你需要更强大的查询能力和更好的性能,可能需要自己开发一个基于 C++ 的插件,或者寻找其他成熟的解决方案。

回到顶部