当前位置: 首页 > news >正文

讲个故事:关于一次接口性能优化的心里路程

        这是一个程序猿写的第一个故事,请各位懂行的客官静下心来,慢慢品读。就知道我为什么要单独写一个文章来记录这次过程了,因为实在是太坎坷了......

背景介绍     

        近期项目投产时遇到一个问题,投产后在验证时发现大部分用户系统登录非常慢。由于没有找到具体原因。只能回退到投产前的版本。

        后来通过分析生产的日志,发现是登录接口中有段代码涉及到频繁切换数据源,这段代码耗时比较长。

        到这里我先简单说下项目,用到oracle和gbase数据库,oracle数据库和业务相关,gbase数据库主要用来存在一些日志的。默认数据源是oracle。项目的一个filter里会把所有请求后台接口的相关信息记录在gbase库中,另外登录接口也会把登录成功与否的情况也记录在gbase库。

        比较耗时的代码就是登录接口有两处分别向gbase库不同表写日志,每次都需要先切换到gbase,写完要切回oracle数据源,而且这2个逻辑紧挨着。所以这里就会4次切换数据源。本次投产增加了其中一次向gbase写库,还有就是本次投产filter向gbase写库的逻辑。

        到这里,基本所有背景交代完了。我先把这次投产向gbase写库的代码注释了。发现登录耗时确实下来了。通过工具性能压测响应时间下来了,但是tps非常低,不到10。这个接口优化路程才真正开始了.........

