防止 Redis 密钥逐出策略

Protect Against Redis Key Eviction Policy

所以我正在将 Redis 添加到一个项目中,并且我正在用缓存调用包装数据库调用。

如果我在模型中有这样的查询(并且模型只是 returns 控制器的数据):

"SELECT * FROM countries";

我的计划是将每个国家缓存在这样的数据结构中:

$cache->hmset("country:1", ['id' => 1, name => 'Ireland']);// 250+ more countries

还要维护国家/地区 ID 的 SET 数据结构,如下所示:

$cache->sadd("countries", 1);

问题

在检索所有国家的情况下,我是否需要编写逻辑来填充两个 redis 数据结构,以防它们中的任何一个不在缓存中? 例如,我的国家模型应该是这样的:

    // Check cache for set of valid countries IDs
    if (!$cache->exists("countries")) {
        $ids = "SELECT id FROM countries";// Pretend $ids is array for simplicity

        // Add countries IDs into cache
        $cache->sadd("countries", $ids);
    }

    /* At this point we know the set of country IDs exists */

    $country_ids = $cache->smembers("countries");

    $response = [];

    /* Retrieve each country */
    foreach ($country_ids as $id) {
        /* If "countries:{$id}" is not in cache */
        if (!$cache->exists("countries:{$id}")) {// Retrieve country from database
            $entity = "SELECT * FROM countries WHERE countries.id = {$id}";// Pretend $entity is array of fields for simplicity

            // Set country entity into cache
            $cache->hset("countries:{$id}", $entity);
        } else {
            $entity = $cache->hgetall("countries:{$id}");
        }

        $response[] = $entity;
    }

    return $response;

更新

国家 table 只是样本数据,但它代表任何 table 正在定期读取和写入的数据。缓存必须始终代表数据库中存储的内容,因此当我们插入新实体或更新现有实体时,我们也会更新缓存。 缓存中还存储了多个其他密钥和用户数据,并且可能会出现缓存逐出某些密钥的情况,并且某些对缓存的请求可能会导致找不到任何内容。

我的问题是:您如何保证预期在缓存中找到的数据是: A)在缓存中找到,或 B) 在缓存中找不到,所以我们把它放在缓存中

是否每个从缓存中获取内容的请求都需要我们 运行 数据库查询以从我们的数据库中检索数据,然后将其放入缓存中,如上例所述?

您需要换个思路,使用 cache-aside pattern 并在 Get 操作中具有从缓存中 retrieve/insert 的逻辑。

查看此伪代码示例(抱歉,我不熟悉 php):

function GetCountry($id)
{
    if ($cache->hexists("countries:{$id}")) {
        $entity = $cache->hgetall("countries:{$id}");
    }
    else
    {
        $entity = $database.GetCountry($id);
        $cache->hmset("country:{$id}", ['id' => $entity->id, ... ]);
    }
    return $entity;
}

function AddCountry($country)
{
    $database.AddCountry($country);
}

function UpdateCountry($id, $data)
{
    $database.UpdateCountry($id, $data);
    $cache->del("country:{$id}");
}

function DeleteCountry($id)
{
    $database.DeleteCountry($id);
    $cache->del("country:{$id}");
}

所以你永远不会更新缓存,你只是在第一次检索对象时添加到缓存,并在updating/deleting实体之后使键无效.