对不起,我不需要预览

现在常常碰到这样的事情,浏览网页,看到一个链接,正准备点过去,鼠标移到链接位置就好像被什么东西沾住一样,然后拖拖拉拉嘎吱嘎吱弹出一个比邮票大一点的tooltip,让你预览一下这个链接对应的地址。

这真是一种很差的用户体验。

一个网页,又不是什么两个小时的电影,我还要看个预告片再决定点不点过去。再说了,你那个屁大点的预览,除了提供这种可怕服务的网站的logo(一般都叫snap什么),基本什么也看不清楚了。至少,你也应该做到象普通tooltip一样的延迟加载,别那么热情的就蹦出来。

强烈建议大家不要搞这种中看不中用的东西。

3 条评论

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,

  1. memcached清除过期缓存c。
  2. 实例A运行foo_action,发现缓存c不存在(Cache.get失败),读取数据d。
  3. 实例B更新数据d’,清除过期缓存c(Cache.delete)。
  4. 实例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”变成“用memcached set方法(也就是memcached-client中的Cache.put)来更新缓存c”,然后在第四步中始终用add方法来更新缓存c,就可以解决问题。也就是说,在能够确认数据是最新的地方,比如after save中,不采用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,修改缓存更新策略吧。

8 条评论

代友招聘 - 微软公司Windows驱动程序开发

有一个微软的驱动程序开发的职位,月薪3万,要求如下:

  • 5到10年的开发经验
  • 五年以上Windows和Linux驱动程序开发经验。
  • 熟悉Windows核模式开发、并发和多线程。
  • 有设备和Firmware开发经验的优先考虑。

有兴趣的直接和Ivy Sun联系,电话010-59796686-827,msn:ivysun87721@gmail.com。

大家踊跃报名啊。

发表评论

Tags:

Bookmarks:

My music: