- 应用监控、机器监控(CPU、磁盘、内存、IO)、中间件监控、网络监控
- 快速发现系统瓶颈
- 容器(Tomcat、Undertow)调优、JVM 调优
- 中间件(MySQL、Redis)调优
- 根据机器监控(CPU、磁盘、内存、IO),确认应用为 CPU 密集型/IO 密集型
- 调整 Tomcat 连接数和线程数及超时时长
- 调取 JVM 的 GC 日志,调整 GC 算法和内存大小
- 调取 JVM 的堆栈日志,确定线程阻塞原因,优化代码
- 首先查看占用内存占用排行(top)
- 查看此进程中占用 CPU 较高的线程排行
- 方法一:ps -mp PID -o THREAD,tid,time|sort -rn|head -n 20
- 方法二:top -Hp PID
- 将最耗 cpu 的线程 id 转换为 16 进制输出(printf "%x\n" tid)
- 用 jstack 查询具体出现问题的代码位置(jstack pid|grep tid-A 30)
- 先通过内存映像工具对 Dump 出来的堆转储快照进行分析,先分清楚到底是出现了内存泄漏还是内存溢出
- 如果是内存泄漏,可进一步通过工具查看泄漏对象到 GC Roots 的引用链。这样就能够找到泄漏的对象是通过怎么样的路径与 GC Roots 相关联的导致垃圾回收机制无法将其回收。掌握了泄漏对象的类信息和 GC Roots 引用链的信息,就可以比较准确地定位泄漏代码的位置
- 如果不存在泄漏,那么就是内存中的对象确实必须存活着,那么此时就需要通过虚拟机的堆参数( -Xmx 和-Xms)来适当调大参数;从代码上检查是否存在某些对象存活时间过长、持有时间过长的情况,尝试减少运行时内存的消耗
- -XX:+HeapDumpOnOutOfMemoryError 和-XX:HeapDumpPath 参数分别用于指定发生 OOM 是否要导出堆以及导出堆的文件路径
- MAT 分析:
- 使用 MAT 打开 JVM 出现 OOM 时导出的 hprof 文件(-XX:HeapDumpPath 参数)
- 选择报告里的泄露嫌疑分析 Leak Suspects Report,可以定位到发生 OOM 的代码段
- Redis 的 RDB 持久化频率太高,导致 IO 压力大,导致查询超时,可以降低 RDB 频率
- 调大 read_buffer_size、read_rnd_buffer_size 大小,提高内存使用率
- 前导模糊查询('%s%')不能命中索引,非前导模糊查询('s%')则可以使用索引,可优化为使用非前导模糊查询
- 数据类型出现隐式转换的时候不会命中索引,特别是当列类型是字符串,一定要将字符常量值用引号引起来(where name='1'会走索引,where name=1 不会)
- 复合索引,查询条件必须包含索引列最左边部分(最左匹配原则),否则不会名字索引
- union、in、or 都能够命中索引,建议使用 in(查询的 CPU 消耗:or > in >union)
- 用 or 分割开的条件,如果 or 前的条件中列有索引,而后面的列中没有索引,那么涉及到的索引都不会被用到(拆分为两个 SQL)
- 负向条件(!=、<>、not in、not exists、not like 等)查询不能使用索引,可以优化为 in 查询(status=2 会,status !=1 不会)
- 数据库执行计算不会命中索引(where age>20 会走索引,where age+1>21 不会)
- 建立索引的列,建议不允许为 null(IS NULL 可以命中索引,IS NOT NULL 不能命中)
- 更新十分频繁的字段上不宜建立索引(更新操作会变更 B+树,重建索引,这个过程十分消耗数据库性能)
- 区分度不大的字段上不宜建立索引(因为不能有效过滤数据,性能和全表扫描相当,返回数据的比例在 30%以上的情况下,优化器不会选择使用索引)
- 业务上具有唯一特性的字段,即使是多个字段的组合,也必须建成唯一索引(唯一索引的查询的速度快)
- 多表关联时,要保证关联字段上一定有索引
- 例如:SELECT * FROM t ORDER BY id LIMIT N,M
- 上面 SQL 中 LIMIT N,M,是取出 N+M 行,丢弃前 N 行,返回 N ~ N+M 行的记录,如果 N 值非常大,效率极差
- 解决办法:SQL:SELECT id FROM t WHERE id > N LIMIT M