草庐IT

php - Redis 增删改查模式

coder 2023-07-18 原文

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

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

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

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

  • 我使用 INCR 生成新网站 ID 的键“prefix:website_ids”
  • 一组“prefix:wslist”,其中我添加了上面生成的网站 id
  • 每个网站“prefix:ws:ID”的散列,包含字段名称和网站

保存/验证问题

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

  • 两个键为“prefix:wsnames”和“prefix:wsdomains”的集合,其中我还添加了网站名称和域。

这样,在添加新网站时,我可以使用 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 并一次性发送所有请求:

选项 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 接口(interface)在大多数应用程序中都很常见。

最佳答案

答案 1

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

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

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

答案 2

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

你的方案一和方案二其实都比较合理。 Redis 快如闪电,因此选项 1 并不像乍看起来那样不合理。从 Redis 的角度来看,选项 2 显然更优,因为所有命令都将被缓冲并同时执行。但是,如您所述,如果您希望数组由 id 索引,则之后需要在 PHP 中进行额外处理。

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

结论

我认为 Redis 听起来是解决您问题的不错的解决方案。请记住,数据集需要始终小到足以保存在内存中。如果这不是一个真正的问题(除非你的领域很大,你应该能够将数千个网站放入只有几 MB 的空间)或者如果你不介意升级你的 RAM 来增加你的数据库,那么 Redis 是非常合适的.

熟悉 Redis 的各种持久化选项和配置,以及它们对可用性和可靠性的意义。另外,请确保您已准备好备份解决方案。我会建议同时拥有一个从主实例脱离的辅助 Redis 实例,以及一个至少每天备份您的 Redis 数据库文件的循环过程。

关于php - Redis 增删改查模式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20923827/

