什么是Redis
Redis是基于内存的数据库,它支持许多数据类型。比如像常见的String,Set,Hash,List,ZSet,Stream等。并且对于这些数据类型,Redis的操作都是原子性的,因此无需考虑并发竞争的问题。
另外,由于他是基于内存的数据,因此读写速度非常快,常用于缓存,消息队列,分布式锁等场景。
初次之外Redis还支持事务、持久化、Lua脚本、多种集群方式、发布/订阅模式(消息传递),内存淘汰机制,过期删除策略等。
Redis和MemCached有什么区别
首先他们的共同点:
他们都是基于内存的数据库,读写操作非常快。
都有过期删除策略。
两者的性能非常高。
异同点:
Redis是支持持久化的,他会将内存的数据保存到硬盘里,重启的时候,可以再次加载并使用。而MemCached不支持持久化,全部数据都在内存里,服务重启或挂掉以后,数据就丢失了。
另外Redis支持许多数据类型,如String,Hash,List,Set,Zset,Stream等,而MamCached只支持最简单的key-value的数据类型。
Redis还支持集群模式,MemCached没有原生的集群模式,只能分片写入数据
Redis支持发布订阅模式,Lua脚本,事务等等。
为什么Redis作为MySQL的缓存
主要是因为Redis有【高性能】和【高并发】两种特性。
什么是缓存穿透?怎么解决?
嗯,我想一下。 缓存穿透是指用户请求的数据在缓存和数据库中都不存在,导致请求完全绕过了缓存,并且无法将数据写到缓存当中,因此可能会导致服务器的压力增大,导致DB挂掉。
解决方法:可以在使用布隆过滤器,或者缓存空值来解决。
你能介绍一下布隆过滤器吗?
嗯! 布隆过滤器原理上是使用hash和bitmap来解决的,主要用于检索一个数据是否存在于当前集合中。我们当初使用的是Redisson实现的布隆过滤器。底层原理是,初始好一个比较大的数组,里面只能放二进制的0和1。一开始都是0,当一个key来了以后,经过三次hash计算,找到数组的下标,然后将0改为1。这样三个位置就标明一个key的存在。查找的过程也是一样的。但是,布隆过滤器可能会出现误判,我们可以设置一个误判率,大概不会超过5%。其实这个误判是必然存在的,要不就得增加数组的长度。5%以内的误判率一般的项目也能接受,不至于高并发下压倒数据库
什么是缓存击穿?怎么解决。
嗯,我想一下。 缓存击穿也叫热点Key问题,指的是对于设置了过期时间的key,在某个时间点过期以后,恰好有大量的key并发的请求过来。这些请求发现缓存过期,一般都会从DB中加载数据并缓存到Redis中。容易对数据库造成巨大的压力,同时可能会导致数据库和缓存不一致的情况。
解决方案:1.使用互斥锁: 当缓存失效时,不要去立马去load db,而是使用Redis的setnx设置一个互斥锁。要求拿到该互斥锁的线程进行缓存重建。其他没拿到的进程进行重试该方法,知道get到缓存。(分布式锁)
2.使用逻辑过期。在设置一些热点key的时候,设置一个过期字段一并加到缓存中,不设置过期时间。 当查询时,判断此key是否过期,如果过期,则开通另一个线程进行缓存重建,当前线程返回旧数据。
当然两个方案各有利弊,如果要数据的强一致性,则建议使用分布式锁的方案。
如果考虑高可用性,则建议使用逻辑过期方案。
什么是缓存雪崩?怎么解决?
嗯,缓存雪崩指的是,缓存中有大量key设置了相同的国旗时间,导致在同一时刻失效,导致大量请求转发到数据库,给数据库造成巨大压力。与缓存击穿的区别是:雪崩是很多key,而击穿是某一个key缓存。解决方案主要是,可以将缓存失效时间分散开。比如,可以在原有的失效时间基础上增加一个随机值,比如1-5分钟随机。这样,每一个缓存的过期时间的重复率就会降低,就很难引发集体失效的事件。
Redis作为缓存,如何实现mysql的数据与Redis进行同步呢(双写一致性-1)
嗯,就说我做的这个项目,我们当时是把抢购优惠券的库存放到了缓存里,因此要要使用强一致性的方案。为了保证数据的强一致性,我们当时采用了Redisson的读写锁来保持数据的同步。首先,如果是单纯的进行读操作,是不会产生数据不一致的情况,只有读和写都存在时,才会出现数据不一致的情况,所以我们当时就用的读写锁。
在读缓存的时候加共享锁,可以保证读读不互斥,读写互斥。当我们更新缓存的时候,加上排它锁,他是读读,读写都互斥。这样能保证在写数据的同时,是不会让其他线程读数据的,避免了脏数据。但是需要注意,读方法和写方法必须使用同一把锁。
那这个排他锁是如何保证读写、读读互斥的呢?
排它锁的底层使用了Redis的setnx,他可以让同一时刻只有一个线程抢占锁并操作锁的方法。
你听说过延时双删吗?为什么不用它呢?
嗯,延时双删指的是在写操作中,采用删除缓存后,操作数据库,过一段时间又删除缓存的方案。其中,这个延时的时间不太好确认,在延时的过程中,依旧可能会出现脏数据,并不能保证数据的强一致性。所以我们项目中没有采用。
redis做为缓存,mysql的数据如何与redis进行同步呢(双写一致性-2)
嗯,就拿我这个项目来说。当时我们有把热点课程信息写到缓存里的功能,虽然是热点数据,但是实时要求性没有那么高。所以我们采用了异步的方案来同步的数据。
我们使用的RabbitMQ做消息队列,数据库更新完数据之后,会通知缓存去删除。这样的方案达到最终一致性的效果。
没有最好的方案,只有最合适的方案