当前位置: 首页 > 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;也就是说该数列已…...

React 第五十五节 Router 中 useAsyncError的使用详解

前言 useAsyncError 是 React Router v6.4 引入的一个钩子&#xff0c;用于处理异步操作&#xff08;如数据加载&#xff09;中的错误。下面我将详细解释其用途并提供代码示例。 一、useAsyncError 用途 处理异步错误&#xff1a;捕获在 loader 或 action 中发生的异步错误替…...

以下是对华为 HarmonyOS NETX 5属性动画(ArkTS)文档的结构化整理,通过层级标题、表格和代码块提升可读性:

一、属性动画概述NETX 作用&#xff1a;实现组件通用属性的渐变过渡效果&#xff0c;提升用户体验。支持属性&#xff1a;width、height、backgroundColor、opacity、scale、rotate、translate等。注意事项&#xff1a; 布局类属性&#xff08;如宽高&#xff09;变化时&#…...

Java如何权衡是使用无序的数组还是有序的数组

在 Java 中,选择有序数组还是无序数组取决于具体场景的性能需求与操作特点。以下是关键权衡因素及决策指南: ⚖️ 核心权衡维度 维度有序数组无序数组查询性能二分查找 O(log n) ✅线性扫描 O(n) ❌插入/删除需移位维护顺序 O(n) ❌直接操作尾部 O(1) ✅内存开销与无序数组相…...

基于服务器使用 apt 安装、配置 Nginx

&#x1f9fe; 一、查看可安装的 Nginx 版本 首先&#xff0c;你可以运行以下命令查看可用版本&#xff1a; apt-cache madison nginx-core输出示例&#xff1a; nginx-core | 1.18.0-6ubuntu14.6 | http://archive.ubuntu.com/ubuntu focal-updates/main amd64 Packages ng…...

1.3 VSCode安装与环境配置

进入网址Visual Studio Code - Code Editing. Redefined下载.deb文件&#xff0c;然后打开终端&#xff0c;进入下载文件夹&#xff0c;键入命令 sudo dpkg -i code_1.100.3-1748872405_amd64.deb 在终端键入命令code即启动vscode 需要安装插件列表 1.Chinese简化 2.ros …...

跨链模式:多链互操作架构与性能扩展方案

跨链模式&#xff1a;多链互操作架构与性能扩展方案 ——构建下一代区块链互联网的技术基石 一、跨链架构的核心范式演进 1. 分层协议栈&#xff1a;模块化解耦设计 现代跨链系统采用分层协议栈实现灵活扩展&#xff08;H2Cross架构&#xff09;&#xff1a; 适配层&#xf…...

现代密码学 | 椭圆曲线密码学—附py代码

Elliptic Curve Cryptography 椭圆曲线密码学&#xff08;ECC&#xff09;是一种基于有限域上椭圆曲线数学特性的公钥加密技术。其核心原理涉及椭圆曲线的代数性质、离散对数问题以及有限域上的运算。 椭圆曲线密码学是多种数字签名算法的基础&#xff0c;例如椭圆曲线数字签…...

大模型多显卡多服务器并行计算方法与实践指南

一、分布式训练概述 大规模语言模型的训练通常需要分布式计算技术,以解决单机资源不足的问题。分布式训练主要分为两种模式: 数据并行:将数据分片到不同设备,每个设备拥有完整的模型副本 模型并行:将模型分割到不同设备,每个设备处理部分模型计算 现代大模型训练通常结合…...

MySQL中【正则表达式】用法

MySQL 中正则表达式通过 REGEXP 或 RLIKE 操作符实现&#xff08;两者等价&#xff09;&#xff0c;用于在 WHERE 子句中进行复杂的字符串模式匹配。以下是核心用法和示例&#xff1a; 一、基础语法 SELECT column_name FROM table_name WHERE column_name REGEXP pattern; …...

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

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