第一章 性能测试、分析与调优基础
1.5 性能分析调优模型
性能测试除了获取性能指标外,更多是为了发现性能瓶颈和性能问题,然后针对性能问题和性能瓶颈进行分析和优化。 结合传统软件模型以及互联网特征,性能调优模型归纳如下图.
网络分发
网络分发是高速发展的互联网时代,常用的降低网络拥塞,快速响应用户请求的一种技术,常用的就是网络分发CDN,内容网络分发,依靠部署在世界各地的边缘服务器,通过中心平台的负载均衡,源服务器内容分发,调度等功能模块,使世界各地的用户就近获取所需服务,而不是用户每次到源服务器获取响应。源服务器内容更新,会被同步到全网各个网络节点,同一个资源有一个人访问会被缓存同步到最近边缘节点,该地区的其他人访问该资源就会从CDN缓存服务器获取,降低源服务器压力,提高网站性能。
Web服务
Web服务器就是用来部署Web服务,用来负责请求的响应和分发以及静态资源的处理。
Web cache
Web服务器的缓存,用来临时缓存Html,Css,图像等静态资源文件
应用程序服务
应用程序部署在应用服务器上,对外提供服务的核心程序或服务,应用服务器就是Tomcat,WildFly,普通的Java应用等,应用程序服务就是提供用户可以访问的服务;
Cache
应用缓存, 程序层的缓存服务,常见的有Redis,MemCached等,缓存可以大量提高高并发的性能,是分布式应用架构经常使用的技术。
外部系统
大部分系统都需要请求外部系统或者内部多模块交互或许数据信息,这需要创建Http连接,消耗服务器资源,也是性能分析需要重点关注的。
数据库
数据库最有可能是系统性能的瓶颈,查询慢或锁线程操作数据库死锁等。
1.6 性能分析调优思想
1.6.1 分层分析
分层分析指的是按照系统模型,系统架构以及调用链路层进行监控分析和排查问题,分层分析需要对系统的架构非常熟悉,熟悉请求的处理链过程, 需要每一层建立ChekList,逐层分析,效率低,但是能发现更多的性能问题,可以自下而上或者自上而下。
关于被测试系统需要考虑的问题:
- CPU消耗是怎么样的?频繁波动吗?上下文切换频繁吗?硬中断多吗?
- Memory消耗是多少?是否存在缓慢上升?会不会释放?虚拟内存消耗多少?
- I/O消耗大吗?存在I/O 等待吗?
- 网络带宽多少?网络吞吐量多少?
- 缓存 :缓存命中率?缓存时效时间 ?内存够用吗 ? 连接够用吗?连接泄露吗?满日志? redis的slow log
- 数据库: 慢查询 ?数据库事务所等待吗? 数据库缓存命中 ? 数据库连接多少? 连接泄露吗? 连接池中连接够用吗? 数据库表监控,查询是全表扫描吗?还是索引查询?数据库执行线程争抢吗?
- 应用服务 : 线程安全吗?线程状态一直是运行中吗?线程阻塞吗?存在死锁吗?gc正常吗?是否频繁full gc? 连接数多少,连接多久释放? 会不会泄露?
- 服务负载均衡分发均匀吗? tcp连接数多少?连接多久释放 ?
- 外部服务响应是异步还是同步? 使用模拟装?
1.6.2 科学论证
发现问题-问题假设--预测--验证论证--分析--发现问题
这是分析性能问题最常用用方式,猜想-验证,
1.6.3 问题追溯和归纳总结
问题追溯 :如果本次测试性能比之前有明显变化,应该去追溯最近系统或者环境发生的变化 ,一般使用于上线生产的版本或者环境变动导致的性能问题,往下游追踪一般能发现问题。
归纳总结 :在出现某种性能瓶颈或者性能问题时根据以往的总结的知识经验逐一排查。
1.7 性能调优技术
1.7.1 缓存调优
互联网高速发展的时代,为了提高用户访问请求的响应时间,缓存的使用已经成为很多大型系统或者电商网站使用的关键技术,合理的设计缓存直接关系到一个系统或者网站的并发访问能力和用户体验。 缓存按照存放的地点不同,分为用户端缓存和服务端缓存,
缓存一般是在内存中读取数据,比mysql和oracle快的多;缓存没有命中才会去数据库查询。
缓存调优的关键点说明 :
- 如何让缓存的命中率更高?
- 如何防止缓存穿透?
- 如何控制好缓存的时效时间?
- 如何做好缓存的监控分析,比如慢日志Slow Log 分析,连接数监控, 内存使用监控等。
- 如何防止缓存雪崩?缓存雪崩指的是缓存服务器宕机,缓存中的数据全部丢失,导致大量的请求全部需要从数据库中直接获取数据,从而使数据库压力过大造成数据库崩溃。
- 缓存击穿?
1.7.2 同步转异步响应
同步请求指的是收到的一个请求后,在该请求没有处理完成时,就一直不返回结果,直到处理完成后才返回响应结果。处理方收到请求后,会等待业务1和业务2处理完成才会返回结果;
异步请求指的是系统收到一个请求后,立即把请求接收成功返回给请求调用者,在请求处理完成后,再异步推送给调用方,或者请求调用方间隔一定时间之后在重新来获取请求结果。
同步转异步主要是解决同步请求时的阻塞等待问题。一直处于阻塞等待的请求,往往会造成请求连接不能快速释放,从而导致高并发处理时连接数不够用,通过队列异步接收请求后,请求处理方再进行分布式并行处理,从而达到处理能力扩展,并且网络连接也可以快速释放。目前常见的处理方式,收到消息先送到Kafka消息中间件,然后异步响应给客户端消息,再异步消费kafka消息,处理业务 。
1.7.3 拆分
拆分是讲系统中的复杂业务调用拆分为多个简单的应用,一般遵循的一下原则:
- 对于高并发的业务请求调用都单独拆分为单个的子系统应用
- 对于并发访问量接近的业务,可以按照产品业务进行拆分,相同的业务的类型是一个后台服务。
注意点: 拆分微服务需要慎重思考,拆分出来服务之间涉及数据交换,内部通信,互相依赖等,会增加很多运维成本和开发维护成本,拆分的不可太细,还要考虑到团队则组织结构,管理模式等。
如上图所示,将高并发业务用子系统单独处理,相近的业务可以合并,提高系统的并发能力,这么拆分带来的好处是高并发业务不会对低并发业务的性能造成影响,而且系统在硬件扩展时,可以有针对性的进行扩展,避免资源浪费。同时系统也需要一个路由服务,作为统一的入口,区分业务的不同,将业务请求分发到各个子系统中。路由服务还可以实现统一的业务鉴权服务和统一的请求、响应处理或业务的统计等功能,避免子系统做公共处理,让子系统专注做业务强相关的事,提高子系统的处理能力。
1.7.4 任务分解与并行计算
任务分解与并行计算指的是将一个任务拆分为多个子任务,然后将多个子任务并行进行计算处理,最后只需要再将并行计算结果合并到一起返回即可,这样处理的目的是通过并行计算的方式来增加处理性能。采用多线程的方式,实现并行计算,提高并发处理能力,但是要注意线程共享数据的线程安全问题。
任务分解方式1 :
任务分解2 :
1.7.5 索引与分库分表
索引指应用程序在查询时,尽量使用数据库索引查询,数据库表在创建是也尽量对查询条件字段建立合适的索引,这里强调的一定合适的索引,如果索引建立不合适,不仅对查询效率没有任何帮助,反而会使数据库在插入数据时变得更慢,因为建立了索引,插入数据时,数据库会自动更新索引,这就加大了数据库插入时的资源消耗。如数据库的一个字段为status, 而status的值只有0,1,2,如果对status建立索引,对查询效率没有任何帮助,因为这个值只有0,1,2三个值,取值范围太少,建立索引后根据status去检索时,需要扫描的数据量还是非常大的。
正确的索引可以很好的提高查询效率,但是如果一个表的数据非常庞大,达到亿万级别,此时索引查询也是很慢,并且插入数据也是很慢,此时就需要对数据进行分表或分库,分库一般是指一个数据库的存储量已经很大,查询和插入时I/O的消耗非常大,此时需要将数据库拆分成两个库,以减轻读写时I/O的压力。
常见的分库分表方式如下 :
- 按照冷热数据分离方式 : 使用频率高的数据称为热数据,查询频率较低的数据被称为冷数据,冷热数据分离后,热数据单独存储,这样数据量就会降下来,查询的性能自然提升了,而且还可以更方便的单独针对热数据进行I/O性能调优。
- 按照时间维度的方式: 实时数据和历史数据分库分表,可以按照年/月时间区间分库分表,尽可能减少每个库表中的数据量
- 按照数据库操作方式 : 数据库读写分离,将查询操作和写操作分离,读写分离就是在主服务器上修改,数据会同步到从服务器,从服务器只能提供读取数据,不能写入,实现备份的同时也实现了数据库性能的优化,以及提升了服务器安全。
数据库分库分表后带来的另一个好处 : 如果单次查询时需要查询多个分表, 此时就可以通过多线程并行方式去查询多个分表,最后合并每个分表的查询结果即可,这样可以使得查询效率更高。