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

接口性能优化思路

目录

前言

优化思路

缓存

异步

合并

拆分

单例

压缩


前言

日常开发中设计接口,响应时间是衡量一个接口质量的重要指标。

接口响应时间这里粗糙地分为三种:

  1. 即时响应:毫秒级,小于500毫秒
  2. 快速响应:秒级,大于500毫秒且小于2秒
  3. 长时间操作:大于2秒,甚至是分钟级别的操作

一般接口都是需要快速响应的,在不考虑任何优化策略的情况下,如果整个业务逻辑走下来,响应时间大于了2秒,那么就应该考虑对这个接口进行性能优化了,以免影响了用户的体验。

优化思路

缓存

毫无疑问,使用缓存是对性能提升最明显的方法。

若是缓存中存在,直接返回结果,否则再走接口逻辑,最后将结果放入缓存中,以便下次查询时使用。

缓存还可以分为本地缓存和分布式缓存

本地缓存:

由于数据是在本地内存,它的访问速度是最快的,同时它的容量也受限于运行本地内存,以及在分布式系统中,本地缓存的数据很可能和其他节点的数据不一致。所以本地缓存一般用来存储一些系统级别上基本上不会改变的内容。

在 Java 实现中,最简单的本地缓存其实可以用一个 ConcurrentHashMap 来实现,不过在实际开发中有更好的选择,可以选择 Caffeine 来做本地缓存,性能更好。

分布式缓存:

分布式缓存相对本地缓存,多了一次网络交互,所以速度会慢一些,但是大小则不会受制于本地服务机器内存了,内存不够用了还可以通过水平扩容来解决,而且在分布式系统中, 数据的一致性能够得以保证。

常用的分布式缓存为 Redis MemCached,MemCached 更加轻量级一些,纯粹的缓存中间件,Redis 不仅仅可以作为缓存,它还支持更多的功能(分布式锁,分布式限流,地理位置应用,布隆过滤器等等)

异步

如果是单线程执行业务逻辑,那么可以考虑对业务逻辑进行拆分,将其中能够并行执行的部分分解出来,然后使用多线程的方式去同时运行,理论上能够将该部分的运行性能提升(提升的大小取决于能够同时运行的线程数)

Java 中可以使用线程池 ThreadPool 来并发执行任务,进阶一点还可以使用 CompletableFuture 来编排异步任务。

合并

合并其实是指将批量操作,将多个操作合并成一个去执行

例如数据库中的批量插入,同一个表的多条插入语句,其实可以优化成一个插入语句,这样可以减少数据库的交互,避免重复地创建数据库连接。Mybatis 中的 BatchExecutor 就是这个思路,将相同的 sql 语句添加到同一个 Satement 对象中等待执行,可以有效地减少 PrepareStatement 地编译操作

Redis 的 Pipeline 也是将多个请求合并,最后一起发送,这样可以将多次网络交互优化成一次网络交互,减少网络交互的时间,从而提升性能。

拆分

拆分其实是针对多线程编程中,对共享资源的一个拆分,避免因为竞争激烈,导致多线程并发执行性能反而比单线程还慢了

代码中如果使用到了锁,可以从两方面考虑

减少锁的持有时间:将不必要的操作尽可能地放到锁外面去执行,避免其他线程等待锁的释放时间过长

减少锁的粒度:参考JUC下并发类的设计

ConcurrentHashMap是一个线程安全的Map,虽然可以直接通过synchronized修饰 put 和 get 方法来得到一个线程安全的HashMap,但是这样显然十分影响性能。

在JDK 1.7中,ConcurrentHashMap采用了分段锁(Segment Lock)的机制来提高并发性能。这种设计将整个哈希表分割成多个段(Segment),每个段都维护着自己独立的锁。这样,当多个线程并发访问ConcurrentHashMap时,它们可以并行地访问不同的段,从而减少了锁的竞争。

在JDK 1.8中,ConcurrentHashMap的锁机制发生了重大变化,它放弃了JDK 1.7中的分段锁设计,转而采用了一种基于CAS(Compare-And-Swap)操作+synchronized锁的细粒度锁机制。

