存储在内存中的PHP统计对象并发更新=数据丢失​​?

时间:2011-03-13 10:14:20

标签: php apc

我想将计算系统中对象的统计数据抽象到一个地方。此时,每个对象在MySQL表中的行上增加一个计数器,即UPDATE sometable SET views = views + 1 WHERE id = ?

为了获得显着的性能提升而不是每次使用对象时都将此更新写入数据库,我想使用apc将单个分析对象存储在此对象的内存增量计数器中并定期保存反对数据库。

但是,我理解如果两个人访问同一页面并增加stats对象,如果他们都$obj->views = $obj->views + 1,那么其中一个视图可能会丢失,因为从apc获得的stats对象可能会丢失相同的总视图数,它们都增加一个,然后相互覆盖。

我该如何解决这个问题?

1 个答案:

答案 0 :(得分:5)

如果您分三步采取行动:

  • 从APC获取条目
  • 正在努力
  • 将其推回APC

然后,是的,您可能会遇到并发问题。


一个更好的解决方案是为每个计数器提供一个APC条目;并使用apc_inc()函数递增它。

这可能意味着有许多条目(每个柜台一个) - 但这也意味着,在大多数注意事项中(当递增计数器时,这将是最多的工作) ,您不必关心并发性:APC会为您处理。


唯一应该保留的问题是你想要:

  • 获取计数器的值
  • 将该值存储到数据库
  • 并重置柜台。

在那里,您可能会再次遇到并发问题。

两种解决方案:

  • 考虑到这种情况不会再发生(与增量相比,此操作应该非常少见),并接受松散一点数据
  • 自己处理锁定机制:
    • 创建一个说“此计数器已锁定”的APC条目
    • 抓取+ DB事物+重置
    • 取消锁定
    • 与此同时,如果其他一些脚本想要递增计数器,它应该检查锁定条目是否存在;如果是这样,请等待几毫秒,直到锁定被移除。


现在作为几个旁注:

  • 你可以用memcached做同样的事情,那天你需要几个网络服务器 - 见Memcache::increment
  • 在这两种情况下,APC和memcached都是缓存机制,而不是持久的数据存储!这意味着他们可以在需要时逐出您的数据(当他们没有足够的内存留给新条目时,或当您的条目变得太旧时,就会发生这种情况)

对于第二点,您可能希望切换到另一个解决方案,即:

  • 比MySQL更快
  • 坚持使用磁盘