调优zuul1.x(基于arthas)

news2024/11/20 13:41:39

0. 目录

      • 1. 说在前面
      • 2. 关键arthas命令
      • 3. 弯路
        • 3.1 铺天盖地的宣传下,对于zuul1.x性能信心不足。
        • 3.2 zuul1.x 避免开启`zuul.debug.request`配置,尤其是在性能调优时。
        • 3.3 redis的读取存在破20ms+的情况。
      • 4. 额外收获
        • 4.1 在线动态启停ZuulFilter:
        • 4.2 快速共享文件
      • 5. 本次优化相关
        • 5.1 定位根源
        • 5.2 优化后
      • 6. 经验总结
      • 7. 参考

1. 说在前面

虽然标题是"调优zuul",但"你一个做业务开发的,轮不到你来做基础技术底层的调优;正如JVM不需要调优,需要调优的是你的业务代码"。本次最终找到的原因也再次印证了这个思路。

所以本文的重点也不是介绍具体的调优点,主要是希望借着这个机会总结下:

  1. 调优过程中arthas命令的使用
  2. 期间走过的弯路,以及带来的经验

最终目的是下次类似的问题出现时候,能够尽量短的时间内解决。

2. 关键arthas命令

单次的调用性能参考意义不大,重要的是平均的耗时。所以在本次基于arthas的性能优化中,monitor 命令使用频率是最高的。

####### 一次对比dashboard —— 所有的自定义PreXxxFilter与整体的Zuul执行耗时
monitor -c 5 -E com.netflix.zuul.http.ZuulServlet|cn.com.xxx.apigateway.filter.Pre* service|preRoute|route|postRoute|run|shouldFilter

####### 异步执行,重定向 
#	https://arthas.aliyun.com/doc/async.html
trace cn.com.xxx.apigateway.filter.PreHeaderFilter serviceName_serviceSourceType -n 3 '#cost>10' > 11111XX.out &

####### redis性能验证. 压测20秒里,这样的个数大约在 190+
monitor -c 5 cn.com.xxx.common.util.RedissonUtil  get '#cost > 10'
#######压测20秒里,单次读取超过1ms的,这样的个数大约在 949 ; 而总共的读取次数大约是 52795.。。。 占比 1.79%
monitor -c 5 cn.com.xxx.common.util.RedissonUtil  get '#cost > 1'

####### 更新完,确认下是否更新到位
jad --source-only com.xxx.yyy.zzz.MController

####### 动态trace
# https://arthas.aliyun.com/doc/trace.html#%E5%8A%A8%E6%80%81-trace
trace cn.com.xxx.apigateway.filter.PreHeaderFilter  run -n 3 '#cost>16'
# 另外起一个shell界面
telnet localhost 3658
trace cn.com.xxx.apigateway.filter.PreHeaderFilter serviceName_serviceSourceType --listenerId 9

####### 抓取指定traceId,去查相应的链路日志
watch cn.com.xxx.apigateway.filter.PreHeaderFilter serviceName_serviceSourceType '{#cost,@org.apache.skywalking.apm.toolkit.trace.TraceContext@traceId()}'  -n 5  -x 3 '#cost>10'  -f


####### AOP切面直接attach
monitor -c 5 cn.com.xxx.common.anno.cache.XxxxExpCacheableAspect getContext
monitor -c 5 cn.com.xxx.common.anno.cache.XxxxExpCacheableAspect *  # 所有方法一次性整体预览

# 找出被AOP的, 实际类型
sc *ServerManagerFuncCaller

3. 弯路

待到问题解决,回头看的时候发现确实走了不少弯路。

3.1 铺天盖地的宣传下,对于zuul1.x性能信心不足。

这导致的直接结果就是搞了裸springcloud-gateway, 裸zuul.1x,裸zuul1.x+undertow,移除所有的自定义zuulFilter的当前架构版本,当前架构版本进行反复对比。最终也是证明了springcloud-gateway性能上确实有优势(大约比裸zuul1.x快了一倍),但是与当前待优化的场景(90ms+)关系并不大。

总结:性能优化不要一上来就怀疑基础框架不行,尤其是当你这性能表现远未达到需要优化底层技术架构的时候。

3.2 zuul1.x 避免开启zuul.debug.request配置,尤其是在性能调优时。

