数据库

博客这类读多写少的站点,Redis 用对了收益很明显,用错了就是白白多一个要维护的服务。这篇讲三种真正值得做的用法。

用法一:整页或片段缓存

最直接也最有效的用法。对于首页、归档页这类「所有人看到的内容都一样」的页面,缓存整段 HTML:

$key = 'page:index:' . $page;
$html = $redis->get($key);

if ($html === false) {
    $html = render_index($page);
    $redis->setex($key, 300, $html);   // 5 分钟过期
}

echo $html;

关键是发布文章时主动删掉相关 key,而不是干等过期:

function on_post_publish($redis) {
    foreach ($redis->keys('page:index:*') as $key) {
        $redis->del($key);
    }
}

用法二:计数器

阅读量这类高频自增,用 Redis 顶住比直接写数据库友好得多:

INCR views:post:42

再定期落库(比如每 5 分钟合并一次):

GETSET views:post:42 0

这么做的好处是:即使 Redis 挂了,丢的也只是几分钟的计数,不会让页面打不开。

用法三:分布式锁

定时任务在多台机器上跑时,需要保证同一时刻只有一个在执行:

$ok = $redis->set('lock:backup', getmypid(), ['nx', 'ex' => 600]);

if (!$ok) {
    exit("已有实例在运行
");
}

// ... 执行备份 ...

$redis->del('lock:backup');

nx 保证只有一个能设置成功,ex 保证进程意外退出后锁会自动释放,不会永久卡死。

一个不该踩的坑

不要把 Redis 当成唯一数据源。 它默认是异步持久化的,进程崩掉可能丢最后几秒的写入。用它做缓存、计数、锁都没问题,但博客正文、评论这类数据必须落在 MySQL 里。

另外记得给 Redis 设置内存上限与淘汰策略:

maxmemory 256mb
maxmemory-policy allkeys-lru

不设 maxmemory 的话,它会把宿主机内存吃光。

小结

  • 缓存:读多写少,配上主动失效。
  • 计数:高频自增,定期落库。
  • nx + ex 组合,避免多实例冲突。

除此之外的用法,先问问自己是不是真的需要。

参与讨论