MySQL 转 Redis - 导入和建模

9
我打算使用Redis来缓存一些用户数据快照,以加快对这些数据的访问速度(其中一个原因是因为我的MySQL表受到锁争用的影响),我正在寻找一种一步导入此类表格的最佳方法(该表格可能包含从几条记录到数百万条记录)。
mysql> select * from mytable where snapshot = 1133;
+------+--------------------------+----------------+-------------------+-----------+-----------+
| id   | email                    | name           | surname           | operation | snapshot  |
+------+--------------------------+----------------+-------------------+-----------+-----------+
| 2989 | example-2989@example.com | fake-name-2989 | fake-surname-2989 |         2 |      1133 |
| 2990 | example-2990@example.com | fake-name-2990 | fake-surname-2990 |        10 |      1133 |
| 2992 | example-2992@example.com | fake-name-2992 | fake-surname-2992 |         5 |      1133 |
| 2993 | example-2993@example.com | fake-name-2993 | fake-surname-2993 |         5 |      1133 |
| 2994 | example-2994@example.com | fake-name-2994 | fake-surname-2994 |         9 |      1133 |
| 2995 | example-2995@example.com | fake-name-2995 | fake-surname-2995 |         7 |      1133 |
| 2996 | example-2996@example.com | fake-name-2996 | fake-surname-2996 |         1 |      1133 |
+------+--------------------------+----------------+-------------------+-----------+-----------+

将数据存储到Redis键值存储中。
我可以有许多“快照”加载到Redis中,基本的访问模式是(类似于SQL语法)
  • select * from mytable where snapshot = ? and id = ?
这些快照也可以来自其他表格,因此“每个快照的全局唯一ID”是列snapshot,例如:
mysql> select * from my_other_table where snapshot = 1134;
+------+--------------------------+----------------+-------------------+-----------+-----------+
| id   | email                    | name           | surname           | operation | snapshot  |
+------+--------------------------+----------------+-------------------+-----------+-----------+
| 2989 | example-2989@example.com | fake-name-2989 | fake-surname-2989 |         1 |      1134 |
| 2990 | example-2990@example.com | fake-name-2990 | fake-surname-2990 |         8 |      1134 |
| 2552 | example-2552@example.com | fake-name-2552 | fake-surname-2552 |         5 |      1134 |
+------+--------------------------+----------------+-------------------+-----------+-----------+

将快照加载到redis中后不会更改,它们仅在TTL期间一周内可用

  • 有没有一种方法可以使用redis-cli --pipeHMSET将这种类型的数据(行和列)一次性加载到redis中?

  • 在存储/获取此数据时,在redis中使用最佳模型是什么(考虑访问模式)?

我发现了redis-cli --pipeRedis Mass Insertion(以及MySQL to Redis in One Step),但我无法想出实现我的要求(从mysql中一次性加载所有行/列,最佳redis模型)的最佳方法,使用HMSET

提前致谢

Cristian。


快照是随着进程添加的,旧的快照不会改变,更新模式是什么? - Joachim Isaksson
@JoachimIsaksson 这些快照永远不会改变,只需要一个TTL(比如1周)之后,数据就可以被丢弃。 - Cristian Porta
然后(作为一个没有任何专业知识的普通用户),我会为每个快照添加一个哈希值,使用“id”作为键。如果其余数据从未被查询,可以将该数据的JSON编码作为值直接使用。 - Joachim Isaksson
@CristianPorta,我建议了一个数据模型,请告诉我你的想法! - FGRibreau
1个回答

9

模型

为了能够像以下方式一样从Redis中查询数据:

select * from mytable where snapshot = ?
select * from mytable where id = ?

你需要下面的模型。

注意:在这里,select * from mytable where snapshot = ? and id = ? 没有太多意义,因为它与 select * from mytable where id = ? 相同。

关键类型和命名

[Key Type] [Key name pattern]
HASH       d:{id}
ZSET       d:ByInsertionDate
SET        d:BySnapshot:{id}

注意:我使用d:作为命名空间,但您可能希望将其重命名为您的领域模型名称。

数据插入

将Mysql中的新行插入到Redis中:

hmset d:2989 id 2989 email example-2989@example.com name fake-name-2989 ... snapshot 1134
zadd d:ByInsertionDate {current_timestamp} d:2989
sadd d:BySnapshot:1134 d:2989

另一个例子:
hmset d:2990 id 2990 email example-2990@example.com name fake-name-2990 ... snapshot 1134
zadd d:ByInsertionDate {current_timestamp} d:2990
sadd d:BySnapshot:1134 d:2990

Cron

这是必须每天或每周运行的算法,具体取决于您的要求:

for key_name in redis(ZREVRANGEBYSCORE d:ByInsertionDate -inf {timestamp_one_week_ago})

 // retrieve the snapshot id from d:{id}
 val snapshot_id = redis(hget {key_name} snapshot)

 // remove the hash (d:{id})
 redis(del key_name)

 // remove the hash entry from the set
 redis(srem d:BySnapshot:{snapshot_id} {key_name})

// clean the zset from expired keys
redis(zremrangebyscore d:ByInsertionDate -inf {timestamp_one_week_ago})

使用方法

select * from my_other_table where snapshot = 1134; 可能是以下两种情况之一:

{snapshot_id} = 1134
for key_name in redis(smembers d:BySnapshot:{snapshot_id})
  print(redis(hgetall {keyname}))

或者编写一个Lua脚本直接在Redis端执行此操作。最终:select * from my_other_table where id = 2989; 将变成:
{id} = 2989
print(redis(hgetall d:{id}))

导入

这部分非常简单,只需阅读表格并按照上述模式操作即可。根据您的要求,您可能需要使用每小时/每天/每周计划任务导入您的所有(或部分)数据。


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