存储在内存中的PHP Stats对象并发更新=数据丢失​​? [英] PHP Stats Object Stored in Memory Concurrent Updates = Data Loss?

查看:92
本文介绍了存储在内存中的PHP Stats对象并发更新=数据丢失​​?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想将统计数据统计到我的系统中的单个位置.此刻,每个对象都会在MySQL表中的行上增加一个计数器,即UPDATE sometable SET views = views + 1 WHERE id = ?

I want to abstract stats counting on objects within my system to a single place. At the moment each object increments a counter on its row in the MySQL table i.e. UPDATE sometable SET views = views + 1 WHERE id = ?

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

In order to get a significant performance gain instead of writing this update to the DB every time the object is used, I'd like to use apc to store a singleton analytics object in memory increment counters within this object and periodically save this object back to the DB.

但是我的理解是正确的,如果两个人访问同一页面并增加stats对象,则如果他们两个都执行$obj->views = $obj->views + 1,则其中一个视图可能会丢失,因为从apc获取的stats对象将具有相同的视图总观看次数,它们都加1,然后彼此覆盖.

However am I right in understanding that if two people visit the same page and increment the stats object it's possible that one of the views could be lost if they both do $obj->views = $obj->views + 1 because the stats object got from apc will have the same total view count, they both increment one and subsequently overwrite each other.

我该如何解决?

推荐答案

如果您采取三个步骤:

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

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

Then, yes, you might have concurrency problems.


更好的解决方案是每个计数器都有一个APC条目.并使用 apc_inc() 函数来增加它.


A better solution would be to have one APC entry for each one of your counters ; and use the apc_inc() function to increment it.

这可能意味着有许多条目(每个计数器一个)-但是这也意味着,在大多数情景中,(增加计数器时,这将是最多的操作) ,您不必在乎并发:APC会为您处理并发.

It probably means having many entries (one per counter) -- but it also means that, in most sitautions (when incrementing the counters, which is what will be done the most), you won't have to care about concurrency : APC will deal with that for you.


唯一应该保留的问题是何时:


Only problem that should remain is when you'll want to :

  • 获取计数器的值,
  • 将该值存储到数据库中,
  • 然后重置计数器.

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

There, You might meet concurrency problems again.

两种解决方案:

  • 考虑到这种情况不会再次发生(与增量操作相比,此操作应该很少见),并接受丢失一些数据
  • 用锁定的机制进行交易:
    • 创建一个显示此计数器已锁定"的APC条目
    • 执行获取+数据库操作+重置
    • 取下锁
    • 同时,如果某些其他脚本想要增加计数器,则应检查是否存在锁条目;如果是这样,请等待几毫秒,直到锁被解除.
    • Consider this will not happen again (this operation should be quite rare, compared to the incrementation), and accept to loose a little bit of data
    • Deal with a locking mecanism yourself :
      • Create an APC entry that says "this counter is locked"
      • Do the fetching + DB thing + reset
      • Remove the lock
      • In the meantime, if some other script wants to increment the counter, it should check if the lock-entry is there ; and if so, wait a couple milliseconds, until the lock is removed.


      作为旁注,现在:


      As a couple of sidenotes, now :

      • 在需要多个Web服务器的那一天,您可以使用memcached执行相同的操作-请参阅 Memcache::increment
      • 在这两种情况下,APC和memcached都是缓存机制,而不是持久性数据存储!这意味着他们可以在需要时随时撤出您的数据(当他们没有足够的内存来容纳新条目时,或者您的条目变得太旧时,就会发生这种情况)
      • You could do the same kind of things with memcached, the day you need several web-servers -- see Memcache::increment
      • In both cases, APC and memcached are caching mecanism, and not persistant data-stores ! Which means they can evict your data whenever they need to (this will happen when they don't have enough memory left for new entries, or when your entries will become too old)

      第二点,您可能想切换到另一个解决方案,那就是:

      For the second point, your might want to switch to another solution, that would :

      • 比MySQL快
      • 坚持到磁盘

      这篇关于存储在内存中的PHP Stats对象并发更新=数据丢失​​?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