除了ConcurrentHashMap,在 JUC 包下还有许多 Adder 类(IntegerAdderLongAdder 等等),当线程竞争不激烈时,直接采用CAS来实现数量的原子递增,如果竞争激励,则使用数组来维护元素个数(将单个资源的竞争拆分成多个),先从数组中随机选择一个,再通过CAS实现原子递增,最后再一起汇总。

单例

单例其实也可以看作是缓存的一种实现方式,本质是避免重复创建对象,直接服用现有的对象,从而减少重复创建对象的时间,提升性能。

在 spring 框架下开发,依赖注入默认就是单例的

压缩

接口的响应时间除了接口本身执行业务逻辑的时间,还有网络传输的时间。在其他条件都不变的情况下,减少网络传输内容的大小,也可以提升接口的性能。

如果接口的返回数据字段很多,可以考虑压缩字段的大小,比如说将返回的json中的有实际意思的单词字段名直接改成简单的f1,f2,f3;这样在返回数据量大的情况下也可以减少网络传输的内容大小。

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • “微软蓝屏”事件暴露的网络安全问题
  • Godot学习笔记2——GDScript变量与函数
  • Unity中UI系统3——UGUI
  • MySQL学习第一阶段
  • 【目标检测】Anaconda+PyTorch配置
  • 图像处理 -- ISP调优(tuning)的步骤整理
  • 2024 HNCTF PWN(hide_flag Rand_file_dockerfile Appetizers TTOCrv_)
  • 以Zookeeper为例 浅谈脑裂与奇数节点问题
  • 东京裸机云多IP服务器全面分析
  • 数学建模学习(2)——决策树
  • OpenCV 安装与基础使用教程(Python)
  • RabbitMQ的学习和模拟实现|GTest测试框架的介绍和简单使用
  • 数据结构代码
  • Git基本使用
  • 3D建模软件--犀牛Rhino for Mac
  • 分享的文章《人生如棋》
  • 【5+】跨webview多页面 触发事件(二)
  • 【JavaScript】通过闭包创建具有私有属性的实例对象
  • 【挥舞JS】JS实现继承,封装一个extends方法
  • Android 初级面试者拾遗(前台界面篇)之 Activity 和 Fragment
  •  D - 粉碎叛乱F - 其他起义
  • in typeof instanceof ===这些运算符有什么作用
  • Js实现点击查看全文(类似今日头条、知乎日报效果)
  • LeetCode541. Reverse String II -- 按步长反转字符串
  • python_bomb----数据类型总结
  • Swift 中的尾递归和蹦床
  • vue2.0项目引入element-ui
  • 阿里中间件开源组件:Sentinel 0.2.0正式发布
  • 对象管理器(defineProperty)学习笔记
  • 分享一个自己写的基于canvas的原生js图片爆炸插件
  • ------- 计算机网络基础
  • 网页视频流m3u8/ts视频下载
  • 《天龙八部3D》Unity技术方案揭秘
  • 没有任何编程基础可以直接学习python语言吗?学会后能够做什么? ...
  • ​云纳万物 · 数皆有言|2021 七牛云战略发布会启幕,邀您赴约
  • ![CDATA[ ]] 是什么东东
  • #stm32驱动外设模块总结w5500模块
  • #数据结构 笔记三
  • (02)Cartographer源码无死角解析-(03) 新数据运行与地图保存、加载地图启动仅定位模式
  • (WSI分类)WSI分类文献小综述 2024
  • (二)延时任务篇——通过redis的key监听,实现延迟任务实战
  • (二十九)STL map容器(映射)与STL pair容器(值对)
  • (二刷)代码随想录第15天|层序遍历 226.翻转二叉树 101.对称二叉树2
  • (附源码)springboot炼糖厂地磅全自动控制系统 毕业设计 341357
  • (机器学习的矩阵)(向量、矩阵与多元线性回归)
  • (免费分享)基于springboot,vue疗养中心管理系统
  • (转)C#调用WebService 基础
  • ****** 二 ******、软设笔记【数据结构】-KMP算法、树、二叉树
  • .net Application的目录
  • .net core 使用js,.net core 使用javascript,在.net core项目中怎么使用javascript
  • .NET框架设计—常被忽视的C#设计技巧
  • @RequestMapping用法详解
  • [20160807][系统设计的三次迭代]
  • [20170705]lsnrctl status LISTENER_SCAN1
  • [2023年]-hadoop面试真题(一)