使用Zipkin-SourceMonitor-AliCheck代码优化

微服务拆分过程中的代码优化

    • 1、摘要:
    • 2、工具组合简单介绍
      • 2.1、Zipkin
      • 2.2、SourceMonitor
      • 2.3、AliCheck
    • 3、工具使用
      • 3.1、Zipkin
      • 3.2、SourceMonitor
        • 3.2.1、函数圈复杂度(Function Complexity)
        • 3.2.2、函数深度(Block Depth)
    • 4、AliCheck
    • 5、总结

1、摘要:

系统做微服务拆分后,有很多业务流程比较慢,这时我们需要使用有效的方法来定位那些地方有问题。其实最好的方法还是利用系统化的检查工具来做这件事情。这里提供一套代码检查工具组合。
注:我们现在用的是 dubbox 微服务架构。

2、工具组合简单介绍

2.1、Zipkin

用于微服务,分布式链路跟踪。我们用zipkin 的主要目的是辅助分析业务流程的性能问题和系统拓扑图的生成并发现调用链出现环的情况。

2.2、SourceMonitor

一个“度量”工具,可以做代码静态质量检查工具,我们用它来找到函数圈复杂度(Function Complexity)比较高的函数。Sonar 也是一款很好的工具,但是配置起来太麻烦,sourceMoitor相对比较轻量级。

2.3、AliCheck

这个是阿里开源的代码规范性检查工具,也可以发现一些潜在的bug。

3、工具使用

3.1、Zipkin

提前说明:dubbo RPC调用会通过RPCfilter生成span 数据,但是服务内部各个类实例之间调用,是通过Spring的Beanfactory 来实现 并不会经过RPCFilter,所以没有span数据。
(1)生成系统拓扑图
测试环境运行一段时间后可以在zipkin Dependencies 中 看到系统拓扑图,也就是系统之间的调用依赖关系,原则上系统拓扑图应该是有向无环图,如果出现环,就说明代码调用出现混乱需要调整,或者系统边界拆分不合理,需要调整系统间的表模型边界。如下图,明显比较乱,调用是有环的,service和 order-service 之间有,common-service 和 user-service 之间也有。
使用Zipkin-SourceMonitor-AliCheck代码优化_第1张图片
(2)找到问题
下面要做的就是要找到调用环。在 zipkin 的find a trace 页面 设置好搜索条件:
使用Zipkin-SourceMonitor-AliCheck代码优化_第2张图片可以看到请求在各个微服务之间数据流转调用的函数,和在各个微服务中执行的时间。如下图:
使用Zipkin-SourceMonitor-AliCheck代码优化_第3张图片(3)最后就是要分析优化

第一步 消除调用环:
服务调用的Depth 为4,其中有条调用路径 service-> order-service->service->user-service 明显不是一个有向无环图。需要把其中的环去掉。采取的方式有两种,第一种方式:service 提前把 order-service 需要的数据查询出来,传递给order-service,这样调用关系就是:service-> order-service。但是这样改容易出现的问题,会把上层服务做的太重量级了,不符合微服务拆分的原则。第二种方式:将接口下沉到下一层服务user-service 里面去。这样调用关系就是:service-> order-service->user-service。 但是在做这种层次拆分的时候,要考虑是否会影响系统边界。如果要读写的表模型恰好在 user-service,那就再好不过了,如果不在 就要权衡上面两种方式的利弊,根据实际情况来定。
优化后的trace 信息如下图,明显已经没有环了,但是order-service.orderservice/orderservicemethod: 10.446s 时间还是没有变化。继续优化,毕竟性能优化不是一蹴而就的,而且最终会涉及到数据层:数据库或redis。
使用Zipkin-SourceMonitor-AliCheck代码优化_第4张图片
第二步 性能优化
可以看到请求耗时绝大部分都在函数:order-service.orderservice/orderservicemethod: 10.446s。但是我们用的RPCFilter 无法获取到微服务内部各个函数调用的span 数据。这时我们采用另外一种方法获取微服务内部函数调用耗时:打印日志,每个函数都在开始执行和结束执行的时候,都打印一行日志,日志中会记录打印时间,开始和结束的时间差就是函数耗时,如下图:
在这里插入图片描述
根据关键词找到 start 和end 之间的执行日志,每行日志都会记录执行时间,并且每行日志打印的线程也是一样的。如下图:
使用Zipkin-SourceMonitor-AliCheck代码优化_第5张图片
最后发现 整个流程中 redis 读取数据的次数太多了。
使用Zipkin-SourceMonitor-AliCheck代码优化_第6张图片优化方法其实很简单:提供一个按需查询的方法,需要哪些就查询哪些key。
CapitalDetailsDto selectRedisCapital(Long custId,String …key);
优化以后 订单的执行时间明显降低很多。
在这里插入图片描述

