目前对程序快速优化,无非两种方式:
一.前段加Nginx(nginx 做反向代理,可以对请求做分发,通过轮训、加权、随机等方式分配到具体某一台实际上的tomcat,通过这种方式来分流)
二.后端加缓存(目前使用Redis做缓存情况比较多,前段分发过来的请求,先查询redis,如果redis中没有,则查询数据库并put到缓存;)
但是加redis会出现以下问题:缓存穿透、缓存击穿、缓存雪崩
1 缓存穿透:分发的请求到达后端,先查redis,再查数据库,但是这个请求数据本身就不存在,例如数据库中只有id(1、2、3、4),但是查询的却是id=5,所以不管怎么查,这个查询会一直做(select * from usertable where id=5),但是查不出数据,io一直存在;(及缓存没有数据,数据库也没有数据)
解决方案:1):缓存空对象,前面请求查询redis,redis没有,查询数据库,数据库返回为null,这个时候把id=5 作为key put到redis,则下次查询就会在redis中能直接查询到,直接返回;
这种方法的弊端:redis中可能会存在大量的垃圾数据,但是这个处理方式很简单
2):使用布隆过滤器,布隆过滤器是如果查询存在的话,则不一定存在,如果查询不存在,则一定不存在;布隆过滤器在一个数组中会有3个点(通过3次hash传入的对象得到,然后对数据取余),所以这种方式有误判,而且布隆过滤器 guava的实现是单机的(JVM层面),如果需要可以通过redis自己实现
这种方式的弊端:布隆过滤器难以删除(因为put的是3个点),所以要做定时器来处理;但是效果好呀
2 缓存击穿:分发的请求到达后端,先查redis,再查数据库,但是这个时候redis数据过期了,而且高并发请求过来,使得大量的操作都会查询数据库(缓存击穿breakdown,及热点key失效,高并发请求过来,及缓存没有数据,数据库有数据,但是都大量请求同一时间都走数据库,导致数据库崩溃)
解决方案:使用分布式锁,加锁后,执行抢到锁的线程,从数据库中查询,并写入缓存,释放锁,下面的线程则从缓存中取数据
3缓存雪崩:出现情况,机器宕机,大量数据失效
解决方案:机器宕机,使用redis高可用(rediscluster)
大量数据失效:redis过期时间错开