【Java】记录一次服务性能问题定位、调优完整过程

news2024/11/19 12:44:13

文章目录

  • 背景
    • 压测准备
    • 初步压测结论
  • 排查过程记录
    • 排除中间件及网络因素
    • 借助Arthas及Skywalking
    • 暴露prometheus指标
    • 修改数据库最大连接池数
      • 场景一
      • 场景二
      • 场景三
      • 场景四
      • 场景五
      • 场景六
      • 场景七
      • 场景八
      • 结论
    • Consumer消费能力优化
      • 增加消费者
      • 增加Topic Queue数量
        • Queue总数:96
        • Queue总数:192
        • Queue总数:900
      • 调整消费程序http最大连接池数
      • Consumer参数微调
  • 总结
    • 优化总结
    • 经验总结

背景

事件中心服务新增定时消息功能:

  1. 基于 RocketMQ 5.0 的 TimerMessage 特性,作为触发定时消息的机制;
  2. 事件中心API(pubsub)提供新的定时消息接口,作为定时消息的提交入口;
  3. 定时消息元数据保存至 TiDB,RocketMQ 内只保存定时消息对应的主键ID;
  4. 定时消息执行服务消费 RocketMQ 指定 Topic ,调用事件中心回调接口,发送消息至Kafka;
  5. 为消息保证顺序性,RocketMQ Consumer 使用顺序消费。

定时消息的链路为:定时消息接口(pubsub) --> TiDB、RocketMQ --> 定时消息执行服务(Consumer) --> 定时消息回调接口 --> Kafka

本次压测及调优,只针对定时消息接口、定时消息执行服务(Consumer)、定时消息回调接口。

压测准备

压测意图

  • 测试提交定时消息接口在不同 QPS 时的 RT 情况

  • 观测pubsub服务在负载情况下的资源使用情况

  • 测试consumer的消费能力、得出消息积压与Consumer数量的比例

  • 测试定时消息回调接口的QPS峰值

场景描述

  • pubsub单实例,最终调整配置和生产环境一致

    • limit:8c-8g
    • -Xms4G -Xmx4G
  • 模拟固定QPS对提交定时消息接口进行压测:

    • QPS 1000
    • QPS 3000
    • QPS 5000
  • 堆积一定数量的定时消息:

    • 观察Consumer消费速度
    • 观察定时消息回调接口RT情况
    • 观察pubsub服务资源使用情况

观测指标

pubsub服务器:

  • 机器CPU使用情况

    • top -Hp {jvm_pid}
  • 查看线程级别 user, system 情况

    • 火焰图
  • 主机 load

  • GC 情况

    • 若没有 gc 日志,用 jstat 临时输出一下
  • 内存增长情况

  • 线程情况

  • 接口耗时(通过压测平台监控查看)

    • 99.99% RT
    • 平均 RT

定时消息执行服务:

  • consumer TPS

  • consumer 服务监控

    • jvm监控
    • httpclient监控
      • QPS
      • RT
  • consumer 主机监控

    • cpu
    • load
    • memory
  • pubsub服务器:

    • 机器CPU使用情况
    • 内存增长情况
  • 消息延迟情况

    • 对比数据库期望发送时间和实际发送时间

初步压测结论

  • pubsub服务2c-6g,单实例;Consumer服务2c-6g,单实例

  • 定时消息提交接口并发数1000,思考时间为1000ms,模拟QPS为1000的场景,平均RT在好几秒,吞吐量只有200左右

  • 单个消费者TPS只有60左右

  • pubsub服务及Consumer服务资源使用率均保持在很低水平

  • pubsub服务young GC频繁

离预期相距甚远,预期是可以承受上万条消息积压仍能保持毫秒级别的误差,所以优化目标为:

  • 提升pubsub定时消息接口单实例QPS至3000+,99.99% RT 在200ms内;
  • 提升Consumer消费TPS至10000+

排查过程记录

排除中间件及网络因素

在pubsub服务实例上ping TiDB、RocketMQ服务地址,延迟均为5ms内,先排除网络原因。

使用相同的压测脚本,尝试压了测试环境的pubsub服务,测试环境的压测结果很正常,QPS达到预期设置的1000,平均RT在10ms内,测试环境使用的是MySQL,生产环境使用的是新申请的阿里云服务器搭建的TiDB,怀疑是TiDB服务端配置或者其他原因导致影响性能。

将生产环境上pubsub使用的TiDB换为同网络环境的MySQL,压测情况并无变化,排除。

