Redis:如何存储用户哈希列表并检索它?

3
我今天开始使用redis,并且已经完成了教程和一些StackOverflow上的链接,但我无法理解如何正确地使用redis来完成一个非常简单的用例。

目标:将几个用户的数据保存到redis中,并一次性读取所有用户的数据。

我启动了一个redis客户端,并从添加第一个用户开始,该用户ID为1

127.0.0.1:6379> hmset user:1 name "vitor" age 35
OK
127.0.0.1:6379> hgetall user:1 
1) "name"
2) "vitor"
3) "age"
4) "35"

我添加了更多的用户,执行了几个类似这样的命令:

127.0.0.1:6379> hmset user:2 name "nuno" age 10

我本来(可能是错误的)期望现在可以通过以下方式查询所有用户:

hgetall "user:"

甚至

hgetall "user:*"

事实上,我在教程中没有看到类似的内容,这说明我在这个使用案例中没有正确使用redis。

您能告诉我应该采取什么方法来处理这个使用案例吗?

2个回答

9
为了理解为什么在NoSQL实现中这些操作似乎是非平凡的,有必要思考为什么NoSQL存在(并且变得非常流行)。
当你看一个早期的NoSQL实现,比如memcached时,第一个用例非常简单但非常重要:快速分布式数据缓存,例如缓存网页数据。很快就添加了像集群和分片这样的东西,因此不是所有数据都必须在集群中的每个节点上同时可用,而是可以按需收集。
NoSQL与关系型数据存储非常不同。不要过度使用它。还应该考虑关系型数据库,因为它们有时更适合你所要完成的任务。在设计任何东西时,问自己“这是否能够良好扩展?”。
好的,回到你的问题。通常做通配符搜索是不好的做法。你需要以一种可扩展的方式准备你的数据,以便检索数据。
Redis是一个非常优雅的解决方案,允许你克服很多NoSQL的限制。
如果“获取所有用户列表”不是你经常需要做的事情,或者不需要良好扩展性,总是“我真的总想要所有用户”,因为它是每天扫描的,那么使用HSCAN。具有适当批量大小的SCAN操作不会妨碍其他客户端,你可以一次检索几千个记录,几次调用后就可以得到所有记录。
你也可以将用户存储在一个SET中。集合中没有排序,因此没有分页。它有助于保持用户名称的唯一性。
如果你想做“获取以字母‘a’开头的所有用户”之类的事情,我会使用ZSET。我会等待一两周的时间,因为ZRANGEBYLEX即将发布,正在进行中。或者使用像Josiah Carlsons的“rom”包这样的ORM。
当你问自己“但是现在我需要做三次调用而不是一次来存储我的数据...?!”:是的,就是这样工作的。如果你需要原子性,请使用Lua脚本或MULTI+EXEC流水线处理。Lua通常更容易。
你还可以问自己是否需要使用HSET。你需要检索单个数据成员吗?每个键或成员都有一些开销。除此之外,HGETALL具有O(N)的Big-O规范,因此它无法良好扩展。最好将整行序列化为JSON或MsgPack,并将其存储在一个HSET成员中,或者只是一个简单的GET/SET。还要阅读SORT。
希望这能帮到你,TW

嗨@Tw Bert,感谢您的回答。我总是考虑关系型数据库,但由于在这种情况下我没有想要存储或查询的关系,所以我考虑使用REDIS,因为我只想存储用户并大多数时间检索它们。根据您的解释,我想我可能需要一个SET,特别是因为即使在非常乐观的情况下,用户列表也永远不会超过1k。 - bitoiu
1
不客气。如果只是局域网上的用户ID,1k并不算什么,所以这是一个很好的起点。如果您使用像Azure或Heroku这样的云服务,情况可能会有所不同,您可能需要通过使用不同的Redis数据类型来进行调整。如果您事先注意到潜在问题,这通常并不难。 - Tw Bert

3
如果你仍然想使用Redis,你可以使用以下类似的代码:
SADD users "{"userId":1,"name":"John", "vitor":"x","age":35}"
SADD users "{"userId":2,"name":"xt", "vitor":"x","age":43}" ...
你可以使用下面的代码来检索相同的内容:
SMEMBERS users

我仍然使用Redis,但最终我将用户存储在简单的键中,但这也是一个不错的选择。 - bitoiu

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