一、为什么使用redis
首先我认为使用redis主要是因为他的性能和并发能力优越,redis也具备做分布式锁的功能,但有其他组件也可以比如zookeeper可以替代,并不是非要使用redis,所以使用redis主要利用他的性能和并发能力。
回答两个问题:性能和并发
性能:
当我们需要从数据库中读取那些不经常变更的信息,可以把信息放到缓存中去读取,请求针对缓存的读取是十分迅速的。
并发:
当有很多的请求直接访问数据库时,会严重影响效率,我们可以让redis做一个缓冲操作,让请求先访问redis,而不是直接到数据库中。
二、项目使用redis的一些问题
1)数据库和缓存双写不一致的问题
2)缓存击穿
3)缓存雪崩
4)缓存的并发竞争问题
三、单线程的redis为什么这么快
Redis 的瓶颈并不在 CPU,而在内存和网络。
内存不够的话,可以加内存或者做数据结构优化和其他优化等,但网络的性能优化才是大头,网络 IO 的读写在 Redis 整个执行期间占用了大部分的 CPU 时间,如果把网络处理这部分做成多线程处理方式,那对整个 Redis 的性能会有很大的提升。
大家所熟知的 Redis 确实是单线程模型,指的是执行 Redis 命令的核心模块是单线程的,而不是整个 Redis 实例就一个线程,Redis 其他模块还有各自模块的线程的。Redis 6.0 网络处理模块是多线程的
1)单线程操作,避免了上下文切换的操作
2)纯内存操作
3)采用了非阻塞I/O多路复用机制
多路复用机制:
四、redis的数据类型,以及他的适用场景
五、redis的过期策略以及内存淘汰机制
六、redis和数据库双写不一致的问题
七、如何应对缓存穿透和缓存雪崩的问题
八、如何解决redis并发竞争key的问题
九、redis分布式锁问题
1、单机版:并发修改问题,加锁就能解决
2、分布式系统,单机版的锁已经没有用了,两台机器同时修改一个变量,加分布式锁(redis的setnx(),java方法中是setIfAbsent)
3、每个单机中都加上分布式锁之后,有加锁必定就需要解锁,解锁加在finally语句中,保证解锁成功
4、单机逻辑执行一半宕机或者被kill -9了没有执行解锁怎么办?加锁时加上过期时间(必须保证加锁和设置过期时间的操作要保证原子性,用setIfAbsent(LOCK,value,10L,TimeUnit.SECONDS))
5、分布式系统中当我们要删除一个锁时,必须首先去判断是自己加的锁才能去删除,不能删除别人的锁(get(LOCK).equalsIgnoreCase(value))
判断是否相等和删除两个操作必须保证原子性,官网上有提供lua脚本保证这个两个操作原子性的方法(还有一个是通过redis的事物,推荐用Lua脚本)
lua脚本通过eval()函数去执行