高性能API设计

背景

设计出一个高性能的API,需要综合网络、业务、数据库的优化。一下是我在实际的开发过程中总结的优化思想和一些效率提升的技巧。

批量思想

很多的数据库操作都含有batch或者bulk的api,如我最近常使用的mybatismybatis plus以及``elastic Search的数据操作API。从单条循环插入到批量插入,减少了session` 的链接,更高的效率。

# 优化前
for (User user: UserList) {
  mapper.insert(user);
}

# 优化后
mapper.batchInsert(UserList);

对应的实际sql为:

insert into user(id, name) values(1,2) 
insert into user(id, name) values(1,2) 
insert into user(id, name) values(1,2) ,(3,4), (5,6)

所以java的开发也有一种规范:禁止在循环中操作数据库

异步思想

对于服务的调用链路特别长的情况,接口的响应时间也特别的长。如果前端再去控制timeout的时间,直接出现接口超时的异常。于是异步的思想就出来了,允许耗时长的操作异步的执行。这类一般见于电商服务的业务流程中。

空间换时间

提到这个有点像算法了,空间复杂度和时间复杂度之间的一个权衡。这里的空间,指的是类似于redis的缓存 中间件。以查询数据为例:

池化思想

在这里不得不提到线程池了,这是多少人的噩梦!面试要问,项目要用,用不好服务直接搞挂!

我们常见的线程池类型有:数据库连接池、线程池、redis连接池

总结下来的功能有:

  • 避免线程的频繁创建和销毁
 Thread t = new Thread(() -> {System.out.println("hello world")});
 t.start();

瞧瞧这new的多恐怖。spring bean都交给容器管理了,线程还要单独new?来看看一段优雅的代码:

    @Override
    public int executeNotify() throws InterruptedException {
        // 获得需要通知的任务
        List<PayNotifyTaskDO> tasks = payNotifyTaskMapper.selectListByNotify();
        if (CollUtil.isEmpty(tasks)) {
            return 0;
        }

        // 遍历,逐个通知
        CountDownLatch latch = new CountDownLatch(tasks.size());
        tasks.forEach(task -> threadPoolTaskExecutor.execute(() -> {
            try {
                executeNotifySync(task);
            } finally {
                latch.countDown();
            }
        }));
        // 等待完成
        awaitExecuteNotify(latch);
        // 返回执行完成的任务数(成功 + 失败)
        return tasks.size();
    }

优雅在任务直接往池子里塞,具体的什么时候完成一直等着就好了。

  • 预分配
  • 循环使用

在这里,我也必须补充一下线程池的构造方法:

    /**
     * 用给定的初始参数创建一个新的ThreadPoolExecutor。
     */
    public ThreadPoolExecutor(int corePoolSize,//线程池的核心线程数量
                              int maximumPoolSize,//线程池的最大线程数
                              long keepAliveTime,//当线程数大于核心线程数时,多余的空闲线程存活的最长时间
                              TimeUnit unit,//时间单位
                              BlockingQueue<Runnable> workQueue,//任务队列,用来储存等待执行任务的队列
                              ThreadFactory threadFactory,//线程工厂,用来创建线程,一般默认即可
                              RejectedExecutionHandler handler//拒绝策略,当提交的任务过多而不能及时处理时,我们可以定制策略来处理任务
                               ) {
        if (corePoolSize < 0 ||
            maximumPoolSize <= 0 ||
            maximumPoolSize < corePoolSize ||
            keepAliveTime < 0)
            throw new IllegalArgumentException();
        if (workQueue == null || threadFactory == null || handler == null)
            throw new NullPointerException();
        this.corePoolSize = corePoolSize;
        this.maximumPoolSize = maximumPoolSize;
        this.workQueue = workQueue;
        this.keepAliveTime = unit.toNanos(keepAliveTime);
        this.threadFactory = threadFactory;
        this.handler = handler;
    }

线程池的逻辑如下:

远程调用串行改并行

对于远程调用一系列接口,可以使用异步调用的方式,减少时间消耗。

为了实现以上的效果,我也结合线程池,用到了异步的方式模拟以上两种方式的效果。

  public int getCoreSize() {
    return Runtime.getRuntime().availableProcessors();
  }

  public static void someMethod(Long minutes) {
    try {
      Thread.sleep(minutes);
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
    System.out.println(Thread.currentThread().getName() + " is running.....");
  }

  public void serial() {
    Date start = new Date();
    someMethod(1000L);
    someMethod(1000L);
    someMethod(300L);
    System.out.println(DateUtil.between(start, new Date(), DateUnit.MS));
  }

  public void parallel() {
    Date start = new Date();
    CompletableFuture<Void> completableFutureOne = CompletableFuture.runAsync(() -> someMethod(1000L), poolExecutor);
    CompletableFuture<Void> completableFutureTwo = CompletableFuture.runAsync(() -> someMethod(1000L), poolExecutor);
    CompletableFuture<Void> completableFutureThree = CompletableFuture.runAsync(() -> someMethod(300L), poolExecutor);
    try {
      // get()方法会阻塞线程
      CompletableFuture.allOf(completableFutureOne, completableFutureTwo, completableFutureThree).get();
    } catch (InterruptedException | ExecutionException e) {
      e.printStackTrace();
    }
    System.out.println(DateUtil.between(start, new Date(), DateUnit.MS));
    poolExecutor.shutdown();
  }

以上就是《高性能API设计》的第一部分了,时间和篇幅原因,剩下的部分将在下一期展开。

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

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

相关文章

【机器学习】西瓜书习题3.3Python编程实现对数几率回归

参考代码 结合自己的理解&#xff0c;添加注释。 代码 导入相关的库 import numpy as np import pandas as pd import matplotlib from matplotlib import pyplot as plt from sklearn import linear_model导入数据&#xff0c;进行数据处理和特征工程 # 1.数据处理&#x…

指针经典笔试题强训(附图详解)

目录 笔试题1&#xff1a; 解析&#xff1a; 运行结果&#xff1a; 笔试题2 解析&#xff1a; 运行结果&#xff1a; 笔试题3 解析&#xff1a; 运行结果&#xff1a; 笔试题4 解析&#xff1a; 运行结果&#xff1a; 笔试题5 解析&#xff1a; 运行结果&#xff1a;…

智慧~经典开源项目数字孪生智慧商场——开源工程及源码

深圳南山某商场的工程和源码免费赠送&#xff0c;助您打造智慧商场。立即获取&#xff0c;提升商场管理效能&#xff01; 项目介绍 凤凰商场作为南山地区的繁华商业中心&#xff0c;提供多样化的购物和娱乐体验。通过此项目&#xff0c;凤凰商场将迈向更智能的商业模式。 本项目…

【第一阶段】kotlin语言的String模板

1.在Java中拼接字符串使用的是“” 2.在kotlin中使用"${}" 3.kotlin语言中if是表达式&#xff0c;更灵活 fun main() {val city"西安"val time24//java中写法println("我在"city"玩了"time"小时")//kotlin中写法&#xff0…

汽车EBSE测试流程分析(四):反思证据及当前问题解决

EBSE专题连载共分为“五个”篇章。此文为该连载系列的“第四”篇章&#xff0c;在之前的“篇章&#xff08;三&#xff09;”中已经结合具体研究实践阐述了“步骤二&#xff0c;通过系统调研确定改进方案”等内容。那么&#xff0c;在本篇章&#xff08;四&#xff09;中&#…

springboot项目如何自动重启(使用Devtools检测修改并自动重启springboot)

1. 问题&#xff1a; 我们在项目开发阶段&#xff0c;可能经常会修改代码&#xff0c;修改完后就要重启Spring Boot。经常手动停止再启动&#xff0c;比较麻烦。 所以我们引入一个Spring Boot提供的开发工具&#xff1b; 只要源码或配置文件发生修改&#xff0c;Spring Boot应用…

力扣 62. 不同路径

题目来源&#xff1a;https://leetcode.cn/problems/unique-paths/ C题解1&#xff1a;动态规划。声明二维数组。 确定dp数组&#xff08;dp table&#xff09;以及下标的含义。dp[i][j] &#xff1a;表示从&#xff08;0 &#xff0c;0&#xff09;出发&#xff0c;到(i, j) …

2023年08月在线IDE流行度最新排名

点击查看最新在线IDE流行度最新排名&#xff08;每月更新&#xff09; 2023年08月在线IDE流行度最新排名 TOP 在线IDE排名是通过分析在线ide名称在谷歌上被搜索的频率而创建的 在线IDE被搜索的次数越多&#xff0c;人们就会认为它越受欢迎。原始数据来自谷歌Trends 如果您相…

【MySQL】DDL和DML

4&#xff0c;DDL:操作数据库 我们先来学习DDL来操作数据库。而操作数据库主要就是对数据库的增删查操作。 4.1 查询 查询所有的数据库 SHOW DATABASES; 运行上面语句效果如下&#xff1a; 上述查询到的是的这些数据库是mysql安装好自带的数据库&#xff0c;我们以后不要操…

精通GPU编程,高效处理Pandas

大家好&#xff0c;当正在使用python处理大型数据集&#xff0c;那么很可能会感受到&#xff0c;当基于CPU的pandas DataFrame难以执行操作时&#xff0c;等待数小时才能完成查询的挫败感。正是在这种情况下&#xff0c;pandas用户应该考虑使用RAPIDS cuDF利用GPU的强大功能进行…

无涯教程-Lua - Arrays(数组)

数组是对象的有序排列&#xff0c;可以是包含行集合的一维数组&#xff0c;也可以是包含多行和多列的多维数组。 在Lua中&#xff0c;数组是使用带有整数的索引表实现的。数组的大小不是固定的&#xff0c;并且可以根据无涯教程的要求(取决于内存限制)来增长。 一维数组 一维…

Linux系统安装部署MongoDB完整教程(图文详解)

前言&#xff1a;本期给大家分享一下目前最新Linux系统安装部署MongoDB完整教程&#xff0c;我的服务器采用的是Centos7&#xff0c;在部署之前我重装了我的服务器&#xff0c;目的是为了干净整洁的给大家演示我是如何一步步的操作的&#xff0c;整体部署还是挺简洁&#xff0c…

react ant icon的简单使用

refer: 快速上手 - Ant Design 1.引入ant npm install antd --save 2.在页面引用&#xff1a; import { StarOutlined } from ant-design/icons; 如果想要引入多个icon&#xff0c;可以这样书写&#xff1a; import { UserOutlined, MailOutlined, PieChartOutlined } fr…

C/C++开发,opencv与qt结合播放视频

目录 一、qt_ui创建 1.1 ui设置 1.2 ui及代码输出保存 二、创建工程 2.1 工程目录及编译设置 2.2 源码设计 三、编译及测试 3.1 程序编译 3.2 程序运行 首先声明&#xff0c;这是一个OpenCV 3学习文档的案例&#xff0c;但是说明有些过于省略&#xff0c;只有一些简短的代码…

golang执行异步任务的第三方库jobrunner库实践

简介 我们在 Web 开发中时常会遇到这样的需求&#xff0c;执行一个操作之后&#xff0c;需要给用户一定形式的通知。例如&#xff0c;用户下单之后通过邮件发送电子发票&#xff0c;网上购票支付后通过短信发送车次信息。但是这类需求并不需要非常及时&#xff0c;如果放在请求…

java+springboot+mysql校园宿舍报修管理系统

项目介绍&#xff1a; 使用javaspringbootmysql开发的校园宿舍报修管理系统&#xff0c;系统包含管理员、维修员、学生角色&#xff0c;功能如下&#xff1a; 管理员&#xff1a;楼栋管理、宿舍管理、维修人员管理、学生管理&#xff1b;报修管理&#xff08;派单给维修员&am…

npm发布包

1.npm 登录 在控制台输入命令 npm login 按提示输入用户名&#xff0c;密码&#xff0c;邮箱后登录 如果出现如下提示 需要将淘宝镜像源切换为npm源&#xff0c;删除或注释以下内容就行 2.发布 进入准备发布的代码的根目录下&#xff0c;输入命令 npm publish 3.删除已发…

微信小程序原生写法传递参数

微信小程序原生写法传递参数 data-xxx 自定义参数名 &#xff0c;接收参数&#xff1a;方法&#xff08;变量名&#xff09; checkVip:function(event) {let that thisconsole.log(event,event)console.log(event.currentTarget.dataset.idx,index)let index Number(eve…

适应于Linux系统的三种安装包格式 .tar.gz、.deb、rpm

deb、rpm、tar.gz三种Linux软件包的区别 rpm包-在红帽LINUX、SUSE、Fedora可以直接进行安装&#xff0c;但在Ubuntu中却无法识别&#xff1b; deb包-是Ubuntu的专利&#xff0c;在Ubuntu中双击deb包就可以进入自动安装进程&#xff1b; tar.gz包-在所有的Linux版本中都能使用…

静态路由下一跳地址怎么确定(静态路由配置及讲解)

一、用到的所有命令及功能 ①ip route-static 到达网络地址 子网掩码 下一跳 // 配置静态路由下一跳指的是和当前网络直接连接的路由器的接口地址非直连网段必须全部做路由路径是手工指定的&#xff0c;在大规模网络上不能用&#xff0c;效率低&#xff0c;路径是固定的稳定的…