redis缓存穿透之setnx使用场景
随着业务的增长,请求并发的增大。很多公司在业务场景中会增加缓存策略,而缓存用的最多的也就是redis了。
今天我们来说一下缓存穿透,我们缓存一般是有时效性的,一定的生命周期过去之后就会消失,一般的系统不会设置永久性的存储,这时候就会遇到一个问题,要么就是主动刷新缓存,要么就是程序被动刷新缓存。
事实证明很多程序当中很少主动刷新因为你要去写脚本,定时去刷新数据,这样的话代价比较大。所以较多的就选择了程序被动刷新缓存,就是在缓存失效之后读库在写入缓存。这里就会导致一个问题那就是:当缓存失效的那一刻大量的请求过来就会直接打到数据库上,如果并发量大的话读库操作肯定会有影响,连接超时,连接数过大这样的情况也会随时遇到。
针对这种情况redis有一个进程锁也就是我们今天说的setnx
下面直接贴代码:
$ret = $this->redis->get('k' . $abbr); if (empty($ret)) { $ret1 = $this->redis->setnx('k'.$abbr,$ret); if($ret1){ $sql = "select * from xxx where a=xx;"; $query = $this->db->query($sql); $ret = $query->result_array(); $this->redis->set('b' , json_encode($ret) , 6400); $this->redis->set('bakk', json_encode($ret) , 10000); } else{ $ret = $this->redis->get('bakk' . $abbr); } }
这段程序的逻辑就是先用一个进程去请求数据如果没有了用setnx锁住这个键只有一个进程去读库操作然后重写两个键值,一个主要的查询键值,一个备份的键值当然缓存时间会长点。这样不管多少请求过来只有一个进程去做读库操作,其他的还是读redis备份数据。用空间来换取时间和效率还是比较划算的。
这就是针对缓存穿透做的一套操作,下面上一下这个流程图: