php解决缓存击穿的问题

缓存击穿是指缓存中没有的数据,而查询非常频繁的数据,导致大量的请求落到了数据库上,因此很容易导致数据库连接数暴增,甚至导致宕机。

下面是 PHP 解决缓存击穿问题的一般解决方案:

// 获取 Key
$key = 'my_key';

// 根据 Key 从 Redis 中获取数据
$data = $redis->get($key);

// 如果数据不存在,尝试从DB中获取数据
if (!$data) {
    // 尝试获取缓存锁
    $lockKey  = 'my_redis_lock';
    $locked   = $redis->set($lockKey, 1, array('nx', 'ex'=>10));

    // 如果获得缓存锁,再从DB中获取
    if($locked) {
        $data = '查询数据库的结果';

        // 将查询结果写入 Redis 缓存中,并设置永久不过期
        $redis->setex($key, 0, $data);
        // 删除锁
        $redis->del($lockKey);
    }
    // 如果获取锁失败,则说明另一个进程已经重新写入了缓存,使用之前写入的数据即可
    else {
        // 设置一个默认的过期时间,以避免缓存被永久锁定
        $redis->setex($key, 60, 'default value');
        // 等待一段时间之后,重新获取缓存
        sleep(1);
        $data = $redis->get($key);
    }
}

该代码逻辑如下:

1.根据指定 Key 从 Redis 中获取数据;

2.如果数据不存在,设置一个缓存互斥锁,防止大量并发访问 DB,再次从 DB/ 获取数据;

3.如果获取到缓存锁,则从 DB 中获取数据,并将数据写入 Redis 中;

4.如果获取不到缓存锁,则说明其他进程已经获取到了缓存锁,等待一段时间后重试,重新获取数据即可。

解决缓存击穿的方法有很多,以上只是其中一种通用的 PHP 解决方法,实际应用中需要结合具体情况选择合适的解决方案。

以下是基于 Redis 分布式锁和补偿任务的代码示例:

// 获取 Key
$key = 'my_key';

// 根据 Key 从 Redis 中获取数据
$data = $redis->get($key);

if (!$data) {
    // 尝试获取分布式锁
    $lockKey = 'my_redis_lock';
    $locked = false; // 是否已经获得锁

    // 尝试获取锁,并最多等待 3 秒钟
    for ($i = 0; $i < 3; $i++) {
        $locked = $redis->set($lockKey, 1, array('nx', 'ex' => 10));
        if ($locked) {
            break;
        }
        sleep(1);
    }

    if ($locked) {
        // 获取数据库数据
        $data = '查询数据库的结果';

        // 将查询结果写入 Redis 缓存中,并设置永久不过期
        $redis->setex($key, 0, $data);
        // 删除锁
        $redis->del($lockKey);
    } else {
        // 使用补偿任务异步处理缓存
        $taskData = array(
            'key' => $key,
        );

        $result = $redis->lpush('my_redis_queue', json_encode($taskData));
        if (!$result) {
            // 记录错误日志
            error_log('Failed to add task to the task queue!');
        }

        // 返回默认值,避免使用错误的数据
        $data = 'default value';
    }
}

// 返回数据
echo $data;

补偿任务相关的代码如下:

// 任务处理函数,将查询结果写入缓存或数据库
function processTask($redis, $taskData) {
    $key = $taskData['key'];
    $data = '查询数据库的结果';

    // 将查询结果写入 Redis 缓存中,并设置永久不过期
    $redis->setex($key, 0, $data);
}

// 拉取任务队列中的任务,并处理任务
function processTaskQueue($redis) {
    while (true) {
        // 从任务队列中阻塞获取任务,最多等待 10 秒钟
        $taskJson = $redis->brpop('my_redis_queue', 10);

        if (!$taskJson) {
            // 没有获取到任务,则结束循环
            break;
        }

        // 解析任务数据
        $taskData = json_decode($taskJson[1], true);

        // 处理任务
        processTask($redis, $taskData);
    }
}

// 启动后台任务处理进程
function startTaskProcessor($redis) {
    while (true) {
        // 处理任务队列中的任务
        processTaskQueue($redis);

        // 等待一段时间后再继续处理任务
        sleep(1);
    }
}

// 在应用程序启动时启动后台任务处理进程
startTaskProcessor($redis);

以上代码示例中,如果获取缓存的进程都无法获得锁并写入缓存,则使用补偿任务异步处理任务,并在后台异步将查询结果写入缓存。补偿任务的处理逻辑与业务逻辑相似,只是将数据的写入缓存操作改为异步操作,并放入任务队列中。后台任务处理进程会不断地从任务队列中获取任务,并进行处理。

