一. 简介
-
Redis是什么?
Redis是一个开源的,使用C语言编写的,支持集群、分布式、主从同步等配置的、基于内存的、可持久化的、单进程的、单线程的k-v框架。 -
优点
a. 性能优越,可支持每秒十几万的读/写操作(性能优越的原因:1. 基于ANSI C语言编写,接近汇编语言的机器语言,运行十分快; 2. 基于内存的读/写; 3. 数据结构简单,只有6种数据类型);
b. 支持集群、分布式、主从同步等配置;
c. 支持一定的事务能力; -
缺点
不支持减法、乘法、除法操作,功能十分有限 -
Redis支持的数据类型
String、list、set、zset(有序集合)、hash、HyperLogLog(基数)
二. Redis数据结构常用命令
- 略
三. Redis的一些常用技术
-
Redis中使用事务的三个过程
a. 开启事务
b. 命令进入队列
c. 执行事务(exec) -
Redis事务命令
multi :开启事务
watch : 监听某些键
unwatch : 取消监听某些键
exec : 执行事务
discard : 回滚事务 -
CAS(比较与替换,Compare And Swap)原理在Redis中的应用
原因:为了克服多线程数据不一致问题原理:
a. 首先,在线程开始时读取这些多线程共享的数据时,并将其保存到当前进程的副本中(即 旧值),watch命令就是样一个功能;
b. 然后,开启线程业务逻辑,multi提供此功能;
c. 在执行更新前,比较当前线程副本保存的旧值和当前线程共享的值是否一致,如果不一致,则更新失败,进行事务回滚;否则更新成功,exec就是提供“类似”的功能
⚠️注意:“类似”并非完全是,因为CAS会产生ABA问题 -
超时命令
a. del命令可以删除一些键值对
b. 还会按照回收机制去自动回收一些键值对 -
如果key超时了,Redis会回收key的存储空间吗?
不会。Redis的key超时不会被其自动回收,它只会标示哪些键值对超时了 -
键值对回收的方法
定时回收:在确定的某个时间触发一段代码,回收超时的键值对;
惰性回收:当一个键值对超时了,被再次get命令访问时,将触发Redis将其从内存中清空。
四. Redis配置
-
Redis备份(持久化)的方式
快照:备份当前瞬间Redis在内存中的数据记录;
只追加文件(AOF):在持久化文件尾部继续跟上操作的命令。 -
Redis内存回收策略
· volatile-lru : 采用最近使用最少的淘汰策略,回收超时的键值对;
· allkeys-lru :采用淘汰最少使用的策略,对所有的键值对(不仅仅是超时的)采用最近使用最少的淘汰策略;
· volatile-random : 采用随机淘汰的策略删除超时的键值对;
· allkeys-random :采用随机淘汰的策略删除所有的键值对;
· volatile-ttl :采用删除存活时间最短的键值对策略;
· noeviction : 不淘汰任何键值对,当内存已满时,只读不写 -
LRU算法
即淘汰机制。 -
复制
- 主从架构设计思路
a. 在多台数据服务器中,只有一台主服务器,且主服务器只负责写入数据,从服务器只负责同步主服务器的数据,并让外部程序读取数据;
b. 主服务器在写数据后,即刻将写入数据的命令发送给从服务器,从而使得主从服务器数据同步;
c. 当主服务器不能工作时,从从服务器中选举一台来当主服务器。
主从同步机制:
2. Redis主从同步过程
3. 哨兵模式
原因:因主服务器中断后,可将从服务器升级为主服务器,以便提供服务,但此过程需手动实现,故redis2.8中提供了哨兵工具来实现自动化的系统监控和故障恢复;
改进:监视主/从服务器是否正常运行,主服务器出现故障时自动将从服务器升级为主服务器。
4.集群
原因:哨兵模式已实现了高可用,读写分离,但这种模式下后台redis服务器都存储相同的数据,很浪费内存,故redis3.0引入了集群模式,实现了redis的分布式存储。
特点:采用无中心结构所有redis节点彼此互联,内部使用二进制协议优化传输速率和带宽节点的fail是通过集群中超过半数的节点检测失效时才生效
- 主从架构设计思路
五. Spring缓存机制和Redis的结合
-
Redis和数据库的读操作
当设置Redis的数据超时后,Redis就无法读出数据,此时就会触发程序读取数据库,然后将读取的数据库数据写入Redis,达到按一定时间间隔刷新一次数据 -
Redis和数据库的写操作
写入业务数据,先从数据库中读取最新数据,然后进行业务操作,更新业务数据到数据库,再将数据刷新到Redis缓存中,避免了脏读。 -
Spring的缓存管理器
Spring项目中提供了接口CacheManager来定义缓存管理器;
@EnableCaching:Spring IoC容器启动了缓存机制; -
缓存注解
- @Cacheable:
表明在进入方法之前,Spring会先去缓存服务器中查找对应key的缓存值,如果找到缓存值,那么Spring将不会再调用方法,而是将缓存值读出,返回给调用者:如果没有找到缓存值,那么Spring就会执行你的方法,将最后的结果通过key保存到缓存服务器中; - @CachePut:Spring会将该方法返回的值缓存到缓存服务器中,这里需要注意的是,Spring 不会事先去缓存服务器中查找,而是直接执行方法,然后缓存。换句话说,该方法始终会被Spring所调用;
- @CacheEvict:移除缓存对应的key的值;
- @Caching:这是一个分组注解,它能够同时应用于其他缓存的注解.
- @Cacheable:
-
自调用失效问题
因为缓存注解也是基于Spring AOP的。 -
Redis缓存击穿,穿透,雪崩问题,及解决方案
参考链接:https://blog.csdn.net/qq_27391133/article/details/80364658 -
Redis扩容原理
参考链接:https://www.cnblogs.com/jaycekon/p/6227442.html -
Redis 哈希槽的概念?
Redis 集群没有使用一致性 hash,而是引入了哈希槽的概念,Redis 集群有16384 个哈希槽,每个 key 通过 CRC16 校验后对 16384 取模来决定放置哪个槽,集群的每个节点负责一部分 hash 槽。 -
Redis 如何做内存优化?
尽可能使用散列表(hashes),散列表(是说散列表里面存储的数少)使用的内存非常小,所以你应该尽可能的将你的数据模型抽象到一个散列表里面。比如你的 web 系统中有一个用户对象,不要为这个用户的名称,姓氏,邮箱,密码设置单独的 key,而是应该把这个用户的所有信息存储到一张散列表里面。 -
使用过 Redis 做异步队列么,你是怎么用的?
答:一般使用 list 结构作为队列,rpush 生产消息,lpop 消费消息。当 lpop 没有消息的时候,要适当 sleep 一会再重试。如果对方追问可不可以不用 sleep 呢?list 还有个指令叫 blpop,在没有消息的时候,它会阻塞住直到消息到来。如果对方追问能不能生产一次消费多次呢?使用 pub/sub 主题订阅者模式,可以实现1:N 的消息队列。如果对方追问 pub/sub 有什么缺点?
在消费者下线的情况下,生产的消息会丢失,得使用专业的消息队列如 RabbitMQ等。如果对方追问 redis 如何实现延时队列?
使用 sortedset,拿时间戳作为score,消息内容作为 key 调用 zadd 来生产消息,消费者用 zrangebyscore 指令获取 N 秒之前的数据轮询进行处理。 -
使用过 Redis 分布式锁么,它是什么回事?
先拿 setnx 来争抢锁,抢到之后,再用 expire 给锁加一个过期时间防止锁忘记了释放。
接着问如果在 setnx 之后执行 expire之前进程意外 crash 或者要重启维护了,那会怎么样?
我记得 set 指令有非常复杂的参数,这个应该是可以同时把 setnx 和expire 合成一条指令来用的!
Redis实现分布式锁