基于分数的PHP内存缓存

时间:2015-07-30 16:33:42

标签: php caching

我试图制作基于分数的PHP内存缓存,但我的性能有问题(如何计算分数和删除低分记录)。

目标

我有大约1000万条记录。 我想只在内存中缓存0.1%的最常见记录,而不是光盘。

我想设置10,000个缓存插槽(0.1%),我想只保留这些插槽中最常用的插槽。

尝试/问题

我尝试了基于文件的缓存,但速度很慢。

我尝试过MySQL和PostgreSQL,但是计算分数和删除低分记录的性能成本太高。

我尝试了基于时间的缓存,例如。 xcache,但是因为我的项目中的数据太多,所以写得太多了。此外,删除最低分数记录并列出所有缓存位置也存在问题,因为它" key->值"。

我找到了Redis,但似乎没有任何得分或类似的东西。

我的问题:

我应该使用什么缓存方法进行基于分数的缓存?

请注意,所有这些帖子都相似,但不包含任何可用的答案:

Fastest PHP memory cache/hashtable

In-memory cache with LRU expiration

In-memory cache architecture/technology?

Need a php caching recommendation

2 个答案:

答案 0 :(得分:1)

听起来LRU缓存应该能满足您的需求。您可以将Redis配置为LRU缓存。可能它会很好地处理你的情况。 以下是redis文档的一些参考:http://redis.io/topics/lru-cache

快速总结一下, 你可以使用“allkeys-lru”驱逐政策,并将“maxmemory”设置为你想要的东西。一旦达到内存限制,redis将释放最近最少使用的项目,并将内存使用量保持在“maxmemory”下。

另一种选择是使用“memcached”,它是一个内存键值存储,默认情况下配置为LRU缓存。

如果您想亲自跟踪分数,并且已经为您的项目设置了某种评分机制,您可以使用Redis,您可以将SortedSet与Hash一起保存以对缓存项目进行排名。

哈希会保留您的缓存数据,而SortedSet会保持您的项目排名。

您需要这些SortedSet命令:

  • 您可以使用“ZADD”
  • 添加和更改项目分数
  • 您还可以使用“ZINCRBY”来更改项目分数。
  • 您可以使用“ZCARD”命令获取已排序集的总数。
  • 您可以使用ZRANGE获取得分最低的项目。
  • 您可以使用ZREM删除项目。

每次插入后,您都必须手动检查SortedSet的计数并限制缓存中的项目数。总的来说,算法是这样的:

缓存插入:

HSET "cacheKey" "itemName" "itemValue"
ZADD "rankingKey" "itemScore" "itemName"
count = ZCARD "rankingKey"
if (count > limit)
    lowestRankedItem = ZRANGE "rankingKey" 0 0
    ZREM "rankingKey" lowestRankedItem
    HDEL "cacheKey" lowestRankedItem

查找将是:

itemValue = HGET "cacheKey" "itemName"

答案 1 :(得分:0)

Pure LRU并不是很好,因为它会缓存所有新密钥,我只需要缓存0.1%的数据(得分很高),因此不会有太多无用的写作。

我确实会按照下一版本的建议实现Redis方法,因为速度要快得多。因此,只有在没有Redis的情况下使用此功能,如果您无法确定得分,只需计算每次点击次数或只是想要保持简单。

但我最好的尝试是使用key =>值memcached,现在只是测试,看起来快速而稳定。在我以错误的方式思考之前...

当缓存新项目时,我们检查缓存中是否存在得分(密钥缓存包含int),如果是,小于我们的限制,我们会增加分数,如果是,高于限制,我们获取内容并保存到缓存。如果缓存包含除数字以外的任何内容,则它是我们的内容(得分高)。如果密钥的缓存根本不存在,我们将int 1作为分数保存到具有非常短的TTL的缓存中,我们只获得没有任何缓存的内容(低分)。

<?php

$minhits = 10; // Min 10 hits for one key
$minhitstime = 60 // Max 60 seconds between hits
$cachettl = 3600; // Cache for 3600 seconds  

$key = "article1";

$mem = new Memcached();
$mem->addServer('localhost', 11211);

$content = $mem->get($key);

if(!$content OR (is_int($content) AND $content<$minhits)){
    $content = getArticleContent(); // Your own function
}

if(is_int($c)){
    if($c>=$minhits){
        $mem->set($key, $content, $cachettl);
    } else {
        $mem->set($key, ($c+1), $minhitstime);
    }
} elseif($c) {
    $content = $c;
} else {
    $mem->set($key, 1, $minhitstime);
}

echo $content;

?>

另外请不要尝试缓存仅限int的值;)如果是,则必须编辑代码。