Java中提升接口性能的一些方法

目录

    • 1.使用线程池并行执行
    • 2.数据库优化
      • 2.1 小表关联大表
      • 2.2 反三大范式操作
      • 2.3 增加索引
      • 2.4 减小事务粒度
      • 2.5 读写分离、分库分表
    • 3.拥抱缓存
      • 3.1 Redis
      • 3.2 内存缓存
    • 4.锁和异步
      • 4.1 减小锁的粒度
      • 4.2 分布式锁

1.使用线程池并行执行

假如有一个接口的逻辑如下:

接口的整体耗时大约在1s左右,那么如果我们使用并行处理,类似木桶效应,接口的响应时间就不再是所有模块的耗时相加,而是取决于耗时最长的模块(600ms)了。

在这里插入图片描述

2.数据库优化

我们可以通过JVM参数调整、应用节点数扩容来增加系统的吞吐量,但是用户的请求最终都会落到数据库上,如果数据库的性能不高的话,就会成为整个链路的性能瓶颈。主要有以下几种数据库的优化方案:

2.1 小表关联大表

生产环境的数据库中的数据量一般都会非常的大,联表查询是一件非常耗时、吃内存的操作,操作不当的话可能会导致服务被拖垮。

所以我们在连表查询时,一般先查询小表,然后再用小表的查询结果作为条件去筛选大表的数据。

2.2 反三大范式操作

一般不会改变的字段,可以在表当中冗余一下,这样可以减少我们的关联查询次数,提升接口响应速度。

比如常见的:用户姓名字段。

2.3 增加索引

比如我们建表时所使用的主键是默认添加索引的,对于经常关联查询的字段也需要添加索引。

当然有一些特殊的查询方式会导致索引失效,我们需要注意一下:

在这里插入图片描述

2.4 减小事务粒度

我们在数据库操作的时候,为了保证数据的一致性,经常会需要使用到数据库的事务。

其实,我们在程序中使用数据库事务的时候,稍稍注意一下也可以提升我们接口的性能。

比如这个方法上面就加了一个 @Transactional 注解来开启事务。

@Transactional
public Boolean bigTransaction() {
    Object a = queryDataFromA();
    Object b = queryDataFromB();
    handleData(a, b);
    insertDataA(a);
    updateDataB(b);
}

那么,其实这里需要保证事务的地方也就只有最后两行 insert 和 update,没有必要将整个方法都放到事务当中。

在这里插入图片描述

最直接的,我们可能会想把这两个事务抽出来,单独用一个带有 @Transactional 注解修饰的方法来执行。

@Transactional
public void handleABTransaction(Object a, Object b)
	insertDataA(a);
    updateDataB(b);
}

但是由于 @Transactional 注解底层是使用 AOP 来实现的,直接在类内部进行方法的调用,事务是不生效的。这里我们可以采用编程式事务来代替声明式事务:

import org.springframework.transaction.support.TransactionTemplate;

@Autowired
private TransactionTemplate transactionTemplate;

public Boolean bigTransaction() {
    Object a = queryDataFromA();
    Object b = queryDataFromB();
    handleData(a, b);
    
    // 编程式事务
    transactionTemplate.execute(() -> {
    	insertDataA(a);
    	updateDataB(b);
    });
}

2.5 读写分离、分库分表

随着业务的发展,数据库中的数据量会越来越多,这个时候就需要进行读写分离、分库分表的技术。尤其是现在微服务高可用的大环境下,不同业务使用不同的数据库已经成为了一种主流的设计。

具体分库分表的逻辑比较复杂,这里可以使用 ShardingJDBC 来实现。

3.拥抱缓存

3.1 Redis

Redis 相信大家都再熟悉不过了,它可以用来做缓存、分布式锁,甚至可以直接用来做数据库。

我们可以把变动不是很频繁,但是访问却非常频繁的数据放到 redis 里面,比如配置数据、热点数据等等。

3.2 内存缓存

