发现程序反应很慢是为什么

近似子问题

1、一条SQL语句执行很慢的原因有哪些?(据说腾讯面试题)

2、一个WEB程序突然很慢的原因?

3、系统上线几个月后突然变慢的原因?

4、你的网站访问很慢的原因?

5、浏览器输入地址后发生了什么?(据说百度面试)

等等…

全局到细节(分类分析)

遇到此类问题,我们要揣测面试官想听到什么样的回答,他想考察的知识点有哪些?

其实,可以问出的知识体系相当的庞大。

  • 一般而言,应该先站在一个比较全局的角度去思考问题,分类分重点一一阐述。

  • 其次,最好举个相关的例子说明,更能表达清楚。

  • 最后,需要注意的是,我们在说明白问题原因之后,必须给上一个切实可行的解决思路或者说具体方案。

回到主题

比如说,最近本人有个面试问题就是:

  • 发现程序反应很慢是什么原因?

如果说是后端面试,那么我们可以完全把问题方向 理解成 后端反应慢的问题。

分情况分析

1、外部条件没变,一直都很慢?

(1)代码问题
(2)服务器问题
(3)数据库问题

2、只是偶尔很慢?(抛开网络信道情况)

(1)服务器问题
(2)数据库问题

3、以前正常,只是近期开始变很慢?

(1)代码问题
(2)数据库问题
(3)服务器问题

阐述

1-1:假设:从程序开发完成部署后,外部条件不变情况下,一直都很慢,是代码问题
编码不规范,导致编译或运行慢

    如:
    没有符合高内聚低耦合原则;
    某些条件判断、循环语句,不规范导致的逻辑问题,由此引发程序执行了无意义的代码,时间复杂度上升;



数据结构使用不良,算法实现效率低下,导致函数处理慢

    如:
    像Java中 ArrayList、String、StringBuilder、StringBuffer、HashMap、HashTable、CurrentHashMap等等数据结构使用情况都是严格规定的;
    算法的话当然不用说,非常重要,像 使用 BF 算法暴力递归 搜寻子字符串,和使用 KMP 算法 动态规划的去查找一个子串,时间复杂度是指数级提升;

设计模式上不讲究或者错误使用,导致资源占用高和执行效率低

    如:
    最简单的工厂模式、单例模式就是很好的证明,减少资源开销,提神速度和性能;

解决:
检查并优化代码(规范、算法、设计模式)

1-2:假设:从程序开发完成部署后,外部条件不变情况下,一直都很慢,是服务器问题
服务器硬件配置低,达不到咱们程序运行环境的最佳配置

服务器软件环境安装或者配置有问题

服务器带宽问题

解决:
先从软件检查,排除了软件环境和配置,就使劲砸钱升硬件,买最豪华套餐

1-3:假设:从程序开发完成部署后,外部条件不变情况下,一直都很慢,是数据库问题
索引问题(如果有一定数据量)

    a.字段没有设置索引
    b.字段有索引,没有命中
    c.特殊骚操作,导致没有使用上索引

其他问题
    不规范频繁删除、插入等

如:

1、字段 c 没有建立索引

1
select c,d,e from t where 100 < c and c < 1000000;

2、加了 c 和 d 两个字段复合索引 INDEX(c,d),但是没加 a 索引。

1
select c,d,e from t where d > 100 and c < 100000 and e < 10000;

虽然,不符合复合索引最左匹配原则,但是查询优化器会自动处理,然而后面的 e 会导致退化为全表查询

3、函数操作导致没有用上索引

1
select c,d,e from t where pow(c,2) = 1000;

4、在字段的左边做了运算,不会用上索引

1
select c,d,e from t where c - 1 = 1000;

解决:

1、优化SQL语句

2、建立有效的字段索引

关于SQL无法命中索引情况,可以详细了解下。

2-1 假设:程序偶尔反应很慢,是服务器问题
高峰期,服务器负载过高,导致IO占用、CPU、内存资源紧缺

    如:某些时候,并发请求服务的数量太多,处理不过来

解决:

1、微服务拆分

2、分布式架构(负载均衡)

2-2 假设:程序偶尔反应很慢,是数据库问题
数据库 在 刷新 脏页【重点】

    以下四种情况会刷新脏页:

    a.redolog写满了
    b.内存不够用了
    c.MySQL 认为系统“空闲”
    d.MySQL 正常关闭的时候

    当我们要往数据库插入一条数据、或者要更新一条数据的时候,
    我们知道数据库会在内存中把对应字段的数据更新了,
    但是更新之后,这些更新的字段并不会马上同步持久化到磁盘中去,
    而是把这些更新的记录写入到 redo log 日记中去,等到空闲的时候,
    在通过 redo log 里的日记把最新的数据同步到磁盘中去。

    redolog写满了就没办法等到空闲的时候再把数据同步到磁盘的,
    只能暂停其他操作,全身心来把数据同步到磁盘中去的,
    而这个时候,就会导致我们平时正常的SQL语句突然执行的很慢,
    所以说,数据库在在同步数据到磁盘的时候,就有可能导致我们的SQL语句执行的很慢了。

    注:
    当内存数据页跟磁盘数据页内容不一致的时候,我们称这个内存页为“脏页”。
    内存数据写入到磁盘后,内存和磁盘上的数据页的内容就一致了,称为“干净页”。


事务锁(拿不到锁,一直等)
    如:我们要执行的这条语句,刚好这条语句涉及到的表,别人在用,
    并且加锁了,我们拿不到锁,只能慢慢等待别人释放锁了。
    或者,表没有加锁,但要使用到的某个一行被加锁了,就等吧。

    注:show processlist 查看当前状态

解决:

除了能该配置,我还能干啥? 不可能不让它 做 redolog 也不可能偷偷把 事务锁 给干掉了。慢是慢,但是稳啊!

3-1:假设:近期开始变很慢,是代码问题
跟踪请求日志,找到最慢的功能模块,检查近期修改或发布的版本记录

    如:某一次上线,某个地方代码修改后有逻辑或规范问题

解决:
加班改,优化(逻辑、算法等)

3-2:假设:近期开始变很慢,是服务器问题
服务器硬件配置不够用了

    如:内存

服务器软件配置不合适了

    如:并发数、连接数

其他软件环境问题

    如:加了其他内容,或者更新了啥

解决:调试改环境配置,加硬件

3-3:假设:近期开始变很慢,是数据库问题
索引【主要】

    如:随着系统运行时间增加,数据量增大,查询字段未设置索引、索引未命中等

锁
    如:近期新增功能中,使用到了新的锁,导致等待时间变长

其他配置不适用了
    如:连接数、语句执行数

解决:

1、主要从索引出发,保证用上索引

2、检查事务锁情况、配置等

最后

其实每个具体问题不是绝对仅限于三个大的场景下,只是根据可能性更高去分析。

具体情况,还得回到实践中去,跟踪、调试才能一步步定位问题的所在,然后解决它。

个人总结,水平有限,欢迎批评指正!