3.2、SourceMonitor

这里有一个博客可以参考下: https://www.cnblogs.com/hrhguanli/p/4797448.html。我们用sourceMoitor主要就是用来检查:函数圈复杂度(Function Complexity)和函数深度(Block Depth)。尤其是大家都在用的一些工具类,必须要优化。

3.2.1、函数圈复杂度(Function Complexity)

圈复杂度指示一个函数可运行路径的数目,下面语句为圈复杂度的值贡献1:if/else/for/while语句,三元运算符语句,if/for/while推断条件中的"&&"或“||”,switch语句,后接break/goto/ return/throw/continue语句的case语句。catch/except语句等。
相应有最大圈复杂度(Max Complexity)和平均圈复杂度(Avg Complexity)。

3.2.2、函数深度(Block Depth)

函数深度指示函数中分支嵌套的层数。相应有最大深度(Max Depth)和平均深度(Avg Depth)

下面是一张我们检查后得到的一张图:

使用Zipkin-SourceMonitor-AliCheck代码优化_第7张图片作为一个工具类HistogramMetric的calculateMetric函数需要优化下。如下图代码片段:
使用Zipkin-SourceMonitor-AliCheck代码优化_第8张图片优化方法:优化判断逻辑减少if/else 的个数,有些情况可以 用 ?号表达式替代 if/else。但是一般逻辑定了,if/else 的个数很难减少。这时只能将if { } else { } 内部代码抽取出来 放到一个独立的函数里作为公共函数,如下代码片段,分出了sort 和notSort 函数。

使用Zipkin-SourceMonitor-AliCheck代码优化_第9张图片

优化后重新检查下代码,发现圈复杂度比之前好多了。
使用Zipkin-SourceMonitor-AliCheck代码优化_第10张图片

4、AliCheck

阿里编码规约扫描插件,支持Eclipse 和IntelliJ IDEA。详细使用方式可以去github 上看下:https://github.com/alibaba/p3c,这里不做详细介绍。这里要讨论的是什么时候做代码规范检查,我觉的是要实时检查,越早发现问题越好。就像《程序员修炼之道:从小工到专家》提到的破窗户”的理论,一扇破窗户,只要有那么一段时间不修理,就会渐渐给建筑物周围的居民带来一种废弃感。于是又一扇窗户破了,人们开始乱扔垃圾,出现了乱涂乱画,慢慢的更严重的结构破坏开始了。在相对较短的一段时间里,建筑就被损毁的超出了业主想象的程度,也超出了业主愿意修理的程度,而废弃感则变成了现实!那我们如何解决呢?很简单,当第一扇破窗户出现时就及时的修理。

5、总结

代码优化涉及的方面很多,比如性能优化,规范化,圈复杂度优化,合理的重构等等,要做这些事情,光靠同事间的肉眼走查是不够的。我觉得最好是使用一套有效的工具来协助解决这些问题。本文只是给出一种解决问题的方式。

你可能感兴趣的:(分布式,微服务)