RocketMQ服务在相同网段进行过压测,压测结果正常,排除。

由于测试环境和生产环境压测结果大相径庭,很长一段时间的排查方向都指向了生产环境k8s的网络、组件间的延迟等,于是又把pubsub部署至生产环境的一台物理机上,结果任然保持不变。

客观测试了一下测试环境和生产环境的网络差异:

并发数 1,思考时间 1000ms

测试环境:

生产环境:

分析

每次接口提交,大致产生的跨进程交互如下:

内容测试环境耗时生产环境耗时
施压机到pubsub主机0.180.6
pubsub主机到tidb,开启事务0.064.9
pubsub主机到tidb,运行 sql0.064.9
pubsub主机到rocketMQ,生产消息0.34
pubsub主机到tidb,提交事务0.064.9
总计0.6619.3
本场景压测RT平均值7.9840.93

结论:

由于测试环境的物理距离问题,天然有至少5倍左右的性能差异,所以测试环境的压测结果超出预期的理想,得益于各组件的网络低延迟,但是生产环境的网络延迟属于正常范围,还需进一步排查。

借助Arthas及Skywalking

使用 Arthas 的 trace 命令,对接口的主要逻辑方法进行耗时追踪:

发现真正执行逻辑的代码只耗时13ms左右,但是执行方法之前,有一个500多ms的耗时。

使用skywalking观察耗时很长的请求,结果如下:

结论相同,在执行SQL前,有一个很长的等待时间,初步定位到问题,怀疑是数据库连接池的问题。

暴露prometheus指标

pom文件中添加:

        <dependency>
            <groupId>io.micrometer</groupId>
            <artifactId>micrometer-registry-prometheus</artifactId>
            <scope>runtime</scope>
        </dependency>

添加配置:

# 对外暴露所有监控指标
management:
  endpoints:
    web:
      exposure:
        include: "*"
  endpoint:
    prometheus:
      enabled: true # 激活普罗米修斯
    health:
      show-details: always # 健康值总是展示细节
  metrics:
    export:
      prometheus:
        enabled: true # 指标允许被导出

启动服务后,访问:/actuator/prometheus

可以看到默认连接池最大数量是10,大量并发情况下,获取连接池时,耗费了大量的时间。

修改数据库最大连接池数

场景一至场景四:并发数 500,思考时间 400 ms

场景一

pubbsub 调整内容:

  1. tomcat 线程数改为 64
  2. connection 连接池数量改为 10

分析

  1. cpu 使用率不高,execute 前执行时间较长,怀疑是获取 jdbc connection 时间较长,更改 hikari 连接池数量为 32
  2. 压测平台与 sk 查看不同,是因为存在请求积压,即等待了一段时间后,才开始被执行

场景二

pubsub 调整内容:

  1. tomcat 线程数改为 64
  2. connection 连接池数量改为 32

第一次压测:

第二次压测:

分析:

  1. 从 skywalking 看执行时间已经明显缩短,应该是增大了 connection 连接数导致
  2. 第二次执行压测时,性能已明显上升,应该是第一次压测时连接池还没有达到指定数量,都要重新建立连接,导致耗时较长
  3. cpu 使用率升高,说明线程使用 cpu 的时间多了起来,是正确的优化方向

场景三

pubsub 调整内容:

  1. tomcat 线程数改为 64
  2. connection 连接池数量改为 64

分析:

  1. 用在等待连接方面的耗时几乎已经没有
  2. cpu 还有一定空闲资源,进一步增大线程数和对应的连接数

场景四

pubsub 调整内容:

  1. tomcat 线程数改为 128
  2. connection 连接池数量改为 128

分析:

  1. cpu 已到达瓶颈,调整线程数量收益应该不太明显了
  2. 这时调整 gc 相关参数应该会有些收益

场景五

尝试提升压力,观察 RT 情况:并发数 500,思考时间 400 ms

分析:

  1. CPU 使用率下降,可能是 c2 代码优化已经完成
  2. TPS 上涨,RT 没有明显变化,继续加压

场景六

并发数 500,思考时间 300 ms

分析

  1. cpu 没有到达瓶颈,继续加压

场景七

并发数 500,思考时间 200 ms

场景八

pubsub 调整内容:

  1. tomcat 线程数改为 200
  2. connection 连接池数量改为 200

分析:

CPU已打满,继续增加线程数无提升,线程数已接近理想状态值。

