目录
缓存-缓存使用-本地缓存与分布式缓存
缓存-缓存使用-整合Redis测试
缓存-缓存使用-改造三级分类业务
缓存-缓存使用-压力测试出的内存泄漏及解决
缓存-缓存使用-缓存击穿、穿透、雪崩
缓存-缓存使用-加锁解决缓存击穿的问题
缓存-缓存使用-本地锁在分布式下的问题
缓存-缓存使用-本地缓存与分布式缓存
使用缓存的好处:提升系统的性能
什么样的数据适合存储到缓存中?
①及时性、数据一致性要求不高的数据,例如物流信息、商品类目信息
②访问量大更新频率不高的数据(读多、写少)
读模式下的使用缓存的流程如下图所示:
本地缓存使用的伪代码如下图所示:
本地缓存最简单的方式就是编写一个Map
使用本地缓存存在的问题:
问题1:
加入请求负载均衡交由服务1处理,服务1将数据从数据库中查出存放到缓存中,但不能保证每次负载均衡到同一个服务,负载到其它服务时,需要再次从数据库中查出数据存放到缓存中。
问题2:
加入需要修改类目,修改请求被负载均衡到服务1,服务1修改了类目并且修改了缓存中的数据,但是负载均衡到其它服务时,其它服务的缓存数据并未被修改,会导致数据不一致的。
解决方案:
使用集中的缓存中间件,解决了上述问题的同时还解决了缓存不足的问题,可以将缓存中间件集群化
分布式缓存
缓存-缓存使用-整合Redis测试Redis的整合步骤:
①导入data-redis-starter
org.springframework.boot
spring-boot-starter-data-redis
ctrl+n 搜索 RedisAutoConfiguration
SpringBoot自动配置好了redisTemplate、StringRedisTemplate用于 *** 作,RedisstringRedisTemplate是用于存放
关于Redis配置的属性都放在RedisProperties中
②简单配置Redis的host等信息
Redis配置,需要配置redis的主机地址和端口号,不配置端口号默认为6379,还可以配置密码
③使用SpringBoot自动配置好的StringRedisTemplate来 *** 作redis
缓存-缓存使用-改造三级分类业务
①将原先的三级分类查询的方法中的@Override去掉,换取新的方法名作为业务处理的方法
② 在原先的实现三级分类查询的方法中编写缓存的使用
要指定value的类型为String,因为String实现了序列化接口,否则存储到redis中的数据会乱码
我们将java对象转化为跨语言、跨平台兼容的json存入到缓存中即为序列化
我们将json数据转化为可用的java对象,即为反序列化
缓存-缓存使用-压力测试出的内存泄漏及解决压测三级分类目录
由于我使用的data-redis-starter是2.3.7版本的,SpringBoot已经针对lettuce进行了优化未出现堆外内存溢出的现象
这里总结一下如果使用data-redis-starter出现堆外内存溢出的解决方案
出现问题:使用data-redis-starter出现堆外内存溢出即OutOfDireMemoryError
出现问题的原因:lettuce使用netty作为网络通信框架,netty默认使用-Xmx作为堆外内存大小,调大Xmx 的大小只能延缓堆外内存溢出的时间但是一定会出现异常,我们也可以通过设置-Dio.netty.maxDirectMemory设置堆外内存的大小
点击下选框
解决方案:不能使用-Dio.netty.maxDirectMemory去调大堆外内存的大小
①升级lettuce客户端 ②切换使用jedis
使用jedis解决堆外内存溢出
①排除lettuce的依赖
② 使用jedis客户端 *** 控redis
lettuce、jedis都是 *** 作redis的客户端。SpringBoot会再次封装redisTemplate
SpringBoot会将redisConnectionFactory、redisConnectionFactory封装成RedisConnectionFactory
缓存-缓存使用-缓存击穿、穿透、雪崩针对缓存穿透、雪崩、击穿的解决方案:
①对null结果缓存:解决缓存穿透
②设置过期时间(加随机值的过期时间):解决缓存雪崩
③加锁:解决缓存击穿
锁加不好会带来很多问题,下面会讲解如何加锁
缓存-缓存使用-加锁解决缓存击穿的问题加本地锁的方式
①使用synchronized修饰方法
②使用synchronized代码段
使用this当锁,this指的是当前实现类对象,在SpringBoot中所有组件都是单例的。因此,使用this当锁是可行可以确保所有线程拿的都是同一把锁。
线程拿到锁之后,需要再次判断一下缓存是否命中
压测一下看下会不会问题:
出现问题 : 查询了数据两次
出现问题的原因:当线程1获得锁之后查询数据库,返回查询的结果并释放锁;线程1在将查询的数据存储到redis时,线程2获得锁,发现此时缓存并未命中,因此进行数据库的查询。
解决方案:确认缓存没有、查询数据库、将查询结果存储到redis中是一个原子 *** 作
缓存-缓存使用-本地锁在分布式下的问题
存在的问题: 本地锁只能锁住当前的服务,其它服务锁不住
测试:
复制几份product服务,端口号从10000-10003,1右键选择copy configuration...
查看结果:
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)