这个配置会导致zuul启用DeepCopy(源码位置:FilterProcessor.processZuulFilter(xxx) —> RequestContext.copy()),这会急剧降低zuul1.x的性能表现。(直接破200ms+)

总结:开启这个本来是为了观察每个ZuulFilter的详细请求耗时,但没想到成了主要的性能消耗来源。在这里插入图片描述

3.3 redis的读取存在破20ms+的情况。

这也是优化后期,导致我们额外浪费半天的原因。在过往的意识里一直认为"性能问题最有可能出现在IO上",导致拿arthas去专门捕获这种情况,进一步强化了这种错误的方向排查。

总结:相信监控给出的结果(图2展示了性能瓶颈不在redis),不要预设了方向再去找证据(图1展示了确实存在性能远超一般情况的特殊情况 —— 单次请求耗时在40ms+)。
图1
图2

4. 额外收获

4.1 在线动态启停ZuulFilter:
zuul:
  debug:
    # 开启这个对于性能影响巨大
    request: false 
# =================> 
#   ZuulFilter.isFilterDisabled() 方法中生效
# 以下配置无需预先定义, 在需要时候添加即可
  PostApiVersionPostFilter:   # Filter的名称
    post:                     # Filter的类型
      disable: false          # 是否禁用, 默认是false, 即启用该Filter.
  Pre3rdPartyRequestFilter:
    pre:
      disable: false
4.2 快速共享文件

在不同的服务器之间快速传递文件,除了scp或者FTP等工具之外,还可以借助linux服务器上内置的python:

############# 1. 导航到您想要共享文件的目录
cd /x/y

############# 2. 开启web静态文件访问服务
# python3
python -m http.server

# python2
python -m SimpleHTTPServer

############# 3. 服务器将会启动并监听默认端口 8000。您可以在浏览器中输入 http://<ip>:8000
http://<ip>:8000

5. 本次优化相关

5.1 定位根源

    // ====== 严重的性能问题...
//    private StandardEvaluationContext getContext(Method method, Object[] args) {
//        // 获取被拦截方法参数名列表(使用Spring支持类库)
//		 ------- 这个 LocalVariableTableParameterNameDiscoverer 类上的注释里其实已经说了: 建议尽量缓存该实例, 也就是不要每次都新建...
//        LocalVariableTableParameterNameDiscoverer discoverer = new LocalVariableTableParameterNameDiscoverer();
//        String[] paraNameArr = discoverer.getParameterNames(method);
//
//        // SPEL上下文
//        StandardEvaluationContext context = new StandardEvaluationContext();
//        // 把方法参数放入SPEL上下文中
//        for (int i = 0; i < paraNameArr.length; i++) {
//            context.setVariable(paraNameArr[i], args[i]);
//        }
//        return context;
//    }

	// ====== 替换为以下实现...
    /**
     * 获取方法上的参数
     *
     * @param method 方法
     * @param args 变量
     * @return {SimpleEvaluationContext}
     */
    private StandardEvaluationContext getContext(Method method, Object[] args) {
        // 初始化Spel表达式上下文
        StandardEvaluationContext context = new StandardEvaluationContext();
        // 设置表达式支持spring bean
        context.setBeanResolver(new BeanFactoryResolver(applicationContext));
        for (int i = 0; i < args.length; i++) {
            // 读取方法参数
            MethodParameter methodParam = getMethodParameter(method, i);
            // 设置方法 参数名和值 为sp el变量
            context.setVariable(methodParam.getParameterName(), args[i]);
        }
        return context;
    }
    
    private static final ParameterNameDiscoverer PARAMETER_NAME_DISCOVERER = new DefaultParameterNameDiscoverer();
    
    /**
     * 获取方法参数信息
     *
     * @param method         方法
     * @param parameterIndex 参数序号
     * @return {MethodParameter}
     */
    static MethodParameter getMethodParameter(Method method, int parameterIndex) {
        MethodParameter methodParameter = new SynthesizingMethodParameter(method, parameterIndex);
        methodParameter.initParameterNameDiscovery(PARAMETER_NAME_DISCOVERER);
        return methodParameter;
    }
5.2 优化后

90ms 降低到 35+ms
在这里插入图片描述

