在redis中存储用户配置文件的数据结构更好



我想将用户的配置文件存储在redis中,因为我必须经常读取多个用户的配置。目前我看到两种选择:

选项1:-为每个用户的配置文件存储单独的哈希密钥

  • 〔hash〕-u1配置文件{id:u1,名称:user1,电子邮件:user1@domain.com,照片:url}
  • 〔hash〕-u2配置文件{id:u2,名称:user2,电子邮件:user2@domain.com,照片:url}
  • 其中,对于每个用户的id,都是散列键和配置文件字段以及JSON序列化的配置文件对象的值。(OR而不是json用户字段值对)

选项2:-使用单个哈希密钥存储所有用户配置文件

  • 〔hash〕-用户配置文件u1{id:u1,名称:user1,电子邮件:user1@domain.com,照片:url}
  • 〔hash〕-用户配置文件u2{id:u2,名称:user2,电子邮件:user2@domain.com,照片:url}
  • 其中,在用户配置文件哈希键中,用户的ids字段和值为JSON序列化的配置文件对象

请告诉我考虑以下哪种选择最好:

  1. 性能
  2. 内存利用率
  3. 读取多个用户的配置文件-对于批量处理,我应该能够一次读取1-100101-200用户的配置
  4. 更大的数据集-如果有数百万用户配置文件怎么办

正如Sergio Tulentsev所指出的,无论如何,将所有用户的数据(尤其是在数据集很大的情况下)存储在一个散列中都是不好的。

将用户数据存储为单独的密钥也是不可取的,如果你正在寻找内存优化,如本文中所指出的

使用分页机制读取用户的数据需要使用数据库,而不是像redis这样的简单缓存系统。因此,建议使用NoSQL数据库,如mongoDB。

但是每次从数据库中读取都是一项成本高昂的操作,尤其是在读取大量记录的情况下。

因此,最好的解决方案是将最活跃的用户数据缓存在redis中,以消除数据库获取开销。

我建议你调查海象。

它基本上遵循以下模式:

@cache.cached(timeout=expiry_in_secs)
def function_name(param1, param2, ...., param_n):
# perform database fetch
# return user data

这确保了频繁访问或请求的用户数据在redis中,并且该函数会自动从redis返回值,而不是进行数据库调用。此外,如果长时间未访问该密钥,则该密钥将过期。

您将其设置如下:

from walrus import *
db = Database(host='localhost', port=6379, db=0)

其中host可以获取远程运行的redis集群的域名。

希望这能有所帮助。

选项#1。

  • 性能:通常这取决于您的用例,但假设您想要读取特定用户(关于登录/注销、授权目的等)。使用选项#1,您只需计算用户哈希并获得用户配置文件。使用选项#2,您将需要获取所有用户配置文件并解析json(尽管您可以使其高效,但它永远不会像选项#1那样高效和简单)

  • 内存利用率:您可以使选项#1和选项#2在redis中具有相同的大小(在选项#1上,您可以避免将哈希/用户id存储为json的一部分)。然而,选择相同的示例来加载特定的用户,您只需要在代码/内存中使用单个用户配置文件json,而不是带有一组用户配置文件的更大json

  • 读取多个用户的配置文件-对于批处理,我应该能够一次读取1-100101-200个用户的概要文件:为此,就像通常对关系数据库所做的那样,您需要进行分页。使用redis进行分页有不同的方法,但使用扫描操作是迭代一组用户的简单方法

  • 更大的数据集-如果有数百万用户配置文件,该怎么办

Redis是一个内存中但持久存在于磁盘上的数据库,因此它代表了一种不同的折衷方案,其中写入和读取速度非常高是在数据集不能大于的限制下实现的存储器

如果你"不能拥有比内存更大的数据集",你可以按照Redis常见问题解答的建议查看分区。在Redis常见问题解答中,您还可以检查其他指标,如"单个Redis实例可容纳的最大密钥数"或"Redis内存占用率">

选项1的PROS(但不要使用散列,使用单个密钥。如SET profile:4d094f58c96767d7a0099d49 {...})

  • 迭代密钥比迭代哈希稍微快一些。(这也是为什么应该将选项1修改为使用SET,而不是HSET)
  • 检索键值比检索哈希字段稍快

选项2的PROS

  • 您可以使用HMGET在一次呼叫中获得所有用户,但前提是您的用户基数不是很大。否则,服务器很难为您提供结果
  • 您可以在一个命令中刷新所有用户。如果您有后备数据库,这很有用

选项3的PROS

选项3是将用户数据分解为哈希桶,哈希桶由用户id的哈希决定。如果你有很多用户并且经常进行批量处理,效果很好。像这样:

HSET profiles:<bucket> <id> {json object}
HGET profiles:<bucket> <id>
HMGET profiles:<bucket> 

最后一个得到一整桶个人资料的。不要建议它的总量超过1mb。适用于顺序id,但不适用于哈希,因为它们可能会增长太多。如果您将其与哈希一起使用,并且它增长得太多,从而减慢了Redis的速度,则可以回退到HSCAN(如选项2中所示),或者使用新的哈希函数将对象重新分配到更多的bucket中。

  • 更快的批量加载
  • 单个对象存储/加载稍慢

如果我理解你的情况,我的建议是使用第三个选项,顺序ID在100范围内。如果您的目标是高数据量,从第一天起就计划集群

最新更新