上接《性能优化那些事儿(一)》《无论项目大小,一旦上线,或多或少都会遇到性能问题。性能问题就像一个诅咒。我们。性能优化应该从什么时候开始有些性能问题是随着时间慢慢积累的。比如系统启动时数据量小,就没有问题。当数据积累到一定程度,问题就会暴露出来;有些问题是访问次数过多造成的。比如系统平时没有问题,但是在搞活动的时候就挂了;还有一些问题是遗留系统被太多人维护和修改,导致各种糟糕的代码气味和性能问题似乎无处不在。性能问题就像一颗定时炸弹。只要数据访问量增加,或者每个团队在开发迭代时不关注性能,迟早会爆发。既然迟早会出问题,那我们什么时候开始性能优化呢?是等问题优化好,还是编码过程中尽量避免那些错误的codepattern,或者用一些手段尽量避免踩坑?有人会说,项目压力很大。考虑性能问题会影响进度。我认为这是在给自己或后代挖坑。我们在一开始设计界面的时候,就要考虑性能问题,不仅要考虑界面的合理性和易用性,还要考虑界面是否有批量调用的情况。最简单的方法就是在设计界面的时候直接设计批量界面,这样界面既可以支持批量也可以支持单机。当然,考虑到批量会多做一些工作,但总比有问题到处填要好。坚强点,这需要我们能够识别未来业务对批处理的需求,并不是每个接口都需要支持批处理操作。我们还可以通过很多方法保证代码质量来提高系统性能,比如:使用合理的数据结构和算法,比如同样是一个列表,LinkedList的插入性能比ArrayList高很多,选择合理的锁类型在多线程环境编写高效的SQL和使用场景,合理使用索引和事务提高数据库性能,使用ORM工具时注意N+1问题,了解一些看似方便的方法的细节再使用。多考虑接口的使用场景,是否有批处理的可能,如果有批处理接口,如果对性能要求高,是否考虑使用Netty等异步手段。你脑子里应该有很多这样的手段。在开发过程中,您可以尽情发挥。但有一点需要强调:不要使用任何你不知道其背后原理的优化技巧。这里有一个有争议的优化方法:“unusedobjectsshouldbemanuallyassignedNULL”来帮助GC更早的回收内存,但是在大多数场景下,未使用的局部变量是否设置为NULL对GC并没有影响,毕竟方法执行后,栈帧从操作数栈中弹出,方法中的局部变量没有了,是否设置为NULL没有影响。但是如果你是在开发中间件,或者复杂的算法,那么手动设置为NULL在某些情况下确实有利于GC。例如,临时变量占用大量内存,如果不主动将其设置为NULL,当JDK运行在“解释”阶段时,确实会导致GC回收变慢。在J.U.C包中经常可以看到xxx=null,注释都是helpgc,但是对于我们经常写业务代码的人来说没有必要。系统开发完成后,可以根据一些预期的指标(如并发数)和硬件资源对系统进行测试,利用各种分析统计工具判断指标是否在预期范围内。系统上线后,需要根据日志和监控系统观察系统性能。一旦发现问题,必须及时分析和修复。这里可以使用的软件很多,比如Dynatrace等APM工具,但是如果你的系统比较定制化、比较奇特,可能很难找到现成的工具。我们可以自己开发一个监控系统。其实知道原理很容易。简单的。不管是新系统还是老系统,无论是上线前还是上线后,性能优化都要遵循两个原则分三步走:两个原则:不优化没有经过测试的软件(单元测??试是必须的,不然优化的时候会丢bug)不知道),不懂的软件不要优化。三步:测试、分析、调优性能测试的主要指标一般来说,衡量系统性能的指标有以下几个:时间细分:比如数据库的响应时间,数据库的响应时间IO,以及HTTPClient的响应时间。当我们优化系统时,通过收集这些响应时间,我们可以查明性能问题发生的位置。并发数并发数是指系统可以同时处理的请求数,这个数也反映了系统的负载能力。吞吐量吞吐量是指单位时间内系统处理的请求数,它反映了系统的处理能力。在Web系统中,常用TPS(每秒事务处理量)或QPS(每秒查询数)来衡量系统的吞吐量。在不考虑网卡等网络设备限制的情况下,可以用下面的公式粗略估算系统的吞吐量:吞吐量=(1000/响应时间ms)×并发数如何严格的做性能测试,如何做它更严格的性能测试?分享一个比较科学的性能测试方法(来自COOLSHELL):(1)定义一个系统的响应时间延迟,建议TP99,成功率。比如路透社的定义:99.9%的响应时间必须在1ms以内,平均响应时间在1ms以内,100%的请求成功。当然一般的web系统不需要这么苛刻的定义,99.9%的响应时间都在100ms以内。(2)在这个响应时间的限制下,测试系统的吞吐量。测试数据需要有大中小各种大小的数据,可以混用。最好使用来自生产线的测试数据。(3)在该吞吐量下进行浸泡测试,例如:使用第二步测试得到的吞吐量连续7天不间断压测系统。然后收集CPU、内存、硬盘/网络IO等指标,检查系统是否稳定。比如CPU稳定,内存占用也稳定。那么,这个值就是系统的性能。()求系统的极限。例如:在成功率为100%的情况下(不管响应时间长短),系统可以维持10分钟的吞吐量。(5)做爆破试验。以第二步得到的吞吐量执行5分钟,再以第四步得到的limit值执行1分钟,返回到第二步的吞吐量5分钟,再执行第四步的权限值for1分钟,这样来回一段时间,比如2天。收集系统数据:CPU、内存、硬盘/网络IO等,观察它们的曲线,以及对应的响应时间,确保系统稳定。(6)针对低吞吐量和小网络数据包的测试。有时,当吞吐量较低时,延迟可能会增加。例如,如果不启用TCP_NODELAY参数,延迟会增加,小的网络包会导致带宽和性能不足。因此,性能测试需要根据实际情况选择性地测试这两种场景。影响系统性能的主要因素我们首先要了解总体上有哪些因素会影响系统性能,这样我们才能一一检查。硬件一般硬件是我们考虑的第一个因素。如果能够改进硬件,一般可以解决一些性能问题。常见的影响因素有CPU、内存、磁盘I/O、网络等,如果内存不够用或者CPU长时间满载,那就需要升级硬件了。如果业务中IO比较重,应该考虑更换SSD硬盘。考虑网络带宽是否足够,网卡性能是否跟得上。与系统系统相关的点太多了。下面介绍几种常见的情况:Linux文件描述符限制,有时默认值比较低,影响并发。在Linux中,强烈建议关闭Swap。打开它弊大于利,还会出现意想不到的问题。大流量应用需要注意网卡中断,使用CPU亲和力绑定网卡。软件一般有几个因素需要重点关注(1)数据库:数据库操作不仅涉及大量的内存和CPU计算,还涉及大量的磁盘读写。优化数据库的性能是整个系统的核心。比如我们常用的各种缓存,就是为了减轻数据库的压力。启用慢SQL收集,通过分析慢SQL优化系统中低效的SQL语句。(2)锁竞争:在单机环境下,锁的使用可能会造成线程资源的大量浪费,从而给系统带来性能开销;在分布式环境中,分布式锁的使用也可能导致大量请求堆积,影响系统整体性能。优化的重点在于锁粒度的控制,以及如何将其替换为无锁模型。(3)线程池:线程池的声明和配置不当也会出现问题。请确保您的线程池是有界的,并且线程池的大小是合理的。(4)异步系统和同步IO:确保你了解Netty相关知识,不要在Reactor线程中使用同步IO。(5)循环和外部请求:不要把外部请求放入循环中,尽量分批进行一个请求。(6)看似方便实则暗藏杀机:很多库提供看似方便的方法,实则暗藏杀机,不要使用不懂原理的所谓高级用法。不管底线策略的性能优化做得多好,系统总会有局限性。因此,底线策略也是性能优化的一部分。常见的底线策略有限流、降级、熔断。很多中间件都有这样的功能,我们要合理使用。另外我们可以通过减少流入服务器的流量来避免高流量对我们服务器的影响,比如访问CDN,利用CDN的节点优化和缓存能力来优化我们的性能,当然我们可以使用更高级的边缘计算技术在某些场景下会产生质的飞跃。需要强调的是,任何性能优化都必须结合业务场景,明确已知的性能问题和性能目标,不能为了优化而优化。市面上有很多APM工具和性能分析工具可以帮助你定位性能问题,但是如果你的系统非常复杂,不是一个标准的容器,那么很有可能你需要自己开发一个APM工具来帮助你定位性能问题,那么如何开发自己的性能分析工具,请听下一章。下一页《??性能优化那些事儿(三)??》
