为什么使用redis作缓存?

内存的读写操作是磁盘的100倍以上,将热点数据缓存到redis上,可以提升我们程序的读写效率,提高了我们程序的性能,同时也可以减轻对数据库的访问压力。

为什么Redis单线程模型效率那么高?

1.C语言实现的,离硬件很近
2.因为内存的读写操作时纳秒级别的,速度很快。所以CPU不是redis的瓶颈,使用多线程反而可能存在线程上下文切换,甚至加锁解锁等造成的性能损耗。
3.redis内部适用了全局哈希表的数据结构来存储数据,一个哈希表,其实就是一个数组,数组中每个元素就是一个哈希桶,哈希桶中的entry保存了key和value的指针,这种好处就是用O(1)的时间复杂度来快速找到键值对,当出现哈希冲突后,redis适用链式哈希,同一个哈希桶的多个元素用一个链表来保存,用指针连接。
当然如果这个数组不变的话,由于数据量的不断增大,hash冲突会变得很多,检索效率肯定会受影响,所以redis需要对数组扩容,此时会存在一个问题,扩容后,原本数组中的元素会分散到不同的位置,这个会涉及到元素的内存地址的改变,必定会导致很多请求阻塞,所以redis采用了渐进式rehash,首先,redis使用了两个全局哈希表,在执行rehash之前,只会使用其中一张。在redis开始执行rehash的时候,redis正常处理请求,但是在每一次处理请求的时候,把数组中一个哈希桶上的元素拷贝到空的那张哈希表中,如此循环,直到把所有数据拷贝完,这样就巧妙的把一次性大量拷贝的开销分摊到多次请求中,避免了耗时操作。

4.redis的瓶颈在于自身内存的大小和网络IO的瓶颈,所以redis6.0在处理网络IO请求这块使用了多线程,实际读写操作的主线程还是单线程,这样就使redis同时可以处理多个网络请求,降低了网络IO瓶颈。同时redis还使用了IO多路复用技术,解决了redis在建立一个链接后一直阻塞等待数据到来,其他请求无法同时被处理的情况。
IO多路复用:核心机制是让单个线程去监视多个链接。
多个socket请求redis时,Redis使用 I/O多路复用程序 将socket请求注册到监听队列中,并同时监控这些请求连接的读写情况。当请求执行读写操作,I/O多路复用程序会将命令封装成一个事件,并传送给文件事件分派器,文件事件分派器根据对应的事件类型,发给对应的事件处理器来执行相关读写操作。redis的I/O多路复用程序其实封装了常见的一些函数在里面,比如说轮询式的select,poll,事件驱动式的epoll。

redis的数据结构使用场景

1.String(字符串)
缓存:第三方平台的token,经常使用,会过期。

 提供给别人的接口,限制接口访问次数 10分钟/20次。

2.hash
hashmap 适合保存对象 hmset user:1 name lijin age 18
3.list(列表)用来存储多个有序字符串
消息队列,Redis 的 lpush+brpop命令组合即可实现阻塞队列,生产者客户端使用lrpush从列表左侧插入元素,多个消费者客户端使用brpop命令阻塞式的“抢”列表尾部的元素,多个客户端保证了消费的负载均衡和高可用性。
4.set(集合)
集合( set)类型也是用来保存多个的字符串元素,但和列表类型不一样的是,集合中不允许有重复元素,并且集合中的元素是无序的,不能通过索引下标获取元素。
5.zset(有序集合)
一个有序的set,他的有序是给集合内部每个元素一个score,根据这个score进行排序,score可以重复。

布隆过滤器:

比如要快速的从100亿个url中判断某url是否存在?可以将所有的url适用哈希算法,然后取模得到一个值,找到bit数组中对应的位置将其从0改为1。下次拿到一个url还是用哈希算法取模,到对应的位置,如果这个位置的值是1,就代表此url存在,如果是0,就代表不存在。

存在的问题:
由于哈希冲突的原因,布隆过滤器存在一定的误判,布隆过滤器判断存在,可能这个值不一定存在(大概率存在)。但是布隆过滤器判断不存在,那么这个值一定不存在,作为缓存,适用布隆过滤器,即使存在误判也没关系,因为哈希冲突造成的这种误判是少数,可以允许这部分请求,去请求数据库。只要屏蔽掉无用的这部分请求就可以了。

redis的持久化

redis的持久化分RDB和AOF两种机制
RDB:rdb持久化是指在某一时刻点把当前redis中的数据生成快照保存到硬盘。在启动rdb的时候,redis主进程会fork一个子进程来将数据写到磁盘,主进程继续提供服务。
缺点:rdb保存的是某一时间节点的数据,如果两次持久化之间,redis发生故障,那么会发生数据丢失。
AOF:AOF持久化是以日志的方式记录每次写命令,恢复的时候重新执行一遍aof文件中的命令,aof解决了数据持久化的实时性。
缺点:文件会比较大,恢复速度比较低。

在rdb和aof混合模式下,会定时将某一时间点的全量数据以rdb方式持久化下来,然后用aof的方式将之后数据的变化保存下来,直到下一次RDB时间点。这样在保证数据不会丢失的情况下,提高了恢复时的效率。

reids的事务

