直接在代码中解释了
redis.php
<?php
// 一个单例模式连接数据库文件
require_once "./single.php";
/**
* Class Redisavalanche
* 缓存雪崩 (大量的redis在同一时间全部失效了,导致大量请求打到关系型数据库中)
* 解决办法:
* set设置redis的时候,加随机时间值,保证大量的redis不会同一时间失效(见 randomTime)
* 设置双缓存策略,就像下面方法avalanche中一样
*/
class Redisavalanche extends Single{
private $redis;
private $redis_key = 'uc.0100';
private $redis_key_cache = 'list_cache';
private $expire = 30;
public function __construct()
{
$this->redis = new Redis();
$this->redis->connect('127.0.0.1', '6379');
$this->redis->auth('123456');
}
public function avalanche()
{
// 双缓存
$cache_result = $this->redis->get($this->redis_key_cache);
$result = $this->redis->get($this->redis_key);
if(!$cache_result) {
$this->redis->set($this->redis_key_cache, 1, $this->expire);
$data = Single::singleTest()->query('select * from sns_page');
foreach($data as $val) {
$this->redis->set($val['PAGE_NAME'], $val['PAGE_URL'], $this->expire * 2);
}
}
return $result;
}
// 给key加过期随机时间
public function randomTime()
{
$cache_result = $this->redis->get($this->redis_key);
if(!$cache_result) {
$data = Single::singleTest()->query('select * from sns_page');
foreach($data as $val) {
$this->redis->set($val['PAGE_NAME'], $val['PAGR_URL'], $this->expire + mt_rand(10,100)); // 包含10和100
}
}
}
}
/**
* Class Redisbreakdown
* 缓存击穿 (一个热点数据,在redis缓存失效的瞬间,大量请求打到关系型数据库)
* 解决:
* redis 互斥锁, 大量请求访问时,允许第一个请求去读取数据库,并把数据放到缓存中,后面请求去读缓存
* 设置redis key不过期,但是需要后面自己去更新key的值
*/
class Redisbreakdown extends Single {
private $redis;
private $redis_key = 'uc.0100';
private $setnx_key = 'n';
private $expire = 30;
public function __construct()
{
$this->redis = new Redis();
$this->redis->connect('127.0.0.1', '6379');
$this->redis->auth('123456');
}
public function breakdown()
{
$redis_val = $this->redis->get($this->redis_key);
if(!$redis_val) {
// 互斥锁
if($this->redis->setnx($this->setnx_key, 1, $this->expire)) {
$data = Single::singleTest()->query('select * from sns_page where PAGE_ID=879');
$this->redis->set($this->redis_key, $data['PAGE_URL'], $this->expire);
$this->redis->del($this->setnx_key);
} else {
// 重新取
sleep(10);
self::breakdown();
}
}
}
}
/**
* Class Redispenetrate
* 缓存穿透 (请求缓存和数据库中都不存在的数据时,会造成堵塞, 比如取id=负数时)
* 解决:
* 布隆过滤器
* 条件限制判断
* 设置空值缓存,时间短点
*/
class Redispenetrate extends Single {
private $redis;
private $redis_key = 'uc.0100';
private $expire = 10;
public function __construct()
{
$this->redis = new Redis();
$this->redis->connect('127.0.0.1', '6379');
$this->redis->auth('123456');
}
// 把空值缓存起来 时间设置短一点
public function penetrate()
{
$result = $this->redis->get($this->redis_key);
if(!isset($result)) {
$data = Single::singleTest()->query('select * from sns_page where PAGE_ID=-1');
if(!$data) {
$result = [];
$redis_val = $this->redis->set($this->redis_key, $result, $this->expire);
}
}
return $result;
}
}
single.php
<?php
/**
* Class Single
* 单例模式
* 三私一公
*/
class Single {
private function __construct(){}
private function __clone(){}
private static $instance;
static public function singleTest()
{
if(!self::$instance) {
try {
self::$instance = new PDO('mysql:host=localhost;dbname=pia_demo;port=3307', 'root', '123456');
} catch (PDOException $e) {
die($e->getMessage());
}
}
return self::$instance;
}
public static function getData()
{
$data = self::singleTest()->query('select * from sns_page');
var_dump($data);
}
}