PHP+Redis는 캐시 고장의 실제 문제를 해결합니다.

藏色散人
풀어 주다: 2023-04-10 21:08:02
앞으로
3734명이 탐색했습니다.

관련 권장 사항: "PHP+Redis는 订单限流 실질적인 문제를 해결합니다."

PHP+Redis는 실용적인 문제를 해결합니다: 캐시 분석

1. 이 시리즈의 각 호는 실용적인 Redis 문제를 해결합니다
2. 각 호의 질문은 각 호의 댓글 중에서 선택됩니다. 3. 관심 있는 질문은 제한됩니다. 다른 질문에는 새로운 질문을 여는 것도 배제하지 않겠습니다. Series
4. 저는 PHP를 자주 사용하므로 주로 PHP
5를 사용합니다. 댓글에 적합한 질문이 없으면 스스로 질문하겠습니다

문제 설명:

이것은 두 번째 문제입니다. 여전히 내 질문이 생겼습니다. [Dog Head]

PHP+Redis가 캐시 고장을 쉽게 피할 수 있는 방법

해결책:

<?php

    /**
     * 防击穿缓存
     * @param string $key       缓存key
     * @param int $expire       缓存过期时间(s)
     * @param bool $refresh     是否强制刷新数据
     * @param callable $func    获取要缓存的数据的回调方法(仅支持返回类型:?string)
     * @return null|string      返回缓存的值,没有值时且没有抢到刷新权且缓存已过期时返回null
     */
    function onceCache(string $key,int $expire,bool $refresh,callable $func): ?string
    {
        //内存,注:如果是cli模式不要使用
        static $dataStatic=[];

        //读取内存
        if(isset(self::$dataStatic[$key])){
            return self::$dataStatic[$key];
        }

        //获取laravel的获取redis连接,其它框架需要修改
        $redis=Redis::connection();

        //原缓存key加后缀"lock"为锁的key
        $lockKey=$key.&#39;:lock&#39;;

        //锁是否有效
        $lock=false;

        //读取数据
        $data=$redis->get($key);

        //如果 非强制刷新 且 缓存非空 ,获取锁
        if(!$refresh && !is_null($data)){
            $lock = $redis->get($lockKey);
        }

        if(!$lock){//如果锁过期或无数据
            $lock=$redis->setnx($lockKey,1);    //仅当锁不存在时设置锁,值1代表数据获取中
            if($lock || $refresh){              //抢到新锁 或 强制刷新
                try {
                    $data=$func();              //从回调函数获取要缓存的数据

                    //有数据则写入缓存,没有则删除数据
                    if(!is_null($data)){
                        $redis->set($key,$data);
                    }else{
                        $redis->del([$key]);
                    }

                    $redis->set($lockKey,2,&#39;ex&#39;,$expire);   //设置锁的过期时间,值2代表数据获取完成
                }catch (Exception $exception){
                    $redis->del([$lockKey]);                //发生异常,删除锁
                }
            }else{
                //如果没有数据,又没有抢到锁
                //30秒内每秒判断抢到锁的用户是否执行完成,执行完成则从缓存得到数据并返回
                $retry=0;
                do{
                    sleep(1);
                    $retry++;
                    $data = $redis->get($key);
                }while(is_null($data) && $redis->get($lockKey)==1 && $retry<30);
            }
        }

        //写入内存
        if(!is_null($data)){
            $dataStatic[$key]=$data;
        }

        //返回数据
        return $data;
    }
로그인 후 복사

코드 해석:

  • 데이터 온톨로지는 만료되지 않습니다

  • 설정 잠금이 만료되면 잠금을 잡은 사용자는 데이터를 새로 고칩니다.

  • 잠금을 잡지 않은 사용자. 데이터를 얻으면 잠금이 직접 반환됩니다. (이때 데이터는 이미 만료된 데이터이며, 데이터 적시성 요구 사항이 높은 경우) 코드를 직접 수정해야 합니다.)

  • 자물쇠를 잡지 않은 사용자가 데이터를 얻지 못하면 잠금을 잡은 사용자가 실행을 완료했는지 1초마다 판단됩니다

  • 잠금은 교착 상태가 될 확률이 매우 적으므로 타이머를 두는 것이 가장 좋습니다. 작업은 정기적으로 처리되며, 매일 업무량이 적은 시간 동안 교착 상태를 해결하는 등

추천 학습: "

PHP 비디오 튜토리얼"

위 내용은 PHP+Redis는 캐시 고장의 실제 문제를 해결합니다.의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

관련 라벨:
원천:learnku.com
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