Feign 默认不是 短连接

疯狂创客圈 Java 高并发【 亿级流量聊天室实战】实战系列 【博客园总入口


疯狂创客圈(笔者尼恩创建的高并发研习社群)Springcloud 高并发系列文章,将为大家介绍三个版本的 高并发秒杀:

一、版本1 :springcloud + zookeeper 秒杀

二、版本2 :springcloud + redis 分布式锁秒杀

三、版本3 :springcloud + Nginx + Lua 高性能版本秒杀

以及有关Springcloud 几篇核心、重要的文章

一、Springcloud 配置, 史上最全 一文全懂

二、Springcloud 中 SpringBoot 配置全集 , 收藏版

三、Feign Ribbon Hystrix 三者关系 , 史上最全 深度解析

四、SpringCloud gateway 详解 , 史上最全

五、图解:tomcat的maxConnections、maxThreads、acceptCount | 秒懂

前言

网上很多文章都说,Feign 默认采用短连接进行远程调用,其实,这种结论是不对的。为什么呢? 下面细致的为大家来解读。

Feign中默认情况下的长连接

Feign中,默认情况下,使用的是JDK1.8中的 HttpURLConnection 基础连接类。该类的内部,使用了JDK1.8自带的 HttpClient 请求客户端类去负责完成底层的socket流操作。另外,JDK1.8还提供了一个简单的长连接缓冲类 KeepAliveCache,实现HttpClient 请求客户端类的缓存和复用。

三个类的所处位置为:HttpURLConnection 类处于 java.net 包中,而 HttpClient 类和KeepAliveCache类,则处于sun.net.www.http 包中。

HttpURLConnection、HttpClient、KeepAliveCache三个类的简单关系为:

每个HTTP请求都是一个HttpURLConnection实例,每个请求都会有一个 HttpClient 客户端实例,一个HttpClient 实例都持有一个TCP socket 长连接。如果 HttpClient 实例可以复用,则暂存在KeepAliveCache 缓存实例中。HttpURLConnection 会优先从缓存中取得合适的HttpClient 客户端,如果缓存中没有,HttpURLConnection 才会选择去创建新的HttpClient 实例。

通过三者之间的关系,可以看出: HttpClient 实例的复用,就是底层 TCP socket 长连接的复用。

JDK1.8 的 HttpClient 实例的复用的流程

下面,通过单步跟踪的方式,说一下HttpClient 实例的复用大致流程。

(1)首先,从默认的 feign.Client.Default 客户端的 execute 方法开始。

execute 方法首先会调用 convertAndSend(connection, request) 方法,打开一个URL连接实例,也即是一个 HttpURLConnection 类型的实例。然后,在convertResponse 方法中,开始获取响应码。这个时候,请求的整个处理过程,才真正开始。

(2) 通过单步跟踪发现,connection.getResponseCode() 语句执行过程中, 会通过调用HttpClient.New(..) 获取一个可用的 HttpClient 客户端实例。

HttpClient.New(..)是一个静态方法,大致的逻辑:它会调用 KeepAliveCache 类型的静态成员 kac 的get方法,去首先获取缓存中的HttpClient 客户端实例。

KeepAliveCache实例的 get方法,会主要以请求的 url 值作为 key,去缓存中查找是否有绑定的 HttpClient 实例,如果有的话直接拿过来用。

(3) 如果KeepAliveCache 缓存实例中没有,则调用HttpClient的构造器,新建一个HttpClient 对象,这个构造方法的最后一行,会调用了openServer() 方法,这个时候才会去真正的建立TCP连接。

(4) 至此,HttpURLConnection 实例的getResponseCode() 方法,终于拿到了内部的 HttpClient 连接,这个时候可以向 SERVER 端写请求数据了,这个时候会调用 writeRequests 方法。

HttpURLConnection 实例的writeRequests方法,首先会判断 httpClient.isKeepAlive 的值,该值默认是true,所以在请求上加上了 Connection:keep-alive 请求头 。

(5)writeRequests 方法写数据完成之后,会调用HttpClient.parseHTTP(..)方法,去解析服务端响应的数据,包括服务的响应头。

在parseHTTP(..)方法中,如果响应头中包含了Connection:keep-alive,并设置了Keep-Alive 头,比如含有以下内容:“Keep-Alive:timeout=xx,max=xxx” ,其中 timeout 表示服务端的‘空闲’超时时间,max表示长连接最多处理多少个请求。则这两个值,将覆盖掉 httpClient对象的keepAliveTimeout 和 keepAliveConnections 属性的值。