6. 经验总结

  1. 基础框架不需要调优,需要调优的是你的代码。
  2. zuul1.x中,zuul.debug.request平时不要开。
  3. 千万级别流量,zuul1劣势不大。
  4. 相信监控直观反应的结果。大胆假设,小心求证;求证过程中要相信监控反馈的结果,不要预设结论之后找证据
  5. 先montior看平均时间,确定方向后再trace,否则容易被少数情况迷惑住,搞偏了方向绕一大圈。
  6. 这种能够稳定复现的,解决起来是最简单的了。
  7. arthas很好用。

7. 参考

  1. Arthas-文档 本次的最大功臣,虽然因为自身预估出现偏差,它进一步强化了这种偏差…但归根到底,还是人的问题

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

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

相关文章

前端页面左右布局,点击左div增加动画过渡效果

效果图如下 以下代码基于Vue2 <template><div class"container"><div class"left-section" :style"{ width: widthLeft vw }" click"toggleRightSection"></div><div class"right-section" :s…

阿里5年经验之谈 —— 接口测试用例如何编写?

接口测试用例如何编写&#xff1f;下面简单给大家讲解一下。 接口测试用例是目前软件开发中不可或缺的一个重要部分&#xff0c;因此编写接口测试用例同样重要。 接口测试用例的作用非常明显&#xff0c;它能够帮助我们了解产品正在考验、调整它如何表现在特定情境之下、产品…

工欲善其事,必先利其器,五款实用的办公软件推荐

​ 你电脑中用的最久的软件是哪些&#xff1f;以下是否有你曾经使用过的软件呢&#xff1f;工欲善其事&#xff0c;必先利其器&#xff0c;今天继续分享五款实用的办公软件。 1.屏幕调节——f.lux ​ f.lux是一款可以根据时间和地点自动调节屏幕亮度和色温的软件&#xff0c;…

除静电感测型离子风棒在无尘车间中的应用

除静电感测型离子风棒是一种能够检测静电并及时释放离子的离子风棒&#xff0c;在无尘车间中应用非常广泛。以下是除静电感测型离子风棒在无尘车间中的应用&#xff1a; 防止静电干扰&#xff1a;在无尘车间中&#xff0c;静电干扰会影响电子元器件和仪器设备的正常工作&#x…

Airpods的电池健不健康不直观,但例行检查很重要!如何检查Airpods的电池健康状况

有几种不同的方法可以检查Airpods的电池健康状况。第一种方法是转到iPhone上的“设置”应用程序&#xff0c;然后选择“电池”在这里&#xff0c;你将看到当前通过蓝牙连接到iPhone的所有设备的列表。 如何在Airpods上检查电池健康状况 从这个列表中选择你的Airpods&#xff0…

Elasticsearch Relevance Engine---为AI变革提供高级搜索能力[ES向量搜索、常用配置参数、聚合功能等详解]

Elasticsearch Relevance Engine—为AI变革提供高级搜索能力[ES向量搜索、常用配置参数、聚合功能等详解] 今天要介绍的 Elasticsearch Relevance Engine™ (ESRE™)&#xff0c;提供了多项用于创建高度相关的 AI 搜索应用程序的新功能。ESRE 站在 Elastic 这个搜索领域的巨人…

【Linux】从零开始学习Linux基本指令(二)

&#x1f6a9;纸上得来终觉浅&#xff0c; 绝知此事要躬行。 &#x1f31f;主页&#xff1a;June-Frost &#x1f680;专栏&#xff1a;Linux入门 &#x1f525;该文章主要了解Linux操作系统下的基本指令。 ⚡️上一篇可以看这里 &#x1f449;【Linux】从零开始学习Linux基本指…

GEE:计算和打印GEE程序的执行时间

作者:CSDN @ _养乐多_ 本文记录了计算和打印程序的执行时间的Google Earth Engine (GEE)代码,并举例说明。 大家在执行GEE代码的时候,有时候为了对比两个不同的脚本,不知道代码执行花费了多少时间。本文记录了打印代码执行时间的函数,并举了一个应用案例说明。可以知道…

如何轻松打造数字人克隆系统+直播系统?OEM教你快速部署数字人SaaS系统源码

数字人做为国内目前最热门的人工智能创业赛道&#xff0c;连BAT都在跑步入局&#xff0c;中小企业更是渴望不渴及。但随着我国数字人头部品牌企业温州专帮信息科技有限公司旗下灰豚AI数字人平台的开源。使得中小企业零门槛可以轻松打造灰豚AI数字人一模一样的平台。灰豚数字人A…

CentOS | 添加普通用户并授权sudo

