数据与发生故障的缓存节点不一致


Inconsistent data with a failed cache node

我遇到一个问题,数据库中的数据正在恢复到旧状态。我想我已经把问题缩小到这种情况了。

想象一下,两次购买的顺序如下:

  • 所有缓存节点都在工作
  • 用户登录(他们的数据从数据库中提取并存储在memcached中)
  • 缓存节点出现故障
  • 用户继续浏览(由于在缓存中找不到他们的数据,因此从数据库中提取数据并存储在memcached中)
  • 用户执行一些操作来转换他们的记录[例如调平](他们的记录在缓存和数据库中更新)
  • 缓存节点返回
  • 我们再次从缓存中提取用户的数据,它来自之前关闭的原始缓存节点
  • 现在我们遇到了一个问题:缓存中的节点已过期
  • 用户执行另一个操作以转换其记录
  • 这被保存在缓存和数据库中,但由于它是基于过时的记录,因此它会践踏以前的更改并有效地恢复它

我们现在已经丢失了数据,因为数据库记录被重写,其中部分信息已过期。

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

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

不幸的是,我很难理解应该更改什么设置才能获得这种行为。

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

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

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

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