memcached使用中的竞争条件
来源:互联网 发布:java case switch 编辑:程序博客网 时间:2024/04/30 18:28
原贴:http://www.robinlu.com/blog/archives/166
在通过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”.
“cas” is a check and set operation which means “store this data but
only if no one else has updated since I last fetched it.”
将第三步中的“清除过期缓存c”变成“用memcachedset方法(也就是memcached-client中的Cache.put)来更新缓存c”,然后在第四步中始终用add方法来更新缓存c,就可以解决问题。也就是说,在能够确认数据是最新的地方,比如aftersave中,不采用Cache.delete,而直接用Cache.put来更新缓存,在不能确认是否是最新数据的其它地方,只使用Cache.add,就能保证过期数据不会在race condition下覆盖新数据。(更新:无论是Cache.delete还是Cache.put,放在after_save中仍然有问题,会因为activerecord的built-in transaction而破坏了数据的完整性,具体参见再谈rails缓存机制的问题)
memcached-client从1.4.0起才开始支持add方法,目前还不支持cas方法。不过add方法已经能够解决不少竞争条件了。如果你也有类似的问题,升级memcached-client,修改缓存更新策略吧。
<script type="text/javascript"><!--google_ad_client = "pub-3840511892024359";google_ad_width = 468;google_ad_height = 60;google_ad_format = "468x60_as";google_ad_type = "text_image";google_ad_channel ="";google_color_border = "FFFFFF";google_color_bg = "FFFFFF";google_color_link = "000000";google_color_text = "999999";google_color_url = "999999";//--></script>有8 条关于 “memcached使用中的竞争条件”的留言
- memcached使用中的竞争条件
- 竞争条件
- Java多线程中的竞争条件、锁以及同步的概念
- Memcached 使用中的问题
- 【Linux编程】竞争条件
- Race Condition(竞争条件)
- php memcached使用中的坑
- 安全编程: 避免竞争条件
- 安全编程: 避免竞争条件
- 安全编程: 避免竞争条件
- 避免竞争条件的实例
- 竞争条件(race condition)
- DigitalOcean的条件竞争漏洞
- 竞争条件和临界区
- 竞争条件和关键区
- 安全编程: 避免竞争条件
- 竞争条件(race condition)
- 竞争条件(race condition)
- 深入分析与破解QQ键盘加密保护
- arm-linux-gcc 4.3.2编译安装过程
- ACE介绍 中文
- 教你删除笔记本上被隐藏的恢复分区
- 教你使用MySQL触发器自动更新memcache
- memcached使用中的竞争条件
- 合理使用Memcached进行缓存部署
- VMware Workstation 6.0.2.59824 Net方式无法上网的解决办法
- 将MySQL数据映射到Memcached中
- Opengoo 1.3 RC1版本正式发布了,简体中文语言包也更新过了。
- LUA语言学习教程收藏
- PHP5 像使用数组一样使用Memcache
- 让memcached和mysql更好的工作
- JAVA中的反射机制详解
Thanks for sharing.
[...] - memcached使用中的竞争条件 » 石锅拌饭 | 互联网 Mac & 软件开发,累计共2个收藏 ror中解决memcached缓存无法及时更新的问题。cas(clear and set) [...]
大多数情况把取数据时候生成缓存的set改成add应该就够了
修改或删除数据时 如果需要set的话 又得去获取一次完整的缓存数据 直接delete 等取数据的时候再生成好了
这样应该会简单些
当然如果能很方便得到完整的需要缓存的数据 在修改后直接set更好 那样可以直接让下次被访问时就直接从缓存取数据
楼上,请仔细阅读我的原文,你就能理解为什么不能在取数据的时候再生成。
直接把set改成add是不能解决问题的,除非你在add的时候能够确认你使用的是新数据,否则可能会把事情搞得更糟糕。
嗯 有竞争的时候确实是会有问题 但是可能被查询到的数据有上亿条 并且有各种组合 不可能把它们全部放进缓存 现在只是当个别被访问到的时候才进行缓存 然后设置一个过期时间 如果不在取数据的时候生成缓存 有什么好方法吗 不吝赐教
设置缓存的时候 数据是从master而不是slave数据库取 基本能保证数据是新的 在取出数据到设置缓存这一瞬间如果有并发的写 确实会有问题
对于你上面提到的情况,如果数据更新相对频繁,对展示准确性要求不是十分严格的情况下,可以通过缩短缓存过期时间来缓解这个问题。如果对数据一致性要求非常严格,可以配合cas方法来解决。cas方法为数据添加了“版本”信息,能解决更多的竞争问题。
目前ruby的memcached-client没有实现cas方法,需要自己实现。
[...]我们首先怀疑是出现了类似“memcached使用中的竞争条件”中提到的问题,于是在缓存清除和创建的地方分别添加日志。结果很让我们吃惊,在after_save里用find取出的数据的确是新的,创建缓存的时间明显晚于after_save被调用的时间,但用同样的方法取出的数据却是旧的。[...]