redis入门
一、为什么使用Redis
1、性能
当我们碰到需要执行耗时特别久,且结果不频繁变动的SQL,就特别适合将运行结果放入缓存。 这样,后面的请求就可以去
缓存中读取,使得请求能够迅速响应
2、并发
在大并发的情况下,所有的请求直接访问数据库,数据库会出现连接异常。 这时候,就需要Redis做一个缓冲操作,让请求先
访问Redis,而不是直接访问数据库
二、Redis的使用缺点
1、缓存和数据库双写一致性问题
2、缓存雪崩问题
3、缓存击穿问题
4、缓存的并发竞争问题
三、单线程的Redis为什么快
1、纯内存操作
2、单线程操作,避免了频繁的上下文切换
3、采用了非阻塞I/O多路复用机制
简单来说,就是Redis-client在操作的时候,会产生具有不同事件类型的socket。在服务端,有一段I/O多路复用程序,将其
放入队列之中。然后,文件事件分派器,依次去队列中取,转发到不同的事件处理器中。
四、Redis的数据类型,及其应用场景
1、string
最常规的set/get操作,value可以是string也可以是数字,一般做一些复杂的计数功能的缓存
2、hash
value存放值是结构化的对象,比较方便的就是操作其中的某个字段。
3、list
可以做简单的消息队列功能,也可以使用lrange命令,做基于Redis的分页功能
4、set
可以做全局去重的功能,可以做些交集、并集、差集
5、sorted set
多了一个权重参数score,集合的元素能够按score进行排列。可以做排行榜应用
五、Redis的过期策略以及内存淘汰机制
Redis采用的是定期删除+惰性删除策略。 Redis默认每100ms检查,是否右过期的key, 有的话则删除。
注意并不是每100ms将所有的key检查一次,而是随机抽取进行检查。 因此,如果使用定期删除的话,
会导致很多key到时间没有删除。 于是,惰性删除在获取到某个key的时候,Redis会检查一下,如果设置
了过期时间,那么是否已过期,如果过期则删除。
如果定期删除没有删除key,然后也没及时去请求key,则惰性删除没生效。 这样的话,Redis内存会
越来越高,这时就需要内存淘汰机制。 在redis.conf中有一行配置信息
#maxmemory-policy volatile-lru
参数列举如下:
1) noeviction 当内存不足以容纳新写入数据时,新写入操作会报错,使用很少
2)allkeys-lru 当内存不足以容纳新写入数据时,在键空间中,移除最近最少使用的key, 推荐使用
3) allkeys-random 当内存不足容纳新写入数据时,在键空间中,随机移除某个key, 较少使用
4) volatile-lru 当内存不足容纳新写入数据时,在设计了过期时间的键空间中,移除最近最少使用的
key。 一般在把Redis当缓存,又持久化存储的情况才用。
5) volatile-random 在内存不足容纳新写入数据时,设置了过期时间的键空间中,随机移除某个key
6) volatile-ttl 当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,有更早过期时间的
key优先移除,不推荐
如果没右设置expire的key, 那么volatile-lru volatile-random volatile-ttl策略的行为和noeviction基本上
一致
六、Redis和数据库双写一致性问题
采取正确更新策略,先更新数据库,再删除缓存。 其次,因为可能在删除缓存失败的问题,提供一个补偿
措施即可,例如使用消息队列
七、换成穿透和缓存雪崩解决方案
1、利用互斥锁,缓存失效的时候,先去获得锁,得到锁,再去请求数据库,没得到锁,则休眠一段时间重试
2、采用异步更新策略,无论key是否取得值,都直接返回。 value值中维护一个缓存失效时间,缓存如果过期,
异步起一个线程去读数据库,更新缓存。需要做缓存预热(项目启动前,先加载缓存)操作
3、提供一个能迅速判断请求是否有效的拦截机制, 比如可以利用布隆过滤器,内部维护一系列合法有效的key
缓存雪崩
1、给缓存的失效时间,加上一个随机值,避免集体失效
2、使用互斥锁,吞吐量下降明显
3、双缓存。 缓存A的失效时间为20分钟,缓存B不设置失效时间。 先做缓存预热操作。 先从缓存A读数据库,有
则直接返回,缓存A没有数据的话,直接从缓存B读取数据,直接返回,并且异步启动一个更新线程, 更新线程
更新缓存A和缓存B
八、Redis的并发竞争key问题
1、如何对这个key操作,不要求顺序,准备一个分布式锁,抢到锁就做set操作
2、如果对这个key操作,要求顺序。 假设有一个key,系统A需要设置value-1, 系统B设置value-2, 系统C设置
value-3,那么顺序应该是value-1、value-2、value-3。 这种情况下,在数据写入数据库的时候就需要保存一个时间戳
value-1 10:00 value-2 10:05 value-3 10:10。 假设,系统B会先抢到锁,将key设置为value-2 10:05, 这时系统A设值
的时候,发现自己的时间戳值早于缓存中的时间戳,那就不要set操作