一千零一个优化-0001-记一次接口性能的“边缘”优化

背刺来袭

“S市的小伙伴们普遍反应测试平台贼不好用,都快要放弃另起炉灶了!” S市的业务测试负责人给上了重重的一记背刺。小树懵在原地,脑袋都是嗡嗡的,脸上也烧了起来。相比之前的反馈,这次生猛了许多。当然理智的小树这时候会开始沉思了,到底是哪里做的不好。背后的问题其中一项是有一个接口请求超过13秒,而且这个接口在使用的主流程中还特别频繁。那这个问题究竟是怎么来的呢,那我们就得从小树刚进入公司H市分部开始说了…

背刺的由来

小树一进入公司,就迅速的搭起了一个基于metersphere的开源测试平台。也顺利推广了开来,开始安然无事,最多就是会有些不知道组件怎么使用的问题,平平安安的度过了3个月。3个月后,小树也正常开始展开做其他相关的平台维护和开发工作,期间偶尔会有些声音抱怨平台有的时候会比较慢,也不知道是开玩笑还是真有问题,一般大家都是笑笑就过了。小树确认过后,没能重现也就不了了之了。

时间转眼又过了2个月,S市的小伙伴反映卡顿的频次逐步升高,这不禁让男主怀疑起来是否有什么问题,于是和H市的同事了解情况,可H市的同学表示快确实不能说是快,但也还能接受。随后S市断断续续的再反馈着,但是也不是特别急迫,于是又带着问题过了2月,从平台初建到现在,小树发现,2地的同事的自动化脚本水平越来越好,从最初的写个单接口写个校验,到最近的模块化,规模化变化都是非常惊人的。脚本的数量级和脚本的复杂程度也不可同日而语。特别是S市的脚本有着翻天覆地的变化,单个脚本的能力都是多样且强大。

话说回来,就在这个时候,H市也陆续有同学开始反馈该接口的响应体感上的不能接受。这个时候小树才正式介入,定位接口,然后通过前端缓存接口内容,减少调用次数,从而减缓延迟带来的体感不适。原以为故事到这里就结束,又恢复天下太平了。

事与愿违,就在又过去2个月后的今天,小树懵在了原地,问题并没有解决,而且S市同学已经不想再忍了,最后捅到了主管那里。其实小树并不会因为主管的压力感到伤感,只是会对反馈感到内疚不安。于是就又开始了重新和问题斗智斗勇。

提刀上马

经过了之前一次调优的经验,小树很快便找到了问题接口的代码,又重新读了一遍,这次明显比之前更快。这里的循环做的恐怕有性能问题,递归加数据库(io)查询,想不慢也难,小树灵机一动,心想:这个平台是个开源平台,想必其他人也有这个问题,很可能已经被开源组织优化了吧。抱着试一试的心态,小树提刀上马找起了开源代码上是否有更新记录。功夫不负有心人,问题块的代码确实被优化过了。

同步了最新代码,本地起了服务并开启了调用链路跟踪监控请求的时间开销。

image.png

不难看出,整个接口请求时间开销只用不到240毫秒,这可比线上的13秒快了不知道多少倍。于是开开心心的结案了,坐等应用发布。问题应该就此解决了,小树开开心心的去做其他工作了。

不出意外,就要出意外了

终于到了发布窗口,发布完后,小树直接找来几个S市同学写的自动化脚本,直接尝试了下这个慢接口对应的功能。性能有提升却不大,从原来的13秒左右降低到了10秒左右。整体功能体验上还是不能接受,太糟糕了。小树感觉到十分无力,迷茫。心说:怎么可能呢,明明我本地秒级的东西到了线上要十秒级。数据库本地连接比服务器连接更慢,要说有变化也应该是服务器上更快才对。

于是用arthas在云服务器上也追踪了下方法的调用时长。整体数据表现和本地表现差不多,甚至确实更快一点。只要130毫秒左右。

小树不解之余,一次次的trace ,折腾了好一阵子,最后发现即使是整个接口方法也只需要不到200毫秒。整个arthas的排查过程花了不到十分钟,却让小树如度春秋,更是雪上加霜,更加没有头绪没有章法。

再战

小树原先盯着Chrome浏览器的开发者模式窗口接口时长上写的9.3秒的眼睛,也慢慢的失去了光泽。 突然间眼里泛起了微光。这里有点点奇怪啊,小树心里萌生了一些东西。因为小树的鼠标焦点移到了瀑布图上的时候,小树发现:

image.png

这里有一个点很奇怪,为什么请求的发送时间比请求处理时间还长这么多? 这个是怎么回事。于是小树查看了下请求数据。瞬间被吓到了,一个请求体居然有6.3MB,这个接口返回只有不到250B,完全是2个数量级。

image.png
然后再联系小树公司使用的都是国外的云服务器,单纯ping云服务都有200多毫秒延迟,小树便大胆猜想了一下,如果网络比较差的环境下,那6.3MB的传输花费远比服务处理时间更久。之所以本地调试的时候无感知,因为本地前后端的传输速度可以忽略不计,因此本地不能重现线上的问题。

