admin管理员组

文章数量:1794759

谷粒商城高级篇&整合面试题(一)

谷粒商城高级篇&整合面试题(一)

性能优化 一.、性能测试

  • 压力测试
  • 性能监控(工具:jconsole jvisualvm)
  • 优化(中间件对性能的影响)
  • 二、nginx动静分离
  • 我们为什么要做动静分离? 1)网站优化的重要点在于静态化网站,网站静态化的关键点则是是动静分离,动静分离是让动态网站里的动态网页根据一定规则把不变的资源和经常变的资源区分开来,动静资源做好了拆分以后,我们则根据静态资源的特点将其做缓存操作。 2)让静态的资源只走静态资源服务器,动态的走动态的服务器 3)Nginx的静态处理能力很强,但是动态处理能力不足,因此,在企业中常用动静分离技术。 4)对于静态资源比如图片,js,css等文件,我们则在反向代理服务器nginx中进行缓存。这样浏览器在请求一个静态资源时,代理服务器nginx就可以直接处理,无需将请求转发给后端服务tomcat。 若用户请求的动态文件,比如servlet,jsp则转发给Tomcat服务器处理,从而实现动静分离。这也是反向代理服务器的一个重要的作用。
  • 三、缓存
  • 那些数据适合放入缓存? 1)即时性、数据性要求不高的 2)访问量大且更新频率不高的数据(读多,写少) 举例:电商类应用,商品分类、商品列表等适合缓存并加一个失效时间
  • 用本地缓存Map作为缓存可参考谷粒商城P151

    本地缓存-我们使用Map-》在我们内存中(存在问题) 1)分布式下,缓存是分开的。负载均衡到的服务不一定有缓存,任然要访问数据库 2)修改了服务1下的数据,在修改其下的缓存。但是别的服务缓存没有改。造成数据不一致的问题。

  • 整合redis缓存之后性能大幅提升,但同时也出现了一些问题: 解决方案(不能调大虚拟机参数,这样只会延迟内存溢出)

  • 缓存穿透

  • 解决:将null结果进行缓存,并加入短暂过期时间

  • 缓存雪崩 缓存雪崩是指缓存同一时间大面积的失效,所以,后面的请求都会落到数据库上,造成数据库短时间内承受大量请求而崩掉。
  • 解决: 1.缓存数据的过期时间设置随机,防止同一时间大量数据过期现象发生 2.一般并发量不是特别多的时候,使用最多的解决方案是加锁排队

  • 缓存击穿
  • 单体应用,如果本地不加同步锁的时候,在高并发的情况下,会发生线程安全问题。 单体应用,如果加上本地锁的时候,在高并发情况下,可以解决安全问题,但是效率会变低,所以就有分布式锁。

    四、分布式锁

    在某些场景中,多个进程必须以互斥的方式独占共享资源,这时用分布式锁是最直接有效的。

    原理与使用:

    使用:

    • redis占坑 使用参数NX(不存在才往里放)setnx key value

    五、Redisson分布式锁

    Redisson是Redis官方推荐的Java版的Redis客户端。它提供的功能非常多,也非常强大。

  • 可重入锁
    • 为什么需要可重入锁? A调用B。AB都需要同一锁,此时可重入锁就可以重入,A就可以调用B。不可重入锁时,A调用B将死锁 可重入加锁的意思就是同一个客户端同一个线程也能多次对同一个锁进行加锁。 也就是同时可以执行多次 lock方法,流程都是一样的,最后也会调用到lua脚本,所以可重入加锁的逻辑最后也是通过加锁的lua脚本来实现的。

    • 释放锁机制 执行lock.unlock(),就可以释放分布式锁。

    Redisson解锁期间 假设断电解锁代码没有运行,会不会出现死锁 不会

    • 注意:当我们使用lock()手动给锁设定了过期时间,到期之后不会自动续期。所以当我们使用这个方法加锁时。注意!!!过期时间一定要大于业务执行时间。
    • 执行原理:如果我们传递了锁的过期时间,就会直接执行redis的lua脚本,此时默认超时时间就是我们指定的时间。
  • 读写锁 在实际的业务场景中,其实会有很多读多写少的场景,那么对于这种场景来说,使用独占锁来加锁,在高并发场景下会导致大量的线程加锁失败,阻塞,对系统的吞吐量有一定的影响,为了适配这种读多写少的场景,Redisson也实现了读写锁的功能。
    • 读写锁的特点: 1)读与读是共享的,不互斥 2)读与写互斥 3)写与写互斥

    分布式可重入读写锁允许同时有多个读锁和一个写锁处于加锁状态。

  • 缓存一致性解决
    • 我们现在将redis写的分布式锁换成使用redisson来写。
    • 出现一个问题,怎么保证数据库和缓存数据一致性问题。(下面两个方案) 解决脏读现象
    • 加锁,给一个写锁。第二个写等第一个写操作完事才能进行操作。
    • 可以容忍暂时性的脏数据问题。(前提是给缓存加上过期时间)

    • 加锁
    • 经常修改?实时性要求高。别整缓存了,直接读数据库吧。

    完美解决方案 canal将自己伪装成从数据库。当主数据库发生改变他就收到,并且更新redis。

    六、SpringCache
  • 简介 不可能,每个要缓存的内容都要写冗余的重复数据吧!所以spring的缓存框架帮我们解决。

  • Cacheable细节设置

  • /** * 每一个需要缓存的数据我们都来指定要放到那个名字的缓存。 * 【缓存的分区(按照业务类型分)】 * 代表当前方法的结果需要缓存,如果缓存中有,方法都不用调用,如果缓存中没有,会调用方法。最后将方法的结果放入缓存 * 默认行为 * 如果缓存中有,方法不再调用 * key是默认生成的:缓存的名字::SimpleKey::[](自动生成key值) * 缓存的value值,默认使用jdk序列化机制,将序列化的数据存到redis中 * 默认时间是 -1: * * 自定义操作:key的生成 * 指定生成缓存的key:key属性指定,接收一个Spel * 指定缓存的数据的存活时间:配置文档中修改存活时间 * 将数据保存为json格式 * @return */
  • 自定义缓存配置
  • @Configuration @EnableCaching @EnableConfigurationProperties(CacheProperties.class) public class MyCacheConfig { /** * 配置文件中的东西没用上 * @return */ @Bean RedisCacheConfiguration redisCacheConfiguration(CacheProperties cacheProperties){ RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig(); // config = config.entryTtl(); config = config.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSeriali zer(new StringRedisSerializer())); config = config.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSeria lizer(new GenericJackson2JsonRedisSerializer())); CacheProperties.Redis redisProperties = cacheProperties.getRedis(); //将配置文件中所有的配置都生效 if (redisProperties.getTimeToLive() != null) { 其他配置测试 config = config.entryTtl(redisProperties.getTimeToLive()); } if (redisProperties.getKeyPrefix() != null) { config = config.prefixKeysWith(redisProperties.getKeyPrefix()); } if (!redisProperties.isCacheNullValues()) { config = config.disableCachingNullValues(); } if (!redisProperties.isUseKeyPrefix()) { config = config.disableKeyPrefix(); } return config; } }

  • @CacheEvict 如果说修改一级分类,要删除两部分的缓存。那么用@CacheEvict还可以么。不行了要使用另一个注解Caching

  • 原理与不足

  • 4、Spring-Cache的不足之处: * 1)、读模式 * 缓存穿透:查询一个null数据。解决方案:缓存空数据 * 缓存击穿:大量并发进来同时查询一个正好过期的数据。解决方案:加锁 ? 默认是无加锁的; 使用sync = true来解决击穿问题 * 缓存雪崩:大量的key同时过期。解决:加随机时间。加上过期时间 * 2)、写模式:(缓存与数据库一致) * 1)、读写加锁。 * 2)、引入Canal,感知到MySQL的更新去更新Redis 过源码RedisCache 值得注意的是这里是一个加锁的方法 * 3)、读多写多,直接去数据库查询就行 * * 总结: * 常规数据(读多写少,即时性,一致性要求不高的数据,完全可以使用Spring-Cache):写 模式(只要缓存的数据有过期时间就足够了) * 特殊数据:特殊设计 * * 原理: * CacheManager(RedisCacheManager)->Cache(RedisCache)->Cache负责缓存的读写

    本文标签: 谷粒面试题高级商城amp