java前端后端交互(Spring Cloud 各个微服务之间为什么要用 HTTP 交互?难道不慢吗?)

java前端后端交互(Spring Cloud 各个微服务之间为什么要用 HTTP 交互?难道不慢吗?)
Spring Cloud 各个微服务之间为什么要用 HTTP 交互?难道不慢吗?

HTTP确实比TCP二进制协议慢,但这件事本身在90%的微服务场景下根本不重要。

先给个数字感受一下。同一内网环境,一次HTTP请求的耗时大概是1-10毫秒(包括序列化+网络+反序列化)。gRPC(基于HTTP/2+Protobuf)大概是0.5-3毫秒。差距在几毫秒级别。

一个典型的电商下单请求,要经过订单服务→库存服务→支付服务→通知服务,每跳一次服务多1-5毫秒,4跳下来多了4-20毫秒。但同时,数据库查询可能要10-100毫秒,外部支付接口调用可能要200-500毫秒。

在这个链路里,服务间通信协议的那几毫秒差距根本不是瓶颈。优化这里的收益,远不如把一条没走索引的SQL优化掉。

HTTP为什么成了默认选择

不是因为HTTP最快,而是因为HTTP的生态成本最低。

调试太简单了。 你用curl就能调一个HTTP接口,用Postman就能测,用浏览器就能看返回值。出了问题,Nginx日志、应用日志、网络抓包工具都能直接读HTTP报文。Dubbo或者自定义TCP协议出了问题,你得用专门的工具解析二进制格式,调试链路复杂得多。

跨语言天然支持。 微服务的一个常见场景是不同服务用不同语言写:Java写订单服务,Go写推送服务,Python写数据分析服务。HTTP+JSON是所有语言都支持的最大公约数,没有任何语言障碍。如果用Dubbo,那Python服务就没法接入了。

基础设施全套。 API网关、服务网格(Istio/Linkerd)、限流熔断(Sentinel)、链路追踪(Sleuth+Zipkin)——这些Spring Cloud生态里的组件都是围绕HTTP设计的。换成私有协议,大半个生态都用不了。

Feign的封装让HTTP调用跟本地调用一样简单。

@FeignClient(name = "inventory-service")public interface InventoryClient {    @GetMapping("/inventory/{productId}")    InventoryDTO getInventory(@PathVariable Long productId);}

调用方写的代码跟调本地方法没区别,HTTP的细节全被Feign封装掉了。这种开发体验是RPC框架才有的,但底层用的是HTTP。

Feign用的不是普通HTTP/1.1

很多人以为Feign就是每次调用都新建TCP连接,所以觉得慢。说实话这个担心不是完全没道理——Feign默认用的是JDK的 HttpURLConnection,确实不支持连接池,每次请求都新建连接。但这不是Feign的上限,是你没配置到位。

引入 feign-httpclient 或者 feign-okhttp 依赖,Feign就会自动切换到Apache HttpClient或OkHttp作为底层实现,这两个客户端都支持连接池和Keep-Alive。一个连接建立之后会被复用,后续请求直接复用已有的TCP连接,不需要重新三次握手。配好连接池之后,HTTP的网络开销跟长连接RPC的差距很小。

HTTP/2更进一步——同一个TCP连接上可以并发发送多个请求(多路复用),不需要等前一个请求返回才能发下一个。gRPC就是基于HTTP/2的,所以gRPC的性能优势其实来自于Protobuf的二进制序列化,而不是来自于用了什么神奇的传输层。

java前端后端交互(Spring Cloud 各个微服务之间为什么要用 HTTP 交互?难道不慢吗?)

HTTP不够用的场景

不是说HTTP永远够用,是说要等真正遇到瓶颈再换。

调用频率极高、数据量小、延迟敏感。 比如服务A每秒要调服务B十万次,每次传几十个字节,对延迟要求在1毫秒以内。这种场景HTTP的Header开销(每次请求几百字节的Header)就显眼了,Protobuf的二进制格式能把数据包大小压缩到HTTP+JSON的1/5到1/10。游戏服务器的实时同步、高频交易的行情推送,这些场景不会用HTTP。

大规模Java-to-Java的内部调用。 如果你的所有服务都是Java,而且调用量很大,Dubbo这类RPC框架是个合理的选择——共享IDL、强类型接口、性能更好。阿里、美团内部大量服务用Dubbo就是这个原因。

流式数据传输。 HTTP在流式场景下(实时推送、大文件传输)有局限,这时候WebSocket或者gRPC的流式传输更合适。

但这些场景跟"Spring Cloud的微服务"典型场景——Java后端业务服务之间的调用——关系不大。普通的订单服务调库存服务,QPS几百到几千,用HTTP绰绰有余。

RPC框架有没有在用

有,而且很多大厂在用。但注意区分两件事:

大厂用Dubbo或者自研RPC,是因为他们先遇到了HTTP的性能瓶颈,然后才换的。不是因为从一开始就觉得HTTP不行。字节内部用的Kitex(Go的RPC框架),是在业务量到了一定规模之后才逐步替换的。

Spring Cloud选HTTP,是因为它的目标用户是大多数中小规模的微服务系统,这些系统永远不会遇到HTTP的性能瓶颈。为了那几毫秒引入RPC框架的复杂度,不值得。

Spring Cloud也没有把你锁死在HTTP上。如果你真的需要更高性能的通信,可以把Feign换成Dubbo Spring Cloud,接口定义不变,底层换成Dubbo协议。生态在那里,需要的时候可以换。

性能优化的基本原则是——量你有多慢再说。不要在没有数据支撑的情况下"预先优化"通信协议。你们系统的真实瓶颈大概率不在Feign的那几毫秒上。

文章版权声明:除非注明,否则均为边学边练网络文章,版权归原作者所有

相关阅读