结论

CPU核数、Tomcat线程数、数据库连接池数比例约为:

1:100:100

将pubsub服务CPU核数修改为:8c,Tomcat线程数、数据库连接池数修改为:800

Consumer消费能力优化

初始状态:

  • Consumer服务:2c-6g,启动一个消费者
  • RocketMQ Topic读写队列总数均为48
  • pubsub服务:8c-6g,单实例
  • 消费者TPS:60左右

增加消费者

将消费者增加至20个:

消费服务资源使用情况:

定时消息回调接口:

消费者TPS:

可以看到增加消费者后,消费能力明显提升,但是个服务资源使用率都未达到上限。

继续增加Consumer数量,TPS并没有提升。

增加Topic Queue数量

Queue总数:96

(这里测试消费能力,可以只修改读队列数)

消费服务实例数单个服务消费者数量消费者总数消费TPS
1203000左右
140403000左右
220405000左右
240805000左右

以上压测过程中,pubsub服务和消费者服务的资源使用率都只维持在中等水平,单个消费者实例上消费者数量达到40时,出现个别报错:

第一次出现这个异常,刚开始没仔细看异常信息,以为是pubsub回调接口处理不过来了,没有在意,造成了一个排查疏漏,走了一些弯路。

Queue总数:192

消费服务实例数单个服务消费者数量消费者总数消费TPS
120203000左右
140403000左右
220405000左右
420808500左右
5201009500左右
6201209500左右

Queue总数:900

消费服务实例数单个服务消费者数量消费者总数消费TPS
4301209000左右
53015012000左右

由于每一轮压测成本过高,已经达到预期,没有继续进行后续压测。

消费者在30*4时,再次出现大量异常:ConnectionPoolTimeoutException

初步结论:

  • 增加消费者数量和 Topic队列数,可以有效提升消费者TPS

  • 目前单个消费服务配置20~30个消费者达到消费峰值,但是消费服务和pubsub服务的资源使用还远远没到瓶颈。

  • 消费服务内有http客户端,怀疑是瓶颈在http连接池上,而之前出现的异常:ConnectionPoolTimeoutException,正式由于http客户端使用了连接池,从连接池内获取http连接超时导致的。

调整消费程序http最大连接池数

消费程序中的http客户端使用的是apache提供的CloseableHttpClient,有两个线程池核心参数:

  • maxTotal:连接池最大连接数
  • defaultMaxPerRoute:每路由最大连接数

maxTotal默认是200,defaultMaxPerRoute默认是50,而消费程序中只会调用一个接口,所以实际只有50个连接是可用的,将defaultMaxPerRoute修改为200。

消费者TPS有提升,不再有报错信息,消费者服务CPU消耗有提升。

Consumer参数微调

对Consumer进行了几个参数的调试,包括:consumeThreadMax、consumeThreadMin、consumeMessageBatchMaxSize、pullBatchSize,其中consumeThreadMax、consumeThreadMin两个参数修改后对消费能力有较明显提升,其余两个对于顺序消费场景无明显提升。

consumeThreadMax、consumeThreadMin默认为20,修改为40:

CPU消耗有提升,加大consumeThreadMin后,消费者TPS可以瞬间达到消费峰值

继续加大consumeThreadMin后,消费TPS出现下滑。

Tips:Consumer客户端会根据消费线程的压力,动态增加消费线程:

总结

优化总结

  • pubsub服务资源为8c-6g,核数和Tomcat线程数比例为1:100、Tomcat线程数和数据库连接池数比例为1:1;
  • 基于以上配置,pubsub单实例定时消息接口QPS理想值为4500左右、回调接口QPS高于此;
  • 目前Consumer最佳配置为单实例30个消费者,每个消费者配置consumeThreadMin=40,按理说可以通过增加资源,来增加单实例上的消费者数量,减少实例数,但是通过测试发现不可行,由于时间原因没有继续探索。
  • 增加Topic 读队列数和消费者数量可以提升消费能力,本次测试过程中,消费者和队列数比例达到1:2时,获得最大消费TPS;
  • pubsub程序初始时没设置xmn,导致young GC比较频繁,后续根据观察各区域内存的变化情况,将xmn设置为总堆大小的3/4。

