应用程序性能优化经验总结——持续更新中。
最近有个产品进行了一些性能优化的工作,虽然具体的优化不是我做的,不过也从中受益良多,把经验总结一下分享给大家。
避免过多的资源消耗
虽然现在的服务器硬件配置都很强悍,但系统设计和开发的时候不控制资源的使用,很容易导致系统资源的耗尽或应用程序性能严重下降,以下几种问题会经常的出现
- 从外部(文件、数据库)加载大量的数据到内存中,从而导致outofmemory或swap
- 创建大量的线程
- Socket无限建立连接,从而导致文件句柄被耗尽。
针对这种问题就要严格控制消耗资源的大小,如果无法通过直接限制大小来实现的话就需要考虑分批、分页载入->处理->释放,对于占用资源比较多的对象(例如Thread)缓存起来重复循环加以使用。
外部资源不可靠
系统中的某个功能的实现需要依赖第三方系统(例如通过接口获取数据、发送电子邮件等等)。如果默认第三方系统高可用的话,很容易受到第三方系统的牵连。所以在对第三方系统有依赖的模块在设计的时候要充分考虑第三方系统不可用的情况下的处理逻辑和方式
- 例如对第三方系统能够采用异步的就采用异步。
- 设计好容错(例如外部资源获取失败或超时情况)的机制。
- 进行适当的对外部资源的重试,并考虑过度的给第三方系统压力,例如重试一定数目以后就放弃。
- 在第三方系统失效的情况下,正确处理内部资源的释放(在设计和CodeReview过程中要重点加以检查),避免由于内部资源的耗尽。
避免过多、过量的外部资源调用
过度、过量的外部资源调用会严重影响程序的性能。例如
- 大量的SQL调用或者一次从数据库中载入大量数据。
- 受限于第三方系统的性能,减少批处理的数量,从而导致大量的远程调用。
此外,如果在事务中嵌入对于第三方系统的请求(例如在数据库操作时去发送邮件或者调用第三方的接口)就会增加事务操作的时间(一般Web应用的事务都不大,单机操作时间也就几毫秒甚至不到1毫秒,一但涉及到外部资源调用提交时节点间的网络通信往返过程也为毫秒级别,对事务响应时间的影响也不可忽视)。由于事务持续时间延长,事务对相关资源的锁定时间也相应增加,从而可能严重增加了并发冲突,影响到系统吞吐率和可伸缩性。
在设计外部接口的时候尽量设计成批量接口,并将批量数设计成运行时可配置化。当外部系统出现突然的响应时间延长的现象时可以灵活的调整批量数参数。对数据库可以采取批量插入、更新的方式提高系统性能。
将主流程和辅助流程分离
项目的某个某块需要保存发送数据,发送数据,保存发送log,向第三方系统发送反馈。这一系列步骤都在一个流程中完成。由于做的事情太多,导致主要的功能点“发送数据”的性能低下。这需要我们把主流程和辅助流程分离,对一些辅助流程采用后台异步的方式,进而提高系统的性能和稳定性。
正确、充分地使用日志并减少对系统性能的影响
日志这块前段时间整理过一份java 日志编码规范。除了这些内容再补充一些
- 减少不必要的字符串累加。再简单不过的东西了,可就是有同学会无视这最基本的原则,无语!
- 在对外部资源的调用前后都要记录日志,并完整记录外部调用的主要参数、批量数。
- 日志记录主要的方法入口和出口都提供开始和结束时间、参数。