我们常用的内存缓存有 Guava Cache,还有现在非常火的,性能非常高的 Caffeine Cache

当我们在使用一些内存缓存框架的时候,我们一定要了解的一点就是内存数据是跟随GVM进程同时存在的。所以当我们重启应用,缓存就会有一段时间的真空期,也就是我们常说的缓存击穿。所以我们需要考虑一下数据预热,或者是选择低谷的时候重启应用。

Caffeine 框架有一个非常好的功能就是它可以自动去刷新缓存,这样就可以保证我们缓存里面一直有数据,而且大概率是最新的数据。

private final LoadingCache<CountryCacheKey, String> appSettingCache = CaffeineCacheUtils
    .createLoadingCache(1000, Duration.ofHours(2), Duration.ofDays(1),
                       "app-setting-thread", // threadName
                       new CacheLoader<CountryCacheKey, String>() {
                           @Nullable
                           @Override
                           public String load(CountryCacheKey key) throws Exception {
                               String k = key.getKey(String.class);
                               String setting = settingApi.getAppSettingByName(k);
                               return setting;
                           }
                       });

4.锁和异步

4.1 减小锁的粒度

这里其实和上面说到的数据库事务是一个道理,我们可以使用 Lock 类来控制锁的范围。它比 synchronized 关键字更为灵活。

在这里插入图片描述

现在我们的系统都是向微服务的演进,一个业务可能涉及多个服务,所以在锁定资源或者做互斥操作的时候,我们需要考虑用到分布式锁。

4.2 分布式锁

常用的分布式锁的解决方案会用到 Redis,上层是用 Redisson 的框架来提供 java 锁的 API。当我们在使用这些框架的时候,需要注意:

  • 获取锁要加一个等待时间,不能让程序一直自旋,一直在获取锁。
  • 对于获取到的锁要添加一个失效时间,如果不添加失效时间的话。拿 Redisson 举例,里面有一个看门狗机制,会不断进行锁的续期,这样就会增加锁的持有时间。
  • 代码中,一定要在 final 代码块中释放锁,否则因为程序 Bug 导致锁没有释放,导致请求就会卡住,当请求的线程占满以后,整个服务就不可用了。

除了锁的粒度意外呢,我们还可以采用异步的方式去提升服务的性能。比如配合使用 @EnableAsync@Async 来异步地处理日志记录等操作。这样就算日志记录异常也不会影响主流程的流转,接口的响应时间也会下降,性能也会得到明显的提升。

另外,系统间交互我们会用到 MQ。MQ 是一个异步处理的方式。消息的生产者制造消息,然后把消息放到消息队列,比如说 RabbitMQ。接下来消费者只需要去监听这个消息队列,有新的消息会自动去触发和处理,如果消费者处理失败了,消息队列还会进行重发。比之前 A 系统同步调用 B 系统,等 B 系统处理之后才能做接下来的事情相比,性能提升了不少。

在这里插入图片描述

整理完毕,完结撒花~ 🌻





参考地址:

1.用4个方法,提升接口性能 | 多线程 | 数据库优化 | 缓存 | 异步与MQ,https://www.bilibili.com/video/BV1QG4y1g7QJ

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/16201.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

针对近日ChatGPT账号大批量封禁的理性分析

文 / 高扬 这两天不太平。 3月31号&#xff0c;不少技术圈的朋友和我闲聊说&#xff0c;ChatGPT账号不能注册了。 我不以为然&#xff0c;自己有一个号足够了&#xff0c;并不关注账号注册的事情。 后面又有不少朋友和我说ChatGPT账号全部不能注册了&#xff0c;因为老美要封锁…

第十六章 预制件prefab(上)

本章节我们介绍一下“预制件”&#xff0c;也有人叫“预制体”&#xff0c;也就是Prefab。在游戏世界中&#xff0c;那些自然环境的游戏对象&#xff0c;我们可以提前创建在场景中&#xff0c;这个大家能够理解。但是&#xff0c;有些游戏对象&#xff0c;需要根据游戏逻辑来通…

