当前位置: 首页 > news >正文

一次性能优化:吞吐量从1提升到2500

专注于Java领域优质技术号,欢迎关注

作者:煮酒科技

性能优化,简而言之,就是在不影响系统运行正确性的前提下,使之运行地更快,完成特定功能所需的时间更短。压测也是检验一个架构设计是否合理的一个重要方法。

项目介绍

这个项目是一个线下支付的交易系统,使用线下设备发起支付。项目使用SpringMVC+Dubbo的微服务开发模式,其中SpringMvc作为Web端部署在tomcat上对外提供rest服务,其他模块使用dubbo开发,SpringMVC调用dubbo服务完成业务功能。

一次性能优化:吞吐量从1提升到2500

优化目的

这一次的性能优化,目的是在不调整业务逻辑的情况下通过压力测试的方式测试下单时接口的性能能达到多少,如果有性能问题,就要在不修改业务逻辑的情况下通过优化各项参数的方式(包括JVM优化、数据库连接数和Dubbo连接数)来提升整体性能。

压测前的准备

压力测试策略

采用循序渐进的方式,逐渐增加并发量的方式,先以1个并发开始,慢慢增加,当达到瓶颈的时候就进行参数调整和优化。

建立压测分支

压测优化过程中,可能随时需要调整配置参数,可能会对一些配置参数进行修改或者对公共代码进行优化。为了不让其他研发人员的开发受到干扰,在git上基于release分支建立了feature_stress分支,专门用来压测过程中,参数配置调优使用,不影响其他研发人员的开发。

搭建压测环境

为了不不影响研发和测试人员的工作,单独申请了三台4C32G的虚拟机进行压力测试,一台部署tomcat,一台部署dubbo服务,一台部署mysql。为什么只申请单机部署的方式压测呢?因为本次测试的目的是看单台服务器的性能情况,优化的目的是将单台服务器的性能最大化。

准备测试脚本

本次测试选用jmeter作为测试工具进行压力测试,由测试人员模拟线下支付的流程写好测试脚本。

初步压测

很保守的,从1个并发开始压测,测试结果让人非常的惊喜,压测开始几分钟后,就出现大量的连接失败,无法继续测试。出现大量的内存溢出的异常。没出现异常时的吞吐量达到了1req/s。同时,通过jconsole控制台监控tomcat,发现其线程数最高到了2万多个。

一次性能优化:吞吐量从1提升到2500

问题分析

这个异常是创建本地线程失败抛出的异常,为什么有这么大量的线程呢?不合常理呀!于是查看对应的代码,原来这是一个自定义的一个人日志Appender,在这个Appender里使用了线程池,这个Appender本来的目的是使用多线程提升日志性能,并且将所有的日志都收集到一个文件中。代码类似如下:

一次性能优化:吞吐量从1提升到2500

log4j.properties中直接将新的Appender添加到了rootLogger下:

初步优化

通过以上代码和日志配置文件就能看出来,每次日志输出都会创建线程,这就是线程为什么越来越多,最后导致无法创建新的本地线程的原因。

为了不影响现有的功能,将LogAppender类append方法中的线程池创建的部分变成了类的属性,并固定只用8个线程:

一次性能优化:吞吐量从1提升到2500

提交代码重新部署压测环境,再进行压测,吞吐量马上就上来了,达到了1700req/s,

一次性能优化:吞吐量从1提升到2500

深入调优

经过上面的优化之后,整体的性能还不是很高,经过jconsole监控发现,线程数还是很高,虽然没有2万那么多了,但还是有3000多的线程,这么多的线程根本无法发挥机器的性能,时间都浪费在线程切换上了,通过查看线程栈发现大量的线程都是dubbo连接的线程,为什么如此之多呢?查看dubbo的配置文件,consumer的链接数都设置成了1000,于是将所有dubbo的consumer连接数均改为了64。同时将log4j.properties中配置了控制台输出的都关闭了。

最终的优化后的测试结果,最高达到了2600req/s。

一次性能优化:吞吐量从1提升到2500

总结

