PHP Stats Object Stored in Memory Concurrent Updat

2019-07-20 22:03发布

问题:

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 = ?

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.

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.

How do I get around this?

回答1:

If you act in three steps :

  • fetching an entry from APC
  • working on it
  • pushing it back to APC

Then, yes, you might have concurrency problems.


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.

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 :

  • Fetch the value of a counter,
  • Store that value to database,
  • And reset the counter.

There, You might meet concurrency problems again.

Two solutions :

  • 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 :

  • 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 :

  • Be faster than MySQL
  • Persist to disk


标签: php apc