热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

性能压测诡异的Requests/second响应刺尖问题

最近一段时间都在忙着转java项目最后的冲刺,前期的coding翻代码、debug、fixbug都逐渐收尾,进入上线前的性能压测。虽然不是大促前的性能压测要求,但是为了安全起见,需要摸

最近一段时间都在忙着转java项目最后的冲刺,前期的coding翻代码、debug、fixbug都逐渐收尾,进入上线前的性能压测。

虽然不是大促前的性能压测要求,但是为了安全起见,需要摸个底心里有个数。

毕竟这次转java的服务都是集团核心公共服务(主要是订单域服务)。(等我们顺利上线了,我再来好好总结下其中的坎坷和壮举。)

废话不多说了,直接进入主题。

由于这次压测主要重点是关注正向的两个核心订单服务,下单服务、查单服务。查单服务初步压测下来问题不大,主要是db的索引和cache的问题。

下单服务有两个核心接口,预订单查询、创建订单。预订单查询主要是订单的前置状态的结算页汇总计算(不仅是结算页),不落具体订单,如,各种促销、卡券码、虚拟币的规则计算等等。

创建订单逻辑稍微复杂点,对周边的系统及中间件依赖也比较多,所以需要重点关注,至少心中要有数,哪怕下游的哪个服务的性能有问题,在下次大促的时候可以优化掉。

(并不是说所有性能问题都需要及时优化,只要保证能撑得起业务量的一定范围就好,因为性能优化无止境,需要把握好节奏。)

提交横向压测前我们需要自己先过一遍,这样才能加快压测的效率,由于时间比较紧再加上客观的环境问题,我将服务中几个没有压测环境的依赖去掉。(有关压测的一些实践我将在下篇文章好好总结下,这里就不展开了。)压测了几轮(时间差不多30分钟左右。),消除了一些环境、代码、依赖的障碍,提交横向走压测流程,接着就去忙其他的事情了。(诡异的问题比较多~_~,mybatis pagehelperplugin好像也有点并发问题,还没定位到,不知道是用的不对还是什么情况,继续排查,有结论了我在总结分享下。)

1.压测报告:

7

8

1

并发用户数没变化,平均响应时间没变化,但是request/second奇怪了。我相信大多数开发的直觉就是fullgc了,我也一样。

立马去看下服务器的GC监控,同时看下程序的GCer配置是CMS。(CMS主要解决低延迟问题《深入理解JAVA虚拟机》)

2.查看服务器监控情况:

JAVA GC:

2

没发现fullgc,再看下几个其他的系统资源是否有异样。

cpu:

3

刺尖的几个点CPU idle 基本都是100%,us也是0%,非常奇怪。再看下其他的资源。

network:

4

也是比较奇怪的,receive到是挺正常的,send基本为0了,感觉像是某个调用或者发送停止了,能接受请求,但是对下游的调用貌似停止了。

memory:

5

内存咋一看好像有点问题,但是了解linux 内存计算方式和使用原理都知道这其实问题不大。(下篇文章中会具体讲解关于压测的时候各个指标如何查看和计算,在压测时候重点关注top中的swap区。)

