Web 缓存设计实践

145 阅读1分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第1天,点击查看活动详情

缓存简介

  • 缓存在现在的Web系统中应用广泛,缓存主要可以帮助我们提升系统的吞吐量。
  • 现在成熟的缓存系统,一般使用Redis或者内存缓存来保障我们Web系统的稳定。缓存有多种分类,下面是我在后端实际开发中常用的缓存伪码,分享给你。

缓存的适用场景

  • 数据实时性要求不高。读多写少,比如常见的网站内容缓存。
  • 高并发场景,用来提升系统的吞吐量。

缓存key设计原则

  • 任何变量的命名都应该有规则,key的命名要有意义 建议采用的规范是 groupName:projectName:xxx:xxx

  • 每一个key要设置过期时间,提升空间利用率。

读缓存

function getData($key) {
    $data = $cache->get($key);
    if (!empty($data)) {
        return $data;
    }
    
    $data = getDataFromDb($key);
    
    $cache->set($key, $data, $expierTime);
    
    return $data;
}

写缓存

function setData($key, $data) {
    try {
        $result = $db->update($data);
        if ($result) {
            $cache->delete($key);
        }
    } catch (Exception $e) {
        // todo 异常处理
    }
}

高并发场景的缓存设计

读缓存

  1. 对于每次数据库都查不到的数据,存在缓存穿透的现象。 即使DB返回的结果为空,我们也设置一个默认值的缓存。
function getData($key) {
    $data = $cache->get($key);
    if (!empty($data)) {
        return $data;
    }
    
    $data = getDataFromDb($key);
    
    if (empty($data)) {
        // 设置默认返回值
        $data = $default_data;
    }
    
    $cache->set($key, $data, $expierTime);
    
    return $data;
}
  1. 缓存失效时间的处理 目标:缓存失效的时候,只有一个请求走db。 思路:把缓存时间放到数据中判断。
function getData($key) {
    $data = $cache->get($key);
    if (!empty($data)) {
        // 未过期,直接返回
        if ($data['expireTime'] > time() ) {
            return $data['data'];
        }
        // 缓存已过期,但未获得锁,返回数据,只让一个请求穿透
        if (!$cache->setNx()) {
            return $data['data'];
        }
    }
    
    $data = getDataFromDb($key);
    
    if (empty($data)) {
        // 设置默认返回值
        $data = $default_data;
    }
    
    // 过期时间提前60s
    $data = [
        'data' => $data;
        'expireTime' => $expierTime - 60;
    ];
    
    $cache->set($key, $data, $expierTime);
    
    return $data;
}