高手,雲集在於REST、gRPC 和GraphQL之間!

2022.08.03
高手,雲集在於REST、gRPC 和GraphQL之間!

Rest是最常用的API交互手段,SpringBoot對其進行了高度的集成。它通過語義化的URL,使用最通用的HTTP協議,完成無狀態的請求交互。

Rest、GraphQL、gRPC,是目前對Web暴露API常用的三種組織方式。

每當看著這些名詞,我都會進入選擇困難症。這些豐富多彩的協議填滿了我們的工具箱,同時也拋出了一個難題:如果我想要自己的程序健康長久,就不得不了解它們到底是什麼東西。

這很讓人討厭,因為它們就像是螺絲螺母的型號,你做的工作只不過是從一堆零件裡挑合適的出來,讓它們配對,並讓它們組合成你想要的功能。

很無趣,也非常沒有價值。但看在錢的面子上,又不得不學。本文就是讓你快速進行選擇,不拖泥帶水,趕緊完成工作,喝杯茶也比瞎糾結有趣的多。

Rest

Rest是最常用的API交互手段,SpringBoot對其進行了高度的集成。它通過語義化的URL,使用最通用的HTTP協議,完成無狀態的請求交互。

Rest是Restfull的簡稱,使用HTTP的POST、GET、 PUT、 PATCH 和DELETE來定義對資源的操作。

雖然有這麼的操作意義,但在平常的使用中,我們習慣只使用它的POST和GET方法,對應在Spring裡就是@GetMapping和@PostMapping註解。沒別的原因,只因為Rest看似很強大,但在企業開發中曲線相對較高,很多聚合資源和復雜的操作,根本無法抽象成資源。

但Rest變種也算Rest,它依然是使用最廣泛的模式。

選擇Rest的原因是因為它的生態太好了。從Ruby到Java、從Golang到Rust,幾乎沒有語言不支持Rest。如果你想要開發一個Web系統,那幾行代碼,非常容易的就能把你的API暴露出去。而且,它與網關的集成度非常高,各種負載均衡組件對HTTP的協議可以說是爐火純青,如果你選擇它的話,真的是非常的省事。

但是,Rest也意味著效率低下。由於它要兼容HTTP1.0,頻繁的短鏈接也造成了資源的浪費。即使是長鏈接,HTTP臃腫的體積也讓它在追求高性能的場景中稍遜一籌。加上它是無狀態的,如果你想傳遞一些伴隨著用戶的數據比如JWT Token,那麼你不得不放在HTTP Header或者Cookie中,這加重了整體的傳輸負擔。

總之,Rest是一個快速的開始,但在高性能、有狀態的場景下,你不得不選擇其他。

gRPC

gRPC當然是Google的作品,因為它傳輸的數據就是google另外一個產品protobuf所編碼的。提到gRPC就不得不提到thrift,它們是一樣的東西。但由於google的光環,gRPC更加流行。

gRPC的开发就不像Rest那么灵活,它需要你定义一份合同,然后在client和server端同时引用和传输它。

有了这份合同,就可以压缩数据。比如我们常用的json,其实冗余信息特别多。如果把json的字段使用固定的int代替,或者放在固定的位置进行传递,那么字段名称就根本不需要占用那么大的空间。

gRPC提供了多种数据传输模式。

  • 类似于Rest的HTTP的一问一答模式;
  • Client-Streaming 客户端发送数据是流的方式,然后以特定信息结尾,然后Server返回结果;
  • Server-Streaming Client请求了服务端,服务端持续发送数据到Client,直到通知它结束;
  • Bidirectional Streaming 双工通道,那就是普通的TCP链接了,全部是流的方式;

gRPC发展了这么多年(2016),对负载均衡的支持也非常好。相对于传统的Rest,它使用HTTP2来传输数据,减少了一问一答的等待,减少了链接的占用。

如果你在搞物联网,或者一些弱网环境的数据收集,这种高压缩比的数据定然让你事半功倍。当然,如果你的微服务体系追求较高的性能,结果Rest就占了一半,那么gRPC是你的不二选择。

当然,弱点也是有的。那就是调试的时候,不如HTTP的生态全面,各种自动化工具缺乏,二进制也通常会让人头晕目眩。

GraphQL

GraphQL也比较年轻,到了2015年才诞生,它规定了一种只取“所需要”数据的能力。

在传统的Rest请求上,访问特定的URL,你会获得相对固定的结果。不管返回的数据里有多少无用的字段,Rest请求都会把请求吐给你。

GraphQL的客户端可以决定取出哪些数据,甚至是取数据的方式和格式--也就是只取它所需要的数据,而不会产生过多的无用数据。

Github就是GraphQL的集大成者。在https://docs.github.com/en/graphql上,详细的列出了这些接口。

下面就是一个典型的带有变量的查询语法。可以看到,这使得请求端比如Js有了类似编程的能力。

query($number_of_repos:Int!) {
  viewer {
    name
     repositories(last: $number_of_repos) {
       nodes {
         name
       }
     }
   }
}
variables {
   "number_of_repos": 3
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.

当然它的弱点也是显而易见的。相对于直接请求某个地址,这些查询语句使得请求的构造变的复杂,学习曲线相对陡峭。

对于复杂的资源查询,尤其是字段非常多,且层次非常深的资源查询,GraphQL不失为一种好的方式。

End

以上就是这三种主要方式的简单介绍。目前,Rest毫无疑问是使用最多的,原因就是因为简单;gRPC有着迅猛的发展势头,尤其在微服务领域已经得到广泛应用;GraphQL很复杂,当然对复杂的业务数据来说是一个好的工具。

当你的业务纯粹是功能为主,访问量一般,那就毫无疑问的使用Rest来快速实现,拿钱完事;如果你的业务对性能要求很高,交互方式上又有流的表现形式,那可以选择gRPC,这一般发生在项目初期,否则还是遵循公司的基础建设为主;GraphQL就相对比较高级了,引入它很痛,周期也较长,是否使用它来组织数据,就看你的决心了。

但无论如何,比起绣花针刺大象,永远不要使用大炮打蚊子。那可能轰不着蚊子,而会炸了自己。

作者简介:小姐姐味道 (xjjdog),一个不允许程序员走弯路的公众号。聚焦基础架构和Linux。十年架构,日百亿流量,与你探讨高并发世界,给你不一样的味道。