#排查过程#

                                第一季:老子代码没问题,怀疑网络节点限流

        我们去掉了一次想gbase写库的逻辑,也就减少了2切换数据源,还剩一次原代码就保留的写gbase库。但是发现这个写gbase还是比较耗时,大概900ms左右,其他业务代码耗时200ms。我就加了线程池,把写gbase库的逻辑放到线程里,包括2次切换数据源。按理说这时候tps会提升不少,结果出人意料,tps还不到10.还是很低。(这里压测的都是测试环境的登录接口。并发量分别50、100、150)测试人员各种并发量压测,tps都是非常低。

       到这里开始怀疑不是代码问题,是不是pod之外的网络节点(比如F5)做了限制。为了验证这个想法我让测试人员在测试环境压测健康检查的接口,健康检查接口非常简单,没有数据库交互,直接返回固定的字符串。竟然发现这个健康检查接口压测的tps也是不到10。这更坚定了我猜测的中间网络节点限流了。健康检查接口的tps都不到10,这肯定是网络节点限流了啊。

        后来通过找相关人员,得到结论F5没有限制任何请求。我靠,奔溃了,那问题在哪啊??????

        这时突然想起,以前的一个同事给项目在filter加过一个流控。(好像发现了新大陆),经过了解这个流控的阈值 是每秒请求1000。我们的还不到10呢,人家流控肯本限制不了我们,但是还是不死心,把流控的代码逻辑注释了,果然tps还是很低,和流控没有任何关系.........

                        第二季:压测本地健康检查接口,发现代码猫腻

        网络节点没问题,流控没问题。说真的不知道是哪里出问题了。一个简单的健康检查接口都tps不到10。怎么才能排除是不是网络节点的问题呢?压测我本地代码,同时把filter的流控的逻辑注释了,还是压测健康检查接口。结果是tps还是非常低不到10。

        完犊子了,这个tps就跨不过10了吗

        由于被压测结果震惊了,却忽略了这次压测测试的目的是什么?直接压测我本地,tps还很低,这中间可没有了任何网络节点,流控也注释了,那只能是我代码问题了。只要找到方向,那就好说了,虽然具体原因还是不清楚。

        上次投产回退的代码,我在filter里加了向gbase写日志的逻辑,难道、或许,应该是这里出问题了吧。那这个好办,把filter里写gbase的逻辑放到线程池里完成,你在耗时去子线程里耗时去吧,别干扰我主线程。

        修改代码后,继续让测试人员压测我本地的健康检查接口。

        结果呢?结果就是tps还是不到10。我当时就原地石化了.........

                                第三季:成也线程池,败也线程池

                程序猿轻易不言败,我们就是踩不死的小强。

                我放了个大招,把filter里写gbase库的逻辑注释了,继续压测我本地健康检查接口。奇迹终于出现了,tps到了190左右。这就不对了,为什么线程池没解决问题呢?我用的线程是实现了Callable,我们都知道这个线程有返回值。我们可以获取每个线程的返回结果。但是我们记录日志,不需要等待返回结果。我就换了一种实现方法,就是实现Runable接口,这个线程就是不会返回结果。(这里只讲故事,不讲技术啊,我就不帖想代码了,如果还有不了解这些的小伙伴,可以参考我以前的关于线程池的文章,关于线程池我写过好几篇文章,其中一篇是:ThreadPoolExecutor线程池详解)

        把线程池相关逻辑更改后,压测本地健康检查接口,tps终于上来了,到达200左右。既然找到问题了,就继续优化我的登录接口,把写gbase库的逻辑放到线程里,以前登录接口的线程也是实现Callable接口,都改成实现Runable接口,奶奶滴,以前还真不知道,这两种写法差别这么大。说实话这块的知识点,还真不知道,以前只知道,要想得到线程执行结果用Callable,不需要线程结果用Runable。我就想了反正都是线程,用哪个不是用,就用Callable呗,万一以后领导想要每个线程执行结果呢?毕竟领导脑袋里想啥,我们有不知道。跑偏了,我们继续讲故事,不吐槽领导了

        登录结果代码的线程池优化后,继续压测我本地的登录接口的tps到155了,这个完全可以满足我们的业务需求了。毕竟是内部系统,没那么大请求量。

        然后就是在测试环境验证,测试环境压测登录接口,50并发情况下,tps到190左右,嗯,还不错,就是偶尔测试环境会慢........

        各位看官,是不是认为到这里就结束了,因为解决了登录慢问题,tps也上来了嘛。嗯,我也是这么认为的,就这样我们就投产了。。。。。

                                      

                                        第四季:忽略小细节,造成大隐患

         路漫漫其修远兮,吾将上下而求索!信心满满,经过这段时间折腾,终于解决了这个问题。终于可以投产了.......啦啦啦啦啦

          然而,现实很残酷,没想到打脸来的如此之快,脸打的如此之响!!!!我们又双叒叕投产失败,回退了..........啊啊啊啊啊。

        这次投产后,登录是没问题,不慢了,就是登录系统后,首页的某些特定操作比较慢,其他的大部分功能都正常。这就很奇怪,如果说我这次优化失败了,测试环境没问题,就是生产也是就某些操作慢而已嘛,怎么是我代码问题呢,绝对不是。当然这是我内心的想法。

        后来发现,慢的操作的接口里有写gbase库,什么这里也写gbase库?

        后来想想,写也没事啊,gbase是本来就是大数据的应用场景,TB级别的数据查询库比oracle快多了。反正就是内心深处不认为是我代码问题,这是不是程序猿的通病啊.......

        通过分析生产的日志发现,filter里大部分线程写gbase库的耗时达到了23s左右(幸亏我当时在线程里记录了耗时情况,看了多打印日志还是比较好的,要不这次问题很难发现)。那问题就明朗了,gbase不抗揍啊。

        这里再简单交代下项目,系统登录后,首页加载会调用大概20多个后端接口获取数据,如果刚投产成功,会存在好多用户登录验证功能,一个用户登录后就调20个接口,如果是50个用户同时登录,就是1000次调用后台接口,这时filter就会同时写gbase库1000次。所以登录后其他操作涉及到写gbase库的都比较慢。

        这时候我突然想到测试环境压测时,偶尔会出现某些操作比较慢,由于我们的关注点一直在登录接口的tps上,把这个忽略了。还有个关键点,就是我们在测试环境压测,是在晚上加班时压测的,这时间点用我们系统的人少,也没人反应,只是测试人员登录测试环境发现的,也是偶然现象,因为并不是所有操作都慢嘛,只有涉及的写gbase库的操作才会慢。也就没有当回事。

        通过这次发现gbase和oracle的区别。打个比喻吧。oracle和gbase是2个剑客高手。

        oracle剑客的优点是,面对众多对手都是小卡拉米、菜鸟时,得心应手。但是对手中有几个高手,那oracle就不行了。

        gbase剑客的优点是,对手是多个和自己水平一样的高手,这能轻松应对。但是对手是一群菜鸟,那gbase就难应付了。

        注:这里得小卡拉米、菜鸟指的是每次和数据库交互的数据量大小

