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

news2024/9/23 9:21:26

目录

    • 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

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

cadence遇到的问题

1、最烦人的&#xff0c;突然卡住。 设置grid卡住&#xff0c;导出libraries卡住&#xff0c;选择其他产品时卡住。 从微软拼音输入法改成美式键盘后能解决一些问题。但不能解决全部。 今天下载了搜狗输入法来替代微软自带输入法。效果奇佳&#xff0c;真的可以诶。 2、如果…

沁恒 CH32V208(一): CH32V208WBU6 评估板上手报告和Win10环境配置

目录 沁恒 CH32V208(一): CH32V208WBU6 评估板上手报告和Win10环境配置 CH32V208 CH32V208系列是沁恒32位RISC-V中比较新的一个系列, 基于青稞RISC-V4C内核, 最高144MHz主频, 64KB SRAM&#xff0c;128KB Flash, 供电电压2.5/3.3V. 这个型号的特点: 除了特有的硬件堆栈区、…

【C++11那些事儿(三)】

文章目录 一、可变参数模板1.1 概念引入1.2 递归函数方式展开参数包1.3 逗号表达式展开参数包1.4 可变参数模板在STL中的应用 二、包装器1.1 function1.2 bind 一、可变参数模板 1.1 概念引入 C11的新特性可变参数模板能够让您创建可以接受可变参数的函数模板和类模板&#x…

链表的添加修改删除操作

