memcached使用中的竞争条件

在通过ruby的memcached-client使用memcached的过程中,遇到一些问题,数据更新时清除了缓存,缓存重建的时候却仍然是老数据,在并发密集的情况下更容易出现。研究了一下,类似这样典型的memcache使用方法: Controller里: … def foo_action … unless d = Cache.get(“key”) d = Data.find(…) Cache.put(“key”, d) end … end … Model里 … def after_save … Cache.delete(“key”) … end … 存在下面的竞争条件(race condition): 存在两个rails应用实例(比如两个并发的mongrel)A和B, memcached清除过期缓存c。 实例A运行foo_action,发现缓存c不存在(Cache.get失败),读取数据d。 实例B更新数据d’,清除过期缓存c(Cache.delete)。 实例A保存缓存c(Cache.put),其中的数据是老数据d。 这时,再有数据访问缓存c的时候,c已经存在,到下一次缓存c被清除前,这个缓存都是存在问题的过期数据。不难看出,即使将第三步中的清除过期缓存c改成更新缓存c,c仍然会被实例A在第四步覆盖。 其实,memcached为了避免这种竞争条件,提供了一些便利的原子操作(参看memcached protocol): “add” means “store this data, but only if the server *doesn’t* already hold data for this key”. Read more about memcached使用中的竞争条件[…]