最后终结

        故事到目前为止算是讲完了,还是做个总结吧。

        第一,线程池那块知识还是掌握不牢固,比如这次Runable和Callble的两个接口,除了线程有无返回值的区别,前者的tps比后者要高的。

        第二,在进行某个接口压测时,一定要站在全局考虑,是否数据库能抗住,是否会影响项目其他功能使用。

        第三,就是不要对自己写的代码太自信了。。。。。。。

         哈哈,细心的人是不是发现了,你问题没解决啊!由于业务其他原因,我们暂时把filter里和登录接口中写gbase的日志逻辑先注释了。

        虽然领导说先不记录日志了,但是我还想研究下,在向gbase记录日志的情况下,怎么解决现在的问题。这里就给大家留下猜测吧,我后续在把以后的故事发展在补充上。

        有人会问,为什么今天不写完呢?因为我们今天也投产,就是把相关写gbase逻辑的代码注释了,当然还有其他功能投产。各位保佑我这次投产顺利吧,都回退2次了,在回退就拜拜了
       

       

相关文章:

讲个故事:关于一次接口性能优化的心里路程

这是一个程序猿写的第一个故事,请各位懂行的客官静下心来,慢慢品读。就知道我为什么要单独写一个文章来记录这次过程了,因为实在是太坎坷了...... 背景介绍 近期项目投产时遇到一个问题,投产后在验证时发现大部分用户系统登…...

Centos7升级到openssh9.9

openssh9.9 是2024.9.20出的最新版ssh。因为客户扫描出一大堆centos7的漏洞,全是这个openssh的,好多补丁,所以索性升级到最新版。 需要自己制作rpm包,这个我是不懂,照这个来: Linux服务器升级openssh9.9最…...

使用 STM32F407 串口实现 485 通信

准备工作 了解485通信基本概念与原理:RS485通信详解_485通讯de接什么口-CSDN博客 安装编译软件:keil uVision 5.6 软件资料:STM32CubeF4 固件包,正点原子RS485通信例程 ​​​​​​​参考视频:第26讲 基础篇-新建H…...

基于NERF技术重建学习笔记

NeRF(Neural Radiance Fields)是一种用于3D场景重建的神经网络模型,能够从2D图像生成逼真的3D渲染效果。它将场景表征为一个连续的5D函数,利用了体积渲染和神经网络的结合,通过学习光线穿过空间时的颜色和密度来重建场…...

webView 支持全屏播放