外卖项目优化-01-redis缓存短信验证码、菜品数据、Spring Cache(注解开发缓存)、(注解开发)缓存套餐数据

文章目录 外卖项目优化-01课程内容前言1. 环境搭建1.1 版本控制解决branch和tag命名冲突 1.2 环境准备 2. 缓存短信验证码2.1 思路分析2.2 代码改造2.3 功能测试 3. 缓存菜品信息3.1 实现思路3.2 代码改造3.2.1 查询菜品缓存3.2.2 清理菜品缓存 3.3 功能测试3.4 提交并推送代码…

Vue(简单了解Cookie、生命周期)

一、了解Cookie 类似于对象响应携带数据 输入用户名密码跳转到指定页面 点击指定页面中其中一个按钮跳转到另一个指定页面&#xff08;再不需用输入用户名密码&#xff09; 例如现在很多浏览器实现七天免密登录 简单理解&#xff1a;就是在网站登录页面之后&#xff0c;服务…

二叉树的遍历及相关衍生

二叉树的遍历及相关衍生 前言二叉树的遍历建树二叉树的遍历遍历的分类代码部分 遍历根的应用打印树中的每个数据代码部分 遍历计算树节点个数代码部分 计算二叉树的深度思路代码部分 第k层个数 结束 前言 如标题所示&#xff0c;在这里我们要研究的是二叉树的遍历。 为什么不…

郑哲:学习、应用初探与探索创新 | 提升之路系列(四)

导读 为了发挥清华大学多学科优势&#xff0c;搭建跨学科交叉融合平台&#xff0c;创新跨学科交叉培养模式&#xff0c;培养具有大数据思维和应用创新的“π”型人才&#xff0c;由清华大学研究生院、清华大学大数据研究中心及相关院系共同设计组织的“清华大学大数据能力提升项…

ros2 foxy创建一个包和节点-ubuntu20.04

文章目录 创建工作区目录创建包和节点colcon build编译CMakeLists.txt文件find_packageadd_executable package.xml面相过程的方式生命一个节点以面向对象的方式创建一个节点 创建工作区目录 mkdir -p ~/ros2_ws/src cd ~/ros2_ws我们创建了两个目录&#xff0c;ros2_ws和在他…

【电商必学】 WhatsApp 全新攻略:什么是交互式消息模板

网购与WhatsApp等社交通讯平台有着密不可分的关系&#xff0c;为什么这么说呢&#xff1f;因为基本上所有的网购的平台都会提供查询、下单方式给客户&#xff0c;而WhatsApp是全世界使用率最高的通讯平台&#xff0c;所以大部分电子商户都会选择WhatsApp Business与电子商务连接…

Linux pthread线程操作 和 线程同步与互斥操作

在Linux系统中玩线程&#xff0c;使用pthread&#xff0c;这篇博客记录如何创建线程和使用线程和线程的同步与互斥。 还有一份nginx线程池的代码供大家阅读学习&#xff01; 目录 一、简介 什么是线程 线程的优点、缺点 线程的应用场合 二、线程的使用 1. 创建线程 - p…

高并发场景下JVM调优实践

一、背景 2021年2月&#xff0c;收到反馈&#xff0c;视频APP某核心接口高峰期响应慢&#xff0c;影响用户体验。 通过监控发现&#xff0c;接口响应慢主要是P99耗时高引起的&#xff0c;怀疑与该服务的GC有关&#xff0c;该服务典型的一个实例GC表现如下图&#xff1a; 可以…

最值得学的编程语言是哪个?

如果让我推荐的话&#xff0c;我肯定首选是python啦&#xff01; 编程语言是一个计算机的概念&#xff0c;在我们有了计算机以后&#xff0c;想让它帮助我们做事情&#xff0c;就要通过计算机语言和它进行对话、交互&#xff0c;计算机语言能够被计算机所执行&#xff0c;完成…

