作者 | 雷卷
來源 | 阿里技術公眾號
大家好,我是陳立兵,花名雷卷,Java/Kotlin工程師、 Alibaba RSocket Broker開發者Reactive基金會的初創成員。目前主要關注於Reactive/RSocket、Serverless、WebAssembly、 Deno/Rust等相關技術。
今天和大家聊聊為什麼我認為Spring仍然會是雲原生時代最佳平臺之一。
時間回到2015年,當時我在華盛頓參與SpringOne 2015大會,主題演講是Cloud Native Enterprise。那次大會的口號也是Cloud Native,鋪天蓋地的海報都與Cloud Native有關。
你可能會感到奇怪,那個時候容器還沒有流行啊,怎麼就敢稱為Cloud Native呢?雖然不少同學對Cloud Native的理解可能不太一樣,但是越來越多的人相信“Cloud native is about culture, not containers”。可以肯定的是,雲原生不等於容器,它是一種軟件開發的文化,即便後續有基於V8隔離的Serverless或者WebAssembly FaaS平臺,也還是雲原生的範疇。
而在雲原生的潮流下,Spring做了很多事情,比如支持分佈式架構的Spring Cloud,它基本是Java應用分佈式和雲化的必備框架,各個雲廠商都有Spring Cloud的對接版本,比如Spring Cloud Alibaba、AWS、Azure、GCP等,Spring Cloud極大地簡化了Java應用和雲服務的對接。
可以說,在微服務逐漸流行的過程中,Spring生態一直處於領先地位。很多人可能會疑惑:Spring之前取得的這些成就我們都知道,可這兩年好像並沒有什麼發展,Spring還能繼續引領該技術趨勢嗎?
其實,之所以會有這樣的疑惑,是因為當我們談到基於雲和雲原生環境的開發時,普遍更關注的是技術棧的選擇,而這背後主要是費用的問題。
每一位開發者或中小公司都希望購買更少的雲資源幹更多的事情,其中最主要的是內存和CPU。內存消耗要求小,如果能編譯為獨立可執行程序,就儘量選擇一些輕量型的開發框架;而且要考慮語言高效且全異步化的框架,這樣可以保證充分利用CPU,避免線程等待等造成的浪費。
綜合來看,很多人會更傾向於選擇Rust、Node.js、Golang等技術棧。而Java啟動慢,消耗內存多,好像還比較費錢,看起來已經不太適合接下來的雲原生時代。
那麼作為基於Java語言的Spring生態,還能否適應新的開發方式,比如Cloud Native、Serverless、Faas等,它還會是雲原生時代的最佳平臺的選擇嗎?
接下來,我將從5個角度來為你分析一下這個問題,分別是:Java和JDK的發展、充滿良性競爭的JVM語言、成熟的面向服務架構的Spring Boot和Spring Cloud、讓事件驅動架構更易使用的Spring Reactive。
一 Java 和 JDK的發展
我們知道Spring基於的是Java框架,而JDK又是運行Java程序的基礎。要探討“Spring還會不會是雲原生的最佳平臺之一”這個問題,我們需要先來看看JDK這個底座怎麼樣,是不是能為Spring與時俱進的發展提供良好的基礎。
首先是版本迭代。現在OpenJDK的開發速度非常快,之前是三年出一個重大版本,現在半年就出一個版本。好多同學感嘆現在都快Java 17了,而自己還在用Java 1.8。我們都說軟件開發要小步快跑,這個是一個好的開發方式:小步快跑、快速反饋、快速迭代開發。類似的還有JavaScript一年一版,TypeScript一年三版,Java一年兩版,可以說都是非常好的節奏。
其次是JDK特性的更新。如果你關注JDK的話就不難發現,越來越多的特性被融入到JDK中,比如類似協程的輕量級線程Loom項目、提升Native調用支持的Panama項目(SIMD支持)、更高級的GC算法等。
而針對我們前面提到的Java啟動慢、消耗內存多的問題,Oracle推出了基於OpenJDK的GraalVM,它可以直接在JVM中運行JavaScript、Python、Ruby等語言,是名副其實的Ployglot JVM。另外,GraalVM還提供了Native Image特性,可以將Java代碼轉換為獨立可執行程序。Spring也推出Spring Native項目,可以非常方便將Spring Boot應用native-image化,這樣Spring應用啟動的速度更快,消耗的內存也更少。native-image化後的Spring應用就可以滿足每一位開發者或中小公司對“上雲且費用更少”的需求。即便是Java的命令行應用,GraalVM也有非常好的解決方案——Picocli + GraalVM Native Image + upx,它可以將Java應用編譯為更便捷的可執行程序。
下圖就是GraalVM多語言和Native Image支持列表,如下:
此外,各個雲廠商也在積極JDK的開發,如AliJDK、Amazon Corretto、Azul等,這些都是對JDK發展有非常好的作用。
所以說,對Spring而言,JDK這個基礎還是非常穩固的。
二 充滿良性競爭的 JVM 語言
JDK並不是只能支持Java這一門編程語言,相反,它可以支持多種,比如Kotlin、Scala、Groovy等,這裡我們統一稱之為JVM語言。當下,JVM語言正處於一個充滿良性的競爭狀態。
我們知道每種語言都有自己擅長的使用場景。在雲原生時代,多語言開發支持非常重要,開發人員需要根據實際的業務場景選擇不同的開發語言。無論JVM語言或者GraalVM支持的語言,都可以和Spring直接整合,方便開發人員充分利用Spring技術棧做開發。
其中,對Spring支持最好的語言是Kotlin。Kotlin和Spring的整合已經滲透到框架的各個方面,比如Spring Boot和Kotlin整合,Spring Webflux對Kotlin Coroutines & Flow的支持,Spring Data、SpringIntegration、SpringCloud Function等也都包含對Kotlin的支持,這些都實現了對Kotlin的深度整合,目的就是讓語言和框架結合得更好,提升開發效率。此外,Kotlin和Scala也是與Spring整合得比較好的語言。
因為Java、Kotlin和Scala這三種語言在Spring中的整合非常好,所以接下來我就對它們具體說明一下,幫助你對JVM語言當前的發展情況有一個比較清晰的認知。
Java
Java語言的發展還是非常快速的,伴隨著OpenJDK的開發,Java半年就會推出一個版本,每個版本都會伴隨著語法的升級、標準庫的升級等,極大地方便了開發人員。從Java 9到16,已經完成了很多語法和特性方面的提升,比如大家知道var關鍵字(局部變量類型推導)、Text block、Pattern Matching for instanceof、Record、sealed interface等。
Kotlin
雖然說Kotlin不完全是針對JVM的,它也包括Native、JavaScript等,但是Kotlin對JVM和Android的支持,目前是眾多Kotlin平臺中特性最多且穩定的。
現在Kotlin的發展勢頭非常迅速,已經孵化了多個子項目,比如最新的Kotlin Multiplatform Mobile(一套代碼支持多個手機平臺)、 Kotlin Compose for Desktop(一套代碼開發多操作系統的桌面端應用)等。當然,這些變化中最引入注目的是Kotlin 1.5推出的Kotlin intermediate representation (IR) ,藉助於新的IR,Kotlin的代碼可以編譯輸出到各種目標平臺且程序更優,如大家都關注的Kotlin WebAssembly。
Scala
Scala 2是2006年3月發佈的,距今已經有非常長的時間了。好的消息是Scala 3.0已經於2021年5月發佈啦。Scala 3在添加新特性的同時,去除了Scala 2中一些晦澀的特性,目的是讓Scala更好使用。如果你有興趣,可以關注下Scala3的官網。
Scala 3還有一個核心的變化是編譯器的調整,名稱為TASTy,是 Typed Abstract Syntax Trees的縮寫,結構如下:
藉助於TASTy,目前已經有Scala.js ,後續有Scala WebAssembly也不奇怪。
Kotlin和Scala對函數編程都非常友好,在這點上都彌補了Java的不足。此外,Kotlin和Scala同時支持JavaScript編譯輸出,這個對基於V8的Serverless平臺幫助非常大,比如Cloudflare的Serverless平臺。此外,Kotlin和Scala也在積極探索對WebAssembly支持,這些都是支持Web開發的好消息。
當然,JVM語言還有很多,如Groovy、Clojure等,也都在積極發展,這些JVM語言彼此競爭,彼此借鑑,這對開發者來說,都是非常好的消息。
Spring依賴的JDK和JVM語言說完了,下面我們來聊聊Spring中非常成功的兩個項目SpringBoot 和 Spring Cloud。
Spring Boot和Spring Cloud是非常成功的兩個項目,基於Java技術棧的互聯網公司基本都在使用。此外,近期如果你有關注Spring頂級佈道師Josh Long的演講的話,就會發現他一直在講Spring Reactive,他還編寫了一本書,就叫《Spring Reactive》。
那為什麼Spring Boot、Spring Cloud和Spring Reactive會如此備受關注呢?
我們知道,對於雲原生來講,有兩種非常重要的架構方案,一個是面向服務化架構,另一個是事件驅動架構。面向服務化架構通常基於同步的請求/響應模型,Spring Boot、Spring Cloud的目標就是支持這一特性;事件驅動架構則基於異步化的消息模型和消息路由,而Spring Reactive這個項目的核心就是支撐這一架構。
接下來,我就帶你看看Spring具體是如何支持雲原生裡這兩種重要的架構方案的,藉此,你也會對Spring裡重要的三個項目Spring Boot、Spring Cloud和Spring Reactive有一個比較清楚的認知。
三 成熟的面向服務架構的 Spring Boot 和 Spring Cloud
通常,雲原生下的應用都傾向於微服務設計,而微服務設計的核心內容就是面向服務化架構設計和應用編程接口(API)管理,Spring Boot和Spring Cloud的目標就是支持這一特性的,而且這兩個項目做得非常成功,基於Java技術棧的互聯網公司基本都在使用。
我們知道,服務化接口最典型的結構就是請求(Request)/響應(Response)模式,尤其是Web的Request/Response模式。當然了,遠程RPC的request/response也在此範疇,比如HTTP REST、gRPC和Dubbo。
對應到Spring中面向服務架構設計,SpringMVC可以非常好地支持Web和HTTP REST API,還包括對OpenAPI的支持。其他RPC類的通訊,也都有對應的Spring Boot starter支持,在Spring Boot中也有對應的starter組件支持,開發也非常便捷。如果要暴露其他形式服務,如Web Service和SOAP等傳統服務形式,也可以哦通過Spring Web Services(spring-ws)項目達成。
另一個特性API管理,主要涉及服務治理和服務消費端調用,對應的核心技術棧主要是Spring Cloud項目。Spring Cloud為服務化架構和API管理提供了多種基礎設置,如服務註冊發現、負載均衡、API Gateway、斷路保護等,這些技術棧方便我們更好地管理和治理服務,同時也讓消費端能更好地調用服務。
綜合下來,服務化架構和API管理,對應到Spring Boot和Spring Cloud技術棧,典型的架構如下:
如果你的架構是面向服務的,如涉及到服務編排、服務治理和API Gateway等,那麼Spring Cloud會是非常好的選擇,特性完備、框架穩定、文檔完善、歷經過諸如阿里巴巴等親自實踐。如果你的公司基於Java技術棧,那麼Spring Cloud是實現微服務架構最好的支持和實踐。
阿里巴巴從2018年7月開始就開源了Spring Cloud Alibaba,截止至今,它已經獲得了超過1.9萬的star數,已經超過了所有其他實現的總和。從X-lab 開放實驗室發佈的《2020年微服務領域開源數字化報告》中,我們也看到Spring Cloud Alibaba已經成為最活躍、最受開發者歡迎、工具鏈最完善的Spring Cloud實現。大家在選型過程中可以考慮。
四 讓事件驅動架構更易使用的 Spring Reactive
前面我們講述了Spring對面向服務架構的支持,還有另外一種架構模式,就是事件驅動架構。事件驅動架構被普遍認為是雲原生首選的架構方案,那麼Spring對這方面支持如何?這就涉及到Spring Reactive這個項目了,其核心就是支撐事件驅動架構。
Spring Reactive是面向異步化消息的,消息或者事件是企業集成模式(EIP)首推的架構模式,你可能聽說過Spring企業集成(SpringIntegration)這個項目,其主要就是負責企業集成。Spring Reactive的目的則是讓事件驅動架構設計也能成為應用架構的首選,而且要更加簡單。
這裡講一個題外話:我和一些資深的Spring Boot和Spring Cloud程序員交流過,大家對各種服務化接口設計如數家珍,甚至包括代碼層級的細節,但是一討論到企業集成模式(EIP),都表示這是Martin Fowler的知名大做,問及大家的系統中是否使用到諸如Apache Camel或者Spring Integration,大家都表示現在面向服務結構已經滿足業務需求啦。
那麼這裡就有一個問題,如此知名的EIP、ESB或者EDA為何沒有在架構設計中所採納?是燈下黑被遺忘、還是門檻太高、或者壓根就是一個純理論,完全脫離實踐?
在面向服務化的架構設計中,基本都是基於服務接口調用,並且調用是同步的,所以服務編排、API管理起著非常重要的作用。當然在面向服務化的架構設計中,我們也會引入一些消息驅動設計,藉助像Kafka或者其他MQ系統,處理一些異步化或者數據分析的場景,如用戶註冊後發一封郵件、用戶登錄觸發事件進行安全審計、商品信息或價格修改後觸發搜索引擎增量索引、用戶下單後觸發各種通知等等。
面向服務有其好處,但是要解決非常多的問題,如非阻塞、服務註冊和發現、高性能、易集成等,這也是很多專家提出雲原生場景中,事件驅動架構才是主流。
事件驅動架構不涉及服務註冊和發現這些負責的機制,基於消息的路由也非常容易,異步化消息通訊的性能更高(當然你的賬單也更小),各種SaaS服務集成也更簡單(EventBridge產品)、FaaS觸發容易等等。如果你想了解更多,可以看看《Building Event-Driven Microservices》這本書。這裡貼一下Redhat推薦的基於微服務思想的事件驅動架構設計,如下:
從這張圖中我們可以看出,所有系統之間的交互都是通過消息進行通訊的,微服務不再是面向接口的請求/響應設計,處理來自不同的應用的Request/Response請求,而是以一種異步化的方式不斷地在處理來自Broker的消息。
說到這裡,你可能明白了,如果說Cloud Native以事件驅動設計架構為核心,那麼Spring Reactive的目的是讓事件驅動架構簡單易用,開發便捷,這個就是Spring Boot和Cloud對面向服務架構的支持是一樣的。此外這兩種架構並不是矛盾的,都是可以相互共存和相互補充的。
要實現更好的事件驅動架構,兩個基礎少不了:異步化和消息化。異步化可以解決線程等待的問題,而消息及其消息路由,可以很好地實現應用的鬆耦合。當前越來越多的產品使用異步化消息方案,各種消息產品中間件自不必說,大家熟知的HTTP/2都是基於異步消息通訊的。
那為何要異步化?我們知道消息處理的模型和同步服務調用是不一樣的,如消息處理的Event Loop和Actor模型,都是非常高效的消息處理方式,如果我們在消息處理的過程中,還要處理基於線程池的同步服務調用,勢必會影響模型和性能。當然也不是完全不能有同步,只是儘量避免過多的服務同步調用的場景。
圍繞異步化和消息的場景,Spring要做非常多的工作,我們都知道Java對異步化支持非常滯後。Java 1.8加入了CompletionStage接口,Java 9添加了Reactive Stream支持介入了Flow。大家一直關注的輕量級線程的Loom項目還在開發中,預計要到Java 17才能發佈。
所以目前Java多數的項目項目都會選擇Reactive框架,當然Spring團隊開發了Reactor框架,增加了Reactor對Netty、Kafka等適配,從而保證從底層開始就是異步化,所以這也是起名為Spring Reactive的原因。
接下來就是大家都看到的場景,Spring Webflux、Spring Integration、Spring Data等眾多項目都添加了對異步化的支持,所有的這些調整,就是要確保從底層開始就是全異步化的,你可以理解為5G的非獨立組網和獨立組網兩種方式,只是Spring選擇了Reactive這種獨立組網、獨立生態的方式,當然工作量也是非常大的。這其中就涉及了兩個非常大的問題:數據庫和分佈式通訊。
目前大多數NoSQL產品都提供了異步化的接口,異步化訪問NoSQL產品沒有什麼問題。雖然NoSQL發展很迅猛,但是還是沒有撼動數據庫的地位,我們都知道Java中數據庫訪問的規範是JDBC,但是JDBC是同步的接口,所以Spring啟動了R2DBC項目,目的就是能夠以Reactive異步化接口訪問數據庫,目前來說,在Spring框架下使用JDBC和R2DBC的體驗幾乎是一致的。
這裡我和同學們同步兩個消息:Spring 5.3已經內置R2DBC支持,也就是spring-r2dbc,和spring-jdbc並列。大家都喜歡使用的MySQL數據庫,也推出了mariadb-r2dbc 1.0.0穩定版,Oracle也推出了R2DBC版本的驅動。當然Java中的DB框架,Spring JPA、MyBatis等都添加了對R2DBC的適配。Hibernate也推出了hibernate-reactive項目(基於Vert.x database),雖然是不是基於R2DBC的,但是也是全異步化的。
另外一個問題就是分佈式通訊,這個在微服務架構中扮演中非常重要的作用。一直以來Spring主要支持HTTP,但是HTTP協議主要是針對瀏覽器設計的,在後端服務之間通訊優勢並不明顯,而且性能上也沒有優勢。當然基於HTTP/2異步消息通訊的gRPC是一個很好的選擇,但是Spring一直沒有內置gRPC支持,當然這對大多數開發者來說,這不是什麼大問題,第三方的grpc-spring-boot-starter做的也非常好。
如果你關注Spring發佈的話應該知道,Spring 5.2後續版本選擇RSocket通訊協議,並將RSocket內置到spring-message項目中。為何?RSocket是全異步的二進制消息通訊協議,提供了完備的通訊模型,而且是對等通訊的,非常匹配事件驅動架構,這也是Spring Reactive將RSocket納入到Spring核心的原因,當然RSocket背後的開發,Spring和阿里團隊起著主導作用。
CNCF下有一個CloudEvents規範,主要解決異構系統的事件通訊,消息和事件在數據結構上是一致的,都是Headers和Payload(data)結構,同時包含消息頭的擴展。最新的cloudevents-java SDK 2.1,Spring messaging添加了對CloudEvents的支持,同時支持CloudEvent接口的編解碼支持,將消息和事件進行了統一和整合,在Spring中處理CloudEvents和消息更簡單。
和企業集成相關產品,如Apache Camel, 基於Akka的Alpakk、MuleSoft的Mule 4、Spring Integration等,這些產品都提供了對Reactive的集成,可以說可以和Spring Reactive無縫對接。
五 總結
回到文章的問題,為什麼Spring 仍然會是雲原生時代最佳平臺之一?總結下來,Java和JDK的開發處以非常好的發展,JVM語言良性發展且充滿競爭。成熟的Spring Boot和Spring Cloud已經讓面向服務的架構設計簡單易用,而Spring Reactive則將事件驅動架構更易被使用,同時可以讓更多的企業系統完成和Spring Reacitve對接,無論是IoT設備、ESB產品、SaaS或者雲服務等。
針對微服務的場景,Spring Cloud提供了成熟的面向架構服務基礎,Spring Reactive則是面向未來的事件驅動架構,當然這裡並不是說,面向服務的架構已經過時,事實上面向服務的架構非常成功,但是在雲原生或新的Serverless環境下,可能事件驅動架構可能更合理一些,或者是兩者的配合使用,不用擔心,Spring在這兩方面都做的非常好。
技術公開課
Spring Cloud微服務架構設計與開發實戰
Java Spring Cloud是全球範圍內最成熟、最完善、最流行的微服務架構方案體系,被眾多互聯網大公司採用。本課程重點講解服務治理、註冊發現、熔斷限流、網關代理、鏈路追蹤、安全監控等核心問題,循序漸進,概念為輔、實戰為主,涵蓋經典面試題,講授成為微服務架構師的必備技能。
點擊這裡,開始學習吧~