Redis CRUD模式

时间:2014-01-04 16:54:03

标签: php nosql redis

我最近开始学习Redis,目前正在构建一个使用它作为唯一数据存储区的应用程序,如果我的一些结论是正确的并且问了几个问题,我想与其他Redis用户联系。我正在使用phpredis,如果这是相关的,但我想问题应该适用于任何语言,因为它更像是一种模式。

例如,考虑使用CRUD接口来保存具有以下要求的网站(名称和域名):

  • 保存/验证新网站时检查现有名称/域(重复检查)
  • 列出所有具有排序和分页的网站

我最初选择了以下“架构”来保存这些信息:

  • 密钥“prefix:website_ids”,其中我使用INCR生成新的网站ID
  • 一组“prefix:wslist”,其中我添加了上面生成的网站ID
  • 每个网站的哈希“前缀:ws:ID”,包含字段名称和网站

保存/验证问题

仅凭上述信息,我无法(据我所知)在添加新网站时检查重复的名称或域名。为了解决这个问题,我做了以下几点:

  • 两组密码为“prefix:wsnames”和“prefix:wsdomains”,其中我也是SADD的网站名称和域名。

这样,在添加新网站时,我可以检查提交的名称或域是否已存在于使用SISMEMBER的这些集合中的任何一个中,并且如果需要则验证失败。 现在如果我用50个字段而不是2个字段保存数据并希望防止重复,我必须为我想要验证的每个字段创建一个类似的集合。

问题1:以上是解决此问题的常见模式,还是人们使用其他/更好的方式来解决此类问题?

列名/排序问题

要列出网站并按名称或域名(升序或降序)排序以及限制分页结果,请使用以下内容:

SORT prefix:wslist BY prefix:ws:*->name ALPHA ASC LIMIT 0 10

这给了我10个按名称排序的网站ID。现在为了得到这些结果,我得到了以下选项(php中的例子):

选项1:

$wslist = the sort command here;
$websites = array();
foreach($wslist as $ws) {
    $websites[$ws] = $redis->hGetAll('prefix:ws:'.$ws);
}

以上为我提供了一个可用的数组,其中包含网站ID作为键和字段数组。不幸的是,这有一个问题,我在循环中做多次redis请求和常识(至少来自RDBM)告诉我这不是最优的。 使用redis pipelining / multi并在一个go中发送所有请求的更好方式是:

选项2:

$wslist = the sort command here;
$redis->multi();
foreach($wslist as $ws) {
    $redis->hGetAll('prefix:ws:'.$ws);
}
$websites = $redis->exec();

这种方法的问题在于,现在我没有获得每个网站的相应ID,除非我再次循环$ websites网格数组以关联每个网站。另一种选择是,也可以使用相应的网站ID以及名称和域名来保存字段“id”。

问题2/3:在不必多次循环的情况下,将这些结果放入可用数组的最佳方法是什么?将id号码保存为散列内的字段是正确还是好的做法,这样我也能得到结果吗?

免责声明:我了解使用像Redis这样的密钥>值数据存储区时的编码和架构构建范例与RDBM和文档存储区不同,因此“最佳方式做X”的概念不同可能会有所不同,具体取决于手头的数据和应用程序。 我也理解Redis可能不是最适合在大多数CRUD类型应用程序中使用的数据存储区,但我仍然希望从更有经验的开发人员那里获得任何见解,因为CRUD接口在大多数应用程序中非常常见。

1 个答案:

答案 0 :(得分:2)

回答1

您的提案看起来很常见。我不确定为什么你需要一个自动递增的ID。我想域名必须是唯一的,或者网站名称必须是唯一的,或者至少两者的组合必须是唯一的。如果是这种情况,听起来你已经有了一个非常好的密钥,那么为什么在你不需要时发明一个整数密钥呢?

拥有域名SET和网站名称SET是快速检查特定域名或网站名称是否已存在的完美解决方案。但是,如果其中一个(域名或网站名称)是您的密钥,您可能甚至不需要这些SET,因为您只需查看密钥prefix:ws:domain-or-ws-name-here是否存在。

此外,为每个网站使用HASH,这样您就可以在网站内存储50个字段的详细信息。这就是哈希的用途。

回答2

首先,我要指出,如果您的网站和域名存储在SORTED SET而不是SET中,则它们已经按字母顺序排列(假设它们的分数相同)。如果你试图支持其他排序选项,这可能没有多大帮助,但想指出它。

您的选项1和选项2实际上都是相对合理的。 Redis闪电般快,所以选项1并不像最初看起来那样不合理。从redis的角度看,选项2显然更加优化,因为所有命令都将被缓冲并一次性执行。但是,如果您希望数组通过id索引,那么之后需要在PHP中进行额外的处理。

有第三种选择:lua脚本。你可以让redis执行一个Lua脚本,它一次性返回id和hash值。但是,不再熟悉PHP以及redis的多字节回复如何映射到PHP数组我不是100%确定lua脚本会是什么样子。您需要查找示例或进行一些试验和错误。不过,它应该是一个非常简单的脚本。

<强>结论

我认为redis听起来像是解决问题的好方法。请记住,数据集需要始终足够小以保留在内存中。如果这不是真正的问题(除非您的字段很大,您应该能够将数千个网站放入几MB),或者如果您不介意升级RAM来扩展数据库,那么Redis非常适合

熟悉redis的各种持久性选项和配置,以及它们对可用性和可靠性的意义。此外,请确保您有适当的备份解决方案。我建议同时拥有一个从主实例中删除的辅助redis实例,以及至少每天备份redis数据库文件的重复进程。