性能优化需要从几个方面考虑:

  1. CPU是否有瓶颈,本项目没有大量的计算,所以CPU没有瓶颈。
  2. IO是否是瓶颈,线程太多或者连接太多都是瓶颈,本项目中并发时创建了大量的线程,达到了服务器的最高可用的连接数,导致内存溢出了,创建太多的线程也会让CPU把时间都浪费在线程切换上了。
  3. 生产环境不要使用控制台输出,因为控制台输出是同步的,输出太多会对性能有很大的影响。
  4. 如果出现吞吐量小的情况可以输出线程栈,看看到底是block在哪里了,是调用服务时间长还是读写数据库时间长。

来源链接:https://www.jianshu.com/p/97bc0b87cec7

相关文章:

  • Eureka自我保护机制与Eureka服务发现(Discovery)
  • __proto__ 和 prototype的关系
  • 这道js题你会吗?
  • java B2B2C源码电子商城系统-Spring Cloud Eureka自我保护机制
  • 基于 React TypeScript Webpack 的微前端应用模板
  • xgboost回归损失函数自定义【一】
  • Java null最佳实践
  • 36氪首发|「优仕美地医疗」获亿元级B轮融资,要打造日间手术机构的连锁服务网络...
  • 阿里云联合8家芯片商推“全平台通信模组”,加速物联网生态建设
  • MySQL设置主从复制
  • 赶紧收藏!新鲜出炉的重庆轨道交通图 首末班时间和线路都在里面
  • 厉害!重庆参加马拉松赛人数7年翻10倍,今年区县马拉松赛事将大增
  • python教程(一)·命令行基本操作
  • TCP三次握手四次挥手
  • C++类中的特殊成员函数
  • [LeetCode] Wiggle Sort
  • CSS中外联样式表代表的含义
  • isset在php5.6-和php7.0+的一些差异
  • Java多线程(4):使用线程池执行定时任务
  • Laravel核心解读--Facades
  • Spring核心 Bean的高级装配
  • 飞驰在Mesos的涡轮引擎上
  • 基于Javascript, Springboot的管理系统报表查询页面代码设计
  • 基于Mobx的多页面小程序的全局共享状态管理实践
  • 如何使用 JavaScript 解析 URL
  • 手写双向链表LinkedList的几个常用功能
  • 一些关于Rust在2019年的思考
  • 译米田引理
  • #!/usr/bin/python与#!/usr/bin/env python的区别
  • #AngularJS#$sce.trustAsResourceUrl
  • #WEB前端(HTML属性)
  • #控制台大学课堂点名问题_课堂随机点名
  • (4)事件处理——(7)简单事件(Simple events)
  • (非本人原创)我们工作到底是为了什么?​——HP大中华区总裁孙振耀退休感言(r4笔记第60天)...
  • (附源码)python旅游推荐系统 毕业设计 250623
  • (附源码)springboot猪场管理系统 毕业设计 160901
  • (黑马出品_高级篇_01)SpringCloud+RabbitMQ+Docker+Redis+搜索+分布式
  • (论文阅读30/100)Convolutional Pose Machines
  • (四)库存超卖案例实战——优化redis分布式锁
  • (完整代码)R语言中利用SVM-RFE机器学习算法筛选关键因子
  • (原創) X61用戶,小心你的上蓋!! (NB) (ThinkPad) (X61)
  • (转)详解PHP处理密码的几种方式
  • .“空心村”成因分析及解决对策122344
  • .gitattributes 文件
  • .net core webapi 部署iis_一键部署VS插件:让.NET开发者更幸福
  • .NET Entity FrameWork 总结 ,在项目中用处个人感觉不大。适合初级用用,不涉及到与数据库通信。
  • .net framwork4.6操作MySQL报错Character set ‘utf8mb3‘ is not supported 解决方法
  • .NET MVC、 WebAPI、 WebService【ws】、NVVM、WCF、Remoting
  • .NET/C# 在 64 位进程中读取 32 位进程重定向后的注册表
  • .NET6实现破解Modbus poll点表配置文件
  • .Net下C#针对Excel开发控件汇总(ClosedXML,EPPlus,NPOI)
  • @Import注解详解
  • @Transactional 竟也能解决分布式事务?
  • [ C++ ] STL_stack(栈)queue(队列)使用及其重要接口模拟实现
  • [bzoj4240] 有趣的家庭菜园