小树通过前后端gzip加压解压的方式进行了优化,由客户端和服务端进行数据的展开,减少网络上的消耗,顺便在紧急发布窗口重新发布了测试平台。

//  前端压缩请求体,公共方法
export function zipString(content) {
  return btoa(pako.gzip(content, {to: 'string'}));
}
// 后端解压请求体,公共方法
public static String ungzip(String content) {
    byte[] bytes = Base64.getDecoder().decode(content);
    try (ByteArrayOutputStream out = new ByteArrayOutputStream();) {
        IOUtils.copy(new GZIPInputStream(new ByteArrayInputStream(bytes)), out);
        return out.toString();
    } catch (IOException e) {
        throw new RuntimeException(e);
    }
}

image.png

请求整体时间从原先的13秒直接压缩到秒级。发布以后问题终于得到了解决,小树心中的大石头终于放下了。等待第二天的到来,好找S市的同学求证最终效果。

小树的总结

为什么这些问题之前没有发生,小树最后整理了下信息,其实自动化平台已经逐步深入人心,同学们的思路也慢慢被打开,使用的方式方法也会越来深入,所以请求内容也就越来越大,小脚本的情况下,这个请求内容也不会有这么大。只能说小树的新目标又有了,为了适配小树的公司环境,小树需要做更多的改造让测试平台能适配发展中的公司了。

有了这次的经验,小树对待技术,又多了一些感悟,在这次问题的解决中,其实问题相对还是比较简单,很快便被定位和解决了。看问题还是得要从头到尾推敲一下,因为无论是开发的工具也好,方法也罢,都是一点点积累起来的,难保某一个小分支小细节不会犯错,所以看待问题的时候还是得有全局视野,去找寻这些问题和方向。

随后小树便开开心心的在晚上12点的钟声敲响前5分钟,关掉了电脑,钻进了被窝.不久就进入了梦乡。

…然后…在某个阴暗的角落,有一个bug正在静静地注视着小树…


欢迎关注微信公众号:树叶小记,发现更多精彩

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 可以的,以下是用 Python 实现冒泡排序的代码: def bubble_sort(arr): n = len(arr) for i in range(n): for j in range(, n-i-1): if arr[j] > arr[j+1] : arr[j], arr[j+1] = arr[j+1], arr[j] return arr arr = [64, 34, 25, 12, 22, 11, 90] print("排序前的数组:") print(arr) print("排序后的数组:") print(bubble_sort(arr)) ### 回答2: 冒泡排序是一种简单直观的排序算法,它的基本思想是通过不断比较相邻两个元素的大小,将较大的元素逐步交换到右侧,从而实现排序的目的。 下面是用Python实现冒泡排序的代码: ```python def bubble_sort(arr): n = len(arr) for i in range(n-1): for j in range(n-i-1): if arr[j] > arr[j+1]: arr[j], arr[j+1] = arr[j+1], arr[j] # 测试 arr = [5, 2, 9, 1, 7] bubble_sort(arr) print(arr) ``` 在冒泡排序算法中,外层循环用于控制排序的趟数,内层循环则负责每一趟的比较处理。在每一趟中,通过比较相邻元素的大小,将较大的元素一步步交换到右侧。 这段代码首先定义了一个名为`bubble_sort`的冒泡排序函数,参数`arr`是待排序的数组。接着,函数内部定义了两个循环,外层循环从0遍历到`n-1`,内层循环从0遍历到`n-i-1`。在每一轮内层循环中,通过比较相邻元素的大小,若前一个元素大于后一个元素,则进行交换操作。 最后,通过调用`bubble_sort`函数对给定的数组进行排序,并打印结果。运行结果为`[1, 2, 5, 7, 9]`,表示数组已经按从小到大的顺序排列好了。 ### 回答3: 冒泡排序是一种简单直观的排序算法,其思想是通过相邻元素之间的比较和交换,将较大(或较小)的元素逐渐沉到底部。下面是用Python编写的冒泡排序算法: ```python def bubble_sort(arr): n = len(arr) for i in range(n-1): for j in range(n-i-1): if arr[j] > arr[j+1]: arr[j], arr[j+1] = arr[j+1], arr[j] return arr # 示例 array = [64, 34, 25, 12, 22, 11, 90] sorted_array = bubble_sort(array) print("排序后的数组:", sorted_array) ``` 这段代码中,我们首先定义了一个函数`bubble_sort`,该函数接受一个输入数组`arr`作为参数。通过双重循环,外层循环控制需要进行比较的轮数,内层循环用于比较相邻元素的大小。 在每一轮比较中,我们通过比较`arr[j]`与`arr[j+1]`的大小关系,如果前者大于后者,则交换两者的位置。通过不断地重复这个过程,直到所有元素都正确地排序。 在示例中,输入数组为`[64, 34, 25, 12, 22, 11, 90]`,经过冒泡排序后,输出结果为`[11, 12, 22, 25, 34, 64, 90]`。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值