sudo -i adduser peter passwd peter whereis sudoers nano /etc/sudoers添加一行新用户到root组 ## Allow root to run any commands anywhere root ALL(ALL) ALL peter ALL(ALL) ALL https://blog.csdn.net/qq_41980405/article/details/105291959https://b…

Opengauss数据类型强转

Opengauss数据类型强转 解决方法案例 解决方法 使用cast(需要转换的字段 as 转换后的类型) 函数进行强转。 提示&#xff1a;以下是本篇文章正文内容&#xff0c;下面案例可供参考 案例 问题&#xff1a;统计各类图书的平均价格&#xff0c;其中在图书表中price字段为money型…

android 查看项目代码总行数

1、 find . -name "*.java" -or -name "*.xml" -or -name "*.kt" -or -name "*.c" |xargs grep -v "^$"|wc -l 2、 使用插件 这里可以自己选择过滤的文件类型 添加要剔除的文件类型、文件目录 这里还有个坑就是记得…

电脑回收站清空后数据如何恢复?还不知道方法的赶紧看

电脑回收站是存放被删除文件的临时存储空间&#xff0c;在清空回收站后无法直接访问这些文件。然而&#xff0c;对于那些意外清空回收站后才发现还有重要数据的人来说&#xff0c;恢复这些文件并不是不可能的。本文将介绍有效的方法&#xff0c;帮助读者恢复电脑回收站清空后的…

如何创建CSR证书请求文件?

在沃通数字证书商店下单后&#xff0c;需要在服务器生成CSR证书请求文件及私钥文件&#xff0c;私钥文件自主妥善保存&#xff0c;CSR文件通过后台提交给沃通。 本篇文章主要介绍如何使用沃通WoSignCode客户端工具生成CSR文件。wosigncode.exe工具下载地址&#xff1a;https://…

云计算认证有哪些?认证考了有什么用?

云计算作为一项快速发展的技术&#xff0c;对人才的需求持续增长。无论是男生还是女生&#xff0c;只要具备相关的技能和知识&#xff0c;都可以在云计算领域找到就业机会。 目前入行云计算最好最便捷的方式就是考证&#xff0c;拿到一个云计算相关的证书&#xff0c;就能开启…

Android之使用QBadgeView给TabLayout顶部栏设置数量角标,数值可更新

TabLayout搭配ViewPager、Fragement使用可看另一篇文章&#xff1a; Android中TabLayoutViewPagerFragment实现顶部导航栏 本文主要描述给TabLayout的某一栏添加角标&#xff0c;数值可更新&#xff1a; 一、效果 二、TabLayout使用 1、xml文件中 <com.google.android.m…

kvm 不同存储池中卷的复制 virsh vol-create-from 的简单使用

virsh vol-create-from 命令介绍 主要用的就是这四个参数 virsh vol-crate-from --help使用方式 sdbpool : 要复制到的存储池名称 (这个是最终文件粘贴的池) virsh pool-list/opt/vol01.xml &#xff1a; 这个是你将要复制卷的xml // sdcvol1&#xff1a; 复制目标 // 导…

【漏洞复现】Casdoor-任意文件读取

目录 【漏洞介绍】 【资产测绘Query】 【漏洞复现】 【漏洞介绍】 Casdoor系统static存在任意文件读取漏洞 【漏洞描述】 Casdoor是一个基于OAuth 2.0、OIDC、SAML 和 CAS 的&#xff0c;UI-first的身份和访问管理(IAM)/单点登录(SSO)平台。使用 Go 和react开发&#xff0…

外汇天眼:外汇投资入门必看!做好3件事,任何人都能提高交易胜率

近年来外汇市场愈来愈热络&#xff0c;许多投资人看准世界金融变化的趋势&#xff0c;纷纷开始入场布局&#xff0c;期望把握行情大赚一笔。 如果你之前没有做过外汇交易&#xff0c;建议最好先透过「外汇天眼学院」学习各种相关的知识与技术分析&#xff0c;等到对外汇有一定的…

JDBC-day06(数据库连接池)

八&#xff1a;数据库连接池 1. 传统连接数据库的模式 在使用开发基于数据库的web程序时&#xff0c;传统的模式基本是按以下步骤&#xff1a; 在主程序&#xff08;如servlet、bea&#xff0c;ns&#xff09;中建立数据库连接进行sql操作断开数据库连接 传统的模式存在的问…