🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
## 1、项目中redis的应用场景? redis的应用场景与其提供的数据结构有关,虽然redis也提供了持久化的功能,但是通常的都会将redis作为缓存来使用。 - redis基本的数据结构有:string、hash、list、set、sortedset。 - 项目中典型的应用场景有缓存token来记录用户的登录状态,缓存session或者缓存一些频繁被查询的数据。 - 由于redis工作线程是单线程的特性,可以实现服务的无状态化和无锁化;单机锁或者分布式锁都可以抽离到redis中实现。   ## 2、set和zset的应用场景? * set是使用哈希表构造的,根据哈希表的特性可以用在给用户打上感兴趣的标签、知道不同用户之间相互的爱好群体或者是用在共同好友的功能上。 * zset使用hashmap和skipList实现;常用在根据时间排序的新闻列表和阅读排行榜上。 >跳表参考:[https://www.cnblogs.com/bigsai/p/14193225.html](https://www.cnblogs.com/bigsai/p/14193225.html)   ## 3、redis是单线程还是多线程? redis的工作线程仍然是单线程,在redis6之前redis只有一个线程处理IO操作和执行指令。在redis6之后出现了IO多线程,每个客户端都会绑定一个IO线程,但是redis服务器执行指令仍然是单线程的。 redis5的工作模式如下:内核到redis服务器的数据、指令搬运都是串行的,只有一个工作线程负责输入、计算、输出。 redis6的工作模式如下:工作线程是单线程,但是每个客户端的IO操作是多线程的,这样可以很好的缩短执行时间,更好的利用网卡的资源。 总之从客户端的时候上来将redis是单线程还是多线程的没有区别。   ## 4、redis存在线程安全问题嘛?为什么? 因为redis的工作线程是单线程的,所以redis服务器内部执行指令不存在线程安全问题;但是业务上的线程安全问题需要程序员自己保证。   ## 5、缓存穿透、缓存击透、缓存雪崩问题? 这三个问题都是在【客户端——redis——数据库】这样的一个拓扑模型下出现的。 1. **缓存穿透**:缓存穿透指的是redis和数据库中都没有用户查询的数据,如果大量这样无效的请求达到数据库则会造成无意义的压力。解决方法为: - 在redis中没有查询到键缓存空值或者默认值。 - 使用布隆过滤器快速判断数据是否存在。 - 进一步优化可以在客户端从redis读取key的时候加入锁,避免数据库中大量事务同时排队,这样也是会直接对数据库造成压力的。 2. **缓存击透**:缓存中的某个或某几个热点数据过期了(或者没有缓存过),同时大量的并发请求访问该热点数据,这些并发请求就会直接去访问数据库。(注意与缓存穿透相比数据库中是有这些数据的),解决方法: - 互斥锁方案,客户端从redis中读取key时加入锁,第一个请求去数据库中读取输入放入redis中,其他请求被阻塞等待;等到第一个锁释放的时候redis中已经有数据了,其他请求直接读取内存中的数据阻塞也就没有意义了(同样快)。 - 不给热点数据设置过期时间,由后台异步更新缓存。 3. **缓存雪崩**:很多热点数据同时过期,或者没有被缓存过,缓存击透可以说是缓存雪崩的子集。缓存雪崩的解决思路与缓存击透一致。   ## 6、redis如何删除过期key? 过期键的删除策略主要有三种,分别为: - 定时删除:在设置过期时间的时候设置定时器,由定时器删除。 - 惰性删除:每次访问数据的时候判断是否过期了,过期了则删除。 - 定期删除:由后台线程按照固定周期的删除。 redis过期键的删除策略采用**惰性删除和定期删除**的组合: 1. 惰性删除策略表现为当每次get一个键的内容的时候,就会先判断(expireIfNeeded方法)键是否过期了,如果过期了则进行删除,不过期的话则获取值返回。 2. 定期删除表现为redis服务器后台会周期性的执行一个函数(activeExpireCycle),检查某几个数据库中的某部分键是否过期,不会一次性的将所有的键都检查一遍;下次执行的时候则会接着上次检查的剩下的继续检查下去,重复循环。 >备注:因为redis工作线程是单线程的,因此后台执行删除键的时候会暂停其他工作服务,所以redis服务器不会让这个延迟时间过长而尽可能的去删除数据。   ## 7、缓存如何淘汰? 在内存空间不足的情况下就会淘汰数据,根据作用数据范围的不同主要有如下的几种淘汰算法: 1. 作用在设置了过期时间的key上: - volatile-TTL:设置过期时间越早的数据越先被淘汰。 - volatile-random:随机淘汰设置了过期时间的数据。 - volatile-LRU:根据LRU算法淘汰过期时间的数据。 - volatile-LFU:根据LFU算法淘汰过期时间的数据。 2. 作用在所有的key上: - volatile-random - volatile-LRU - volatile-LFU   ## 8、如何进行缓存预热? 手动的提前将数据放入redis中,但是有个如何区分哪些数据是热点数据的问题!需要分析具体的业务得出。也是会造成缓存穿透、缓存击透和雪崩问题。   ## 9、数据库和redis如何解决缓存不一致问题? 对于缓存不一致的问题一般有4种解决思路: 1. 先更新数据库,再更新缓存。 2. 先更新缓存,再更新数据库。 3. 删除缓存,再更新数据库。 4. 先更新数据库,删除缓存:在单机中最终采取这种方案,有时也会采用延迟删除的方式删除缓存。 但是第四种方案在mysql主从架构中容易出现问题,主要问题在于从服务器复制主服务器的数据可能存在网络延迟,因此一般在分布式中都会采用binlog的订阅机制来解决。 阿里云开发的canal可以模拟mysql 的slave来订阅主服务器的binlog,因此通过canal订阅binlog来更新redis中的缓存是现在开发中常用的解决方案。同时如果为了实现高可用,避免redis宕机时更新的数据丢失,可以使用MQ来保存更新的数据。(注意使用这种方式mysql与redis不再直接连接。)