目录
1、高客户端连接服务端处理
2、Redis缓存数据一致性及问题
2.1、如何保证缓存和数据库数据一致性
3、缓存问题
3.1、缓存穿透-查不到
3.2、缓存击穿-量太大,缓存过期
3.3、缓存雪崩
当客户端比较多,高并发时,服务端可能处理不过来,服务端可能会崩溃;所以在服务端采用集群方式处理,集群方式,即存在多个服务器;这个时候需要有一个管理者nginx,每当客户端请求时,由nginx根据ip进行哈希等来处理分配服务端,使得负载均衡,可以在一定程度上解决高并发问题。对于数据库端高并发问题,可以采用缓存的方式进行处理。
①缓存数据插入时机:
对于服务器而言,查询数据步骤:
1、首先到缓存查询数据,如果数据存在,则直接获取数据返回。
2、如果缓存不存在,需要查询数据库,从数据库获取数据并插入缓存,将数据返回。
3、当第二次查询时,后续查询操作就可以查询缓存数据。
②更新数据时操作:
1、先删除缓存再更新数据库
进行更新数据库数据时,先删除缓存,然后更新数据库,后续的请求再次读取数据时,会从数据库中读取数据更新到缓存。
存在问题:删除缓存之后,更新数据库之前,这个时间段内如果有新的请求过来,就会从数据库中读到旧的数据写入缓存,再次造成数据不一致,并且后续读操作都是旧数据。
2、先更新数据库再删除缓存
进行更新操作,先更新数据库,成功之后,再删除缓存,后续请求将新数据写回缓存
存在问题:更新MySQL和删除缓存这段时间内,请求读取的还是缓存内的旧数据,不过等数据库更新完成后,就会恢复一致。
3、异步更新缓存
数据库的更新操作完成后不直接操作缓存,将操作命令封装成消息放到消息队列里,然后由Redis自己去更新数据,消息队列保证数据操作数据的一致性,保证缓存数据的数据正常。
概念:
缓存穿透是指用户想查询一个数据,发现Redis中没有,也就是缓存没有命中,就向持久层数据库发起查询,发现数据库也没有这个数据,于是查询失败了,当用户请求很多的情况下,缓存没有命中,数据库也没有数据,会给数据库造成很大的压力,这就是缓存穿透。
解决方案:
第一种解决方案:使用布隆过滤器
使用布隆过滤器之后,将存储的数据放入布隆过滤器,每次数据查询首先查询布隆过滤器,当在过滤器中判断存在时,再到缓存查询,如果没有进入数据库查询,如果在过滤器不存在,则直接返回告诉用户该数据查不到,这样能大大减轻数据库查询压力。
第二种方案:缓存空对象
当数据库数据不存在时,及时返回的空对象也缓存起来,同时设置一个过期时间,之后在访问数据将从缓存中获取,保护了数据库。
存在问题:
1、对空值设置过期时间,在过期之前的一点时间内,对数据库中该数据的更新是不会同步到缓存的,缓存数据有问题,会对要保证数据一致性的业务造成影响。
2、会需要更多的空间来存储更多的控制,造成内存中有大量的空值的键。
缓存击穿是指一个key是一个热点key,在不停的扛着大量的并发,当key在失效的瞬间,持续的大并发就会穿破缓存,直接请求到数据库,对数据库造成瞬间压力过大。
解决方案:
第一种方案:热点数据永不过期
从缓存角度看,没有设置过期时间,就不会存在缓存过期之后产生的问题,但是对于数据库中的更新操作无法及时同步到缓存。
第二种方案:加互斥锁
使用分布式锁,保证对每个key的访问同一时刻只能一个线程去查询后端服务,其他没有获取锁权限的线程则等待即可。
缓存雪崩是指在某一个时间段,缓存集中过期失效或者Redis宕机。
对于数据库而言,所有请求压力会全部到达数据库,导致数据库调用量暴增,可能也造成数据库宕机的情况
解决方案:
第一种方案:Redis采用高可用
这种方案的思路就是将Redis中的数据存放在服务器上,即使一个服务器挂掉,其他服务器还可以继续工作。
第二种方案:限流降级
这种思路就是在缓存失效后,通过加锁或者队列来控制读取数据库的线程数量让线程在队列排队,控制整体请请求速率。
第三种方案:数据预热
数据预热就是在正式部署服务之前,先访问一遍数据,可以将大部分的数据加载到缓存中,在即将发生大并发之前已经加载不同的key,设置不同的过期时间,让缓存失效的时间更加均匀。