webView 支持全屏播放 直接上代码 public class CustomFullScreenWebViewClient extends WebChromeClient {WebView webView;Context context;/*** 视频全屏参数*/protected static final FrameLayout.LayoutParams COVER_SCREEN_PARAMS new FrameLayout.LayoutParams(ViewG…...

QGIS之三十二DEM地形导出三维模型gltf

效果 1、准备数据 (1)dem.tif (2)dom.tif 2、qgis加载dem和dom数据 3、安装插件 插件步骤可以参考这篇文章 QGIS之二十四安装插件 安装了Qgis2threejs插件,结果...

【python爬虫】携程旅行景点游客数据分析与可视化

一.选题背景 随着旅游业的快速发展,越来越多的人选择通过互联网平台预订旅行产品,其中携程网作为国内领先的在线旅行服务提供商,拥有大量的旅游产品和用户数据。利用爬虫技术可以获取携程网上各个景点的游客数据,包括游客数量、游…...

python实现onvif协议下控制摄像头变焦,以及融合人形识别与跟踪控制

#1024程序员节 | 征文# 这两天才因为项目需要,对网络摄像头的视频采集以及实现人形识别与跟踪技术。对于onvif协议自然起先也没有任何的了解。但是购买的摄像头是SONY网络头是用在其他地方的。因为前期支持探究项目解决方案,就直接拿来做demo测试使用。 …...

【Vue】Vue3.0(十四)接口,泛型和自定义类型的概念及使用

上篇文章: 【Vue】Vue3.0(十三)中标签属性ref(加在普通标签上、加在组件标签上)、局部样式 🏡作者主页:点击! 🤖Vue专栏:点击! ⏰️创作时间&…...

【C++】红黑树万字详解(一文彻底搞懂红黑树的底层逻辑)

目录 00.引入 01.红黑树的性质 02.红黑树的定义 03.红黑树的插入 1.按照二叉搜索树的规则插入新节点 2.检测新节点插入后,是否满足红黑树的性质 1.uncle节点存在且为红色 2.uncle节点不存在 3.uncle节点存在且为黑色 04.验证红黑树 00.引入 和AVL树一样&am…...

开源FluentFTP实操,操控FTP文件

概述:通过FluentFTP库,轻松在.NET中实现FTP功能。支持判断、创建、删除文件夹,判断文件是否存在,实现上传、下载和删除文件。简便而强大的FTP操作,提升文件传输效率。 在.NET中,使用FluentFTP库可以方便地…...

论文解读 | ECCV2024 AutoEval-Video:一个用于评估大型视觉-语言模型在开放式视频问答中的自动基准测试...

点击蓝字 关注我们 AI TIME欢迎每一位AI爱好者的加入! 点击 阅读原文 观看作者讲解回放! 作者简介 陈修元,上海交通大学清源研究院硕士生 概述 总结来说,我们提出了一个新颖且具有挑战性的基准测试AutoEvalVideo,用于全…...

postgresql14主从同步流复制搭建

1. 如果使用docker搭建请移步 Docker 启动 PostgreSQL 主从架构:实现数据同步的高效部署指南_docker安装postgresql主从同步-CSDN博客 2. 背景 pgsql版本:PostgreSQL 14.13 on x86_64-pc-linux-gnu, compiled by gcc (GCC) 4.8.5 20150623 (Red Hat 4…...

企业信息化管理中的数据集成方案:销售出库单对接

企业信息化管理中的数据集成方案:销售出库单对接 销售出库单旺店通→金蝶:高效数据集成案例分享 在企业信息化管理中,数据的高效流动和准确对接是实现业务流程自动化的关键。本文将聚焦于一个具体的系统对接集成案例:如何将旺店通…...

3.cpp基本数据类型

cpp基本数据类型 1.cpp基本数据类型 1.cpp基本数据类型 C基本数据类型和C语言的基本数据类型差不多 注意bool类型&#xff1a;存储真值 true 或假值 false&#xff0c;C语言编译器C99以上支持。 C语言的bool类型&#xff1a;要添加 #include <stdbool.h>头文件 #includ…...

MCK主机加固与防漏扫的深度解析

在当今这个信息化飞速发展的时代&#xff0c;网络安全成为了企业不可忽视的重要议题。漏洞扫描&#xff0c;简称漏扫&#xff0c;是一种旨在发现计算机系统、网络或应用程序中潜在安全漏洞的技术手段。通过自动化工具&#xff0c;漏扫能够识别出系统中存在的已知漏洞&#xff0…...

《软件估算之原始功能点:精准度量软件规模的关键》

《软件估算之原始功能点&#xff1a;精准度量软件规模的关键》 一、软件估算的重要性与方法概述二、原始功能点的构成要素&#xff08;一&#xff09;数据功能&#xff08;二&#xff09;事务功能 三、原始功能点的估算方法&#xff08;一&#xff09;功能点分类估算&#xff0…...

序列化与反序列化

序列化和反序列化是数据处理中的两个重要概念&#xff0c;它们在多种场景下都非常有用&#xff0c;尤其是在分布式系统、网络通信、持久化存储等方面。下面是对这两个概念的详细解释&#xff1a; 序列化&#xff08;Serialization&#xff09; 定义&#xff1a;序列化是将对象…...

安装nginx实现多ip访问多网站

[rootlocalhost ~]# systemctl stop firewalld 关防火墙 [rootlocalhost ~]# setenforce 0 关selinux [rootlocalhost ~]# mount /dev/sr0 /mnt 挂载点 [rootlocalhost ~]# dnf install nginx -y 安装nginx [rootlocalhost ~]# nmtui 当前主机添加多地址 [rootlocal…...

每日回顾:简单用C写 冒泡排序、快速排序

冒泡排序 冒泡排序&#xff08;Bubble Sort&#xff09;是一种简单的排序算法&#xff0c;它通过重复遍历要排序的数列&#xff0c;一次比较两个元素&#xff0c;如果他们的顺序错误就把他们交换过来。遍历数列的工作是重复进行直到没有再需要交换&#xff0c;也就是说该数列已…...

接口测试中缓存处理策略

在接口测试中&#xff0c;缓存处理策略是一个关键环节&#xff0c;直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性&#xff0c;避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明&#xff1a; 一、缓存处理的核…...

如何在看板中体现优先级变化

在看板中有效体现优先级变化的关键措施包括&#xff1a;采用颜色或标签标识优先级、设置任务排序规则、使用独立的优先级列或泳道、结合自动化规则同步优先级变化、建立定期的优先级审查流程。其中&#xff0c;设置任务排序规则尤其重要&#xff0c;因为它让看板视觉上直观地体…...

【SpringBoot】100、SpringBoot中使用自定义注解+AOP实现参数自动解密

在实际项目中,用户注册、登录、修改密码等操作,都涉及到参数传输安全问题。所以我们需要在前端对账户、密码等敏感信息加密传输,在后端接收到数据后能自动解密。 1、引入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId...

Keil 中设置 STM32 Flash 和 RAM 地址详解

文章目录 Keil 中设置 STM32 Flash 和 RAM 地址详解一、Flash 和 RAM 配置界面(Target 选项卡)1. IROM1(用于配置 Flash)2. IRAM1(用于配置 RAM)二、链接器设置界面(Linker 选项卡)1. 勾选“Use Memory Layout from Target Dialog”2. 查看链接器参数(如果没有勾选上面…...

【Zephyr 系列 10】实战项目:打造一个蓝牙传感器终端 + 网关系统(完整架构与全栈实现)

🧠关键词:Zephyr、BLE、终端、网关、广播、连接、传感器、数据采集、低功耗、系统集成 📌目标读者:希望基于 Zephyr 构建 BLE 系统架构、实现终端与网关协作、具备产品交付能力的开发者 📊篇幅字数:约 5200 字 ✨ 项目总览 在物联网实际项目中,**“终端 + 网关”**是…...

CMake 从 GitHub 下载第三方库并使用

有时我们希望直接使用 GitHub 上的开源库,而不想手动下载、编译和安装。 可以利用 CMake 提供的 FetchContent 模块来实现自动下载、构建和链接第三方库。 FetchContent 命令官方文档✅ 示例代码 我们将以 fmt 这个流行的格式化库为例,演示如何: 使用 FetchContent 从 GitH…...

华为云Flexus+DeepSeek征文|DeepSeek-V3/R1 商用服务开通全流程与本地部署搭建

华为云FlexusDeepSeek征文&#xff5c;DeepSeek-V3/R1 商用服务开通全流程与本地部署搭建 前言 如今大模型其性能出色&#xff0c;华为云 ModelArts Studio_MaaS大模型即服务平台华为云内置了大模型&#xff0c;能助力我们轻松驾驭 DeepSeek-V3/R1&#xff0c;本文中将分享如何…...

什么?连接服务器也能可视化显示界面?:基于X11 Forwarding + CentOS + MobaXterm实战指南

文章目录 什么是X11?环境准备实战步骤1️⃣ 服务器端配置(CentOS)2️⃣ 客户端配置(MobaXterm)3️⃣ 验证X11 Forwarding4️⃣ 运行自定义GUI程序(Python示例)5️⃣ 成功效果![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/55aefaea8a9f477e86d065227851fe3d.pn…...

深入浅出深度学习基础:从感知机到全连接神经网络的核心原理与应用

文章目录 前言一、感知机 (Perceptron)1.1 基础介绍1.1.1 感知机是什么&#xff1f;1.1.2 感知机的工作原理 1.2 感知机的简单应用&#xff1a;基本逻辑门1.2.1 逻辑与 (Logic AND)1.2.2 逻辑或 (Logic OR)1.2.3 逻辑与非 (Logic NAND) 1.3 感知机的实现1.3.1 简单实现 (基于阈…...

比较数据迁移后MySQL数据库和OceanBase数据仓库中的表

设计一个MySQL数据库和OceanBase数据仓库的表数据比较的详细程序流程,两张表是相同的结构,都有整型主键id字段,需要每次从数据库分批取得2000条数据,用于比较,比较操作的同时可以再取2000条数据,等上一次比较完成之后,开始比较,直到比较完所有的数据。比较操作需要比较…...