2

一旦我的特定事件发生,我希望能够在我的 Ruby on Rails 应用程序中使基于欧姆的对象的全部内容失效。目前是否可以配合 Redis + expire 来执行此操作?使用 Ohm 时,对象有多个与之关联的键,包括索引等。我想确保一切都得到正确清理 - 这就是为什么我想知道是否有官方支持的方式来执行此操作。

4

3 回答 3

2

抱歉不行。解决这个难题已经进行了多次尝试,但我所看到的每一个都在 Ohm 数据集中留下了伪影。它们都没有独特的属性,据我所知,它们都使欧姆数据处于不一致的状态。

一些例子:

例如,当一个 Ohm 模型保存时,有几个字段添加到 Redis 哈希,还有成员添加到 Redis 集。虽然您可以在整个哈希或集合上设置过期时间,但您不能使 Redis 哈希的单个字段或集合的单个成员过期。整个哈希或集合都过期了。

这是主要问题:如果这些集合和散列过期,您将丢失模型上的整个索引,或者您的唯一属性的完整记录。因此,使用任何 Ohm expire mixin 时的一个常见问题是,即使主数据键过期,调用find仍会从索引中返回一条记录,但哈希值为零。而且,如果您在模型中指定了唯一属性create,则即使数据本身已过期,您也不能再次使用过期值调用该模型而不会引发异常。

Redis 中没有过期回调,因此无法在特定键过期时触发删除哈希字段或设置成员。有几个人要求允许散列字段或集合成员在 Redis 问题列表中包含 TTL,但他们都(相当合理地)关闭了以下答案

嗨,这不会由原始设计实现:

键中没有嵌套类型。聚合数据类型的单个字段中没有复杂的功能。推理要复杂得多,并且受个人感觉、偏好和敏感性的影响很大,所以我没有客观的方法可以告诉你这是更好的;)

关闭。感谢您的报告。

例如,以下是 Ohm 源代码 ( ohm.rb, 651-699 ) 中的一些注释:

  # The base class for all your models. In order to better understand
  # it, here is a semi-realtime explanation of the details involved
  # when creating a User instance.
  #
  # Example:
  #
  #   class User < Ohm::Model
  #     attribute :name
  #     index :name
  #
  #     attribute :email
  #     unique :email
  #
  #     counter :points
  #
  #     set :posts, :Post
  #   end
  #
  #   u = User.create(:name => "John", :email => "foo@bar.com")
  #   u.incr :points
  #   u.posts.add(Post.create)
  #
  # When you execute `User.create(...)`, you run the following Redis
  # commands:
  #
  #   # Generate an ID
  #   INCR User:id
  #
  #   # Add the newly generated ID, (let's assume the ID is 1).
  #   SADD User:all 1
  #
  #   # Store the unique index
  #   HSET User:uniques:email foo@bar.com 1
  #
  #   # Store the name index
  #   SADD User:indices:name:John 1
  #
  #   # Store the HASH
  #   HMSET User:1 name John email foo@bar.com
  #
  # Next we increment points:
  #
  #   HINCR User:1:counters points 1
  #
  # And then we add a Post to the `posts` set.
  # (For brevity, let's assume the Post created has an ID of 1).
  #
  #   SADD User:1:posts 1
  #

但是人们通常尝试使欧姆数据过期的方式是使用更简单的方法(不操作唯一性或模型范围的索引):

  Ohm.redis.expire(object.key, @expire)
  Ohm.redis.expire("#{object.key}:_indices", @expire)

总之,在 Redis 中对数据过期进行细粒度控制的最佳方法是使用低级接口(例如redis-rb )设计自己的存储方法。

于 2013-07-20T23:41:43.473 回答
1

与使用 Redis 相比,使 Ohm 对象过期的更可靠方法是直接检查和删除对象,例如通过使用单独的过期线程。这可以检查模型对象,检测那些已过期的对象,并通过 Ohm 请求删除。

Ohm 使用Lua 脚本以原子方式执行删除,这会正确清除与对象关联的所有键,并从其他 Ohm 结构中删除对对象的引用。使用欧姆删除是干净到期的最佳选择。

通过使用这样的设计,您可能需要在性能与可靠性之间进行权衡:您的程序本质上将在所有已知对象上执行垃圾收集,这可能涉及大量内存访问和/或 Redis 查询。

下面是一个清理线程如何工作的示例:

def start_expiry_thread expiry_cycle

  Thread.new {

    while (true) do

      MyOhmModel.all.each do |object|
        object.delete if object.expired
      end

      sleep expiry_cycle

    end

  }

end

在 Ohm::Timestamps 模块的支持下,可以在 Ohm 模型类(通过继承或 mixin)中按照以下行实现过期函数:

@max_life = 3600

def expired            
    (time_since_update > @max_life)
end

def time_since_update
    updated_secs = self.updated_at.to_i
    (Time.now.to_i - updated_secs)
end

笔记:

  • 引入线程时要小心——使用锁定来防止两个线程同时访问同一个对象,或者简单地避免共享对象并让你的过期线程直接进入 Redis。

  • 如果您的应用程序进程有定期计划重启,另一种方法是在启动过程中执行清理,然后再启动任何其他工作线程。

  • 确保您的其他应用程序代码优雅地处理到期 - 底层 Redis 对象将消失,这意味着应用程序代码持有的任何等效对象都将无效。

  • 以上是生产系统代码的简化版本,因此在简化过程中可能会出现错误。

  • 更一般地说:请检查您是否真的需要欧姆。如果您正在考虑在键值存储之上添加相当于关系层的内容,您应该认真考虑系统的技术设计。

于 2014-09-11T22:12:53.107 回答
0

我为 Ohm 开发了一个 gem 来处理它。

看看:ohm-expire

于 2012-05-16T13:07:48.503 回答