Spring Cloud 系列之 Feign 声明式服务调用(二)
本篇文章为系列文章,未读第一集的同学请猛戳这里:Spring Cloud 系列之 Feign 声明式服务调用(一)
本篇文章讲解 Feign 性能优化的问题,Gzip压缩、HTTP连接池、请求超时等。
1|0Feign 性能优化
1|1Gzip 压缩
gzip 介绍:gzip 是一种数据格式,采用 deflate 算法压缩数据;gzip 是一种流行的文件压缩算法,应用十分广泛,尤其是在 Linux 平台。
gzip 能力:当 Gzip 压缩一个纯文本文件时,效果是非常明显的,大约可以减少 70% 以上的文件大小。
gzip 作用:网络数据经过压缩后实际上降低了网络传输的字节数,最明显的好处就是可以加快网页加载的速度。网页加载速度加快的好处不言而喻,除了节省流量,改善用户的浏览体验外,另一个潜在的好处是 Gzip 与搜索引擎的抓取工具有着更好的关系。例如 Google 就可以通过直接读取 gzip 文件来比普通手工抓取更快地检索网页。
HTTP 协议关于压缩传输的规定
- 客户端向服务器请求中带有:
Accept-Encoding:gzip
,deflate
字段,向服务器表示客户端支持的压缩格式(gzip 或者 deflate),如果不发送该消息头,服务端默认是不会压缩的。 - 服务端在收到请求之后,如果发现请求头中含有
Accept-Encoding
字段,并且支持该类型压缩,就会对响应报文压缩之后返回给客户端,并且携带Content-Encoding:gzip
消息头,表示响应报文是根据该格式进行压缩的。 - 客户端接收到请求之后,先判断是否有
Content-Encoding
消息头,如果有,按该格式解压报文。否则按正常报文处理。
Gzip 压缩案例
局部
只配置 Consumer 通过 Feign 到 Provider 的请求与相应的 Gzip 压缩。
服务消费者 application.yml
全局
对客户端浏览器的请求以及 Consumer 对 Provider 的请求与响应都实现 Gzip 压缩。
服务消费者 application.yml
测试
访问:http://localhost:9090/order/1 结果如下:
1|2HTTP 连接池
点击链接观看:HTTP 连接池视频(获取更多请关注公众号「哈喽沃德先生」)
为什么 HTTP 连接池能提升性能?
HTTP 的背景原理
- 两台服务器建立 HTTP 连接的过程是很复杂的一个过程,涉及到多个数据包的交换,很耗时间。
- HTTP 连接需要的 3 次握手 4 次挥手开销很大,这一开销对于大量的比较小的 HTTP 消息来说更大。
解决方案
采用 HTTP 连接池,可以节约大量的 3 次握手 4 次挥手,这样能大大提升吞吐量。
Feign 的 HTTP 客户端支持 3 种框架:HttpURLConnection
、HttpClient
、OkHttp
;默认是 HttpURLConnection
。可以通过查看源码 org.springframework.cloud.openfeign.ribbon.FeignRibbonClientAutoConfiguration.java
得知。
- 传统的 HttpURLConnection 是 JDK 自带的,并不支持连接池,如果要实现连接池的机制,还需要自己来管理连接对象。对于网络请求这种底层相对复杂的操作,如果有可用的其他方案,没有必要自己去管理连接对象。
- HttpClient 相比传统 JDK 自带的 HttpURLConnection,它封装了访问 HTTP 的请求头,参数,内容体,响应等等;它不仅使客户端发送 HTTP 请求变得容易,而且也方便了开发人员测试接口(基于 HTTP 协议的),既提高了开发的效率,又提高了代码的健壮性;另外高并发大量的请求网络的时候,也是用“连接池”提升吞吐量。
HttpClient
将 Feign 的 Http 客户端工具修改为 HttpClient。
添加依赖
修改 Consumer 项目,添加两个依赖,因为本文中使用的 Spring CLoud 版本已经默认集成了 apache httpclient 依赖,所以只需要添加一个依赖即可。
配置文件
PS:如果使用 HttpClient 作为 Feign 的客户端工具。那么在定义接口上的注解是需要注意的,如果传递的参数是一个自定义的对象(对象会使用 JSON 格式来专递),需要配置参数类型,例如:
@GetMapping(value = "/single/pojo", consumes = MediaType.APPLICATION_JSON_VALUE)
。本文中使用的 Spring CLoud 版本,已无需手动配置。并且使用了 HttpClient 客户端以后,我们还可以通过 GET 请求传递对象参数。
服务提供者
我们主要演示如何通过 GET 请求传递对象参数,POST 请求的方式代码无需任何改变。
ProductService.java
ProductServiceImpl.java
ProductController.java
服务消费者
ProductService.java
ProductController.java
测试
访问:http://localhost:9090/product/pojo?id=6&productName=耳机&productNum=1&productPrice=288
结果如下:
1|3状态查看
浏览器发起的请求我们可以借助 F12 Devtools
中的 Network
来查看请求和响应信息。对于微服务中每个接口我们又该如何查看 URL,状态码和耗时信息?我们可以使用配置日志的方式进行查看。
logback.xml
Consumer 项目添加 logback.xml
日志文件,内容如下(logback 日志的输出级别需要是 DEBUG 级别):