Out of Process in memory database table 支持高速缓存查询

Out of Process in memory database table that supports queries for high speed caching

我有一个 SQL table 可以持续访问但很少更改。

Table按UserID分区,每个用户在table中有多条记录。

我想节省数据库资源并将此 table 移动到更靠近某种内存缓存中的应用程序。

进程内缓存过于占用内存,因此它需要在应用程序外部。

像 Redis 这样的键值存储被证明是低效的,因为在 Redis 之间序列化和反序列化 table 的开销。

我正在寻找可以将此 table(或数据分区)存储在内存中的东西,但让我只查询我需要的信息,而无需为每次读取序列化和反序列化大块数据。

是否有任何东西可以提供支持高速缓存查询的内存数据库 table 中的进程外?

搜索表明 Apache Ignite 可能是一个可能的选择,但我正在寻找更明智的建议。

既然是进程外的,那就得做序列化和反序列化了。你关心的问题是如何减少serialization/deserizliation的工作量。如果你使用 Redis 的 STRING 类型,你不能减少这些工作。

但是,您可以使用 HASH 来解决问题:将您的 SQL table 映射到 HASH.

假设您有以下table:person: id(varchar), name(varchar), age(int),您可以将人id作为键,将nameage作为字段。当你想搜索某人的姓名时,只需要获取姓名字段(HGET person-id name),其他字段不会被反序列化。

Ignite 确实是一个可能的解决方案,因为您可以通过使用内部二进制表示来访问对象的字段来优化 serialization/deserialization 开销。您可以参考此文档页面以获取更多信息:https://apacheignite.readme.io/docs/binary-marshaller

还可以通过禁用读时复制选项来优化访问开销 https://apacheignite.readme.io/docs/performance-tips#section-do-not-copy-value-on-read

Ignite 也可以通过用户 ID 进行数据配置:https://apacheignite.readme.io/docs/affinity-collocation

正如@for_stack 所说,Hash 将非常适合您的情况。

你说每个用户在数据库中都有很多行由 user_idtag_id 索引。所以就是(user_id,tag_id)唯一指定一行。每一行的功能都取决于这个元组,你可以使用这个元组作为 HASH KEY。

例如,如果您要保存行 (user_id、tag_id、用户名、年龄),其值为 ("123456"、"FDSA"、"gsz" , 20) 到redis, 你可以这样做:

HMSET 123456:FDSA username "gsz" age 30

当你想查询带user_id和tag_id的用户名时,你可以这样做:

HGET 123456:FDSA username

所以每个Hash Key都是user_idtag_id的组合,如果你想让key更易读,你可以添加一个前缀字符串,比如"USERINFO" .例如: USERINFO:123456:FDSA .

但是如果你只想用一个user_id查询并用这个user_id获取所有行,上面的这个方法是不够的。

你可以在redis中为你构建secondary indexes HASH。

如上所说,我们使用user_id:tag_id作为HASH键。因为它可以唯一指向一行。如果我们要查询一个user_id.

的所有行

我们可以使用 sorted set 构建二级索引来索引哪些 Hashes 存储关于此 user_id 的信息。

我们可以在 SortedSet 中添加:

ZADD user_index 0 123456:FDSA

如上,我们将member设置为string of HASH key,将score设置为0。规则是我们应该将这个zset中的所有分数都设置为0然后我们可以使用字典顺序进行范围查询。参考 zrangebylex.

例如我们想要获取关于 user_id 123456,

的所有行
ZRANGEBYLEX user_index [123456 (123457

它会return所有前缀为123456的HASH键,然后我们使用这个字符串作为HASH键和hget或hmget来检索我们想要的信息。

[表示包含,(表示不包含。为什么我们使用 123457?这很明显。所以当我们想得到所有带有 user_id 的行时,我们应该指定上限以使 user_id 字符串最左边的字符的 ascii 值加 1。

更多关于 lex 索引你可以参考我上面提到的文章。

你可以试试intel启动的apache mnemonic。 Link-http://incubator.apache.org/projects/mnemonic.html。它支持 serdeless 特性

对于以读为主的工作负载 MySQL MEMORY engine 应该可以正常工作(写入 DML 锁定整个 table)。这样您就不需要更改数据检索逻辑。

或者,如果您不介意更改数据检索逻辑,那么 Redis 也是一种选择。除了@GuangshengZuo 所描述的内容之外,还有 ReJSON Redis 动态可加载模块(适用于 Redis 4+),它在 Redis 之上实现文档存储。它可以进一步放宽通过网络来回编组大型结构的要求。

仅需 6 个原则(我收集 here),一个 SQL 有头脑的人很容易适应 Redis 方法。简而言之,它们是:

  1. The most important thing is that, don't be afraid to generate lots of key-value pairs. So feel free to store each row of the table in a different key.
  2. Use Redis' hash map data type
  3. Form key name from primary key values of the table by a separator (such as ":")
  4. Store the remaining fields as a hash
  5. When you want to query a single row, directly form the key and retrieve its results
  6. When you want to query a range, use wild char "*" towards your key. But please be aware, scanning keys interrupt other Redis processes. So use this method if you really have to.

link 只是给出了一个简单的 table 示例以及如何在 Redis 中对其进行建模。遵循这 6 条原则,您可以继续像正常 table 一样思考。 (当然没有一些不太相关的概念,如 CRUD、约束、关系等)

想到在 MYSQL 之上使用 Memcache 和 REDIS 组合。