1.redis
redis高性能的key-value数据库,支持持久化,不仅仅支持简单的key-value,还提供了list,set,zset,hash等数据结构的存储,支持数据的备份(master-slave模式)
redis:性能极高,丰富的数据类型,原子操作,丰富的特性
2.redis数据类型
String-字符串,hash-哈希,list-列表,set-集合, zset-有序集合
3.好处
速度快,丰富的数据类型,支持事务(操作原子性),丰富的特性(用于缓存,消息,按key设置过期时间,过期后将自动删除)
4.memcached与redis区别
5.redis是单进程单线程的,利用队列技术将并发访问变为串行访问,消除了传统数据库串行控制的开销
6.一个字符串类型的值能存储最大容量是 512M
7.redis持久化机制是什么,优缺点?
持久化机制:RDB和AOP
RDB持久化:原理是将Redis在内存中的数据库记录定时dump到磁盘上的RDB持久化
AOF持久化:原理是将Redis的操作日志以追加的方式写入文件
rdb和aof
8.常见性能问题和解决方案
9.redis过期键的删除策略
10.redis回收策略(淘汰策略)
使用策略规则
11为什么redis需要把所有数据放到内存中?
为了达到最快的读写速度将数据都读到内存中,并通过异步的方式将数据写入磁盘。
12.redis同步机制
redis可以使用主从同步,从从同步。
13.pipeline的好处
可以将多次io往返的时间缩减为一次,前提是pipeline执行的指令之间没有因果相关性,使用redis-benchmark进行压测的时候可以发现影响redis的qps峰值的一个重要因素是pipeline批次指令的数目。
14.redis集群的原理
15.redis集群方案什么情况下会导致整个集群不可用
有ABC三个节点的集群,在没有复制模型的情况下,如果节点b失败了,那么整个集群就会以为缺少5501-11000这个范围的槽而不可用。
Redis Sentinel 及 Redis Cluster
16.redis哈希槽的概念?
redis集群有16384个哈希槽,每个key通过crc16校验后对16384取模来决定放置哪个槽,集群的每个节点负责一部分hash槽。集群最大节点个数:16384个
17.redis集群的主从复制模型?
为了使在部分节点失败或大部分节点无法通信的情况下集群仍然可用,所有集群使用了主从复制模型,每个节点都会有N-1个复制品。复制方式:异步复制
18.redis事务
19.redis内存优化
尽可能使用散列表(散列表里面存储的数少,使用内存非常小),尽可能将数据模型抽象到一个散列表里面,eg:一个用户对象,不要为这个用户的名称,姓氏,邮箱,密码设置单独的key,而是应该把这个用户的所欲信息存储到一张散列表里面。
20.redis回收进程如何工作?
客户端运行新的命令,添加新的数据,redis检查内存使用情况,如果大于maxmemory限制,则根据设定好的策略进行回收。
通过不断达到边界然后不断地回收回到边界以下,如果一个命令的结果导致大量内存被使用,不用多久内存限制就会被这个内存使用量超越。
21.降低redis内存使用情况
如果使用的是32位redis实例,可以利用hash,list等集合类型数据。
22.redis内存用完会发生什么
如果达到设置的上限,redis的写命令会返回错误信息(读命令正常返回),或者可以将redis当缓存来使用配置淘汰机制,当redis达到内存上限时会冲刷掉旧的内容。
23.mysql里有2000w数据,redis中只存20w的数据,如何保证redis中的数据都是热点数据?
使用redis提供的6中数据淘汰策略,redis内存数据集大小上升到一定大小时候,就会施行数据淘汰策略。
24.redis最适合的场景?
25.假如redis里有1亿个key,其中10w个key是以某个固定的已知的前缀开头的,如果将他们全部找出来?
keys指令可以扫出指定模式的key列表。
但由于redis是单线程的,keys指令会导致线程阻塞一段时间,线上服务会停顿,直到指令执行完毕,服务才能恢复。
可以用scan指令,可以无阻塞的提取出指定模式的key列表,但有一定的重复概率,在客户端做一次去重就可以了,但整体时间会比直接用keys长。
26.redis做异步队列?
一般使用list结构作为队列,rpush生产消息,lpop消费消息,当lpop没有消息的时候,适当sleep一会再重试。
不用sleep?blpop在没有消息的时候,他会阻塞住直到消息到来。
生产一次消费多次?使用pub/sub主题订阅者模式,可以实现1:N的消息队列
pub/sub缺点:消费者下线的情况,生产的消息会丢失,使用专业的消息队列如rabbitMQ
redis实现延时队列:使用sortedset,拿时间戳作为score,消息内容作为key调用zadd来生产消息,,消费者用zrangebyscore指令获取N秒之前的数据轮询进行处理。
Redisson 的分布式延时队列 RedissonDelayedQueue 运行流程
//发送消息
String queueKey
RBlockingDeque<Object> blockingDeque = redissonClient.getBlockingDeque(queueKey);
RDelayedQueue<Object> delayedQueue = redissonClient.getDelayedQueue(blockingDeque);
delayedQueue.offer(value, delay, timeUnit);
//获取消息
RBlockingDeque<Object> blockingDeque = redissonClient.getBlockingDeque(queueCode);
redissonClient.getDelayedQueue(blockingDeque);
return (T) blockingDeque.take();
redisson 源码里一共创建了三个队列:
流程:
发送延迟消息,发送的延迟消息会先存在【消息延时队列】和【消息顺序队列】,如果【消息延时队列】原本是空的,会发布订阅信息提醒有新的消息。
获取延迟消息只需要从【消息目标队列】阻塞的取就行了,因为里面都是到期数据。
初始化延时队列:判断时间到了,把【消息延时队列】里的消息移动到【消息目标队列】里
定时从【消息延时队列】查询最新到期时间,定时去把【消息延时队列】里的消息移动到【消息目标队列】里。
如果【消息延时队列】是空的,就不会再定时查,而是等待发布订阅信息提醒,再定时把【消息延时队列】里的消息移动到【消息目标队列】里。
27.redis分布式锁
先拿setnx来争抢锁,抢到之后,再用expire给锁加一个过期时间防止锁忘记了释放
setnx之后执行expire之前进程意外crash或者要重启维护了,会怎么样?
set指令的复杂参数,可以把setnx和expire合成一条指令用的。
28.解决key冲突
29 什么是缓存穿透
缓存雪崩
30 保证缓存和数据库数据的一致性
淘汰缓存:数据如果为较为复杂的数据时,进行缓存的更新操作就会变得异常复杂,推荐选择淘汰缓存,而不是更新缓存。
选择先淘汰缓存,再更新数据库:假如先更新数据库,再淘汰缓存,如果淘汰缓存失败,那么后面的请求都会得到脏数据,直至缓存过期。假如先淘汰缓存再更新数据库,如果更新数据库失败,只会产生一次缓存穿透,相比较而言,后者对业务则没有本质上的影响。
延时双删策略:
如下场景:同时有一个请求A进行更新操作,另一个请求B进行查询操作。
次数便出现了数据不一致问题。采用延时双删策略得以解决。
public void write(String key,Object data){
redisUtils.del(key);
db.update(data);
Thread.Sleep(100);
redisUtils.del(key);
}
这么做,可以将1秒内所造成的缓存脏数据,再次删除。这个时间设定可根据俄业务场景进行一个调节。
数据库读写分离的场景
两个请求,一个请求A进行更新操作,另一个请求B进行查询操作。