我们正在使用Yii框架和Memcached进行缓存。
我们遇到以下问题:
如果我们在设置memcache密钥之前再次请求相同的查询q(在步骤4之前) 然后因为未设置memcache密钥,我们再次查询db。
我们希望将此行为更改为:
以下是发生的事情和我们想要的伪代码:
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框架的哪一部分吗?
答案 0 :(得分:0)
Mysql具有以下系统范围的锁定功能,可以提供帮助:get_lock
和release_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]