边缘缓存模式 Cache Aside Pattern

未匹配的标注

描述

从存储器中需要的数据加载到缓存。

背景和问题

应用程序使用缓存能优化重复访问存储器数据的问题。但是缓存和存储器的数据可能不一致。

解决方案

读缓存
先读cache,再读db。
1. 如果cache里有数据,直接返回数据。
2. 如果cache里没有数据,那么访问db,并且把数据写到缓存中。

更新缓存
双删缓存策略,最大限度保障数据的一致性。
1. 删除cache。
2. 更新 db。
3. 再删除 cache。

注意事项

1. 缓存的生命周期(有效期TTL)。
2. 缓存淘汰策略。一般采用最近最少使用的策略,但是淘汰缓存是很耗资源的,最好的淘汰策略就是不用启动缓存淘汰机制。
3. 预分配缓存策略。
4. 缓存和储存器数据之间的一致性策略。
5. 使用共享缓存或者分布式缓存而不是本地缓存。

何时使用

需要统一管理缓存时。

可用到的设计模式思维

缓存可以有很多选择,例如:redis,memcache,
数据的存储也是,例如:mysql,mongo,甚至是文件。
这里是典型的桥接模式。

结构中包含的角色

1. Cache 抽象缓存接口
2. Storage 抽象仓库接口
3. RedisCache 具体缓存类
4. MysqlStorage 具体仓库类
5. CacheAsideManager 边缘缓存管理者

最小可表达代码 - 桥接模式实现

interface Cache
{
    public function get($key);

    public function set($key, $value, $tll = null);

    public function del($key);
}

interface Storage
{
    public function get($id);

    public function update($id, $value);   
}

class RedisCache implements Cache
{
    private $data = []; // 没别的意思,模拟效果而已

    public function get($key)
    {
        return $this->data[$key] ?? null;
    }

    public function set($key, $value, $tll = null)
    {
        $this->data[$key] = $value;
    }

    public function del($key)
    {
        unset($this->data[$key]);
    }
}

class MysqlStorage implements Storage
{
    private $data = [
        ['name' => '张三'],
    ];

    public function get($id)
    {
        return $this->data[$id] ?? null;
    }

    public function update($id, $value)
    {
        $this->data[$id] = $value;
    }
}

class CacheAsideManager
{
    private $cache;
    private $storage;

    private const TTL = 3600;
    private const CACHE_KEY_TEMPLATE = 'test:{key}';

    public function __construct(Cache $cache, Storage $storage)
    {
        $this->cache = $cache;
        $this->storage = $storage;
    }

    public function get($id)
    {
        $key = $this->getCacheKey($id);

        $data = $this->cache->get($key);
        if ($data) {
            var_dump('获取缓存');

            return $data;
        }

        $data = $this->storage->get($id);
        if ($data) {
            var_dump('设置缓存');

            $this->cache->set($key, $data, self::TTL);
        }

        var_dump('获取原数据');

        return $data;
    }

    public function update($id, $value)
    {
        $key = $this->getCacheKey($id);

        $this->cache->del($key);

        $this->storage->update($id, $value);

        $this->cache->del($key);
    }

    protected function getCacheKey($id)
    {
        return strtr(self::CACHE_KEY_TEMPLATE, ['{key}' => $id]);
    }
}

$id = 0;
$cacheAsideManager = new CacheAsideManager(new RedisCache, new MysqlStorage);
$data = $cacheAsideManager->get($id);
$data = $cacheAsideManager->get($id);
var_dump($data);

$cacheAsideManager->update($id, [
    'name' => '李四',
]);
$data = $cacheAsideManager->get($id);
var_dump($data);

本文章首发在 LearnKu.com 网站上。

上一篇 下一篇
《L05 电商实战》
从零开发一个电商项目,功能包括电商后台、商品 & SKU 管理、购物车、订单管理、支付宝支付、微信支付、订单退款流程、优惠券等
《L04 微信小程序从零到发布》
从小程序个人账户申请开始,带你一步步进行开发一个微信小程序,直到提交微信控制台上线发布。
讨论数量: 0
发起讨论 只看当前版本


暂无话题~