(6) parseHTTP(..)方法读取完数据之后,最终会调用到httpClient.finished方法,将当前httpClient对象,加入到缓存中,这个地方是实现 TCP 连接复用的关键。

(7)HttpClient的 putInKeepAliveCache方法,主要以请求的 url 值作为 key (因为这里的第二个参数总是写死为 null ),以当前 HttpClient 实例为 value,放入到KeepAliveCache 类型的静态成员 kac 缓存中,以便后面进行复用 。

通过以上的七步,JDK1.8 实现了HttpURLConnection 的长连接。

这里,有一个问题:什么Feign调用会默认在请求头中加上Connection:keep-alive?

原因是这样的,在 sun.net.www.http.HttpClient 类的静态初始化代码部分,包括了 keepAliveProp 静态属性的初始化。keepAliveProp 静态属性的值,是决定HttpClient 客户端实例是否复用的关键之一,如果keepAliveProp 静态属性值为false,则无论如何都不会进行连接复用。sun.net.www.http.HttpClient 类的静态初始化代码节选如下:

 static {
String var0 = (String)AccessController.doPrivileged(new GetPropertyAction("http.keepAlive"));
//…省略不相干代码
if (var0 != null) {
keepAliveProp = Boolean.valueOf(var0);
} else {
keepAliveProp = true; //默认值为true
}
//…省略不相干代码
}

可以看到,首先取得一个系统配置项 http.keepAlive 的值,如果该配置项的值没有做专门的设置或者修改,则sun.net.www.http.HttpClient 静态属性 keepAliveProp 的值,默认被赋值为true。

通过阅读源码可以知道,静态属性 keepAliveProp 的值,是决定HttpClient 的实例对象是否放入长连接缓冲池 KeepAliveCache 的一个重要关键属性值。也就是说,这个属性为true,则 HttpClient 实例对象具备复用的可能,否则,HttpClient 实例对象不能被复用。

至此,关于JDK1.8 实现如何实现长连接,也就介绍完了。不过,细心的读者可能会发现,HttpURLConnection 内部的长连接复用,和URL有关:只有在URL字符串相同的情况下,才能进行复用。这就有一个问题,如果URL中带有变量值,比如 /order/1/detail、/order/2/detail ,则不同的参数,不能进行HttpClient 实例对象的复用。

JDK默认的HttpClient 实例对象的复用的问题

和ApacheHttpClient 连接复用相比,JDK默认的HttpClient 实例对象的复用,有以下问题:

(1)JDK默认的 HttpClient 实例对象复用的粒度太小,只有URL相同的情况下,才能进行连接复用。而 ApacheHttpClient 连接复用的粒度则大很多,同路由的连接,就可以复用。

(2)在URL字符串变化比较大的场景下,JDK默认的 HttpClient 实例对象的内部连接,会保持一段时间才被释放,会占用系统的连接资源,更加不利于高并发。

所以,从以上两点出发,由于不能相同保证URL的请求数据巨大,所以不建议使用JDK默认的HttpClient 实例对象。建议在Feign中,使用ApacheHttpClient 连接池进行连接的复用

最后,介绍一下疯狂创客圈:疯狂创客圈,一个Java 高并发研习社群博客园 总入口

疯狂创客圈,倾力推出:面试必备 + 面试必备 + 面试必备 的基础原理+实战 书籍 《Netty Zookeeper Redis 高并发实战


疯狂创客圈 Java 死磕系列

  • Java (Netty) 聊天程序【 亿级流量】实战 开源项目实战

ty) 聊天程序【 亿级流量】实战 开源项目实战**


