• 长连接的原理


    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;
                }
            }
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 这时候请求get接口,客户端是卡住的
      在这里插入图片描述

    • 当有结果设置的时候才会响应,调set接口来设置结果
      在这里插入图片描述

    • 如果一直没有结果设置,就会等到超时的时候才会响应
      在这里插入图片描述

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

    原理

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

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

    回答

    • 阻塞是通过socket来实现的,只要socket请求之后不往回写response,就会一直等待
      spring判断controller是DeferredResult异步请求,就会把这个请求挂起,请求的信息先保存起来,不返回response
    • 超时唤醒是利用tomcat的能力,tomcat会启动线程去扫描队列里面挂起的请求,如果有超时时间到的,会重新dispatch
    • setResult会AsyncManager保存的request,把结果设置之后,重新dispatch
  • 相关阅读:
    Java 多线程(七):线程池
    JNI 使用案例详解(一)
    男孩姓舒取什么名字好听
    《Python魔法大冒险》010 魔法宝箱:列表与元组的探险
    docker Desktop开启远程访问端口
    JVM优化(OOM,内存溢出),查看线程快照,堆内存情况等问题
    CH2--x86系统架构概览
    软件逆向破解入门系列(1)—xdbg32/64的常见配置及功能窗口
    windows10录屏神器,轻松保存高光时刻
    Codeforces Round #833 (Div. 2)
  • 原文地址:https://blog.csdn.net/chunlaiqingke/article/details/134066416