目录

线上常见问题案例及排查工具

目录

目录

问题背景:

问题摘要:

[CPU 利用率高:](#CPU 利用率高:)

OOM/内存泄露:

[GC 问题,其实也就是内存泄漏导致内存被占满,无法分配内存导致JVM触发GC:](#GC 问题,其实也就是内存泄漏导致内存被占满,无法分配内存导致JVM触发GC:)

MySQL死锁问题:

慢SQL、慢查询

消息队列消息积压

分布式锁使⽤不当导致超卖:

缓存雪崩,缓存穿透、缓存击穿,热key,大key

缓存一致性问题

详细参考:



问题背景:

你在做这个项⽬的时候遇到了什么问题?( 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/**内存泄露:

  1. JDK ⾃带的 VisualVM :使⽤ jmap 命令⽣成堆转储快照也就是 dump ⽂件,然后通过
    VisualVM 分析 dump ⽂件。
  2. 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 死锁问题的思路:

  1. 使⽤ show engine innodb status; 查看死锁⽇志,然后分析死锁⽇志。
  2. 如果第⼀种⽅式⽆法解决死锁问题,可以通过 binlog ⽇志获取锁事务所执⾏的全部
    SQL 。有了具体 SQL 语句,就能进⾏具体的锁冲突分析了。

慢SQL、慢查询

解决 MySQL 慢SQL 问题的思路:

  1. 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秒级一致设计实践(最终一致性)

干货 | 分布式缓存与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通过业务提供的接口增量轮询该表,确保所有消息都被及时消费掉。

事务问题

插入数据后事务没有立马提交导致更新数据失败:

问题:往任务表中插入任务后,发送消息异步处理任务,并更新任务状态失败。

解决方案:由于插入任务和发送消息操作在一个事务里,消费者收到任务消息后,会立马处理并更新状态,由于事务还没提交,导致更新不到该任务数据,导致更新状态失败;解决办法是在发送消息前先提交插入任务的事务。

详细参考:

知识星球 | 深度连接铁杆粉丝,运营高品质社群,知识变现的工具

知识星球 | 深度连接铁杆粉丝,运营高品质社群,知识变现的工具

知识星球 | 深度连接铁杆粉丝,运营高品质社群,知识变现的工具

如何进行GC调优-CSDN博客

MySQL - 性能优化-CSDN博客

Java服务,CPU100%问题如何快速定位?_java服务,cpu100%问题如何快速定位?-CSDN博客

Java服务,内存OOM问题如何快速定位?_java oom 如何确定sql-CSDN博客


本文是转载文章,点击查看原文
如有侵权,请联系 xyy@jishuzhan.net 删除
相关推荐
Linux运维老纪6 小时前
运维之 Centos7 防火墙(CentOS 7 Firewall for Operations and Maintenance)
linux·安全·centos·云计算·运维开发·火绒
豪越大豪6 天前
豪越消防一体化安全管控平台:消防管理智能化
大数据·运维开发
Linux运维老纪7 天前
内网YUM源搭建手册(Internal Network yum Source Construction Manual)
linux·网络·阿里云·云计算·运维开发
Linux运维老纪8 天前
Linux之 权限提升(Linux Privilege Escalation)
linux·服务器·数据库·mysql·云计算·运维开发
demonlg011210 天前
Jenkins 共享库(Shared Libraries)使用说明文档
java·运维·python·jenkins·运维开发·devops
demonlg011210 天前
Jenkins CustomTools 插件使用说明文档
运维·jenkins·运维开发·devops
demonlg011210 天前
Jenkins集成Trivy安全漏洞检查指南
java·运维·python·jenkins·运维开发·devops
SG.xf11 天前
k8s的控制应用Helm
linux·运维开发
luckyext13 天前
SQLServer列转行操作及union all用法
运维·数据库·后端·sql·sqlserver·运维开发·mssql
Linux运维老纪13 天前
K8S集群新增和删除Node节点(K8s Cluster Adds and Removes Node Nodes)
linux·云原生·容器·kubernetes·云计算·运维开发