缓存杂谈

1:memcache是原子操作吗?
所有被发送到memcache的单个命令都是原子的。比如你对同一份数据发送了一个set命令和一个get命令,它们之间不会影响对方,它们将被串行化,先后执行,即使在多线程模式下,所有命令的执行也都是原子的。但命令序列不是原子的,如果你通过get命令获取了一个item,修改了它,然后想把它set回memcache,我们不保证这个item没有被其他进程修改过,而且在并发的情况下,你也可能覆写了一个被其他进程set的item。

2:redis的主要缺点是数据库容量受到物理内存的限制,不能用作海量数据的高性能读写。读写分离架构的缺陷在于不管是master还是slave,每个节点都必须保存完整的数据。在数据量比较大的情况下,集群的扩展能力受限于单个节点的存储能力。

3:redis相对于memcache有哪些优势?
a:memcache的值只能是字符串,而redis支持字符串、哈希、列表、有序集合、集合等五种类型。
b:redis可以持久化数据,并且支持事务。
c:redis最大可以存着值为1G的数据,而memcache只能存储1M的数据。

4:redis常见性能问题以及解决方案:
a:master最好不要做任何持久化操作,如RDB内存快照和AOF日志文件。因为master写内存快照会阻塞主线程的工作,当快照比较大时会对性能有较大的影响。可能造成间断性的暂停服务。所以,master最好不要写内存快照,AOF文件过大会影响master重启的恢复速度。
b:如果数据比较重要,可以在某个slave开启aof备份数据。
c:为了主从复制的速度和连接的稳定性,master和slave最好在同一个局域网中。

5:set(key,value,nxx,expx,time) set方法一共有5个参数:
a:第一个为key,我们使用key来锁,因为key是唯一的。
b:第二个为value,我们传的是requestId,有人会问,有key作为锁不久够了吗?为什么还要用到value呢?通过给value赋值为requestId,我们就知道这把锁是哪个请求加的,在解锁的时候就有依据了。
c:第三个为nxxx,这个参数我们填的是nx,意思是当key不存在时,我们进行set操作,若key已经存在,则什么都不做。
d:第四个为expx,这个参数我们传的是px,意思是我们要给这个key加一个过期时间,具体的时间由第五个参数决定。
e:第五个参数为time,代表key的过期时间。
总的来说,执行上面的set方法就只会导致两种结果:
a:当前没有锁(key不存在),那么就进行加锁操作,并对锁设置有效期。
b:已有锁存在,则不做任何事情。

set加入了nx参数,可以保持如果已有key存在,则函数不会调用成功,也就是说只有一个客户端能持有锁。其次,由于我们对锁设置了有效期,即使锁的持有者后续发生崩溃而没有解锁,锁也会因为到了过期时间而自动解锁,不会发生死锁。最后由于我们将value赋值为requestId,代表加锁客户端的请求标识,那么客户端在解锁时就可以校验是否是同一个客户端。

