SpringBoot 业务中 通过嵌套异步的方式 提高业务表数据同步效率

前言

之前给公安行业做过一个项目,其中有一个需求是建设了一个人员库,这个人员库由各单位录入一些需要长期关注的人员,例如情绪不稳定、游手好闲、曾扬言报复社会等等之类的。当时还应客户的需求,做了一些人员标签功能,共有六类,用来供民警来判断该人员危险程度。这些标签的值,有相关部门提供了接口,我们传入身份证号,接口返回对应数据。最近客户有一个要求,要求整个人员库,至少每天更新一次标签信息,经协商 决定每天0点 通过定时任务刷新一次,因为这时候也没有人使用系统。在这个过程中遇到一些问题,在这里分享下。

表结构

我将表结构业务字端脱敏后分享下,也没有什么复杂的

思路

当时该项目的人员库已经有大概12000+数据了,然后相关部门提供的接口响应时间大概是1-1.5秒,这样如果单线程执行的话,单个人员就大概需要消耗 6 * 1.5 = 9 秒,再进行一些计算及数据库更新,相当于每个人员消耗10秒。刷新一遍大概33+小时,所以这里要进行异步处理。

一开始想到,每个人员的6个接口 使用 CompletableFuture 异步处理,算上网络延迟、数据更新等等,可能单个人员需要2秒,算下来更新一遍也需要6-7个小时,这样肯定不行。而且后面人员库的规模肯定会继续扩大。

最后我的方案是 异步套异步,创建两个线程池:线程池1用于提交每个人员数据,线程池2用于提交每个人员调用接口时的 CompletableFuture,并且 网络请求一般为IO密集型任务,即线程大部分时间是在等待接口响应,所以这里尽量将线程池2的最大线程数设置大一些。

由于业务上,线程池1每提交1个任务,线程池2就提交6个任务,所以我将两个线程池的部分配置项设置为了1:6。代码如下

代码

java 复制代码
/**
 * 人员标签刷新job 每天0点执行一次
 */
@Component
public class PersonTagsRefreshJob {

    @Autowired
    private PersonService personService;

    @Autowired
    private PersonInterfaceService personInterfaceService;

    private static final ThreadPoolExecutor executor1 = new ThreadPoolExecutor(
            Runtime.getRuntime().availableProcessors() * 2,
            Runtime.getRuntime().availableProcessors() * 4,
            1, TimeUnit.MINUTES, new LinkedBlockingQueue<>(100),
            new ThreadPoolExecutor.CallerRunsPolicy()
    );

    private static final ThreadPoolExecutor executor2 = new ThreadPoolExecutor(
            Runtime.getRuntime().availableProcessors() * 12,
            Runtime.getRuntime().availableProcessors() * 24,
            1, TimeUnit.MINUTES, new LinkedBlockingQueue<>(600),
            new ThreadPoolExecutor.CallerRunsPolicy()
    );

    public void execute() {
        for (PersonEntity person : personService.list()) {
            executor1.execute(() -> invokePersonInterface(person));
        }
    }

    private void invokePersonInterface(PersonEntity person) {
        String idCard = person.getIdCard();

        //异步调用人员接口
        CompletableFuture<Boolean> focusFuture = CompletableFuture.supplyAsync(() -> personInterfaceService.isFocus(idCard), executor2);
        CompletableFuture<Boolean> criminalFuture = CompletableFuture.supplyAsync(() -> personInterfaceService.isCriminal(idCard), executor2);
        CompletableFuture<Boolean> fugitiveFuture = CompletableFuture.supplyAsync(() -> personInterfaceService.isFugitive(idCard), executor2);
        CompletableFuture<Boolean> wantedFuture = CompletableFuture.supplyAsync(() -> personInterfaceService.isWanted(idCard), executor2);
        CompletableFuture<Boolean> involvedCaseFuture = CompletableFuture.supplyAsync(() -> personInterfaceService.isInvolvedCase(idCard), executor2);
        CompletableFuture<Boolean> drugFuture = CompletableFuture.supplyAsync(() -> personInterfaceService.isDrug(idCard), executor2);

        //等待所有接口调用完成
        CompletableFuture<Void> futures = CompletableFuture.allOf(focusFuture, criminalFuture, fugitiveFuture, wantedFuture, involvedCaseFuture, drugFuture);

        try {
            futures.get();

            person.setIsFocus(focusFuture.get());
            person.setIsCriminal(criminalFuture.get());
            person.setIsFugitive(fugitiveFuture.get());
            person.setIsWanted(wantedFuture.get());
            person.setIsInvolvedCase(involvedCaseFuture.get());
            person.setIsDrug(drugFuture.get());
            person.setUpdateTime(LocalDateTime.now());

            personService.updateById(person);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

总结

以上就是我的解决方案,运行了一段时间感觉效率还可以,当时12000+的数据10-15分钟可以更新完毕。希望能够帮到有需要的人 谢谢。

相关推荐
indexsunny2 小时前
互联网大厂Java面试实录:Spring Boot微服务与Kafka消息队列实战解析
java·spring boot·微服务·面试·kafka·电商·技术解析
乂爻yiyao2 小时前
2.1 JVM对象创建
java
Re.不晚2 小时前
JAVA进阶之路——网络通信的层级密码:Socket切入,理解TCP与HTTP协议
java·tcp/ip·http
Vivienne_ChenW2 小时前
Apollo 配置中心核心用法(实战版)
java·开发语言·分布式·阿里云·产品运营
一灰灰blog2 小时前
Jar包会自己消失?Excel会“记忆“数据?我遇到了两个灵异bug
java·spring boot·bug·excel
计算机毕设指导62 小时前
基于微信小程序的非物质文化遗产推广管理系统【源码文末联系】
java·spring boot·mysql·微信小程序·小程序·tomcat·maven
BYSJMG2 小时前
大数据分析案例:基于大数据的肺癌数据分析与可视化系统
java·大数据·vue.js·python·mysql·数据分析·课程设计
czlczl200209252 小时前
基于 Maven 的多模块项目架构
java·架构·maven
短剑重铸之日2 小时前
《设计模式》第八篇:三大类型之创建型模式
java·后端·设计模式·创建型设计模式
野犬寒鸦3 小时前
从零起步学习并发编程 || 第四章:synchronized底层源码级讲解及项目实战应用案例
java·服务器·开发语言·jvm·后端·学习·面试