【问题标题】:Cache invalidation causing high load缓存失效导致高负载
【发布时间】:2014-03-09 21:59:47
【问题描述】:

假设我们的 php 脚本每秒有 10K 请求。

每个请求都在检查 memcached(或任何其他缓存存储)中的缓存。如果找到缓存 - 一切正常并返回缓存值。如果未找到缓存,我们将执行慢速 SQL 查询来填充缓存。它是最常见和最简单的缓存方案:

$result = $this->loadFromCache($key);
if (empty($result)) {
    $result = $this->makeSlowSqlQuery();
    $this->writeToCache($key, $result);
}
//do something with $result;

在我们没有太多请求之前,此方案运行良好。一旦我们有太多的请求,我们将面临大量请求在缓存中找不到任何东西并尝试重新填充它的情况。所以它们都将开始执行慢速 SQL 查询,这将导致高负载影响。解决办法是什么?

作为可能的解决方案,我看到以下情况:发现缓存无效的第一个请求应该创建一些触发器,说明缓存重新填充已经开始,另一个请求应该等待新缓存或使用旧(以前)版本。

你如何解决类似的问题?

【问题讨论】:

    标签: php caching memcached high-load


    【解决方案1】:

    你本质上想要的是一个锁模式:

    $lockPrefix = "!lock__";
    $result = $this->loadFromCache($key);
    if (empty($result)) {
         $sleepLimit = 2000; // 2s timeout
         $sleepCount = 0;
         $cacheBlocked = 0;
         while ($this->loadFromCache($lockPrefix . $key) == 1) {
             // signal that something else is updating the cache
             $cacheBlocked = 1;
             // sleep for 1ms
             usleep(1000);
             // timeout logic...
             $sleepCount++
             if ($sleepCount == $sleepLimit) {
                 die("Cache read timeout.");
             }
         }
         if ($cacheBlocked == 1) {
             // something else updated the cache while we were waiting
             // so we can just read that result now
             $result = $this->loadFromCache($key);
         } else {
             $this->writeToCache($lockPrefix . $key, 1); // lock
             $result = $this->makeSlowSqlQuery();
             $this->writeToCache($key, $result);
             $this->writeToCache($lockPrefix . $key, 0); // release
         }
    }
    

    这个想法是缓存是全局的,因此可用于跨请求保持锁定模式。您实际上是在缓存条目中创建一个互斥体,并添加了一些逻辑,以确保只启动一个慢查询。

    【讨论】:

      猜你喜欢
      • 2012-07-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-11-29
      • 1970-01-01
      • 1970-01-01
      • 2020-11-26
      • 2023-03-05
      相关资源
      最近更新 更多