6:setnx的作用是如果key不存在就设置,expire方法是给锁加一个过期时间,咋一看好像和前面的set方法的结果一样,然而,由于这是两个redis命令,不具有原子性,如果程序在执行完setnx命令之后突然崩溃,导致锁没有设置过期时间,那么就会发生死锁。如:
$resunt = r e d i s − > s e t n x ( redis->setnx( redis>setnx(key, r e q u e s t I d ) ; i f ( requestId); if( requestId);if(result){
r e d i s − > e x p i r e ( redis->expire( redis>expire(key,200);
}
如果程序在执行完setnx后崩溃,会导致死锁。

7:假如redis里有1亿个key,其中有10万个是以某个固定已知的前缀开头,如何将他们全部找出来呢?
redis里有一个keys命令,可以通过它来查询。如果这个redis正在给线上业务提供服务,那么使用keys指令会有什么问题呢?
redis是单线程的,keys命令会导致线程阻塞一段时间,线上服务器会停顿,直到keys命令执行完毕,服务才能恢复。不过redis提供了一个scan命令,它可以无阻塞的取出指定模式的key列表,但可能有定的重复概率,需要在客户端去重。

8:使用过redis做异步队列吗?
一般使用list结构作为队列,rpush生成消息,lpop消费消息,当lpop没有消息的时候要sleep一下,一会在重试。

9:如果有大量的key需要设置同一时间过期,一般需要注意什么?
如果大量的key的过期时间设置的过于集中,到过期的那个时间点,假如有大量的访问涌进来,那么这些访问都会落到mysql上,有可能导致mysql崩溃,所以,最好不要有大量的key在同一时间过期,可以给这些key的过期时间设置一个随机的时间点,让它们分散过期。

10:redis是如何做持久化的?
使用bgsave做镜像全量持久化,aof做增量持久化,因为bgsave需要设置时间段,如果在这个时间段里redis崩溃,则数据就会丢失,所以需要aof来配合使用。在redis实例重启时,会使用bgsave持久化文件重新构建内存,在使用aof重放近期的操作指令来实现完整恢复重启之前的状态。那么如果突然机器掉电会怎样呢?这取决于aof日志sync属性的配置,我们可以设置成1秒同步一次数据到磁盘,这个时候最多会丢失1s的数据。那么bgsave的原理是什么呢?redis通过创建子进程在操作bgsave,子进程创建后,父进程会提高读写服务。

11:缓存穿透?频繁查询一个不存在的数据,由于缓存不会命中,每次都要查询数据库,这么以来缓存就失去意义了。
解决方法:当持久层查询不到时,在redis里设置一个空结果,并设置相应的过期时间,这样下一个查询就不会再去查询数据库了。

12:缓存雪崩?缓存大量失效的时候,会造成大量的查询落到数据库上。
解决方法:把缓存失效的时间均匀分布,比如我们可以在原有失效时间的基础上增加一个随机值,这样每个缓存过期的时间就会分散,很难引发集体失效的事件。

13:热点key:某个key’的访问非常频繁,当key失效的时候有大量线程来构建缓存,这个动作本身对redis的影响不大,但在构建缓存的过程中需要去查询数据库,有可能导致负载增加,系统崩溃。
解决方法:
互斥锁:只允许一个请求重建缓存。请求检测到key返回数据为空时,在redis里设置一个锁,然后去构建缓存,此时,其他线程检测到锁如果存在,则sleep一下,等待缓存构建成功后再去获取数据。构建缓存的那个线程在构建完成后需要把锁删除。

14:缓存击穿:对于一些设置了过期时间的key,如果这些key可能会在某些时间点被超高并发的访问,是一种非常热点的数据,这个时候需要考虑一个问题,就是缓存在某个时间点过期的时候,很多请求都会去后端db加载数据并回设到redis里,这个时候大并发的访问db,有可能把db弄崩溃。
解决方法:在缓存失效的时候(判断取出的值是否为空),不是立即去db获取数据,而是使用setnx命令创建一个锁,当返回成功时,再进行load db的操作并回设缓存,否则就sleep一下,等待缓存被构建成功后在从redis获取数据,总之呢,就是只有一个请求可以构建缓存。

15:mysql里有2000万的数据,redis里只存20万的热点数据,如何保证redis中都是热点数据?
访问量不大:直接给key设置过期时间,过期之后从后端取,然后回设到redis中即可。
访问量大:这个时候因为缓存过期后会有大量访问直接落到db上,会给db带来很大的压力,我们可以使用锁来解决这个问题,即只有一个请求可以重建缓存,可以使用setnx加一个锁,这样就可以解决这个问题。

16:redis提供了两种数据持久化的方式?
a:RDB持久化可以在指定的时间间隔内生成数据集的快照。
优点:
aa:RDB是一个非常紧凑的文件,它保存了redis在某个时间点的数据集。它非常适合于备份,比如你可以1小时备份一次,这样的话,即使遇到问题,也可以将数据集还原到不同的版本。
bb:RDB可以最大化redis的性能,父进程在保存RDB文件时只需要fork一个子进程,子进程就可以处理接下来所有的保存工作,父进程无需执行任何磁盘io操。
cc:在恢复大数据时速度比AOF快。
b:AOF持久化会记录服务器执行的所有写操作命令,并在服务器启动时,通过重新执行这些命令来还原数据集。

17:redis和mysql做数据同步:
并发不高的情况:
读:读redis,有数据则直接返回,没有数据,则去读mysql,并把读取到的数据写入redis中。
写:写mysql,成功后写redis。
并发高的情况:
读:读redis,有数据则直接返回,没有数据,则去读mysql,并把读取到的数据写入redis中。
写:先写redis缓存,然后直接返回数据,定期或特定动作执行时才将数据保存到mysql,这样可以做到多次更新一次保存。

18:memcache与redis在删除失效主键的时候有何异同?
首先,memcache在删除失效主键时也是采用消极的方法,memcache内部不会监视主键是否失效,而是通过get访问主键时才会检查其是否已经失效,其实,memcache不会向redis那样真正地去删除失效的主键,而只是简单的将失效主键占用的空间标记为可用,当有新的数据写入到系统中时,memcache会优先使用失效主键的空间,如果失效主键的空间用光了,memcache还可以通过LRU机制来回收那些长期得不到访问的空间。

19:redis的内存回收:redis通过引用计数的方式对内存进行管理。
a:当创建一个新对象时,对象的引用计数的值会被初始化为1.
b:当对象被一个程序使用时,它的引用计数会加1.
c:当对象不再被程序使用时,它的引用计数值会减1.
d:当对象的引用计数值为0时,对象所占的内存就会被释放。

20:AOF、RDB和复制功能对过期键的处理:
a:生成RDB文件:在执行SAVE命令或者BGSAVE命令创建一个新的RDB文件时,程序会对数据库中的键进行检查,已过期的键不会被保存到RDB文件中。
b:载入RDB文件:在启动redis服务器时,如果服务器开启了RDB功能,那么服务器就会载入RDB文件,如果服务器以主服务器的模式运行,那么载入RDB文件时,程序会对文件中保存的数据进行检查,未过期的键会被载入到数据库中,而过期的键则会被忽略。如果服务器以从服务器的模式运行,那么在载入RDB文件时,文件中保存的所有键都会被载入到数据库中,不过因为主从服务器在进行数据同步的时候从从服务器的数据库会被清空,所以,一般来讲,过期键对载入RDB文件的从服务器也不会有英雄。
c:当服务器以AOF持久化的模式运行时,如果数据库中的某个键已经过期,那么AOF文件不会因为这个过期键而产生任何影响。当过期键被删除时,程序会向AOF文件追加一条DEL命令,来显示地记录该键已经被删除。
d:AOf重写:和生成RDB文件类似,在执行AOF重写的过程中,程序会对数据库中的键进行检查,已经过期的键不会被保存到重写后的AOF文件。

21:服务器在载入rdb文件期间,会一直处于阻塞状态,直到载入完成为止。也就是说主服务器在传输rdb文件给从服务器时,客户端的命令请求会被阻塞到传输rdb文件结束后执行,从服务器在载入rdb文件时,会阻塞命令请求,直到载入完成之后在执行。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值