redis的事务有两个命令,multi代表事务的开始,exec代表事务的结束。在这两个命令中间,redis支持一次按顺序执行多个命令,其他请求提交的命令不会插到事务执行命令的序列中。并且redis的事务是不支持回滚的,也不保证原子性,事务中的如果有命令执行失败,不影响其他命令的执行。

使用redis实现分布式锁

在分布式环境下,同一个服务部署在多个节点上,普通的JVM级别的锁已经不能满足多个进程对共享资源的访问的排他性。redis中的setnx具备这种天然的排他性,只允许设置缓存成功的线程去访问共享资源。
如果在一个进程拿到这把锁的时候,服务宕机了,锁一直没有释放,就会造成死锁,所以需要给缓存加上过期时间。
如果这个过期时间设置的不好,可能会造成锁时间到了,业务逻辑还没执行完,所以需要一个定时任务去给指定的key进行续期,redission这个组件,帮我们封装了分布式锁的实现,其中有一个watch dog的机制来对key去作续期。
如果redis搭建了集群的情况,在主从切换的时候导致key失效导致锁失效,redis官方提供了一个redlock来解决这个问题,但是实现上很复杂。

缓存击穿

一个非常热点的key,在这个key失效的瞬间,大量的请求直接打到数据库里,造成数据库非常大的压力甚至服务宕机。
解决办法:
使用redis的互斥锁setnx,在缓存失效的时候,不是立即去访问数据库,而是去抢锁,只有抢到锁的才有机会访问数据库,然后重新设置缓存,没抢到的可以让他sleep一会然后去缓存中读取。这样就保证了在缓存击穿的时候,只会由一个请求到数据库,从而保护了数据库。

缓存穿透

是指查询一个根本不存在的数据,缓存和数据库中都不会命中,于是这个请求可以随意访问数据库。
解决办法:
可以使用布隆过滤器

缓存雪崩

同一时间缓存大面积失效,所有请求全部到达数据库
将缓存的失效时间分散开,可以在原有的失效时间基础上加一个随机值,这样缓存同时失效的概率就会很低。
搭建redis高可用集群

redis过期策略

定期删除:Redis默认每隔100ms就随机抽取一些设置了过期时间的key,把他们标记为已过期,放入到一个链表中,等Redis内存使用率达到一定阈值时,Redis会对这些key进行回收。定期删除是Redis的主动删除策略,他可以确保过期的key能及时被清理掉,但是会占用cpu资源去扫描key。
惰性删除:当一个key过期后,不会立即从内存中删除,而是在访问这个key的时候才会触发删除操作。惰性删除是Redis的被动删除策略,他可以节省cpu资源,但是会导致过期的key始终保存在内存中,占用内存空间。
Redis的过期策略采用的是定期删除和惰性删除相结合的方式。

Redis内存淘汰算法

1.random算法:随机移除某个KEY
2.TTL算法:最早过期时间
3.LFU:访问频率最低
3.LRU算法:最近最少使用
阿里云默认:volatile-lru:从设置了过期时间的key中选择最近最少使用的key删除

如何保证redis和mysql数据一致性

先删除缓存再更新数据库,下一次访问的时候发现redis中数据是空的,就会取数据库中重新拿出来保存到缓存中。
问题:如果在极端情况下,在删除了缓存,还未更新数据库的时候,有其他线程访问,发现缓存中为空,去数据库中拿到旧数据重新设置了缓存就会出现不一致。解决这种情况,可以使用延时双删策略。
延时双删:就是在删除了缓存,更新课数据库后,休眠1S,再次删除缓存。这样就可以保证一致性。
问题:如果mysql是读写分离的架构,主从同步也是需要一定时间的,在这个主从同步时间内,还是会发生不一致,这是后就可以用异步的延时双删。
异步的延时双删:在删除缓存更新数据库后,将删除缓存发送给MQ,异步执行删除缓存,保证最终一致性。

redis的集群模式

主从复制模式

主从之间怎么同步的
1.从库连接上主库上后,向主库发送SYNC命令,请求同步数据
2.主库收到SYNC命令后,开始执行BGSAVE命令生成RDB文件并在缓冲区记录这个时间点后主库的写入命令
3.主库BGSAVE执行完后,向从库发送RDB文件,并在发送期间继续记录主库的写入命令
4.从库收到RDB文件后丢弃所有旧数据,载入RDB文件数据
5.主库发送RDB文件完后,向从库发送缓冲区的写入命令,从库载入RDB文件数据完成后,执行这些命令
主从模式的优点
1.读写分离,分担master的压力
2.解决单点故障问题
3.方便做容灾恢复
主从模式的缺点
1.不具备自动容错恢复功能,需要人工介入
2.主库宕机,宕机前有部分数据未能及时同步到从库,切换IP后会导致数据不一致的情况

哨兵模式

工作模式
1.每个哨兵会每秒向整个集群中master,salve以及其他哨兵发送PING命令
2.如果master回复PING命令超过down-after-milliseconds选项设定的值,会被哨兵标记为主观下线
3.当足够数量的哨兵在指定时间范围内标记了master为主观下线,则master会被标记为客观下线
4.master故障后,集群中哨兵会触发Raft算法,重新从salve节点中选举一个新的master出来。
哨兵模式优点
1.哨兵模式是基于主从模式的,所有主从的优点他都有
2.master单点故障后,会自动选一个新master出来,可用性更高


MockingJay
7 声望3 粉丝

下一篇 »
spring