点关注,不迷路;持续更新Java架构相关技术及资讯热文!!!
1. 什么是redis?
Redis 是一个基于内存的高性能key-value数据库。
2. Memcache与Redis的区别都有哪些?
存储方式
Memecache把数据全部存在内存之中,断电后会挂掉,数据不能超过内存大小。
Redis可以把数据保存在硬盘上,用来保证数据的持久性。数据类型
Memcache的数据类型比较简单。
Redis有复杂的数据类型。使用底层模型不同
它们之间底层的实现方式 以及与客户端之间通信的应用协议不一样。value大小
redis最大可以达到1GB,而memcache只有1MB
3. Redis有哪些数据结构?
字符串String、字典Hash、列表List、集合Set、有序集合SortedSet。
更进一步,redis还有数据结构HyperLogLog、Geo、Pub/Sub、BloomFilter,RedisSearch,Redis-ML等
4. 为什么redis需要把所有数据放到内存中?
Redis为了达到最快的读写速度,将数据都读到内存中,并通过异步的方式将数据写入磁盘。所以redis具有快速和数据持久化的特征。
如果不将数据放在内存中,磁盘I/O速度为严重影响redis的性能。
如果设置了最大使用的内存,则数据量达到内存限值后,将不能继续插入新值。
5. 怎么用Redis创建分布式锁
先用setnx来争抢锁,抢到之后,再用expire给锁加一个过期时间防止锁忘记了释放。
注意:如果在setnx之后,并且在执行expire之前,进程意外崩溃或者要重启维护了,这个锁就永远得不到释放了。
为了解决这个问题,set指令有非常复杂的参数,可以同时把setnx和expire合成一条指令
6. 假如Redis里面有1亿个key,其中有10万个key是以固定的前缀开头的,如何将这些全部找出来?
使用keys命令可以扫出指定模式的key列表。
但是,如果这个redis正在给线上的业务提供服务,因为redis的单线程的,所以keys命令会导致线程阻塞一段时间,线上服务会停顿,直到命令执行完毕,服务才能恢复。
为了解决这个问题,可以使用scan命令,scan命令可以无阻塞的提取出指定模式的key列表,会有一定的重复概率,在客户端做一次去重就可以了,但是整体所花费的时间会比直接用keys命令长。
7. 如果有大量的key需要设置同一时间过期,需要如何处理?
如果大量的key过期时间设置的过于集中,那么当到了过期的那个时间点,redis可能会出现短暂的卡顿。
这种情况下,可以在时间上加一个随机值,使得过期时间分散一些。
8. Redis如何做持久化的?
bgsave做镜像全量持久化,aof做增量持久化。
因为bgsave会耗费较长时间,达不到实时,在停机的时候会导致大量丢失数据,所以需要aof来配合使用。
如果不要求性能,在每条写指令时都sync一下磁盘,就不会丢失数据。但是在高性能的要求下每次都sync是不现实的,一般都使用定时sync,比如1秒1次,这个时候最多会丢失1s的数据。
Redis会定期做aof重写,压缩aof文件日志大小。
在redis实例重启时,优先使用aof来恢复内存的状态,如果没有aof日志,就会使用rdb文件来恢复。
9. 讲一下对Redis的同步机制的理解
Redis可以使用主从同步,从从同步。
第一次同步时,主节点做一次bgsave,并同时将后续修改操作记录到内存buffer,待完成后将rdb文件全量同步到复制节点,复制节点接受完成后将rdb镜像加载到内存。
加载完成后,再通知主节点将期间修改的操作记录同步到复制节点进行重放就完成了同步过程。
10. 对Redis的回收策略的理解
- volatile-lru:从已设置过期时间的数据集(server.db[i].expires)中挑选最近最少使用的数据淘汰
- volatile-ttl:从已设置过期时间的数据集(server.db[i].expires)中挑选将要过期的数据淘汰
- volatile-random:从已设置过期时间的数据集(server.db[i].expires)中任意选择数据淘汰
- allkeys-lru:从数据集(server.db[i].dict)中挑选最近最少使用的数据淘汰
- allkeys-random:从数据集(server.db[i].dict)中任意选择数据淘汰
- no-enviction(驱逐):禁止驱逐数据
11 对多级缓存的理解?
多级缓存就是有多个缓存,将ehcache配合redis缓存,比如ehcache作为1级缓存,使用redis作为2级缓存。
12. 如何解决DB和缓存一致性问题?
当修改了数据库后,没有及时修改缓存就会造成不一致的情况。
而修改缓存失败的情况,最主要的原因就是缓存服务器挂了。
如果因为网络问题引起的没有及时更新,可以通过重试机制来解决。
然而如果缓存服务器死了,那么客户端的请求自然也就无法到达,从而请求会直接打到数据库。
因此,我们在修改数据库后,无法修改缓存,那么其中一个方案可以将这条数据放到数据库中,同时启动一个异步任务,定时去检测缓存服务器是否连接成功,一旦连接成功则从数据库中按顺序取出未同步的数据,依次进行同步缓存。
13. 如何解决缓存穿透
生产中,通常都是先检查缓存中是否存在,如果存在直接返回缓存中内容,如果不存在就直接查询数据库,然后再缓存查询结果并返回。
这个时候如果查询的某一个数据在缓存中一直不存在,就会造成每一次请求都查询DB,这样缓存就失去了作用,在流量大时,就造成了缓存穿透。
有一个解决方案,可以将这个不存在的key预先设定一个值。是将缓存的KEY预先设置一个值,如,"key":"&&"。
如果查询请求过来,得到的返回值是发现是预先设定的"&&", 那我们的应用就可以决定是否继续等待继续访问,还是放弃掉这次操作。
如果继续等待访问,过一个时间轮询点后,再次请求这个key,如果取到的值不再是"&&",则认为这时候key有值了,从而把大量的类似请求阻挡在缓存之中,也就避免了缓存穿透。
14. redis常见性能问题和解决方案
- Master最好不要做任何持久化工作,如RDB内存快照和AOF日志文件
- 如果数据比较重要,某个Slave开启AOF备份数据,策略设置为每秒同步一次
- 为了主从复制的速度和连接的稳定性,Master和Slave最好在同一个局域网内
- 尽量避免在压力很大的主库上增加从库
- 主从复制不要用图状结构,用单向链表结构更为稳定,即:Master <- Slave1 <- Slave2 <- Slave3...
这样的结构方便解决单点故障问题,实现Slave对Master的替换。如果Master挂了,可以立刻启用Slave1做Master,其他不变。
点关注,不迷路;持续更新Java架构相关技术及资讯热文!!!