性能优化,实践浅谈

  当经历了无数的日日夜夜,朝九晚九,攻克了无数难关,终于将系统预定功能开发完成,通过测试,部署上线后。你是否会感觉志得意满,到达了人生巅峰,高唱无敌是多么寂寞。

  现实情况是,如果你这个系统,业务没有做起来,没啥人用,huan则罢liao。如果有越来越多的人,持续使用。随着用户增多,业务数据增多,那系统一定会暴露一些性能问题。而对这些问题的优化解决,以及监测,往往需要比开发具体功能,更高更全面的技术素质及能力。

  一、性能问题监控

  锅叔云:性能问题是具有隐蔽性,服务器硬件性能良好不等于系统服务性能良好。这么说可能经验欠缺的同学难于理解。不就是系统慢么,用户会告诉我们啊? 我们有服务器监控啊,如果cpu,或者内存满了,会有监控报警啊?

  首先,系统慢用户未必会告诉你,如果比你的竞品慢太多,用户会用脚投票。然后,如果你开发的系统在把硬件跑到瓶颈之前都快如闪电,请收下锅叔的膝盖-_-|| 。

  常见的性能问题,往往是欠缺性能考虑引起的,响应巨慢的同时,硬件利用率可能5%不到,这类问题也是此次锅叔主要讨论的。

  经验上来说,对于性能问题的监控预警是难于解决具体的性能问题的。实践中我们需要一些日常机制来筛查系统性能问题,避免病入膏肓。

  数据库慢查询日志——是一个重要的监控途径,其中记录了耗时较长的数据库操作记录。可以通过手动或自动分析慢查询日志,筛查可能存在的性能问题,主流数据库都支持慢查询日志生成,具体的配置方式此处不做赘述。非统计类的数据操作通常应该在100ms以下。

  接口性能监控——后台系统通常是通过服务接口向外提供服务的,前端页面或者移动设备是通过调用服务端接口来完成对应操作的。接口的粒度是大于数据库操作的,一个接口调用可能包含很多个数据库调用。接口性能更接近于用户体验,因为多数时候用户的一个操作动作会对应一个服务接口(如保存,确认)。在不存在慢查询的时候,接口性能可能也会不满足要求,可能的原因如,一个接口循环调用了1000次数据库操作,或者调用了一些第三方接口等。对接口的性能监测原理上就是用调用结束的时间减去进入的时间点计算总耗时,并把这个耗时记录下来,以便时候筛查。Spring的切片能力可以方便的实现该需求。非报表,导出类接口,锅叔认为应当在1秒内完成为佳。

  消息队列——如果你的系统中使用到了类似消息队列的机制,对队列中排队的消息数,同样应当进行监测,消息如果发生了堆积,说明在这个阶段内,系统的整体消费能力已经不能满足输入要求了。

  以上三个监控维度是互不重叠的,应该同时进行。

  二、性能问题的定位

  除了数据库慢查询日志可以明确提示具体SQL缓慢外,上面另外两种情况所能直接提示定位到的粒度都比较大,对应一个接口或者一段处理过程代码。

  定位更细问题的具体方法也很容易想到,即分段输出各阶段的耗时。如对于一个100行的方法,可以在第30,60,100,分别计算并日志输出这3段执行耗费的时间。重复进行,就最终可以定位到将问题所在。

  性能问题的定位需要有一些性能常识,所谓性能常识即,通常做一件事情需要完成的时间,不用很准确,但量级要清楚。比如一次数据库操作,一般在数十毫秒,与内存的交互在纳秒或者微秒间,与第三方系统的接口可能在数百毫秒到几秒之间。有了这些经验我们才能够对耗时是否合理有个基本判断。比如对于一个50毫秒的数据库操作,循环100次就是5秒,已经很慢了,可以考虑是不是可以合并成一次批量操作。

  三、应用性能优化方法

  合并远程调用——根据经验,实践中因为循环进行数据库操作,或对第三方系统接口进行循环调用,是引起性能问题的非常非常常见的原因。对于此类问题的优化方式通常就是优化调用的方式,使用批量操作。例如,如果需要去数据库中查询锅叔近一年的打卡记录,可以用准确日期,查询365次,也可以用时间范围一次查询出365条,后面的方法肯定比前面的快很多。如果方法比较复杂,冗长,可以从中抽取所需的公共数据,进行统一的批量查询取出,放入内存备用,会比哪里用到哪里查要快很多。同样写入,修改操作,也尽量批量进行。

  使用缓存——对于访问频率较高的数据,可以在内存中存储,利用内存存取要快于硬盘很多的特性,来进行访问加速。常见的场景如各种计数——锅叔的文章有多少次浏览之类。

  多线程并行——通过多线程把串行修改为并行。例如与设备通信查询状态,逐个查询和并行同时向设备查询,后者要快得多。现实中多数的操作耗时是在IO上,因此多线程方式可以有效提高性能,避免“空”等。多线程并行需要注意做好线程同步。

  四、数据库性能优化

  数据库是一个现代系统都会依赖的组件,对他的性能问题解决也是开发人员需要掌握的。

  增加索引——加索引,是数据库优化的首选方案。原理是利用空间换时间。现在存储的成本下降非常快,基本上可以做到常规业务数据查询都可以走索引。对于复杂的sql 有时需要分析下怎么加索引,可以通过执行计划来分析。

  锁等待——数据库是有锁概念的,一个事务占有X锁未提交前,其他事务是不能够对该记录进行操作的,只能等待。未使用唯一索引的数据库写操作,可能会对全表加写锁,在提交前,全表记录无法操作。因此对数据库锁,应当有所认识,尽量晚上锁,尽快解锁,尽量小范围上锁。推论可得,实践中,如果是长事务,尽量把更新操作后移,把耗时的非事务性操作(如无依赖的第三方接口等),设法从事务中移除。

  事务隔离级别——选择合适的事务隔离级别,事务隔离级别与数据库锁有关,如最严格的串行隔离级别,所有的事务将串行进行。广泛使用的数据库MYSQL,其默认隔离级别为“可重复读”,但带来了间隙锁的限制,增加了锁抢占的概率。如无特别,可以根据实际情况调整为“读提交”

  中间结果——本质可以理解为数据库层次的缓存,如果一些结果从全量记录中计算数据量巨大,耗时必然很长。可以分批计算,存储中间结果。以加速数据取得。如计算锅叔家近一年的总支出,可以通过每笔记录加起来,也可以每个月算一次,这样只需要查询近12个月的支出加起来就可以啦。

  

 2 total views,  1 views today

页面下部广告