微服务后端查询超时立即返回的处理方法

博客针对向用户提供区间查询功能时,因用户输入时间区间过大导致的查询问题,提出解决方案。在业务层开启线程池,用两个线程分别执行查询任务和监控超时打断任务。设定查询任务和守护任务,将二者丢进线程池处理,代码已上线且运行稳定。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

背景描述

    功能:向用户提供区间可查询,用户输入时间区间,或者其他特定参数,后端调用底层平台获取数据后再进行业务处理、分页等封装以便展示。
    问题:1. 当用户输入时间区间过大可能会导致跨平台查询底层数据量过大,查询速度慢、超时、撑爆内存,进而造成服务卡死或宕机。2. 由于数据量的多少和时间区间的长短并无之间联系(数据量多少与业务有关,有时候一秒内几千笔,而有时候数小时内都可能无记录),因此输入区间限制不宜在前端控制,而后端接收参数后也需跨平台调用接口,后端业务层入口也无法做范围限制。
    愿景:我们需要对查询接口做超时处理,即查询有结果立即返回,若查询耗时超过30秒之后无论是否有结果也立即返回。

解决方案

    该功能实现的业务层中开启线程池,启动两个线程来分别执行查询任务和监控超时打断任务。

技术思路
  • 设定一个查询任务,将有可能查询超时及复杂业务处理的逻辑写进任务中,该查询任务丢给子线程执行;
  • 再设定上述查询任务的守护任务,该任务先sleep 30秒,然后询问查询任务是否已完成,若未完成或未取消,则将查询任务终止。毫无疑问,这里的守护任务需持有查询任务的future对象;
  • 业务层中将这两个任务丢进线程池,若查询结果很快有结果则立即返回并关闭守护线程;若查询超过30秒,则查询线程被守护线程打断,主线程继续处理超时异常并关闭守护任务及线程池;
代码实现

    查询任务Task类

public class RangeQueryTask implements Callable<List> {

    //复杂耗时查询的句柄
    private ComplexRangeQuery complexRangeQuery;


    public RangeQueryTask(ComplexRangeQuery complexRangeQuery){
        this.complexRangeQuery = complexRangeQuery;
    }
    
    @Override
    public List call() throws Exception {
        try{
            //执行查询逻辑  略

            //返回数据处理及封装  略

        }catch (Exception e){
            //不同的异常的对应处理  略

        }
        return new ArrayList();
    }
}

    守护任务Task类

public class RangeQueryDemonTask  implements Callable<Integer> {

    private Future<List> complexRangeQryTaskFuture;

    public RangeQueryDemonTask(Future<List> complexRangeQryTaskFuture){
        this.complexRangeQryTaskFuture = complexRangeQryTaskFuture;
    }

    @Override
    public Integer call() throws Exception {
        try{
            sleep(30000);
        }catch (InterruptedException e){
            e.printStackTrace();
        }finally {
            if (!complexRangeQryTaskFuture.isDone()||!complexRangeQryTaskFuture.isCancelled()){
                complexRangeQryTaskFuture.cancel(true);
            }
            //此处将超时异常抛给前端处理
            throw new BussinessException(EnumErrorInfo.QRY_TIMEOUT.getCode(),EnumErrorInfo.QRY_TIMEOUT.getMsg());
        }
        return null;
    }
}

    业务层处理逻辑

ThreadPoolExecutor threadPoolExecutor = null;
List resultList;
try{
    //拟用ComplexRangeQuery指代耗时查询,输入参数为起始时间及终止时间
    ComplexRangeQuery complexRangeQuery = new ComplexRangeQuery("startTime","endTime");
    threadPoolExecutor = new ThreadPoolExecutor(2,2,10, TimeUnit.MILLISECONDS,new LinkedBlockingDeque<>());
    // 定义查询任务
    RangeQueryTask rangeQueryTask = new RangeQueryTask(complexRangeQuery);
    Future<List> qryTaskFuture = threadPoolExecutor.submit(rangeQueryTask);
    // 定义守护任务  并将查询任务结果句柄传入
    RangeQueryDemonTask rangeQueryDemonTask = new RangeQueryDemonTask(qryTaskFuture);
    Future<Integer> demonTaskFuture = threadPoolExecutor.submit(rangeQueryDemonTask);
    // 业务主线程一直阻塞于此,若30秒之后查询任务未结束,则查询任务线程被打断后向下继续执行
    resultList = qryTaskFuture.get();
    if (null != resultList){
        //对于查询之后立即返回结果的  也需将守护线程终止
        if (!demonTaskFuture.isDone()||!demonTaskFuture.isCancelled()){
            demonTaskFuture.cancel(true);
        }
    }

}catch (Exception e){
    // 各类异常的相应处理 略
}finally {
    //关闭线程池
    if (null!=threadPoolExecutor&&!threadPoolExecutor.isShutdown()){
        threadPoolExecutor.shutdownNow();
    }
}
return resultList;

本代码亲测有效,现已上线,运行稳定。

### 设计和实现后端微服务架构的最佳实践 #### 服务注册中心的选择与集成 为了支持动态的服务发现和服务管理,在构建微服务架构时,选择合适的服务注册中心至关重要。常见的选项包括Eureka、Consul 和 Zookeeper。这些工具不仅提供了基本的服务注册功能,还具备健康检查等功能来确保只有健康的实例参与流量分配[^1]。 ```java // 使用Spring Cloud Eureka客户端进行服务注册 @EnableDiscoveryClient @SpringBootApplication public class ServiceApplication { public static void main(String[] args) { SpringApplication.run(ServiceApplication.class, args); } } ``` #### API网关的设计 API网关作为进入整个系统的入口点,负责路由请求至相应的微服务,并处理跨横切关注点的任务如身份验证、限流等。采用像Kong 或者 Spring Cloud Gateway这样的框架可以简化这一过程并增强安全性。 ```yaml spring: cloud: gateway: routes: - id: user_service_route uri: lb://USER-SERVICE predicates: - Path=/api/users/** ``` #### 负载均衡策略实施 有效的负载均衡对于维持高可用性和性能非常重要。可以在基础设施层面上利用Nginx或HAProxy做反向代理;也可以借助Ribbon/Hystrix组合实现在应用程序内部完成智能的客户端侧负载分发逻辑。 ```properties # Ribbon配置文件示例 service.ribbon.NFLoadBalancerRuleClassName=com.netflix.loadbalancer.RandomRule ``` #### 实现熔断降级机制 当某个下游依赖不可用时,应该立即返回默认响应而不是长时间等待超时失败。Hystrix是一个流行的库用于创建具有弹性的分布式系统组件之间的交互接口,它允许开发者定义回退方法以应对异常情况下的快速恢复路径。 ```java @HystrixCommand(fallbackMethod = "getDefaultUser") public User getUserById(Long userId){ // 正常业务逻辑... } private User getDefaultUser(){ return new User(-1L,"default"); } ``` #### 日志监控体系建立 良好的日志记录习惯加上集中式的日志收集平台(例如ELK Stack),可以帮助团队更好地理解和诊断生产环境中的问题所在。此外,Prometheus搭配Grafana可用于可视化展示各种指标数据以便于实时跟踪系统状态变化趋势[^4]。 ```bash curl -X POST http://localhost:9200/_bulk --data-binary @/path/to/logfile.json ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值