为什么Redis的操作是原子性的,怎么保证原子性的?
对于Redis而言,命令的原子性指的是:一个操作的不可以再分,操作要么执行,要么不执行。
Redis的操作之所以是原子性的,是因为Redis是单线程的。
Redis本身提供的所有API都是原子操作,Redis中的事务其实是要保证批量操作的原子性。
Redis过期键删除策略
被动删除:当读/写一个已经过期的key时,会触发惰性删除策略,直接删除掉这个过期key
主动删除:由于惰性删除策略无法保证冷数据被及时删掉,所以Redis会定期主动淘汰一批已过期的key
当前已用内存超过maxmemory限定时,触发主动清理策略
redis 查询单个key内存大小
MEMORY USAGE keyname
返回值:the memory usage in bytes
redis主从复制原理
复制初始化:当从数据库启动后会向主数据库发送sync命令。主数据库收到sync命令后会开始在保存快照(RDB的过程),并将保存快照期间的命令缓存起来。快照完成后Redis将快照文件和缓存命令发送给从数据库,从数据库载入快照并执行缓存命令。
运行期间:主数据没收到写命令就会将命令同步给从数据库从而保证主从一致性。
redis和memcached的区别
redis支持单核,持久化,有5种数据类型,支持事务
memcached支持多核,不支持持久化,不支持事务,只有k-v类型
redis持久化的方式
RDB(Redis DataBase)
: 在一定时间内有多少个键被改变后redis会fork一个进程将内存中的数据(fork那一刻的数据)生成快照替换旧的RDB文件
AOF(Append Only File)
:在每秒或每次修改都会将数据追加到aof文件中,到达一定的阀值会重写aof文件
redis 怎么实现分布式锁?
先拿setnx来争抢锁,抢到之后,再用expire给锁加一个过期时间防止锁忘记了释放。
如果在setnx之后执行expire之前进程意外crash或者要重启维护了,那会怎么样?set指令有非常复杂的参数,这个应该是可以同时把setnx和expire合成一条指令来用的!
总的来说,执行上面的set()方法就只会导致两种结果:1. 当前没有锁(key不存在),那么就进行加锁操作,并对锁设置个有效期,同时value表示加锁的客户端。2. 已有锁存在,不做任何操作。
redis 为什么是单线程的?
数据都存在内存里,单线程避免多线程多上下文的切换浪费时间
当list中值被清空时,键还在吗?
lists,sets, Sorted Sets 和 Hashes,当为空时,都会被自动删除!
你对Memcach的理解,优点有哪些?
Memcache是一种缓存技术,在一定的时间内将动态网页经过解析之后保存到文件,下次访问时动态网页就直接调用这个文件,而不必在重新访问数据库。使用memcache做缓存的好处是:提高网站的访问速度,减轻高并发时服务器的压力。
Memcache的优点:稳定、配置简单、多机分布式存储、速度快。
缓存穿透+缓存雪崩+缓存击穿?
缓存穿透
:访问一个不存在的key,缓存不起作用,请求会穿透到DB,流量大时DB会挂掉。
解决方案:采用布隆过滤器,使用一个足够大的bitmap,用于存储可能访问的key,不存在的key直接被过滤;
访问key未在DB查询到值,也将空值写进缓存,但可以设置较短过期时间。
缓存雪崩
:大量的key设置了相同的过期时间,导致在缓存在同一时刻全部失效,造成瞬时DB请求量大、压力骤增,引起雪崩。
解决方案:可以给缓存设置过期时间时加上一个随机值时间,使得每个key的过期时间分布开来,不会集中在同一时刻失效。
增加二级缓存
使用队列处理请求
缓存击穿
:一个存在的key,在缓存过期的一刻,同时有大量的请求,这些请求都会击穿到DB,造成瞬时DB请求量大、压力骤增。
解决方案:在访问key之前,采用SETNX(set if not exists)来设置另一个短期key来锁住当前key的访问,访问结束再删除该短期key。
热点数据永不过期
public function get($key) {
$value = $this->redis->get($key);
if (is_null($value)) {
if ($this->redis->setnx($k, $exprieTime)) {
$value = $this->db->get($key);
$this->redis->set($key, $value);
$this->redis->del($k);
} else {
usleep(50);
return $this->get($key);
}
}
return $value;
}