服务端自我保护之超时处理

论坛 期权论坛 脚本     
已经匿名di用户   2022-5-29 19:21   1611   0

该文章适用于比较重的操作的服务端。

我们经常会遇到远程调用超时的情况,一般这种情况客户端会有一个超时时间,超过该时间,那客户端抛异常,客户端可以进行重试等操作,那此时此刻,服务端呢?

最近遇到了一个线上问题,我的一个服务是文件处理,所有的接口都会进行文件转换相关的操作(word转pdf、word转html等操作),文件操作是比较重的操作,遇到比较大的文件,服务可能要处理很长很长时间。某用户上传了一个不算大的excel文件,只有437.64KB,但是这个文件有一百多万行,这个文件请求到服务端,服务端会一直处理(处理了一天多还没有处理完),占用了大量的cpu、内存资源,此时客户端可能还会重试,那么其他的文件转换操作都会变得很慢。

百度了很久,发现大家都是作为客户端设置超时时间,那我们来一点不一样的,想一想服务端遇到这种情况要怎么自我保护,防止超过自己能力的请求将自己拉垮。

我们如何定义超过自己能力的请求?文件大小?文件复杂程度?

首先我们排除文件大小,上面说过,用户上传的excel只有437.64KB

那文件复杂程度?稍微想一想也可以排除,要得到文件的复杂程度是要解析这个文件的,解析这个文件本身就很慢。

最终采取了转换时间的方案,如果转换时间超过某个阈值,那就放弃这次处理。

因为文件转换服务都是文件操作,都比较重,我直接在所有的controller上加了切面(项目是spring boot),不多说了,直接上代码

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;

import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Component
@Aspect
public class TimeLimitAspect {


    @Around("(execution(* com.kuaishou.is.controller..*.*(..)))")
    public Object around(ProceedingJoinPoint pjp) {
        TimeLimitThread timeLimitThread = new TimeLimitThread();
        timeLimitThread.setPjp(pjp);
        timeLimitThread.setFather(Thread.currentThread());
        timeLimitThread.start();

        try {
            Thread.sleep(5 * 60 * 1000);
            timeLimitThread.interrupt();
        } catch (InterruptedException e) {
            log.info("执行完成");
        }
        return timeLimitThread.getRes();
    }

    private static class TimeLimitThread extends Thread {

        @Setter
        private ProceedingJoinPoint pjp;
        @Setter
        private Thread father;
        @Getter
        private Object res;

        @Override
        public void run() {
            Object r = null;
            try {
                r = pjp.proceed();
            } catch (Throwable throwable) {
                log.error("aspect error: ", throwable);
                r = ResponseEntity.unprocessableEntity().build();
            }
            this.res = r;
            this.father.interrupt();
        }
    }

}

分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:81
帖子:4969
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP