一、专业名词介绍
1。 缓存穿透(数据库没值,redis也没设置空值,高并发请求这条数据)
条件:访问一个不存在的数据
说明:当访问一个不存在的数据时,因为缓存中没有这个key,导致缓存形同虚设。最终访问后台数据库。但是数据库中没有该数据所以返回null。
隐患:如果有人恶意频繁查询一个不存在的数据,可能会导致数据库负载高导致宕机。
总结:业务系统访问一个不存在的数据,称之为缓存穿透。
解决:将 null 值或者空字符串设置给 redis
2、缓存击穿(数据库有值,但是redis没值,并被高并发请求)
条件:当缓存key失效/过期/未命中时,高并发访问该key
说明:如果给一个key设定了失效时间,当key失效时有一万的并发请求访问这个key,这时缓存失效,所有的请求都会访问后台数据库。称之为缓存击穿。
场景:微博热点消息访问量很大,如果该缓存失效则会直接访问后台数据库,导致数据库负载过高。
解决:设置分布式锁,只允许一个请求访问数据库,取得值后将数据库值设置到redis中,数据库中没有值就设置空字符串,这样其他请求再次调用方法时会再次查询redis,这时redis中已存在值。
3、缓存雪崩(缓存大量未命中,高并发请求数据库)
前提:高并发访问,缓存命中较低或者失效时
说明:假设缓存都设定了失效时间,在同一时间内缓存大量失效。如果这时用户高并发访问。缓存命中率过低。导致全部的用户访问都会访问后台真实的数据库。
场景:在高并发条件下。缓存动态更新时
解决:利用随机数,设置随机的失效时间。
4、脑裂
出现脑裂的可能原因:①主机 master 挂掉推选新的 master 时出现问题;②主机 master 网络连接异常,但是没有宕机,slave推选新的 master 导致脑裂
说明:由于推选机制同时选举出多台主机,导致程序不能正常的执行。该问题称之为脑裂。
解决办法:①机器的数量是奇数台;②配置的服务器的量一定要多。
5、 什么时候集群崩溃
说明:如果主节点在宕机时没有从节点则集群崩溃。
问题:3主6从 宕机几次集群崩溃?
特点:集群中如果主机宕机,那么从机可以继续提供服务,
当主机中没有从机时,则向其他主机借用多余的从机。继续提供服务。
如果主机宕机时没有从机可用,则集群崩溃。
答案:9台机器,宕机5-7次集群崩溃了。
6、Java程序连接异常
问题描述:
如果java程序链接redis时,报错没有可用的集群节点时。检测虚拟机的IP地址和配置文件的地址是否匹配。
为什么:因为虚拟机的IP地址发生了变化。
7、解决redis同一对象在同一时间被多个请求修改的问题:
穿透:利用不存在的
key
去攻击
mysql
数据库
击穿:在正常的访问情况下,如果缓存失效,如果保护
mysql
,重启缓存的过程
雪崩:缓存中的很多
key
失效,导致数据库负载过重宕机
使用
redis
数据库的
分布式锁
,解决
mysql
的访问压力问题
第一种分布式锁:
redis
自带一个分布式锁
,set px nx
第二种分布式锁:
redisson
框架,一个
redis
的带有
juc
的
lock
功能的客户端的实现
(
既有
jedis
的功能,又有
juc
的锁功能
)
|
8、问题
问题1:如果在redis中的锁已经过期了,然后锁过期的那个请求又执行完毕,回来删锁,删除了其他线程的锁,怎么办?
场景解释:自己线程的锁过期,而redis的值还没有设置(出现可能原因如mysql读取时间过长,锁设置时间太短,网络慢等),那么其他请求就会重新设置锁,进行读mysql设置redis一系列操作;如果此时反应慢的线程回来删除锁,就会删除掉其他线程创建的锁,这时又有线程进来重复操作,最后导致缓存穿透。
解决:在上锁的时候生成一个 UUID,设置为锁的值,再删除锁的时候进行取值判断,如果是值对应就删除,否则就不删除。
问题2 如果碰巧在查询redis锁还没删除的时候,正在网络传输时,锁过期了怎么办?
场景解释:在获取锁的过程中,获取的时候存在,但是进行删除时已经不存在了(可能原因,网络慢,线程阻塞了,锁失效等)
解决:使用 lua 脚本,在获取到与设定值相等的锁时就将其删除。
二、
一致性
哈希算法
说明:redis分片时采用一致性哈希算法,实现数据动态的绑定。
术语:①节点(node) :代表真实的redis服务器 ②key:用户保存/读取关键字
1、均衡性
问题:由于node节点是经过hash一致性算法计算的结果。那么可能会出现计算的节点所分配的内存不均。如果内存不均,会导致某些节点内存负载过高。特点说明:要求全部的数据,尽可能的均匀分配到不同的节点中,每个节点中保存的数据尽可能接近1/n实现步骤: 如果遇到节点负载不均时,会自动的启动虚拟节点,进行数据的平衡。
2、单调性(节点增加,数据动态迁移)
说明:如果节点的个数增加,原有的节点的挂载会自动的发生变化。将满足条件的数据自动的挂载到新的节点中。原则:尽可能保证原有的数据不变
总结:节点增加,数据动态发生迁移。
3、分散性(分布式环境下,服务需要获取所有的节点,以保证不会出现,键值冲突情况)
说明:由于分布式的项目部署,导致项目不能全部获取node节点。
特点:一个key对应了多个位置。
4、负载
说明:负载是从另一个角度谈论分散性。
特点:一个位置,对应多个key
综上所述:
在分布式应用时,应该使用全部的node节点,避免出现这样的现象。
三、分片和哨兵说明
分片后数据如何读取呢?读取方式不变,一致性哈希算法保证了数据的多分片可读性。
1、哨兵主要功能
(1)集群监控,负责监控redis master 和slave进程是否正常工作。(2)消息通知,如果某个redis实例有故障,那么哨兵负责发送消息作为报警通知给管理员。(3)故障转移,如果master node挂掉了,会自动转移到slave node上。(4)配置中心,如果故障转移发生了,通知client客户端新的master地址。
2、哨兵核心知识
(1)哨兵至少需要3个实例,来保证自己的健壮性。
(2)哨兵+redis主从的部署架构,是不会保证数据零丢失的,只能保证redis集群的高可用性
(3)对于哨兵+redis主从这种复杂的部署架构,尽量在测试环境和生产环境,都进行充分的测试和演练。
3、分片和哨兵优缺点
优点:①分片可以实现内存的动态的扩容 ②使用分片能够将数据分开保存,如果宕机/数据损坏只丢失1/n的数据 ③哨兵可以实现redis的高可用。
缺点:①如果分片中的一个节点宕机,那么整个分片将不能正常运行。② 分片中的数据因为一致性哈希的原因,可能会导致数据分布不是特别的平均。
③如果哨兵宕机,则整个服务陷入瘫痪。
4、redis哨兵主备切换的数据丢失问题
两种丢失情况:
(1)异步复制导致的数据丢失:
因为master->slave的复制是异步的,所以可能有部分数据还没复制到slave,master就宕机了,这些数据就丢失了。
(2)脑裂导致的数据丢失:
脑裂,也就是说,某个master所在机器突然脱离了正常的网络,跟其他slave机器不能连接,但是实际上master还运行着
这个时候,集群中就会出现两个master。
此时虽然某个slave被切换成了master,但是可能client还没来得及切换到新的master,还继续写向旧master数据可能就会丢失。
因此master在恢复的时候,会被作为一个slave挂到新的master上,自己的数据会被清空,从新的master复制数据
5、解决异步复制和脑裂导致的数据丢失:
min-slaves-to-write 1
min-slaves-max-lag 10
要求至少有1个slave,数据复制和同步的延迟不能超过10秒
如果说一旦所有slave,数据复制和同步的延迟都超过了10秒钟,那么这个时候,master就不会再接收任何请求了。
(1)减少异步复制的数据丢失
有了min-slaves-max-lag这个配置,就可以确保说,一旦slave复制数据和ack延时太长,就认为可能master宕机后损失的数据太多了,那么就拒绝写请求,这样可以把master宕机时由于部分数据未同步到slave导致的数据丢失降低的可控范围内
(2)减少脑裂的数据丢失
如果一个master出现了脑裂,跟其他slave丢了连接,那么上面两个配置可以确保说,如果不能继续给指定数量的slave发送数据,而且slave超过10秒没有给自己ack消息,那么就直接拒绝客户端的写请求
这样脑裂后的旧master就不会接受client的新数据,也就避免了数据丢失
上面的配置就确保了,如果跟任何一个slave丢了连接,在10秒后发现没有slave给自己ack,那么就拒绝新的写请求
因此在脑裂场景下,最多就丢失10秒的数据
四、持久化策略说明
说明:因为redis中保存的数据都在内存中,当断电/宕机。缓存中的数据都会被清空。如果redis中没有配置持久化策略,安全性不够完善。
策略说明:
1、RDB方式
该方式是redis默认选择的持久化策略
特点:持久化的效率更高,定期持久化可能会丢失数据
2、AOF方式
该方式需要通过配置文件手动开启
特点:持久化效率低,每秒持久化/每次操作持久化,保证数据尽可能不丢失,文件过大导致恢复时操作时间过长。
持久化步骤:
1、当用户set操作时,redis中的数据会新增/更新
2、这时根据用户选择的持久化的策略,自动的进行数据持久化操作,以下以RDB模式为例。
3、定期会将redis中全部的数据通过xxx.RDB文件的方式保存。
4、如果redis服务器宕机重启时,首先会加载持久化文件xxx.RDB。恢复内存中的数据。
5、当用户使用redis时,这时redis内存中已经恢复了数据,为用户继续提供服务。
5、内存优化策略
1、需求说明
因为redis中的数据全部都写入内存中,当redis中的数据不能再次写入时这时redis服务会有问题,所以应该保证redis服务永远可写。如何实现redis数据内存优化呢?
LRU算法(Least Recently Used,最近最久未使用法):内存管理的一种页面置换算法,思想:最近使用的页面数据会在未来一段时期内仍然被使用,已经很久没有使用的页面很有可能在未来较长的一段时间内仍然不会被使用。
2、内存优化手段:
volatile-lru -> 将设定超时时间的数据并且其中使用较少的数据进行删除
allkeys-lru -> 将redis中全部key进行LRU筛选,之后进行删除
volatile-random -> 设定了超时间的数据,随机删除
allkeys-random -> 全部的key随机删除
volatile-ttl -> 将已经设定了超时时间的数据,按照存活时间排序,将马上要过期的数据进行删除.
noeviction -> 不做任何操作,将报错信息返回给用户。
6、Redis 集群
说明:redis集群实质上将redis分片和redis哨兵的机制进行整合。redis集群中每个节点都可以与其他节点进行通讯,同时集群内部有心跳检测,如果节点发生宕机的现象,由所在集群的全部服务器负责推选,保证服务的正常运行;如果全部的从节点宕机,并且这时主节点宕机,那么整个集群才会奔溃。