0

我们使用 Yii 框架和 Memcached 进行缓存。

我们有以下问题:

  1. 我们进行数据库查询 q
  2. 如果 q 已经被缓存,我们从 memcache 中获取数据
  3. 否则yii查询Mysql
  4. 设置缓存值
  5. 我们从 memcache 中取回结果

如果我们在设置 memcache 键之前(在步骤 4 之前)再次请求相同的查询 q,那么因为没有设置 memcache 键,我们再次查询 db。

我们想将此行为更改为:

  1. 我们进行数据库查询 q
  2. 如果 q 的键存在于内存缓存中并且值不为空,则返回值
  3. 否则,如果设置了 key 并且 value 为 null 设置 memcache key => null
  4. 设置缓存值
  5. 我们从 memcache 中取回结果

这是发生了什么以及我们想要什么的伪代码:

get(q):
    if q not in memcache:
        value = query_db(q)
        memcache[q] = value
        return memcache[q]
    else:
        return memcache[q]

getNew(q):
    if q not in memcache:
        memcache[q] = null
        value = query_db(q)
        memcache[q] = value
        return memcache[q]
    elif q in memcache and memcache[q] != null:
        return memcache[q]
    else:
        while True:
            if memcached[q] != null:
                return memcached[q]
            else:
               sleep(3)

换句话说,我们希望在结果为 null 之前设置 memcache 键,并且相同查询的其他请求检查该值是否为 null 并等到该值不为 null (这意味着查询已经在处理)。

你知道yii frameworkd的哪一部分应该修改吗?

4

1 回答 1

0

Mysql 具有这些系统范围的锁定功能,可以提供帮助:get_lock并且release_lock 这些锁定名称字符串。

这个想法是定期检查你已经拥有的内存缓存,然后检查这个确切的查询本身是否已经使用锁名称进行处理。为此,每个查询都需要一个唯一的锁名称。锁定名称可以使用十六进制crc32($sql)(php 中最快的非加密哈希算法)生成,这将为每个查询生成一个 4 字符的唯一十六进制字符串。

TIMEOUT可能是一个很大的数字

getNew(q):
    if q not in memcache:
        hash = crc32hex(q)
        if mysql-is_free(hash) == 0 # means query is processing
            # now attach youself to the other thread's synchronous exit
            if(mysql-get_lock(hash,TIMEOUT)==1) #waiting...
                release_lock(hash)
                # call self since by now, memcache has your value
                return getNew(q)                     
            endif
        endif
        if(mysql-get_lock(hash,TIMEOUT)==1)  
            value = query_db(q)  
            memcache[q] = value
            mysql-release_lock(hash)
        endif
        return memcache[q]
    else:
        return memcache[q]
于 2013-03-21T15:20:54.327 回答