16

我有一个不断访问但很少更改的 SQL 表。

该表由 UserID 分区,每个用户在表中都有许多记录。

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

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

由于在 Redis 之间对表进行序列化和反序列化的开销,事实证明,像 Redis 这样的键值存储效率低下。

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

是否有任何东西可以在支持高速缓存查询的内存数据库表中提供 Out of Process ?

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

4

7 回答 7

9

由于它是进程外的,它必须进行序列化和反序列化。您关心的问题是如何减少序列化/反序列化工作。如果你使用 Redis 的STRING类型,你不能减少这些工作。

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

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

于 2017-09-01T05:45:32.483 回答
4

Ignite 对您来说确实是一个可能的解决方案,因为您可以通过使用内部二进制表示来访问对象的字段来优化序列化/反序列化开销。您可以参考此文档页面了解更多信息: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

于 2017-09-01T11:03:37.027 回答
2

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

您说每个用户在 db 中有许多由user_idand索引的行tag_id。所以它是 (user_id, tag_id) 唯一指定一行。每一行的功能取决于这个元组,你可以使用元组作为 HASH KEY。

例如,如果要将值为 ("123456", "FDSA", "gsz", 20) 的行 (user_id, tag_id, username, age) 保存到 redis 中,您可以这样做:

HMSET 123456:FDSA username "gsz" age 30

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

HGET 123456:FDSA username

所以每个哈希键都是和的组合user_idtag_id如果你想让键更易于阅读,你可以添加一个前缀字符串,比如“USERINFO”。例如:USERINFO:123456:FDSA

但是如果您只想使用 user_id 查询并获取具有此 user_id 的所有行,则上述方法是不够的。

您可以在 redis 中为您的 HASH构建二级索引。

如前所述,我们使用user_id:tag_idHASH 键。因为它可以唯一点到一行。如果我们想查询关于一个 user_id 的所有行。

我们可以使用sorted set构建二级索引来索引哪些哈希存储有关此 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

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

[意味着包容,(意味着排斥。为什么我们使用123457?这很明显。所以当我们想要获取所有带有 user_id 的行时,我们应该指定上限,使 user_id 字符串的最左边 char 的 ascii 值加 1。

有关 lex 索引的更多信息,您可以参考我上面提到的文章。

于 2017-09-06T07:53:37.333 回答
1

你可以试试intel 启动的apache mnemonic。链接 - http://incubator.apache.org/projects/mnemonic.html。它支持 serdeless 功能

于 2017-09-07T07:44:12.127 回答
1

对于以读取为主的工作负载,MySQLMEMORY引擎应该可以正常工作(编写 DML 锁定整个表)。这样您就不需要更改数据检索逻辑。

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

于 2017-09-10T11:55:35.410 回答
1

只需 6 条原则(我在此处收集),有 SQL 头脑的人很容易适应 Redis 方法。简而言之,它们是:

  1. 最重要的是,不要害怕生成大量的键值对。因此,请随意将表的每一行存储在不同的键中。
  2. 使用 Redis 的哈希映射数据类型
  3. 通过分隔符(如“:”)从表的主键值中形成键名
  4. 将剩余字段存储为哈希
  5. 当您要查询单行时,直接形成键并检索其结果
  6. 当你想查询一个范围时,对你的键使用通配符“*”。但请注意,扫描键会中断其他 Redis 进程。因此,如果您确实需要,请使用此方法。

该链接仅提供了一个简单的表格示例以及如何在 Redis 中对其进行建模。遵循这 6 条原则,您可以继续像对待普通桌子一样思考。(当然没有一些不那么相关的概念,如 CRUD、约束、关系等)

于 2017-09-11T06:07:34.123 回答
0

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

于 2017-09-12T11:37:52.377 回答