권장(무료): redis
캐시 침투: 키에 해당 캐시 데이터가 존재하지 않아 데이터베이스에 대한 요청이 발생하여 데이터베이스에 대한 부담이 두 배로 증가합니다.
캐시 분석: redis가 만료되는 순간 많은 수의 사용자가 동일한 캐시된 데이터를 요청하므로 이러한 요청이 모두 데이터베이스를 요청하게 되어 키에 대한 데이터베이스 압력이 두 배로 늘어납니다. 캐시 사태:
캐시 서버가 다운되거나 특정 기간에 많은 수의 캐시가 집중되어 모든 요청이 데이터베이스로 이동하게 되어 데이터베이스 압력이 두 배로 증가합니다. 1. 캐시 침투에 대한 솔루션
일반적인 방법은 Bloom 필터 방법을 사용하여 데이터를 가로채는 것입니다. 둘째, 요청된 데이터가 다음과 같은 경우 다른 솔루션이 있습니다. 비어 있으면 빈 값도 캐시됩니다.
<?php class getPrizeList { /** * redis实例 * @var \Redis */ private $redis; /** * @var string */ private $redis_key = '|prize_list'; /** * 过期时间 * @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; } }
常用方法可以采用布隆过滤器方法进行数据拦截,其次可以还有一种解决思路,就是如果请求的数据为空,将空值也进行缓存,就不会发生穿透情况
<?php class getPrizeList { /** * redis实例 * @var \Redis */ private $redis; /** * @var string */ private $redis_key = '|prize_list'; /** * @var string */ private $setnx_key = '|prize_list_setnx'; /** * 过期时间 * @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 = '|prize_list'; /** * 缓存标记key * @var string */ private $cash_key = '|prize_list_cash'; /** * 过期时间 * @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 중국어 웹사이트의 기타 관련 기사를 참조하세요!