我程序里面基本上没有用到什么大量的磁盘操作,基本上就一个日志输出,别的没有了。(linux cache区不管是读还是写都会被cache住,会在cache里维护一个逻辑地址空间。我将在下篇文章中演示出来,每当我删除磁盘的日志文件,cache区都会瞬间释放。https://www.ibm.com/developerworks/cn/linux/l-cache/index.html)

重点是关注下JAVAGC 容量:(java程序的内存分配由“内存分配器+GC完成”《java性能优化权威指南》)

6

这是压测的下单服务机器资源情况。

3.查看DB情况:

9

10

11

12

看了下DB情况,也没啥异样,都是在相同的时间点,一下子负载没有了,时间都能对上。网络、磁盘、CPU都没有活动。

4.分析

上面图中有一幅图有点问题,不知道大家看出来了没有。就是我下单服务的应用服务器的网络流量有问题,receive、send对不上。

4

我们分析下,receive、send不配对意味着什么,我们有200并发,延迟1秒启动,基本上跑上个十几分钟,你能大概想象出200并发的请求空间路线图么。其实它会呈现出每秒钟都有请求进来,这是压力机的请求,每秒也会有请求出去,去访问它所依赖的服务或者中间件。如果,我们设想从压力机为开始点,把请求和响应想象成一个圆,那在圆的任何一个角度上都有请求和响应。

我们注意看下,DB的网络流量图,它就是比较正常的,没有请求没有发送。而应用服务器有点说不通,只有进来的没有出去的,这段时间内到底在干嘛,而且分布很平均。

5.排查

其实这个时候有一个结论,就是服务器其实没有瓶颈,不管是应用服务器还是DB、cache。那问题应该是在程序方面。(性能分析由上至下、由下至上集合分析《java性能优化权威指南》)。

开始尝试排查依赖服务,下单服务主要依赖商品、促销。cache不是问题,因为本地有一级缓存,而且缓存的过期时间对不上,压测环境的redis和MySQL在一台机器上。所以DB没有问题,基本上redis应该也没啥问题。(这台机器很强悍)还有部分的依赖业务方的接口我已经注释掉了,不会有依赖。

开始怀疑商品、促销,但是我之前分别对这两个服务进行过压测,这两个服务基本上都是命中cache,QPS基本上接近18000。现在也只好对这两个服务再进行一轮详细的压测。

结果很遗憾,没啥线索,性能很好。

开始排查线程池问题,是否有block线程,通过jstack 打印出线程,基本上都是XNIO的condition wait,也没有啥不正常。因为下单服务的其他接口都挺正常的,线程池问题应该不大。下单成功之后有意个hold的场景,就是hold虚拟币、卡券码等等之类的逻辑,这里面使用了fiexd线程池(5个,设置了饱和策略及日志输出。),问题也不大。

开始排查日志,restful-slow.log,jdbc-slow.log、错误日志等等,一顿cat… grep…wc Cl,啥也没有异常。(shit开始冒汗了。。。)

只能上大招了,开始尝试注代码,然后压测,逐个尝试,先注释DB、然后线程池hold逻辑、然后发送消息。(无赖之举。。。)

6.浮出水面

等我尝试注释掉发送消息的逻辑时候发现问题不出现了,有希望了。开始进去看代码,没啥逻辑,走的是spring 的RabbitTemplate.convertAndSend 方法。(这是个同步方法,没有任何声明说他是async的。)

/**发送消息*/
template.convertAndSend(messageConfig.getExchangeName(), routingKey, message, amqpMessage -> {

翻了下资料,没啥特殊的使用要求。

顺便看了下配置文件,发送消息走的是qa环境,这个我知道,因为当时压测环境的rabbitmq一时还没好,而且我们走的是先定义再使用queue的流程,所以如果要用我需要先上去配置好才能使用。当时图省事就先用了,自己压测下来也没啥问题,毕竟MQ的设计吞吐量都很高的,TPS足够我们用的,再加上我之前也压过qa的MQ没啥问题。

(资源没隔离是因为一些客观原因,有时候压测环境是临时搭建的。用到qa环境的中间件还有codis,但是codis基本是二级缓存,所以问题不大,先过。(回头没辙再来找它。)

搞来了qa环境的rabbitmq服务器账号,同时打开rabbtimq管理界面中的dashboard。开始重点关注这台服务器。(top命名打开,P\M看下rabbitmq各项指标。)

13

问题一如既往的出现了(我已经能接受了~_~,它要是不出现我才想死尼,已经来回折腾很久了。)很好,rabbtimq dashboard也出现刺尖了。

14

现在基本上是rabbtimq服务器的性能问题了,可能你会觉得问题找到了。但是我还是无解,为什么出现这个问题,为什么时间这么规律,肯定有蹊跷,继续排查,到底是rabbtimq服务器的CPU问题还是disk问题,还是network问题。这次重点看下top。

15

16

17

18

同样问题的出现CPU不正常,而且wait 率比较高。是不是可以这样推理,wait率高了,导致大量线程(子进程)挂起,所以看起来CPU利用率占的就高,也说的通。(先这么假设,来验证它就知道了)

有一点我可以肯定,根据rabbtimq推送消息原理,一个消息必须发送给所有监听的queue,这些queue必须落盘才算这次publish成功,才会返回。(可以参考《Rabbitmq in Action》)

也就是说发送消息不是发送给exchange就结束了,我们配置的是topic模式,这个消息类型后面有4个queue,同时这几个queue都有消费者在获取消费消息。但是由于获取消息的方式是pull模式,也不会存在多大的并发获取消息的情况。而且这些queue里面的消息都非常多,当我不压的时候CPU也不高,pull消息的开销对服务器来说network多点,CPU不会太多。

上图中的cpu wait率有点不正常是因为exchange同步写4个queue且落盘,所以有这个问题。

基于这个推理,我考虑用一个空exchange来接受消息,根据原理指导,exchange收到消息之后如果发现没有任何queue可以投递就直接丢弃了。

压测下来一切正常,没有出现刺尖情况(真爽~_~),cpuwait 正常0。基本上定位到问题了。是因为rabbtimq本身的负载不够了,性能跟不上所以导致这个问题,这也算加深了rabbtimq的部分原理。

在基于这个推理,我用了一个不持久化的queue来接受消息,也就是说这个消息是不会持久化的,cpuwait应该是0。

压测下来一切正常,cpuwait为0(心情无比的顺畅)。

提交横向第二轮压测。

7.打脸

等我在开会的时候,压测兄弟找我,哥哥那个问题又出现了。

19

(我一时蒙蔽,我擦什么情况。)调整了下,仔细看了下那个刺尖的出现的时间比以前长了。原来大概十五分钟,现在要半小时。由于qa环境机器没有安装压测监控工具,不知道那段时间里发生了什么。(压测执行时间1小时)

我之前都是30分钟,我尝试用空exchange压了一小时(已是周五晚24:00点左右,洗澡睡觉,明早上看结果)。

早上起来看没出现那个问题。为什么我用不持久的queue还有问题,而且这个queue是没有任何consumer的,这已经涉及到rabbtimq的底层原理了。rabbtimq用的是erlang语言写的,看源码一时半会估计路都找不到。还是想其他办法。

又尝试用持久化queue来压测一把,看下到时候啥情况,仔细盯着rabbtimq dashboard,果然又出现了。(计算机问题永远不存在巧合,不确定。)

20

21

23

22

注意看下图中的In memory,shit原来落盘了,哪怕你设置不持久化为了内存利用率,它会将消息落盘,注意看Persistent没有任何消息。消息总量1.1G,内存中只有119MB。

为什么会有那么大的disk write。由于大量的磁盘写入,导致publish消息的时候block了。具体为什么会这样就要去研究rabbtimq源码了。这些在rabbtimq的配置中应该有策略的,由于不是太熟悉rabbtimq,所以这里就只好先告一段落了。

8.总结

能隔离环境的尽量隔离,排查环境问题最头疼,但是有时候又无法避免。(下篇压测文章分享下,环境问题的排查方式和工具)

遇到问题一定要搞清楚根源,就算找不到根源也知道把它限定在某个范围内,比如限制到DB、操作系统等等。


推荐阅读
  • 本文是Java并发编程系列的开篇之作,将详细解析Java 1.5及以上版本中提供的并发工具。文章假设读者已经具备同步和易失性关键字的基本知识,重点介绍信号量机制的内部工作原理及其在实际开发中的应用。 ... [详细]
  • 如何利用Java 5 Executor框架高效构建和管理线程池
    Java 5 引入了 Executor 框架,为开发人员提供了一种高效管理和构建线程池的方法。该框架通过将任务提交与任务执行分离,简化了多线程编程的复杂性。利用 Executor 框架,开发人员可以更灵活地控制线程的创建、分配和管理,从而提高服务器端应用的性能和响应能力。此外,该框架还提供了多种线程池实现,如固定线程池、缓存线程池和单线程池,以适应不同的应用场景和需求。 ... [详细]
  • 在iOS开发中,基于HTTPS协议的安全网络请求实现至关重要。HTTPS(全称:HyperText Transfer Protocol over Secure Socket Layer)是一种旨在提供安全通信的HTTP扩展,通过SSL/TLS加密技术确保数据传输的安全性和隐私性。本文将详细介绍如何在iOS应用中实现安全的HTTPS网络请求,包括证书验证、SSL握手过程以及常见安全问题的解决方法。 ... [详细]
  • Python全局解释器锁(GIL)机制详解
    在Python中,线程是操作系统级别的原生线程。为了确保多线程环境下的内存安全,Python虚拟机引入了全局解释器锁(Global Interpreter Lock,简称GIL)。GIL是一种互斥锁,用于保护对解释器状态的访问,防止多个线程同时执行字节码。尽管GIL有助于简化内存管理,但它也限制了多核处理器上多线程程序的并行性能。本文将深入探讨GIL的工作原理及其对Python多线程编程的影响。 ... [详细]
  • 基于Web的Kafka管理工具Kafkamanager首次访问Web界面的详细配置指南(附图解)
    首次访问Kafkamanager Web界面时,需要对Kafka集群进行配置。这一过程相对简单,用户只需依次点击【Cluster】>【Add Cluster】,按照提示完成相关设置即可。本文将通过图文并茂的方式,详细介绍每一步的配置步骤,帮助用户快速上手Kafkamanager。 ... [详细]
  • 大类|电阻器_使用Requests、Etree、BeautifulSoup、Pandas和Path库进行数据抓取与处理 | 将指定区域内容保存为HTML和Excel格式
    大类|电阻器_使用Requests、Etree、BeautifulSoup、Pandas和Path库进行数据抓取与处理 | 将指定区域内容保存为HTML和Excel格式 ... [详细]
  • 深入解析 Synchronized 锁的升级机制及其在并发编程中的应用
    深入解析 Synchronized 锁的升级机制及其在并发编程中的应用 ... [详细]
  • 性能测试中的关键监控指标与深入分析
    在软件性能测试中,关键监控指标的选取至关重要。主要目的包括:1. 评估系统的当前性能,确保其符合预期的性能标准;2. 发现软件性能瓶颈,定位潜在问题;3. 优化系统性能,提高用户体验。通过综合分析这些指标,可以全面了解系统的运行状态,为后续的性能改进提供科学依据。 ... [详细]
  • 服务器部署中的安全策略实践与优化
    服务器部署中的安全策略实践与优化 ... [详细]
  • 深入解析CAS机制:全面替代传统锁的底层原理与应用
    本文深入探讨了CAS(Compare-and-Swap)机制,分析了其作为传统锁的替代方案在并发控制中的优势与原理。CAS通过原子操作确保数据的一致性,避免了传统锁带来的性能瓶颈和死锁问题。文章详细解析了CAS的工作机制,并结合实际应用场景,展示了其在高并发环境下的高效性和可靠性。 ... [详细]
  • 在最近的WWDC17大会上,苹果公司宣布了多项重要更新,其中一项是macOS High Sierra 10.13 Final的正式发布。这一版本经过优化,显著提升了系统的稳定性和响应速度,为用户在任何Mac设备上提供了更加流畅的使用体验。本文将详细介绍如何在Windows系统中利用VMware虚拟机软件安装并运行macOS High Sierra 10.13 Final,帮助用户在非苹果硬件上体验这一先进操作系统。 ... [详细]
  • 线程能否先以安全方式获取对象,再进行非安全发布? ... [详细]
  • 资源管理器的基础架构包括三个核心组件:1)资源池,用于将CPU和内存等资源分配给不同的容器;2)负载组,负责承载任务并将其分配到相应的资源池;3)分类函数,用于将不同的会话映射到合适的负载组。该系统提供了两种主要的资源管理策略。 ... [详细]
  • SAP 实用技巧:如何高效终止运行中的进程
    在ERP系统中,通过事务代码SM66和SM51可以查看服务器上的进程执行情况。在某些特殊情况下,可能需要终止占用资源的进程。本文详细介绍了几种高效终止进程的方法,并提供了操作步骤和注意事项,帮助用户在遇到问题时快速解决。 ... [详细]
  • 尽管我们尽最大努力,任何软件开发过程中都难免会出现缺陷。为了更有效地提升对支持部门的协助与支撑,本文探讨了多种策略和最佳实践,旨在通过改进沟通、增强培训和支持流程来减少这些缺陷的影响,并提高整体服务质量和客户满意度。 ... [详细]
author-avatar
射手座的双子55
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有