有关php - Redis 增删改查模式的更多相关文章

  1. ruby-on-rails - Rails - 子类化模型的设计模式是什么? - 2

    我有一个模型:classItem项目有一个属性“商店”基于存储的值,我希望Item对象对特定方法具有不同的行为。Rails中是否有针对此的通用设计模式?如果方法中没有大的if-else语句,这是如何干净利落地完成的? 最佳答案 通常通过Single-TableInheritance. 关于ruby-on-rails-Rails-子类化模型的设计模式是什么?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.co

  2. ruby - 解析 RDFa、微数据等的最佳方式是什么,使用统一的模式/词汇(例如 schema.org)存储和显示信息 - 2

    我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i

  3. ruby - 如何在续集中重新加载表模式? - 2

    鉴于我有以下迁移:Sequel.migrationdoupdoalter_table:usersdoadd_column:is_admin,:default=>falseend#SequelrunsaDESCRIBEtablestatement,whenthemodelisloaded.#Atthispoint,itdoesnotknowthatusershaveais_adminflag.#Soitfails.@user=User.find(:email=>"admin@fancy-startup.example")@user.is_admin=true@user.save!ende

  4. ruby - 是否有用于序列化和反序列化各种格式的对象层次结构的模式? - 2

    给定一个复杂的对象层次结构,幸运的是它不包含循环引用,我如何实现支持各种格式的序列化?我不是来讨论实际实现的。相反,我正在寻找可能会派上用场的设计模式提示。更准确地说:我正在使用Ruby,我想解析XML和JSON数据以构建复杂的对象层次结构。此外,应该可以将该层次结构序列化为JSON、XML和可能的HTML。我可以为此使用Builder模式吗?在任何提到的情况下,我都有某种结构化数据-无论是在内存中还是文本中-我想用它来构建其他东西。我认为将序列化逻辑与实际业务逻辑分开会很好,这样我以后就可以轻松支持多种XML格式。 最佳答案 我最

  5. ruby-on-rails - environment.rb 中设置的常量在开发模式中消失 - 2

    了解Rails缓存如何工作的人可以真正帮助我。这是嵌套在Rails::Initializer.runblock中的代码:config.after_initializedoSomeClass.const_set'SOME_CONST','SOME_VAL'end现在,如果我运行script/server并发出请求,一切都很好。然而,在我的Rails应用程序的第二个请求中,一切都因单元化常量错误而变得糟糕。在生产模式下,我可以成功发出第二个请求,这意味着常量仍然存在。我已通过将以上内容更改为以下内容来解决问题:config.after_initializedorequire'some_cl

  6. Ruby:标准递归模式 - 2

    我经常迷上ruby​​的一件事是递归模式。例如,假设我有一个数组,它可能包含无限深度的数组作为元素。所以,例如:my_array=[1,[2,3,[4,5,[6,7]]]]我想创建一个方法,可以将数组展平为[1,2,3,4,5,6,7]。我知道.flatten可以完成这项工作,但这个问题是作为我经常遇到的递归问题的一个例子-因此我试图找到一个更可重用的解决方案。简而言之-我猜这种事情有一个标准模式,但我想不出任何特别优雅的东西。任何想法表示赞赏 最佳答案 递归是一种方法,它不依赖于语言。您在编写算法时要考虑两种情况:再次调用函数的情

  7. ruby - 在 Ruby 中查找多个正则表达式匹配的模式和位置 - 2

    这应该是一个简单的问题,但我找不到任何相关信息。给定一个Ruby中的正则表达式,对于每个匹配项,我需要检索匹配的模式$1、$2,但我还需要匹配位置。我知道=~运算符为我提供了第一个匹配项的位置,而string.scan(/regex/)为我提供了所有匹配模式。如果可能,我需要在同一步骤中获得两个结果。 最佳答案 MatchDatastring.scan(regex)do$1#Patternatfirstposition$2#Patternatsecondposition$~.offset(1)#Startingandendingpo

  8. ruby - sinatra 框架的 MVC 模式 - 2

    我想开始使用“Sinatra”框架进行编码,但我找不到该框架的“MVC”模式。是“MVC-Sinatra”模式或框架吗? 最佳答案 您可能想查看Padrino这是一个围绕Sinatra构建的框架,可为您的项目提供更“类似Rails”的感觉,但没有那么多隐藏的魔法。这是使用Sinatra可以做什么的一个很好的例子。虽然如果您需要开始使用这很好,但我个人建议您将它用作学习工具,以对您来说最有意义的方式使用Sinatra构建您自己的应用程序。写一些测试/期望,写一些代码,通过测试-重复:)至于ORM,你还应该结帐Sequel其中(imho

  9. ruby-on-rails - Rails 如何创建数据模式种子数据 - 2

    有没有一种方法可以自动生成种子数据文件并创建种子数据,就像您在下面链接中的Laravel中看到的那样?LaravelDatabaseMigrations&Seed我在另一个应用程序上看到在Rails的db文件夹下创建了一些带有时间戳的文件,其中包含种子数据。创建它的好方法是什么? 最佳答案 我建议你使用Fabrication的组合gem和Faker.Fabrication允许您编写一个模式来构建您的对象,而Faker为您提供虚假数据,如姓名、电子邮件、电话号码等。这是制造商的样子:Fabricator(:user)dousernam

  10. ruby-on-rails - Ruby on Rails 应用程序的只读模式 - 2

    我有一个交互式RubyonRails应用程序,我想在特定时间将其置于“只读模式”。这将允许用户读取他们需要的数据,但阻止他们执行写入数据库的操作。执行此操作的一种方法是在数据库中放置一个true/false变量,该变量在进行任何写入之前进行检查。我的问题。有没有更优雅的解决方案来解决这个问题? 最佳答案 如果你真的想阻止任何数据库写入,我能想到的最简单的方法是覆盖readonly?始终返回true的模型方法,无论是在选定模型中还是对于所有ActiveRecord模型。如果模型设置为只读(通常通过调用#readonly!来完成),任何

随机推荐