经验总结

  • 压测时间需要尽量长一点,需要等编译优化完成后,程序的性能才能达到一个稳定值,尤其是对刚启动的项目;
  • 优化过程中要注意小细节,对任何出现的异常都需要精确定位后再继续,避免大方向错误;
  • 借助Trace工具、prometheus指标暴露插件能更快定位问题;
  • 若性能达到瓶颈时,资源使用率没有提升,需要考虑各环节中使用到的线程池、连接池的限制;
  • 注意版本不同时,一些配置的变化,如:Tomcat线程数配置,spring 2.3版本之前:server.tomcat.max-threads,spring 2.3版本之后:server.tomcat.threads.max
  • 做优化前,需要有一个整体的规划,对整体的性能瓶颈点有一个预先的认知,包括服务本身、使用到的各中间件配置、客户端配置等,逐个进行排除

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/541478.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Redis:哨兵模式——可以理解为主从复制的升级版

如果不懂什么是主从复制&#xff0c;可以看我的上一篇文章&#xff0c;这一篇文章与上一篇文章息息相关&#xff0c;可以先去大概去了解一下。 Redis:主从复制_通过此功能实现对内存上的数据更好的保护_不想睡醒的梦的博客-CSDN博客 什么是哨兵模式&#xff1f; 上一篇文章主…

【穿针引线】基于ElAdmin项目论Spring Security的工作原理,实现前后端OAuth2单点登录,源码分析

【穿针引线】基于ElAdmin项目论Spring Security的工作原理&#xff0c;源码分析 序一、核心类1.1 SecurityContext 安全上下文1.2 网安适配器WebSecurityConfigurerAdapter1.3 认证器 Authentication1.4 信息认证提供者1.4.1 抽象用户信息认证提供者 AbstractUserDetailsAuthen…

01-C++-VSCode配置C++环境(windows)

VSCode配置C环境 前言安装VSCode安装mingw编译器VSCode配置C环境 前言 本篇来学习写使用VSCode配置C环境 安装VSCode 下载地址&#xff1a;VSCode 下载后路next安装即可 安装mingw编译器 下载地址&#xff1a;mingw64 点击Files 向下拉&#xff0c;点击下载(建议windows6…

Python系列之字符串和列表

感谢点赞和关注 &#xff0c;每天进步一点点&#xff01;加油&#xff01; 目录 一、字符串 1.1 字符串的定义与输入 1.2 字符串的拼接与格式化输出 1.3 字符串的下标 1.4 字符串的切片和倒序 1.5 字符串的常见操作 二、列表-List 2.1 列表的常见操作 2.2 列表合并和拼…

【云原生-深入理解Kubernetes-2】容器 Linux Cgroups 限制

文章目录 系列文章目录&#x1f479;关于作者回顾一、Docker Engine 和 Hypervisor 区别二、容器比虚拟机受欢迎&#xff1f;优势劣势 三、Linux Cgroups 限制使用 Cgroups 子系统配置文件- 前提知识- 限制 ✊ 最后 系列文章目录 【云原生-深入理解Kubernetes-1】容器的本质是进…

一文理解RocketMQ

概述 RocketMQ是阿里开发的基于JMS的分布式消息中间件&#xff0c;是由纯JAVA实现的。放弃了比较重量级的Zookeeper作为注册中心&#xff0c;使用自研的NameServer实现元数据的管理&#xff0c;支持事务消息&#xff0c;顺序消息&#xff0c;批量消息&#xff0c;定时消息以及消…

软件体系结构复习题

2020 论述题 统一软件过程RUP&#xff1a;用例驱动、以架构为中心的迭代增量开发 一个用例可能需要多个功能来实现&#xff0c;一个功能也可能被用于多个用例 边界类、控制类、实体类 顺序图、通信图、定时图、交互概述图 扩展关系《extend》、包含关系《include》、…

python将图片批量排版插入Word文档

今天分享一个将图片批量插入word文档的小脚本&#xff0c;本脚本可以实现 jpg\png图片&#xff0c;可以混合在一起&#xff01; 首先 我们需要设置每页word文档的排版需求&#xff0c;如&#xff1a;每页6张图片&#xff0c;一共是3行2列 pics_per_page 6&#xff0c;这是每页…

解说天下之操作系统

