雲端計算設計模式-邊緣快取模式

long2ge發表於2021-12-18

描述

  從儲存器中需要的資料載入到快取。

背景和問題

  應用程式使用快取能最佳化重複訪問儲存器資料的問題。但是快取和儲存器的資料可能不一致。

解決方案

讀快取

  先讀cache,再讀db。
  1. 如果cache裡有資料,直接返回資料。
  2. 如果cache裡沒有資料,那麼訪問db,並且把資料寫到快取中。

更新快取

  雙刪快取策略,最大限度保障資料的一致性。
  1. 刪除cache。
  2. 更新 db。
  3. 再刪除 cache。

注意事項

  1. 快取的生命週期(有效期TTL)。
  2. 快取淘汰策略。一般採用最近最少使用的策略,但是淘汰快取是很耗資源的,最好的淘汰策略就是不用啟動快取淘汰機制。
  3. 預分配快取策略。
  4. 快取和儲存器資料之間的一致性策略。
  5. 使用共享快取或者分散式快取而不是本地快取。

結構中包含的角色

  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);
本作品採用《CC 協議》,轉載必須註明作者和本文連結
Long2Ge

相關文章