目录
目录
[CPU 利用率高:](#CPU 利用率高:)
[GC 问题,其实也就是内存泄漏导致内存被占满,无法分配内存导致JVM触发GC:](#GC 问题,其实也就是内存泄漏导致内存被占满,无法分配内存导致JVM触发GC:)
问题背景:
你在做这个项⽬的时候遇到了什么问题?( OOM 问题、 GC 问题等等)
你⽤过哪些分析定位 Java 故障 / 性能的⼯具?( JDK ⾃带⼯具、 MAT 、 Arthas 等等)
如果项⽬遇到了 OOM 问题,你会如何排查?(常⽤ MAT )
有什么办法可以监控到 JVM 的实时运⾏状态?( Arthas )
⽣产环境有⼀个接⼝很慢,如何排查?(Arthas、Cat、 Pinpoint、Skyworking )
CPU100% ,你是怎么处理的?( jstack 或者 Arthas )
你是如何定位线上问题的?(说说⾃⼰了解的⼯具,然后根据⾯试官提示继续深⼊聊即
可)
项⽬中遇到了哪些线上故障,你是如何解决的?
问题摘要:
CPU 利用率高:
1、找到最耗CPU的进程(top -c),找到最耗CPU的线程(top -Hp 进程ID),jstack查看最耗CPU的堆栈信息(jstack 10765 | grep '0x2a34' -C5 --color)
2.、 阿⾥开源的全能的故障诊断⼯具 Arthas :
dashboard 命令查看 TOP N 线程, thread 命令查看堆栈信息。
内部集成的⽕焰图⼯具 async-profiler
***OOM/**内存泄露:
- JDK ⾃带的 VisualVM :使⽤ jmap 命令⽣成堆转储快照也就是 dump ⽂件,然后通过
VisualVM 分析 dump ⽂件。- MAT (Memory Analyzer Tool) : MAT 也可以分析 dump ⽂件。
GC 问题,其实也就是内存泄漏导致 内存被占满,无法分配内存导致JVM触发GC:
1、Full GC问题 :
公司的监控系统:大部分公司都会有,可全方位监控JVM的各项指标。
JDK的自带工具,包括jmap、jstat等常用命令:
#查看堆内存各区域的使用率以及GC情况
jstat-gcutil-h20pid 1000
#查看堆内存中的存活对象,并按空间排序
jmap-histo pid head-n20
#dump堆内存文件
jmap-dump:format=b.file=heap pid
可视化的堆内存分析工具,JVisualVM、MAT等
2、Young GC问题排查(YGC频率过快、YGC持续耗时过长)
YGC问题其实比较难排查。相比FGC或者OOM,YGC的日志很简单,只知道新生代内存的变化和耗时,同时dump出来的堆内存必须要仔细排查才行。
排查思路也是:查看监控、确认JVM配置、查看代码、对dump的堆内存文件进行分析,排查大对象,正常大对象YGC多次后会晋升到老年代,不应该是YGC持续耗时过长的原因,不断的往静态变量List中添加新对象,从而引发YGC持续耗时过长的问题。
使⽤ guava cache 的时候,没有设置最⼤缓存数量和弱引⽤,导致频繁触发 Young GC
对于⼀个查询和排序分⻚的 SQL ,同时这个 SQL 需要 join 多张表,在分库分 表下,直接调⽤ SQL 性能很差。于是,查单表,再在内存排序分⻚,⽤了⼀个 List 来保存数据,⽽有些数据量⼤,造成了Young GC和Old GC都非常频繁 。
接口线程池满导致会在同一时间Full GC,重启后,线程数量恢复正常水位。3、JVM性能优化
通过观察 GC 频率和停顿时间,来进⾏ JVM 内存空间调整,使其达到最合理的状态。调整过
程记得⼩步快跑,避免内存剧烈波动影响线上服务。 这其实是最为简单的⼀种 JVM 性能调
优⽅式了,可以算是粗调吧。
*MySQL****死锁问题:
解决 MySQL 死锁问题的思路:
- 使⽤ show engine innodb status; 查看死锁⽇志,然后分析死锁⽇志。
- 如果第⼀种⽅式⽆法解决死锁问题,可以通过 binlog ⽇志获取锁事务所执⾏的全部
SQL 。有了具体 SQL 语句,就能进⾏具体的锁冲突分析了。
慢SQL、慢查询
解决 MySQL 慢SQL 问题的思路:
- explain字段分析, 比较重要的字段有:
select_type : 查询类型,有简单查询、联合查询、子查询等
key : 使用的索引
rows : 扫描的行数
type :访问类型排列结果值从最好到最坏:
system>const>eq_ref>ref>fulltext>ref_or_null>index_merge>unique_subquery>index_subquery>range>index>all
一般来说,得保证查询至少达到range级别,最好能到达ref
system:表只有一行记录(等于系统表),这是const类型的特例,平时不会出现
const:表示通过索引一次就能够找到
eq_ref:唯一性索引扫描,对于每个索引键,表示只有一条记录与之匹配,常见于主键或唯一索引扫描
ref:非唯一性索引扫描,返回匹配某个单独值的所有行
range:只检索给定范围的行,使用一个索引来选择行,一般就是在where语句中出现了between、<、>、in等的查询
index:index比all快,因为index是从索引中读取,all是从硬盘中读取
all:遍历全表才能找到
慢SQL案例:
in中参数太多(分批处理);
返回的查询结果过多(分页处理);
强制指定了使用orderId索引但where条件中并没有orderId;
忘写了join的on条件导致全表扫描;
where条件下的多个条件,在不确定哪种索引是最优时,可以尝试建立不同的索引,观察语句在不同索引情况下的执行情况进行权衡;
MySQL优化器选错索引、强制走主键索引;
尽量要避免隐式转换,因为⼀旦发⽣隐式转换除了会降低性能外, 还有很⼤可能会出现不期望的结果;慢查询优化是一个长期的过程,长期有耐心!
消息队列消息积压
1、Kafka:
问题:项⽬中某 Kafka 消息组消费特别慢,导致在设置的时间内没有提交offset,kafka对这个消费组的消费者进行再平衡,一直循环往复导致消息积压,有时候在 kafka-manager 控制台看到有些消费者已被踢出消费组。该消费组在短时间内重平衡了 600 多次。
解决办法:根据业务逻辑调整 max.poll.records (一次最大拉取消息条数)与 max.poll.interval.ms (消费者处理消息逻辑的最大时间)之间的平衡点,避免出现消费者被频繁踢出消费组导致重平衡。
2、RabbitMQ:
消息延迟 : TTL + 死信队列(⽐较麻烦)、 RabbitMQ 延迟队列插件(更简单,相关阅
读: RabbitMQ 延迟插件的使⽤ )
消息堆积解决:增加消费者、多线程、扩⼤队列的容量、惰性队列(更灵活但消息的时
效性降低,接收到消息后直接存⼊磁盘⽽⾮内存,⽀持百万级消息的存储)3、消息队列(MQ)消息堆积问题排查与解决思路-CSDN博客
- Redis
分布式锁使⽤不当导致超卖**:**
问题:因 Redis 分布式锁,项目中飞天茅台抢购活动超卖的重大事故。原因是用户服务响应延迟致锁失效被覆盖,非原子性库存校验。
解决方案:包括实现相对安全的分布式锁和安全的库存校验,基于LUA脚本实现原子性的get and compare,可以利用Redisson的分布式锁。redis的incr原子操作会返回操作之后的结果。
缓存雪崩,缓存穿透、缓存击穿,热key,大key
简述:Redis 线程模型、Redis 的核心数据结构的使用场景、各种缓存高并发的使用场景:缓存雪崩,缓存穿透、缓存击穿,热key,大key等_redis线程模型及使用场景-CSDN博客
缓存一致性问题
缓存最终一致性 :
问题和解决方案:读数据时,是先读缓存,缓存没有再读数据库,再更新缓存,更新缓存一般有两种方式:先更新数据库,再删除缓存;延迟双删,先删除缓存再更新数据库,延迟一段时间再删除缓存。
缓存强一致性:
解决方案:悲观锁、乐观锁和分布式事务也可以用于保证数据一致性,但实现复杂度较高。
也可以结合业务实现相对强一致性,比如携程的做法。
分布式缓存与DB秒级一致设计实践(最终一致性)
问题:C端爆款项目需求:高流量、部分商品会成为热卖商品、承担下单职能、让用户尽可能看到最新的信息,即:本地热点key缓存、分布式缓存(按需进行缓存)和DB一致性问题
方案:采用:client和server方式,
1、缓存访问组件client(jar包)提供给各业务方进行按需异步将缓存中需要增、删、改的键值对通过消息传递给缓存更新平台server,让其进行实际的缓存更新操作。
2、对热点key进行本地缓存与更新,避免对某个key的大量请求直接打到缓存导致缓存雪崩。
3、缓存更新都是发生在缓存更新平台server,所以其可以将发生变化的缓存key通过消息队列广播给所有缓存访问组件,组件消费到这条消息后,若key是热点key,则进行本地缓存的更新。
4、本地缓存设置很短的失效时间。
5、计算key的hash值,然后对其取模,可以将相同的key分配到相同的线程处理。
6、旧值覆盖新值的问题,采用缓存版本的概念来解决这个问题,我们认为每条缓存的数据都应该有一个版本号(业务提供,例如可以是修改数据的时间戳,只要满足单调递增即可)。基于此,缓存的增、删、改操作全部基于这个版本号来进行判断是否执行操作,消息版本号必须大于缓存中的版本号才进行增改操作,消息版本号必须大于缓存中的版本号才进行删除操作。
7、缓存访问组件client(jar包)内部会将每条消息记录到业务DB。缓存更新平台server通过业务提供的接口增量轮询该表,确保所有消息都被及时消费掉。
事务问题
插入数据后事务没有立马提交导致更新数据失败:
问题:往任务表中插入任务后,发送消息异步处理任务,并更新任务状态失败。
解决方案:由于插入任务和发送消息操作在一个事务里,消费者收到任务消息后,会立马处理并更新状态,由于事务还没提交,导致更新不到该任务数据,导致更新状态失败;解决办法是在发送消息前先提交插入任务的事务。
详细参考:
知识星球 | 深度连接铁杆粉丝,运营高品质社群,知识变现的工具
知识星球 | 深度连接铁杆粉丝,运营高品质社群,知识变现的工具
知识星球 | 深度连接铁杆粉丝,运营高品质社群,知识变现的工具
Java服务,CPU100%问题如何快速定位?_java服务,cpu100%问题如何快速定位?-CSDN博客
Java服务,内存OOM问题如何快速定位?_java oom 如何确定sql-CSDN博客