Yii一个Memcache

时间:2013-03-21 11:47:59

标签: php caching yii memcached

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

我们遇到以下问题:

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

    如果我们在设置memcache密钥之前再次请求相同的查询q(在步骤4之前) 然后因为未设置memcache密钥,我们再次查询db。

    我们希望将此行为更改为:

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

      以下是发生的事情和我们想要的伪代码:

      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框架的哪一部分吗?

1 个答案:

答案 0 :(得分:0)

Mysql具有以下系统范围的锁定功能,可以提供帮助:get_lockrelease_lock 这些采取锁名称字符串。

这个想法是定期进行memcache检查,然后检查这个确切的查询本身是否已经使用锁名进行处理。为此,每个查询都需要一个唯一的锁名称。锁定名称可以使用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]