7

我遇到了数据库中的数据恢复到旧状态的问题。我想我已经将问题缩小到这种情况。

想象一下像这样发生的两次购买的序列:

  • 所有缓存节点都在工作
  • 用户登录(他们的数据从数据库中提取并存储在 memcached 中)
  • 缓存节点宕机
  • 用户继续浏览(由于在缓存中找不到他们的数据,因此从数据库中提取并存储在 memcached 中)
  • 用户执行一些操作来转换他们的记录[例如升级](他们的记录在缓存和数据库中更新)
  • 缓存节点恢复
  • 我们再次从缓存中拉取用户的数据,它来自之前关闭的原始缓存节点
  • 现在我们有一个问题:缓存中的节点已过期!
  • 用户进行另一个操作来转换他们的记录
  • 这保存在缓存和数据库中,但由于它基于过时的记录,因此它会踩踏先前的更改并有效地还原它

我们现在丢失了数据,因为数据库记录被部分过时的信息重写。

如何使用 PHP5 和具有持久连接的 libmemcached 来防止这种情况发生?我想我想要的是让缓存节点根本不进行故障转移;它应该只是无法读取和写入该节点,但不会将其从池中删除,这样我就不会得到重复的记录。

当一个节点出现故障时,这将使我的数据库上的负载增加 1/n(其中 n 是缓存节点的总数),但这比以不一致的数据结束要好。

不幸的是,我无法理解应该更改哪些设置才能获得此行为。

4

2 回答 2

2

我喜欢Doctrine ORM 中实现的版本控制和乐观锁方法。你也可以做到的。它不会增加数据库的负载,但需要进行一些重构。

基本上,您向所有正在缓存的表添加版本号,将update查询更改为递增版本version = version + 1并添加where version=$version条件(请注意$version来自您的 php/memcache)。您将需要检查受影响的行数,如果为 0,则抛出异常。

如何处理此类异常取决于您。您可以只使该记录的缓存无效,并要求用户重新提交表单,或者您可以尝试合并更改。此时,您有来自缓存的陈旧数据、来自用户输入的更新以及来自数据库的新数据,因此唯一不可恢复的情况是同一列有 3 个不同的值。

于 2016-01-12T10:13:02.973 回答
1

您正在使问题变得更加复杂,一个简单的方法应该只是将缓存标记为脏并重建它,而不仅仅是将其重新投入使用,并且上面有不一致的数据。

于 2016-01-15T20:02:38.037 回答