文章来源:刘俊涛的博客 欢迎关注公众号、留言、评论,一起学习。


若有帮助到您,欢迎捐赠支持,您的支持是对我坚持最好的肯定(_)

原文链接:https://www.cnblogs.com/lovebing/p/17223016.html

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:php解决缓存击穿的问题 - Python技术站

(0)
上一篇 2023年4月17日
下一篇 2023年4月17日

相关文章

  • 小程序微信退款功能实现方法详解【基于thinkPHP】

    下面就详细讲解一下“小程序微信退款功能实现方法详解【基于thinkPHP】”这篇文章的完整攻略。 标题 文章的标题是“小程序微信退款功能实现方法详解【基于thinkPHP】”,这个标题很明确地表明了文章的主题和内容,方便读者对文章有一个明确的认知。 概述 在概述部分,我们应该简要说明文章的主题和涵盖内容,让读者能够对整个文章有一个大致了解,同时也能引导读者进…

    PHP 2023年5月23日
    00
  • php array_filter除去数组中的空字符元素

    当我们遍历数组时,有时候需要剔除数组中的空字符元素以得到有效数据。array_filter() 函数可以帮助我们完成这项任务。 函数原型 在介绍使用方法前,先看一下该函数的原型: array array_filter ( array $input [, callable $callback [, int $flag = 0 ]] ) 参数说明 $input:…

    PHP 2023年5月26日
    00
  • 使用Apache打造完美限制的HTTP下载服务器

    使用Apache打造完美限制的HTTP下载服务器 简介 Apache是一款著名的开源Web服务器软件,具有稳定、高效、安全等优点,能够支持多种操作系统和多种编程语言,因此得到了广泛的应用。本文将详细介绍如何利用Apache打造完美限制的HTTP下载服务器,防止非法下载和恶意攻击。 步骤 1. 安装Apache 首先需要在服务器上安装Apache。对于Ubun…

    PHP 2023年5月27日
    00
  • php使用SAE原生Mail类实现各种类型邮件发送的方法

    下面是使用SAE原生Mail类实现各种类型邮件发送的完整攻略。 1. 前置条件 在使用SAE原生Mail类实现邮件发送之前,需要做好以下准备工作: 在SAE控制面板中开启邮件服务功能 从SAE控制面板获取SMTP服务器、端口、发件人邮箱等信息 在SAE应用中安装SMTP类库 2. 发送简单文本邮件 <?php require_once ‘saemail…

    PHP 2023年5月27日
    00
  • PHP 微信扫码支付源代码(推荐)

    PHP 微信扫码支付源代码(推荐)攻略 概述 微信支付是一种常见的移动支付方式,可以方便快捷地进行线上支付,而PHP微信扫码支付源代码则是一种前台支付方式,用户可以通过微信扫码支付,实现线上支付。 前提条件 具备PHP编程的基础知识 拥有微信公众号或企业账号 在微信公众平台上开通微信支付功能,并配置好相关参数 配置好服务器环境(需支持HTTPS协议) 实现步…

    PHP 2023年5月23日
    00
  • 2个比较经典的PHP加密解密函数分享

    以下是关于“2个比较经典的PHP加密解密函数分享”的详细讲解: 概述 在PHP开发中,数据加密是十分重要且必要的。本文将介绍两个比较经典的PHP加密解密函数,分别是MD5和AES加密。 MD5加密 MD5(Message-Digest Algorithm 5)是一种由Ron Rivest设计的单向加密算法,可以将任意长度的数据加密成固定长度(128位)的散列…

    PHP 2023年5月25日
    00
  • PHP 正则表达式之正则处理函数小结(preg_match,preg_match_all,preg_replace,preg_split)

    PHP 正则表达式之正则处理函数小结 在 PHP 中,使用正则表达式可以很方便地进行字符串处理。PHP 提供了以下几个正则表达式处理函数:preg_match、preg_match_all、preg_replace、preg_split。下面分别详细介绍这几个函数的用法,并提供实例说明。 preg_match preg_match 用于在字符串中查找一个匹配…

    PHP 2023年5月26日
    00
  • 使用PHP导出Word文档的原理和实例

    使用PHP导出Word文档的原理和实例 前言 随着互联网的发展,更多的应用程序需要将数据以Word文档的形式导出,这就需要我们使用PHP来实现。而本文就是一份基于PHP导出Word文档的攻略,通过本文中的示例代码,你将会学会如何使用PHP来实现导出Word文档。 导出Word文档的原理 要将数据以Word文档的形式导出,需要从以下几个方面来考虑: Word文…

    PHP 2023年5月26日
    00
合作推广
合作推广
分享本页
返回顶部