>  기사  >  데이터 베이스  >  Redis 캐시 침투, 캐시 분해, 캐시 눈사태의 원리와 솔루션을 함께 알아보세요.

Redis 캐시 침투, 캐시 분해, 캐시 눈사태의 원리와 솔루션을 함께 알아보세요.

coldplay.xixi
coldplay.xixi앞으로
2021-01-28 18:13:132358검색

Redis 캐시 침투, 캐시 분해, 캐시 눈사태의 원리와 솔루션을 함께 알아보세요.

권장(무료): redis

  • 캐시 침투: 키에 해당 캐시 데이터가 존재하지 않아 데이터베이스에 대한 요청이 발생하여 데이터베이스에 대한 부담이 두 배로 증가합니다.

  • 캐시 분석: redis가 만료되는 순간 많은 수의 사용자가 동일한 캐시된 데이터를 요청하므로 이러한 요청이 모두 데이터베이스를 요청하게 되어 키에 대한 데이터베이스 압력이 두 배로 늘어납니다. 캐시 사태:

    캐시 서버가 다운되거나 특정 기간에 많은 수의 캐시가 집중되어 모든 요청이 데이터베이스로 이동하게 되어 데이터베이스 압력이 두 배로 증가합니다
  • . 1. 캐시 침투에 대한 솔루션

일반적인 방법은 Bloom 필터 방법을 사용하여 데이터를 가로채는 것입니다. 둘째, 요청된 데이터가 다음과 같은 경우 다른 솔루션이 있습니다. 비어 있으면 빈 값도 캐시됩니다.

<?php
class getPrizeList {
    /**
     * redis实例
     * @var \Redis
     */
    private $redis;

    /**
     * @var string
     */
    private $redis_key = &#39;|prize_list&#39;;

    /**
     * 过期时间
     * @var int
     */
    private $expire = 30;

    /**
     * getPrizeList constructor.
     * @param $redis
     */
    public function __construct($redis)
    {
        $this->redis = $redis;
    }

    /**
     * @return array|bool|string
     */
    public function fetch()
    {
        $result = $this->redis->get($this->redis_key);
        if(!isset($result)) {
            //此处应该进行数据库查询...
            //如果查询结果不存在,给其默认空数组进行缓存
            $result = [];
            $this->redis->set($this->redis_key, $result, $this->expire);
        }

        return $result;
    }
}
    2. 캐시 침투 해결 방법
  • 常用方法可以采用布隆过滤器方法进行数据拦截,其次可以还有一种解决思路,就是如果请求的数据为空,将空值也进行缓存,就不会发生穿透情况
<?php
class getPrizeList {
    /**
     * redis实例
     * @var \Redis
     */
    private $redis;

    /**
     * @var string
     */
    private $redis_key = &#39;|prize_list&#39;;

    /**
     * @var string
     */
    private $setnx_key = &#39;|prize_list_setnx&#39;;

    /**
     * 过期时间
     * @var int
     */
    private $expire = 30;

    /**
     * getPrizeList constructor.
     * @param $redis
     */
    public function __construct($redis)
    {
        $this->redis = $redis;
    }

    /**
     * @return array|bool|string
     */
    public function fetch()
    {
        $result = $this->redis->get($this->redis_key);
        if(!isset($result)) {
            if($this->redis->setnx($this->setnx_key, 1, $this->expire)) {
                //此处应该进行数据库查询...
                //$result = 数据库查询结果;
                $this->redis->set($this->redis_key, $result, $this->expire);
                $this->redis->del($this->setnx_key); //删除互斥锁
            } else {
                //其他请求每等待10毫秒重新请求一次
                sleep(10);
                self::fetch();
            }
        }

        return $result;
    }
}

二、缓存击穿解决办法

  • 使用互斥锁(mutex key),就是一个key过期时,多个请求过来允许其中一个请求去操作数据库,其他请求等待第一个请求成功返回结果后再请求。
<?php
class getPrizeList {
    /**
     * redis实例
     * @var \Redis
     */
    private $redis;

    /**
     * @var string
     */
    private $redis_key = &#39;|prize_list&#39;;

    /**
     * 缓存标记key
     * @var string
     */
    private $cash_key = &#39;|prize_list_cash&#39;;

    /**
     * 过期时间
     * @var int
     */
    private $expire = 30;

    /**
     * getPrizeList constructor.
     * @param $redis
     */
    public function __construct($redis)
    {
        $this->redis = $redis;
    }

    /**
     * @return array|bool|string
     */
    public function fetch()
    {
        $cash_result = $this->redis->get($this->cash_key);
        $result = $this->redis->get($this->redis_key);
        if(!$cash_result) {
            $this->redis->set($this->cash_key, 1, $this->expire);
            //此处应该进行数据库查询...
            //$result = 数据库查询结果, 并且设置的时间要比cash_key长,这里设置为2倍;
            $this->redis->set($this->redis_key, $result, $this->expire * 2);
        }

        return $result;
    }
}

三、缓存雪崩的解决办法

  • 这种情况是因为多个key同时过期导致的数据库压力,一种方法可以在key过期时间基础上增加时间随机数,让过期时间分散开,减少缓存时间过期的重复率
  • 另一种方法就是加锁排队,这种有点像上面缓存击穿的解决方式,但是这种请求量太大,比如5000个请求过来,4999个都需要等待,这必然是指标不治本,不仅用户体验性差,分布式环境下就更加复杂,因此在高并发场景下很少使用
  • 最好的解决方法,是使用缓存标记,判断该标记是否过期,过期则去请求数据库,而缓存数据的过期时间要设置的比缓存标记的长,这样当一个请求去操作数据库的时候,其他请求拿的是上一次缓存数据
뮤텍스 키(mutex key) 사용 즉, 키가 만료되면 요청 중 하나가 데이터베이스를 작동할 수 있도록 여러 요청이 들어오고, 다른 요청은 다시 요청하기 전에 첫 번째 요청이 결과를 성공적으로 반환할 때까지 기다립니다. 🎜🎜rrreee🎜🎜3. 캐시 눈사태에 대한 솔루션🎜🎜🎜🎜이러한 상황은 여러 키가 동시에 만료되어 발생하는 데이터베이스 압박으로 인해 발생합니다. 키 만료 시간을 기준으로 시간 난수를 추가하여 만료 시간을 분산시키고 캐시 시간 만료의 재발률을 줄입니다.🎜🎜또 다른 방법은 잠금 및 대기열입니다. 이는 위의 캐시 고장 해결 방법과 약간 비슷하지만 요청량이 너무 많습니다. 예를 들어 5,000개의 요청이 들어오고 4,999개의 요청이 기다려야 한다는 것은 근본 원인을 해결하지 못하는 지표일 것입니다. 사용자 경험이 좋지 않을 뿐 아니라 분산 환경에서는 훨씬 더 복잡하므로 동시성이 높은 시나리오에서는 거의 사용되지 않습니다.🎜🎜가장 좋은 솔루션은 다음을 사용하는 것입니다. 캐시 태그를 사용하여 태그가 만료되었는지 확인합니다. 만료된 경우 데이터베이스를 요청하고, 캐시 데이터의 만료 시간은 캐시 표시보다 길게 설정하여 데이터베이스 작동 요청 시 다른 요청이 수행되도록 해야 합니다. 마지막으로 캐시된 데이터 가져오기🎜🎜rrreee

위 내용은 Redis 캐시 침투, 캐시 분해, 캐시 눈사태의 원리와 솔루션을 함께 알아보세요.의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 csdn.net에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제