接口优化方案

发布于:2025-03-09 ⋅ 阅读:(20) ⋅ 点赞:(0)

接口优化方案

一、并发编程

场景:性能不达标接口内部串行调用,优化方案:调整为并发调用
案例如下:
pom文件配置:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>cn.demo</groupId>
    <artifactId>java_base</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>java_base</name>
    <description>java_base</description>
    <properties>
        <java.version>1.8</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <spring-boot.version>2.4.2</spring-boot.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
            <version>1.18.36</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.testng</groupId>
            <artifactId>testng</artifactId>
            <version>7.11.0</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring-boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>${spring-boot.version}</version>
                <configuration>
                    <mainClass>cn.demo.java_base.JavaBaseApplication</mainClass>
                    <skip>true</skip>
                </configuration>
                <executions>
                    <execution>
                        <id>repackage</id>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

</project>

两种方式完成接口的并发调用,参看方法:
方法一:通过Callable创建任务,结合线程池实现并发调用,参看方法:testCallable
方法二:通过Completable的任务编排作用,结合线程池实现并发调用,参看方法:testCompletableFutures
两者获取结果时会产生阻塞,所以建议异步调用完全部接口后统一获取结果。
该方案优化场景适用于有性能瓶颈的接口,通过方法调用链路排查出内部服务调用耗时较长,可以调整为并行调用。

/**
 * @Auther: gina
 * @Date: 2025-03-06
 * @Description:并发处理测试
 */
@SpringBootTest
public class CallableTest {
    private static final Logger log = LoggerFactory.getLogger(CallableTest.class);

    //线程池+多个Callable创建的任务,并发调用
    @Test
    void testCallable() throws InterruptedException, ExecutionException {
        //创建线程池
        ExecutorService es = Executors.newFixedThreadPool(3);
        Date start = new Date();
        //使用Callable创建多任务
        List<Callable<String>> tasks = new ArrayList<>();
        tasks.add(() -> {
            return a100();
        });

        tasks.add(() -> {
            return b200();
        });

        tasks.add(() -> {
            return c230();
        });
        List<Future<String>> futures = es.invokeAll(tasks);


        String a100 = futures.get(0).get();
        String b200 = futures.get(1).get();
        String c230 = futures.get(2).get();
        Date endTime = new Date();
        Long consTime = endTime.getTime() - start.getTime();
        es.shutdown();
        log.info("testCallable:: a100={},b200={},c230={},累计消耗时间{}", a100, b200, c230, consTime);
    }

    @Test
    void testCompletableFutures() throws ExecutionException, InterruptedException {
        //创建线程池
        ExecutorService es = Executors.newFixedThreadPool(3);
        Date start = new Date();
        //使用Callable创建多任务
        CompletableFuture<String> aFuture = CompletableFuture.supplyAsync(() -> {
            try {
                return a100();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }, es);

        CompletableFuture<String> bFuture = CompletableFuture.supplyAsync(() -> {
            try {
                return b200();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }, es);

        CompletableFuture<String> cFuture = CompletableFuture.supplyAsync(() -> {
            try {
                return c230();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }, es);


        String a100 = aFuture.get();
        String b200 = bFuture.get();
        String c230 = cFuture.get();
        Date endTime = new Date();
        Long consTime = endTime.getTime() - start.getTime();
        es.shutdown();
        log.info("CompletableFuture:: a100={},b200={},c230={},累计消耗时间{}", a100, b200, c230, consTime);
    }

    private String c230() throws InterruptedException {
        Thread.sleep(230);
        return "ok";
    }

    private String b200() throws InterruptedException {
        Thread.sleep(200);
        return "ok";
    }

    private String a100() throws InterruptedException {
        Thread.sleep(100);
        return "ok";
    }
}

执行结果分别为:

testCallable:: a100=ok,b200=ok,c230=ok,累计消耗时间236
CompletableFuture:: a100=ok,b200=ok,c230=ok,累计消耗时间237

由此,接口的响应时间只取决于调用服务里,最长的那个。若还是不满足,可以从sql优化,或者缓存等方面,具体看瓶颈进行分析。

持续更新中…