当前位置:首页 > 编程笔记 > 正文
已解决

调优zuul1.x(基于arthas)

来自网友在路上 174874提问 提问时间:2023-10-19 18:23:18阅读次数: 74

最佳答案 问答题库748位专家为你答疑解惑

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 beancontext.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-文档 本次的最大功臣,虽然因为自身预估出现偏差,它进一步强化了这种偏差…但归根到底,还是人的问题
查看全文

99%的人还看了

猜你感兴趣

版权申明

本文"调优zuul1.x(基于arthas)":http://eshow365.cn/6-19774-0.html 内容来自互联网,请自行判断内容的正确性。如有侵权请联系我们,立即删除!