解说天下之操作系统 本文由桌案drawon (https://www.drawon.cn)&#xff0c;云晶&#xff08;https://www.yunjingxz.com&#xff09;创始人根据多年从业经验&#xff0c; 从操作系统的起源&#xff0c;应用分类&#xff0c; 设计分类&#xff0c;以及资源使用角度对操作系统进…

leetcode 数据库题 175~185

leetcode 数据库题 175. 组合两个表176. 第二高的薪水177. 第N高的薪水178. 分数排名180. 连续出现的数字181. 超过经理收入的员工182. 查找重复的电子邮箱183. 从不订购的客户184. 部门工资最高的员工185. 部门工资前三高的所有员工小结 嗯。。。数据库题目就不贴原题内容了&…

00后是真卷不过,工作没两年,跳槽到我们公司起薪20K都快接近我了

在程序员职场上&#xff0c;什么样的人最让人反感呢? 是技术不好的人吗?并不是。技术不好的同事&#xff0c;我们可以帮他。 是技术太强的人吗?也不是。技术很强的同事&#xff0c;可遇不可求&#xff0c;向他学习还来不及呢。 真正让人反感的&#xff0c;是技术平平&…

cocosCreator自动化打包工具

前言&#xff1a; 使用nodeJs脚本化Cocos Creator自动化构建、编译。 版本&#xff1a;cocosCreator2.4.5。 简述&#xff1a;使用自动化构建-编译工具前提&#xff0c;你终端上配置了相关的环境&#xff0c;比如JDK、NDK、SDK&#xff08;对于原生平台&#xff09;&#xff0c…

Express实战个人订阅号实现网站登录

今天我们来实现一个使用个人订阅号实现网站的功能&#xff0c;后端使用的是 express 。其它框架原理基本一致&#xff0c;只是定义路由或返回响应数据部分代码跟 express 有所出入。先来一波效果图&#xff1a; 1. 前言 20 年 3 月在掘金写过一篇文章&#xff0c;介绍了使用 e…

使用cmake 构建构建新项目的时候,编译提示库找不到怎么办?

昨天帮其他部门同事解决Linux下Qt编译找不到Qt 依赖库 core的问题。过程很有特征性&#xff0c;可以推广到Linux下使用cmake构建项目时找不到库文件的广泛性问题。 先上图&#xff0c;结合事情经过讲述&#xff1a; 事情经过&#xff1a; 这里给大家介绍第一个重点&#xff1…

秘塔写作猫

秘塔写作猫是集AI智能写作、多人协作、改写润色、文本校对等功能为一体的AI原生创作平台&#xff0c;可以帮助不同群体大幅提升写作效率和生产力。 接下来小编就带大家了解一下该软件具体的一些功能&#xff0c;不论你是学生、上班族还是自媒体从业者等&#xff0c;该工具绝对可…

箭头函数与普通的函数有什么区别-M

箭头函数与普通的函数有什么区别 1、写法不同 在 js 中&#xff0c;像命名式函数、函数表达式都称为普通函数。对于普通函数&#xff0c;需要用function关键字来声明。而箭头函数则不需要使用function关键字&#xff0c;在箭头前面的括号里面写参数&#xff0c;后面的大括号里…

Linux 安装MySQL-5.7.30

1.官网下载MySQL 进入官网https://www.mysql.com/ 从下载页面下载社区版本其中社区版本免费&#xff0c;免费的午餐不提供技术支持. 页面中MySQL Enterprise Edition是企业版&#xff0c;企业版收费但是会提供技术支持&#xff0c; 点击图中红框下载社区版本 选择Download Arc…

AC,AP以及三阶段项目

特点&#xff1a;access&#xff1a;连接终端设备 只能通过1个vlan trunk&#xff1a;交换机与交换机相连 可以通过多个vlan 共同特点&#xff1a;交换机的端口收发数据的规则&#xff1a; 收&#xff1a;如果收到的数据&#xff0c;没有携带任何标签&#xff0c;则使用该端口…

01SpringCloudRibbon负载均衡

Ribbon负载均衡 Ribbon Eureka帮我们集成了负载均衡组件&#xff1a;Ribbon&#xff0c;简单修改代码即可使用。 什么是Ribbon&#xff1a;客户端负载均衡组件 开启负载均衡 1、Eureka中已经集成了Ribbon&#xff0c;所以我们无需引入新的依赖&#xff0c;直接修改代码。 2、…

Redis的主从集群搭建与配置

文章目录 Redis主从集群模式搭建过程分级管理容灾冷处理 Redis主从集群模式 Redis的集群模式 主从复制模式&#xff1a;利用主从复制原理&#xff0c;一主多从架构。读写分离&#xff0c;主节点可读可写&#xff0c;从节点只能提供读服务。哨兵模式&#xff1a;哨兵实现了自动化…