public class HeroNodeDemo {public static void main(String[] args) {HeroNode hero1 new HeroNode(1, "松江");HeroNode hero2 new HeroNode(2, "武松");HeroNode hero3 new HeroNode(3, "及时雨");HeroNode hero4 new HeroNode(4, "…

AWVS-window版本安装

Acunetix Web Vulnerability Scanner&#xff08;简称AWVS&#xff09;是一款知名的网络漏洞扫描工具&#xff0c;它通过网络爬虫测试你的网站安全&#xff0c;检测流行安全漏洞。 一、下载 链接&#xff1a;https://pan.baidu.com/s/1GuLCmYBmhVYA2_qBwfjZhw 提取码&#x…

管家婆安装导致电脑蓝屏问题解决方案

安装完管家婆后&#xff0c;电脑蓝屏&#xff0c;重启还是蓝屏&#xff0c;这该怎么办&#xff1f; 导致的原因&#xff1a;因加密狗驱动不适配于Windows10系统&#xff0c;导致电脑蓝屏 修复方案&#xff1a;进入电脑安全模式&#xff08;怎么进入问度娘&#xff09;&#…

css奇淫巧计

1.input文本内容替换 -webkit-text-security&#xff1a;通过用形状替换字符,仅影响那些字段不是的typepassword 可选值:none &#xff08;无&#xff09;&#xff0c;circle &#xff08;圆圈&#xff09;&#xff0c;disc &#xff08;圆形&#xff09;&#xff0c;square &a…

【STM32CubeMX】串口通信

前言 本文记录下我学习STM32CubeMX时的流程&#xff0c;方便以后回忆。本章记录串口通信。这里居然有玄学问题&#xff0c;给我整了好久&#xff0c;头都大了。可能也是我能力有限才有的吧&#xff0c;泪目。 目录 串口通信 串口通信 STM32CubeMX中的串口配置&#xff0c;配…

MiniGPT-4引领潮流,GPT-4提前发布图片阅读功能

ChatGPT中国站翻译自medium.com 让我们来看看如何玩Minigpt-4并将其应用到日常生活中。 今年三月&#xff0c;OpenAI 宣布了 GPT-4 的图像识别功能&#xff0c;这意味着 GPT 技术又被提升一个维度。-4 尚未发布给大众使用很长时间&#xff0c;所以终于有人忍不住了&#xff01;…

由 ChatGPT 团队开发,堪称辅助神器!IntelliJ IDEA 神级插件

什么是Bito&#xff1f; 为什么要使用Bito&#xff1f; 如何安装Bito插件 如何使用Bito插件 什么是Bito&#xff1f; Bito是一款由ChatGPT团队开发的IntelliJ IDEA编辑器插件&#xff0c;旨在提高开发人员的工作效率。此插件强大之处在于它不仅可以帮助开发人员更快地提交…

vulnhub靶机sar

准备工作 下载连接&#xff1a;https://download.vulnhub.com/sar/sar.zip 下载完后解压&#xff0c;然后双击打开&#xff0c;VMware导入OVA 网络环境&#xff1a;DHCP、NAT 信息收集 主机发现 先扫描整个C段 192.168.100.132应该就是我们的目标 端口扫描 扫描目标主机…

3个经典线程同步问题

生产者消费者问题 问题描述 系统中有一组生产者进程和一组消费者进程&#xff0c;生产者进程每次生产一个产品放入缓冲区&#xff0c;消费者进程每次从缓冲区中取出一个产品并使用。生产者、消费者共享一个初始为空、大小为n的缓冲区 伪码描述 semaphore mutex 1;//互斥信…

Zabbix服务端监控目标主机的Web服务(网站的访问延迟)

zabbix服务端和目标主机的部署见上一篇文章&#xff1a; http://t.csdn.cn/XD5Hc Zabbix服务端监控目标主机 服务端启动zabbix服务后&#xff0c;在浏览器上访问&#xff1a;http&#xff1a;//IP/zabbix 1.创建主机群主&#xff08;名字自定义&#xff09; 2.创建主机 主…

javaEE基于SSh学生选课系统

设计内容1. 搜集相关资料、作出功能需求分析&#xff1b; 2. 各个功能模块的基本功能大体如下&#xff1a; (1). 管理员模块 包括个人中心、专业管理、班级管理、课程管理、教师管理、选课管理。&#xff0e; (2).教师模块 包括个人中心、课程信息、出勤管理、成绩管理。 (3)…

大数据-玩转数据-netcat

Netcat&#xff08;简称nc&#xff09;是一款强大的命令行网络工具&#xff0c;用来在两台机器之间建立TCP/UDP连接&#xff0c;并通过标准的输入输出进行数据的读写。 一、Windows 下载安装 netcat(nc)命令 1、netcat(nc)下载地址&#xff1a; https://eternallybored.org/…

《程序员面试金典(第6版)》面试题 16.08. 整数的英语表示

题目描述 给定一个整数&#xff0c;打印该整数的英文描述。 示例 1: 输入: 123输出: “One Hundred Twenty Three” 示例 2: 输入: 12345输出: “Twelve Thousand Three Hundred Forty Five” 示例 3: 输入: 1234567输出: “One Million Two Hundred Thirty Four Thousand…

Kali 更换源(超详细,附国内优质镜像源地址)

1.进入管理员下的控制台。 2. 输入密码后点击“授权”。 3.在控制台内输入下面的内容。 vim /etc/apt/sources.list 4.敲击回车后会进入下面的页面。 5.来到这个页面后的第一部是按键盘上的“i”键&#xff0c;左下角出现“插入”后说明操作正确。 6.使用“#”将原本的源给注释…

武汉大学惯性导航课程合集【2021年秋】1.2 惯性器件的误差和标定

前提平台惯导NED与本地对齐&#xff0c;body系和navigation对齐。地表IMU感受到的是 朝天上的力【0&#xff0c;0&#xff0c;-9.8】和 赤道的【15deg/hr&#xff0c;0&#xff0c;0】或者北极 【0&#xff0c;0&#xff0c;-15deg/hr】或者【15cos纬度&#xff0c;0&#xff0…

「STM32入门」USART串口通信

通信 通信的目的&#xff1a;将一个设备的数据传送到另一个设备&#xff0c;扩展硬件系统 通信协议&#xff1a;制定通信的规则&#xff0c;通信双方按照协议规则进行数据收发 STM32常见的通信协议 本文将介绍USART 概念解释 TX、RX分别是Transmit和Receive的缩写&#xff0c…

一文把 JavaScript 中的 this 聊得明明白白

文章目录 1.this 是什么&#xff1f;2.this的指向2.1 全局上下文的 this 指向2.2 函数&#xff08;普通函数&#xff09;上下文中的 this 指向2.3 事件处理程序中的 this 指向2.4 以对象的方式调用时 this 的指向2.5 构造函数中的 this 指向2.6 在 类上下文中 this 的指向。2.7…