【MFAC】基于全格式动态线性化的无模型自适应控制(Matlab代码)

例题来源&#xff1a;侯忠生教授的《无模型自适应控制&#xff1a;理论与应用》&#xff08;2013年科学出版社&#xff09;。 &#x1f449;对应书本 4.4 单输入单输出系统(SISO)全格式动态线性化(FFDL)的无模型自适应控制(MFAC) 上两篇博客分别介绍了基于紧格式和偏格式动态线…

Linux命令集(Linux常用命令--cat指令篇)

Linux命令集&#xff08;Linux常用命令--cat指令篇&#xff09; Linux常用命令集&#xff08;cat指令篇&#xff09;4.cat(concatenate)1. 查看文件内容&#xff1a;2. 连接多个文件&#xff1a;3. 创建文件并通过终端写入内容4. 输出内容编号 Linux常用命令集&#xff08;cat指…

【英语】大学英语CET考试,写作部分(论述文+应用文,6篇范文)

文章目录 3项评分标准&#xff08;内容&结构&#xff0c;语言&#xff09;0.1 论述文个人小结 1、论述文&#xff1a;审题与功能句2、论述文&#xff1a;修饰内容和名言模板3、论述文&#xff1a;现象作文&利弊分析4、论述文&#xff1a;给出权威论据和有侧重的现象5、…

在amd64与arm上用paddlelite部署paddelOCR(Ascend硬件)

由于部署的硬件是华为昇腾 NPU&#xff08;Ascend310&#xff09;&#xff0c;参考网址https://www.paddlepaddle.org.cn/lite/v2.10/demo_guides/huawei_ascend_npu.html#npu-paddle-lite 先拉取paddlelite用来编译库 git clone https://github.com/PaddlePaddle/Paddle-Lit…

反转字符串——leetcode344、leetcode541

文章目录 简单反转字符串题目详情分析Java完整代码 反转链表进阶问题题目详情分析Java完整代码 简单反转字符串 题目详情 编写一个函数&#xff0c;其作用是将输入的字符串反转过来。输入字符串以字符数组 s 的形式给出。 不要给另外的数组分配额外的空间&#xff0c;你必须…

RMAN-03009、ORA-19566数据文件坏块报错处理方法

在备份数据库的时候&#xff0c;出现RMAN-03009、ORA-19566报错&#xff1a; RMAN-03009: backup 命令 (c3 通道上, 在 04/29/2023 10:58:11 上) 失败 ORA-19566: 超出损坏块限制 0 (文件 E:\APP\ADMINISTRATOR\ORADATA\JHSEMR\JHEMR2.DBF) 继续执行其他作业步骤, 将不重新运行…

Github创建一个新仓库,关联本地数据并上传文件的图文步骤

工作中&#xff0c;我们经常会使用github来承享别人的代码果实&#xff0c;同时我们也会把自己的成果分享给别人&#xff0c;互相帮助。 今天的这篇图文教程非常重要&#xff0c;目标是使用Github来创建一个远程仓库&#xff0c;并和本地仓库对接&#xff0c;同时要做上传新内容…

区域医疗云his系统源码,具有可扩展、易共享、易协同的优势

云HIS系统采用SaaS软件应用服务模式&#xff0c;提供软件应用服务多租户机制&#xff0c;实现一中心部署多机构使用。相对传统HIS单机构应用模式&#xff0c;它可灵活应对区域医疗、医疗集团、医联体、连锁诊所、单体医院等应用场景&#xff0c;并提升区域内应用的标准化与规范…

python处理图像的各种技术镜像、旋转、遮挡、叠加、条带化

2.6 图像镜面对称 1、将图像水平镜面转换。 2、将图像垂直镜面转换。 import random #导入模块 import numpy as np import matplotlib.pyplot as plt a plt.imread("1.jpg") # 将图像沿着水平方向重复三次。 ba.copy() da.copy() # 将图像水平镜面转换。&…