纠错:Feign 没用 短连接的更多相关文章

  1. 误人子弟的网络,谈谈HTTP协议中的短轮询、长轮询、长连接和短连接

    引言 最近刚到公司不到一个月,正处于熟悉项目和源码的阶段,因此最近经常会看一些源码.在研究一个项目的时候,源码里面用到了HTTP的长轮询.由于之前没太接触过,因此LZ便趁着这个机会,好好了解了一下HT ...

  2. HTTP协议中的短轮询、长轮询、长连接和短连接

    HTTP协议中的短轮询.长轮询.长连接和短连接 引言 最近刚到公司不到一个月,正处于熟悉项目和源码的阶段,因此最近经常会看一些源码.在研究一个项目的时候,源码里面用到了HTTP的长轮询.由于之前没太接 ...

  3. (转)对Http协议的长连接和短连接新的认识

    转载来自:http://www.cnblogs.com/zuoxiaolong/p/life49.html一直对长连接短连接模模糊糊,看着该博主的文章,豁然开朗~ 引言 最近刚到公司不到一个月,正处于 ...

  4. 转---谈谈HTTP协议中的短轮询、长轮询、长连接和短连接

    作者:伯乐在线专栏作者 - 左潇龙 http://web.jobbole.com/85541/ 如有好文章投稿,请点击 → 这里了解详情 引言 最近刚到公司不到一个月,正处于熟悉项目和源码的阶段,因此 ...

  5. 谈谈HTTP协议中的短轮询、长轮询、长连接和短连接

    引言 最近刚到公司不到一个月,正处于熟悉项目和源码的阶段,因此最近经常会看一些源码.在研究一个项目的时候,源码里面用到了HTTP的长轮询.由于之前没太接触过,因此LZ便趁着这个机会,好好了解了一下HT ...

  6. http的长连接和短连接(史上最通俗!)

    1.以前的误解 很久之前就听说过长连接的说法,而且还知道HTTP1.0协议不支持长连接,从HTTP1.1协议以后,连接默认都是长连接.但终究觉得对于长连接一直懵懵懂懂的,有种抓不到关键点的感觉. 今天 ...

  7. TCP同步与异步,长连接与短连接【转载】

    原文地址:TCP同步与异步,长连接与短连接作者:1984346023 [转载说明:http://zjj1211.blog.51cto.com/1812544/373896   这是今天看到的一篇讲到T ...

  8. HTTP的长连接和短连接

        本文总结&分享网络编程中涉及的长连接.短连接概念.     关键字:Keep-Alive,并发连接数限制,TCP,HTTP 一.什么是长连接 HTTP1.1规定了默认保持长连接(HTT ...

  9. HTTP的长连接和短连接——Node上的测试

        本文主要从实践角度介绍长.短连接在TCP层面的表现,借助Node.JS搭建后台服务,使用WinHTTP.Ajax做客户端请求测试,最后简单涉及WebSocket.     关键字:长连接.短连 ...

随机推荐

  1. VMware Workstation虚拟机安装CentOS-7-Minimal经验分享

    本文主要为0基础的小白准备,有一定经验的大神请忽略.因为最近刚接触linux,在其中也是遇到无数的弯路,本着互惠互利原则,特写这个博客,希望后来人能少走点弯路,更快的进入状态.话不多说,上货. 一,首 ...

  2. MATLAB实例:绘制条形图

    MATLAB实例:绘制条形图 作者:凯鲁嘎吉 - 博客园 http://www.cnblogs.com/kailugaji/ 用MATLAB绘制条形图,自定义条形图的颜色.图例位置.横坐标名称.显示条 ...

  3. 七、3Dslicer的坐标系

    一.参考博客 https://blog.csdn.net/Huadong_eddy/article/details/84988166

  4. centos7 链路聚合+KVM桥接连网

    一.两个物理网卡做链路聚合(em3,em4) 1)创建team类型的网卡,连接别名为team0,使用的模式为activebackup-主备/loadbalance-负载均衡nmcli con add ...

  5. ElementPath

    ElementTree库附带了一个简单的类似XPath的路径语言ElementPath主要区别在于,可以在ElementPath表达式中使用{namespace}标记符号但是,诸如值比较和函数之类的高 ...

  6. C++笔记——快读快写

    直接开始吧 额m~,这里就没什么好说的了,无非就是用getchar加快cin或printf的读入速度. 代码: inline int read() { int X=0; bool flag = 1; ...

  7. 从web到游戏,走出舒适区

    最近很久没有更新博客了,实在太忙.因为在这段时间里我做了一个改变了我现在职业生涯的一个决定,而我现在正在为这个决定而加倍的努力付出. 我认为我还是有必要把这个比较重要的节点记录下来,我也是第一次在自己 ...

  8. [灵魂拷问]MySQL面试高频100问(工程师方向)

    作者:呼延十 juejin.im/post/5d351303f265da1bd30596f9 前言 本文主要受众为开发人员,所以不涉及到MySQL的服务部署等操作,且内容较多,大家准备好耐心和瓜子矿泉 ...

  9. 使用Kubernetes进行ProxySQL本机群集

    自v1.4.2起,ProxySQL支持本机群集.这意味着多个ProxySQL实例可识别群集; 他们了解彼此的状态,并能够通过根据配置版本,时间戳和校验和值同步最新的配置来自动处理配置更改. Proxy ...

  10. 微信小程序头像为什么是模糊的?小程序头像模糊怎么办?

    「柒留言」更新的换国旗头像小功能,获取头像显示模糊... 1.头像模糊 国庆之前,更新了「柒留言」小程序加国旗头像的小功能,但是头像模糊这个坑我在发布新版之前还没解决. 一直以为是代码出了问题,各种搜 ...