性能优化
nginx 动静分离
emall.conf :
数据库多次查询变为一次
- 查出所有数据
1 | List<CategoryEntity> selectList = baseMapper.selectList(null); |
- 抽取方法,根据条件在 LIST 中过滤数据
1 2 3 4 | private List<CategoryEntity> getParent_cid(List<CategoryEntity> selectList, Long parent_cid) { List<CategoryEntity> collect = selectList.stream().filter(item -> item.getParentCid() == parent_cid).collect(Collectors.toList()); return collect; } |
缓存 : Redis
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | @Override public Map<String, List<Catalog2Vo>> getCatalogJson() { String catalogJSON = redisTemplate.opsForValue().get("catalogJSON"); if (StringUtils.isEmpty(catalogJSON)) { // select Map<String, List<Catalog2Vo>> catalogJsonFromDB = getCatalogJsonFromDB(); // put in cache String s = JSON.toJSONString(catalogJsonFromDB); redisTemplate.opsForValue().set("catalogJSON", s); } Map<String, List<Catalog2Vo>> result = JSON.parseObject(catalogJSON, new TypeReference<Map<String, List<Catalog2Vo>>>() { }); return result; } |
缓存穿透
查询一个不存在的数据, 导致查询数据库
解决: 将查询的
缓存血崩
设置缓存时 key 采用了相同的过期时间, 缓存在同一时刻失效
解决: 随机的失效时间
缓存击穿
对于一些设置了过期时间的key,如果这些key可能会在某些时间点被超高并发地访问,是一-种非常"热点”的数据。如果这个key在大量请求同时进来前正好失效,那么所有对这个key的数据查询都落到db。
击穿。
解决: 加锁。大量并发只让一个去查,其他人等待,查到以后释放锁,其他人获取到锁,先查缓存,就会有数据,不用查询db
分布式锁 : Redisson
通过 RedissonClient 对象, 操作 Redisson
锁续期
- 锁自动续期, 如果业务时间长,会自动续上30s
- 加锁业务完成后,不会给锁续期。即时不执行解锁代码, 也可以解锁
超时时间
- 如果传递了锁的超时时间, 就发送给redis执行脚本,进行占锁
- 如果未指定锁的超时时间,则使用默认 30 s 【lockWatchDogTimeout】。只要加锁成功,就会启动定时任务,重新给 锁设置过期时间(30 s),定时任务的时间默认是 看门狗的 1/3
缓存数据一致性
- 如果是用户纬度数据(订单数据、用户数据),这种并发几率非常小,不用考虑这个问题,缓存数据加上过期时间,每隔一段时间触发读的主动更新即可
- 如果是菜单,商品介绍等基础数据,也可以去使用canal订阅binlog的方式。
- 缓存数据+过期时间也足够解决大部分业务对于缓存的要求。
- 通过加锁保证并发读写,写写的时候按顺序排好队。读读无所谓。所以适合使用读写锁。 (业务不关心脏数据,允许临时脏数据可忽略) ;
总结:
-
能放入缓存的数据本就不应该是实时性、- 致性要求超高的。所以缓存数据的时候加上过期时间,保证每天拿到当前最新数据即可。
-
不应该过度设计,增加系统的复杂性
-
遇到实时性、一 致性要求高的数据,就应该查数据库,即使慢点。
解决方案
- 设置缓存数据过期时间, 过期后下一次查询主动更新
- 读写数据时加入分布式读写所
SpringCache
自定义
-
指定生成缓存的 key
-
指定 缓存失效时间
-
指定缓存保存为JSON
修改默认 redisConfig1
2
3
4
5
6
7
8
9
10
11
12@Configuration
@EnableCaching
public class CacheConfig {
@Bean
RedisCacheConfiguration redisCacheConfiguration(){
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig();
config = config.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()));
config = config.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new GenericFastJsonRedisSerializer()));
return config;
}
}