边缘缓存模式 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 管理、购物车、订单管理、支付宝支付、微信支付、订单退款流程、优惠券等
《L03 构架 API 服务器》
你将学到如 RESTFul 设计风格、PostMan 的使用、OAuth 流程,JWT 概念及使用 和 API 开发相关的进阶知识。
讨论数量: 0
发起讨论 只看当前版本


暂无话题~