思维导图:
1.RDBMS与NOSQL的区别
-
RDBMS:关系型数据库管理系统
- 应用:业务性数据存储
- 特点:体现数据之间的关系,支持完善事务,业务稳定且安全,数据量小的情况下性能较好
-
NOSQL:非关系型数据库
- 应用:高并发情景下的数据缓存和数据存储
- 特点:读写速度特别快,并发量高,但事务支持不完善,稳定性和安全性较差
2.Redis的功能和应用场景
- 定义:基于内存的分布式的NoSQL数据库
- 功能:提供高性能高并发的数据读写
- 特点:
- ①.基于C语言开发,与硬件的交互性较好
- ②.基于内存实现数据的读写,性能快(高性能)
- ③.分布式架构,扩展性和稳定性好(高并发)
- ④.支持事务,支持多种数据类型
- String:类似于java的字符串
- Hash:类似于java中的Map集合
- List:有序可重复的元素集合
- Set:无序且不可重复的元素集合,一般用于去重
- Zset:Sorted Set,有序不可重复
- 应用场景:
- ①.缓存:适合于高并发大数据量的数据缓存
- ②.数据库:适合于高性能小数据量的持久性存储
- ③.消息队列:一般不用
3.Redis的数据是什么结构?Value的常用类型有哪几种?
- 数据结构:K-V对,数据直接存储在数据库
- K:String
- V:String、Hash、List、Set、Zset
4.Redis常用的通用命令
- 1.Keys *:列举当前数据库中所有Key
- 2.del key :删除某个KV
- 3.exists key :判断某个Key是否存在
- 4.type key :判断这个K对应的V的类型的
- 5.expire K 过期时间 :设置某个K的过期时间,一旦到达过期时间,这个K会被自动删除
- 6.ttl K :查看某个K剩余的存活时间
- 7.select N :切换数据库的
- ①Redis默认有16个数据:db0 ~ db15,个数可以通过配置文件修改,名称不能改
- ②Redis是一层数据存储结构:所有KV直接存储在数据库中
- ③默认进入db0
- 8.move key N :将某个Key移动到某个数据库中
- 9.Flushdb :清空当前数据库的所有Key
- 10.Flushall :清空所有数据库的所有Key
5.每种类型的常用命令有哪些?
- String:set、mset、setnx、get、mget、strlen、getrange
- Hash:hset、hmset、hget、hmget、hgetall、hvals、hlen
- List:lpush、rpush、lrange、lpop、rpop
- Set:sadd、smembers、sismembers、srem、scard
- Zset:zadd、zrange、zrevrange、zrem、zcard、zscore
- bitmap:setbit/getbit/bitcount/bitop
- hyperloglogs:pfadd,pfmerge
6.实现Jedis的客户端连接
- 实现步骤:
Step1:构建连接对象
Jedis jedis = null;
@Before
public void getConnection(){
//方式一:直接构建Jedis对象
// jedis = new Jedis("node1",6379);
//方式二:通过连接池构建Jedis
//构建连接池配置对象
JedisPoolConfig config = new JedisPoolConfig();
config.setMaxTotal(10);//总连接构建
config.setMaxIdle(5);//最大空闲连接
config.setMinIdle(2);//最小空闲连接
//构建连接池对象
JedisPool jedisPool = new JedisPool(config,"node1",6379);
//获取连接
jedis = jedisPool.getResource();
}
//Step2:调用连接对象的方法实现操作
……
//Step3:释放连接
@After
public void closeConnection(){
jedis.close();
}
7.Jedis中有哪些类和方法?
- Jedis:客户端连接对象
- 与命令保持一致
- JedisPool:连接池对象
- getResource:获取连接对象
- JedisPollConfig:连接池配置对象
8.Redis如何保证数据的安全性?
持久化机制:persist
- (1)RDB:默认机制
-
①思想:在一定时间周期内发生一定次数数据更新【插入、删除、修改】操作,就对整个内存中所有的数据拍摄全量数据快照存储在磁盘上(覆盖先前的)
-
②实现
- 1)手动:save(前端运行)/bgsave(后台运行)/shutdown(关闭服务端)/flushall(清空,没有意义),当执行某些命令时,会自动拍摄快照【一般不用】
- 2)自动:按照一定的时间内发生的更新的次数,拍摄快照
-
Redis可以设置多组rdb条件,默认设置了三组,这三组共同交叉作用,满足任何一个都会拍摄快照
-
为什么默认设置3组?
- 原因:如果只有一组策略,面向不同的写的场景,会导致数据丢失,针对不同读写速度,设置不同策略,进行交叉保存快照,满足各种情况数据的保存策略
-
③优点:二进制文件的全量快照、更快、更小、fork进程实现性能更好
-
④缺点:有一点概率出现数据丢失
-
⑤应用:缓存场景,数据备份和回复
-
- (2)AOF:灵活性更好(安全和性能可以自由选择)
-
①思想:按照一定规则,将内存数据变化的日志追加记录在文件中
-
②实现:
- 1)Appendfsync always:每写一条内存就追加一条到磁盘
- 安全性最高,性能最低
- 2)Appendfsync Everysec: 每一秒追加一次磁盘
- 安全和性能权衡,性能高于always,但会有数据丢失风险,最多1S
- 3)Appendfsync No:交给系统来做,不有Redis控制,不用
- 1)Appendfsync always:每写一条内存就追加一条到磁盘
-
③优点:灵活性更高,可以自由选择安全性和性能
-
④缺点:加载恢复数据比较慢,文件失普通文本,过大并且包含很多无用操作【定期构建快照】
-
⑤应用:永久性的存储数据(数据库)
-
- (3)持久化方案:两种方案怎么选?
- ①两种方案都用:默认不配置AOF,使用的RDB
- ②问题:两种都用,重启Redis加载的是谁的数据?
答:加载AOF
9. Redis的事务有什么特点?
-
事务定义:事务是数据库操作的最小工作单元,包含原子性、一致性、隔离性、持久性
-
1.Redis本身是单线程,本身没有事务概念
-
2.Redis支持事务的本质是一组命令的集合,将多条命令放入队列中,按照顺序依次串行执行
-
3.一般不用,不保证原子性
-
4.没有隔离性:批量的事务命令执行前在缓存队列中,没有事务交叉,不存在脏读幻读等问题
-
实现过程:
- (1)开启事务
- (2)提交事务
- (3)执行事务
-
常用命令:
- (1) multi:开启事务
- (2) exec:执行事务
- (3) discard:取消事务
- (4) watch:监听机制,类似于乐观锁
- 乐观锁:总是假设最好的情况,每次去拿数据的时候都认为别人不会修改,所以不会上锁,只在更新的时候会判断一下在此期间别人有没有去更新这个数据
- (5) unwatch:取消监听
10.Redis的数据过期机制和内存淘汰机制是什么?
-
问题:Redis使用的是内存,内存如果满了,怎么解决?
-
1.过期策略
-
设计思想:避免内存满,指定Key的存活时间,到达存活时间以后自动删除
-
(1)定时过期:指定Key的存活时间,一直监听这个存活时间,一旦达到存活时间,自动删除
- 注:需要CPU一直做监听,如果Key比较多,CPU的消耗比较严重
-
(2)惰性过期:指定Key的存活时间,当使用这个Key时,判断是否过期,如果过期就删除
缺点:如果某个Key设置了过期时间,但是一直没有使用,不会被发现过期了,就会导致资源浪费 -
(3)定期过期:每隔一段时间就检查数据是否过期,如果过期就进行删除
-
Redis中使用了惰性过期和定期过期两种策略共同作用
-
-
2.内存淘汰机制
- 设计思想:Redis的内存淘汰策略是指在Redis的用于缓存的内存不足时,怎么处理需要新写入且需要申请额外空间的数据, Redis 源码中的默认配置
- (1)过期Key:随机、LRU、TTL
- (2)所有Key:随机、LRU
- (3)直接报错
- (4)缓存:所有Key-LRU
- (5)持久化:过期Key-LRU
11.Redis的主从复制集群、哨兵集群、分片集群各自有什么特点?
- 1.主从复制集群
- (1)主(Master):提供读写
- (2)从(slave):提供写,与Master同步数据
- (3)优点:实现了读写分离,分摊了读写的压力负载,如果一台Redis的Slave故障,其他的Redis服务节点照常对外提供服务
- (4)问题:Master存在单点故障问题
- 2.哨兵集群
- (1)基于主从复制+引入哨兵机制
- (2)哨兵进程:监听所有节点,实现故障恢复,配置同步
- (3)功能:允许Slave选举成为Master(解决主从复制的master单点故障问题)
- (4)过程:
- ①step1:某个哨兵发现master故障(主观性故障)
- ②step2:等到一定数量哨兵(半数以上)认为master故障,客观性故障
- ③Step3:从Slave选举新的Master
- ④Step4:修改其他Slave的配置与新的master同步数据
- (5)缺点:资源不足
- 3.分片集群:分布式内存
- 问题:Redis哨兵集群中的存储容量只有单台机器,如何解决大量数据使用Redis存储问题?
- 思想:将多个小的Redis集群逻辑上合并成一个大的Redis集群,每个小的集群就是一个分片
- ①分片规则:虚拟槽位计算来进行分片,每个分片对应一定的槽位数
- ②读写数据时:CRC16【K】&16383=0~16383
- ③每个小的Redis集群里有master和slave(只读写master)
12.常见面试题
-
(1) 什么是缓存击穿,怎么解决?
- ①现象:有一个Key,经常需要高并发的访问,这个Key有过期时间的,一旦达到过期时间,这个Key被删除,所有高并发落到了MySQL中,被击穿了
- ②解决
- 1)step1:资源充足的情况下,设置永不过期
- 2)step2:对这个Key做一个互斥锁,只允许一个请求去读取,其他的所有请求先阻塞掉
- a.第一个请求redis中没有读取到,读了MySQL,再将这个数据放到Redis中
- b.释放所有阻塞的请求
-
(2) 什么是缓存雪崩,怎么解决?
- ①现象:大量的Key在同一个时间段过期,大量的Key的请求在Redis中都没有,都去请求MySQL,导致MySQL奔溃
- ②解决
- 1)step1:资源充足允许的情况下,设置大部分的Key不过期
- 2)step2:给所有Key设置过期时间时加上随机值,让Key不再同一时间过期
-
(3) Redis中的Key怎么设计?
- ①使用统一的命名规范
- ②一般使用业务名(或数据库名)为前缀,用冒号分隔,例如,业务名:表名:id。
- 例如:shop:usr:msg_code(电商:用户:验证码)
- ③控制key名称的长度,不要使用过长的key
- ④在保证语义清晰的情况下,尽量减少Key的长度。有些常用单词可使用缩写,例如,user缩写为u,messages缩写为msg
- ⑤名称中不要包含特殊字符、包含空格、单双引号以及其他转义字符
-
(4) 为什么Redis是单线程的?
- ①因为Redis是基于内存的操作,CPU不是Redis的瓶颈
- ②Redis的瓶颈最有可能是机器内存的大小或者网络带宽
- ③单线程容易实现,而且CPU不会成为瓶颈,所以没必要使用多线程增加复杂度
- ④可以使用多Redis压榨CPU,提高性能
-
(5) 为什么Redis的性能很高?
- ①完全基于内存,非常快速
- ②数据结构简单,对数据操作也简单
- ③采用单线程,避免了不必要的上下文切换和竞争条件
- ④多路I/O复用模型,非阻塞IO