长连接的原理

Apollo的长连接实现是

  • Spring的DeferredResult来实现的,先看怎么用

import ...

@RestController
@RequestMapping("deferredResult")
public class DeferredResultController {

    private Map<String, Consumer<DeferredResultResponse>> taskMap = new HashMap<>();

    private String requestId = "demo";
    @GetMapping("get")
    public DeferredResult<DeferredResultResponse> deferredResult(){
        DeferredResult<DeferredResultResponse> ret = new DeferredResult<>();
        ret.onTimeout(() -> {
            DeferredResultResponse deferredResultResponse = new DeferredResultResponse();
            deferredResultResponse.setCode(HttpStatus.REQUEST_TIMEOUT.value());
            deferredResultResponse.setMsg(DeferredResultResponse.Msg.TIMEOUT.getDesc());
            ret.setResult(deferredResultResponse);
        });
        taskMap.put(requestId, ret::setResult);
        return ret;
    }

    @GetMapping("set")
    public void setResult(){
        DeferredResultResponse deferredResultResponse = new DeferredResultResponse();
        deferredResultResponse.setCode(HttpStatus.OK.value());
        deferredResultResponse.setMsg(DeferredResultResponse.Msg.SUCCESS.getDesc());
        taskMap.get(requestId).accept(deferredResultResponse);
        taskMap.remove(requestId);
    }

    public static class DeferredResultResponse{
        private Integer code;
        private String msg;

	   ...

        public enum Msg {
            TIMEOUT("超时"),
            FAILED("失败"),
            SUCCESS("成功");
            private String desc;

           ...
            Msg(String desc) {
                this.desc = desc;
            }
        }
    }
}

  • 这时候请求get接口,客户端是卡住的
    长连接的原理_第1张图片

  • 当有结果设置的时候才会响应,调set接口来设置结果
    长连接的原理_第2张图片

  • 如果一直没有结果设置,就会等到超时的时候才会响应
    长连接的原理_第3张图片

  • 对于Apollo的客户端来说请求流程也是这样的
    调用notification/v3接口等待获取变更的数据(namespace),如果一直没有变更,就会等到60秒超时的时候才响应。

原理

在了解原理之前,问几个问题?

  • 这个客户端阻塞是怎么实现的?
  • 超时是怎么唤醒的?
  • 设置值的时候如果找到原来的请求

回答

  • 阻塞是通过socket来实现的,只要socket请求之后不往回写response,就会一直等待
    spring判断controller是DeferredResult异步请求,就会把这个请求挂起,请求的信息先保存起来,不返回response
  • 超时唤醒是利用tomcat的能力,tomcat会启动线程去扫描队列里面挂起的请求,如果有超时时间到的,会重新dispatch
  • setResult会AsyncManager保存的request,把结果设置之后,重新dispatch

你可能感兴趣的:(ApolloConfig,spring,tomcat,java,DeferredResult)