在after_commit挂钩中缓存数据时确保一致性

时间:2016-09-07 07:22:49

标签: ruby activerecord concurrency thread-safety

对于特定的数据库表,我们需要一个始终与数据库同步的数据的内存缓存。我目前的尝试是将更改写入after_commit挂钩中的缓存 - 这样我们就确保不会对缓存进行任何更改,以便以后可以恢复。

但是,此策略容易受到以下情况的影响:

  1. 线程A锁定并更新记录,存储值1
  2. 主题A提交更改
  3. 线程B锁定并更新记录,存储值2
  4. 线程B提交更改
  5. 线程B运行after_commit挂钩,因此缓存现在具有值2
  6. 线程A运行after_commit挂钩,因此缓存现在具有值1但值应为2
  7. 我对这个问题是对的吗?如何解决这个问题?

2 个答案:

答案 0 :(得分:2)

你对这个问题是正确的。

有一个after_save回调在同一个事务中运行。您可能希望使用那个而不是在事务之后运行的after_commit挂钩。

但是你需要自己处理回滚交易。

或者您可能希望以不依赖于特定实例的方式编写缓存方法。但是,首先通过从数据库重新加载记录来缓存数据库中找到的最新版本。

但即便如此:多线程系统很难保持同步。而且你甚至无法确保是否会存储发送到缓存的第一个或第二个更新,因为缓存系统也可能是多线程的。

您可能想了解different consistency models

答案 1 :(得分:1)

我们提出的解决方案是锁定缓存以进行读/写before_commit并在after_commit中解锁。这似乎可以解决问题。