使用SpringCloud將單體遷移到微服務

banq發表於2018-07-12

現在SOA架構下的服務管理面臨很多挑戰,比如面臨一個非常大型的程式碼庫,版本合併困難,甚至存在不同專案不同版本,維護量極其龐大,無法快速響應不同的業務需求;同時這些大型程式碼庫由於沒有前後端分離,導致打包成一個大型的WAR包,服務自身無法獨立打包部署,在執行階段,隨著專案應用規模擴大無法平滑伸縮,只能通過部署新的應用伺服器粗粒度應付;還有一個問題就是大量環境配置的管理相當複雜。

從單體遷移到微服務的實踐之道是:前後端分離,後端暴露restful api給前端。只有前後端分離,前端和後端才能分離部署,只有使用基於http的restful介面,後端才與周圍環境真正分離,如果只是使用RPC,雙方還和java介面耦合,而使用rest/json資料格式,雙方只要進行序列化和反序列化,雙方耦合沒有那麼緊密,這非常類似非同步通訊中訊息資料格式的耦合,用效能小降代價換來後端服務與周圍環境的解耦,只有這樣我們才能對後端再進行切分成微小服務,打包進入Docker,放入K8s平臺中排程執行。說白了,挖樹需要把樹根與周圍分離,整個樹才能移植,後端服務只有通過rest API前後端分離,才能安裝上Docker+K8s。

SpringBoot預設情況下已經開啟restful埠,這種約定大於配置的做法大大簡化了程式設計過程,同時也“強行”將微服務與Rest介面進行了繫結。

系統=大前端(SpringMVC或SPA等)+REST+後端

當後端服務從前端的約束羈絆中解放出來以後,完全走向了自由,可以為多個前端客戶端或其他系統提供服務API,當然系統也由此走上了分散式不歸路,服務之間呼叫不再通過JVM內部直接方法呼叫,而是通過rest/json互動,整個系統的複雜性也由此上升,SpringCloud為基於SpringBoot的分散式微服務開發提供了透明且開箱即用的開發方式,將很多屬於系統管理配置職責帶入了開發,由此對開發人員素質提出更高要求,這也是devops一詞的來由,devops=開發+運維。

下面談談SpringCloud的幾個分散式架構元件是如何簡化分散式開發和系統運維配置的。

配置伺服器

配置伺服器能夠將各種配置集中在一起,配置資訊是一種鍵值對,暴露rest API,可以加密,能夠快速失效,也可以強制更新,在執行時能夠通過下面方式強行重新整理到最新配置:

curl –X POST http://localhost:8080/refresh

CONFIG SERVER

這是一個很簡單方式,但是也要防止程式設計師不小心一個delete資料庫的災難事情發生。

API閘道器

如果說後端微服務組成了一個服務群,這個群是群主的,群主可以批准你加入也可以剔除你,API閘道器就是微服務的守門人,專業上稱為邊緣服務,微服務是核心,它是邊緣。

API閘道器的群主職責也還有其他:

1.設計上的適配層,或稱Facade模式,後端微服務可能過於細粒度,通過API閘道器進行內外適配,前後端轉換,如果220v轉換成110v一樣。

2.執行階段:將外部請求路由分發到內部各個微服務,負載平衡和路由策略是需要的。

Springcloud之前使用NETFLIX ZUUL作為API閘道器,雖然它有很多好處,容易設定,限速和日誌過濾,可授權,智慧負載平衡,攻擊探測和阻止,但是很難管理閘道器和API的超時。使用Spring ZUUL程式設計時,最大特徵就是編制各種過濾器,事前過濾器 路由過濾器和事後過濾器。

在很多地方,也有使用Nginx作為API閘道器,Nginx官方有不少文章講述Nginx如何在微服務架構中扮演重要角色的.

NGINX和zuul 1.0是堵塞的,而Zuul 2.0、Spring Cloud Gateway和Linkerd, Envoy是非堵塞的,後兩者藉助API閘道器推出服務網格概念,能夠統一對成千上百微服務進行管理,不過這好像又回到了伺服器為王的時代,微服務好不容易打破伺服器的約束,走出伺服器的多租戶空間獨立成王,現在又會被打著API閘道器旗幟的新的統一管理方式關起來嗎?

SpringCloud提供Reactive響應式架構,使得分散式網路通訊效率大大提高,分散式系統的IO不再成為效能瓶頸。

服務發現

在分散式環境,許多服務例項都不斷因為開發而不斷變化,時而上線,時而下線,微服務之間如何好好發現活著的對方也是個問題,這就是需要服務註冊器,每個微服務向其註冊,其他需要呼叫的微服務通過註冊器發現對方進行呼叫,呼叫時可加入負載平衡策略.

Spring Cloud推薦使用NETFLIX EUREKA,用CAP定理來看,它屬於AP,而Zookeeper屬於CP,因此後者不是非常適合應用在服務發現場合,它本來誕生於大資料應用場景,雖然後來被Hadoop拋棄。

NETFLIX EUREKA易於設定,基於Rest的服務註冊,支援複製,支援客戶端快取,速度快雖然資料容易不一致(AP)。

如果直接基於Eureka進行服務註冊和發現,需要手工將負載平衡策略與REST處理繫結在一起,而通過Feign元件能夠預設實現負載平衡+REST方式的通訊,只要像普通REST呼叫即可,大大提高了開發效率,其內部使用Ribbon負載平衡器和hystrix斷路器。

@FeignClient(name="PengProducerService")
public interface ConsumerService {

    @GetMapping("/articles")
    List<Article> getAllArticles();
}
<p>

運維

SpringCloud提供了SLEUTH方便跟蹤請求級別的微服務呼叫,是一種分散式跟蹤解決方案,與Zipkin等結合,形成生產運維監控管理,能夠掌握每個微服務例項呼叫時間。

HYSTRIX斷路器能夠增強系統的彈性,在微服務無法訪問時重試,重試幾次後就放棄,也能進行快速失效,不把時間耗費在無謂的等待上,防止故障爆炸。提供儀表板實時情況。

身份驗證和授權

前後端通過REST分離以後,需要一種基於令牌的方法來與前端對話,還需要對每個請求進行身份驗證和許可權驗證。

OAuth2是一種開放的標準授權協議規範,雖然目前不能完全取代OAuth1.0a,但是會不斷日趨完善。

一旦使用者請求通過OAuth進行了身份驗證和許可權驗證,API閘道器會放行這個請求到後端微服務中,但是如果請求中沒有攜帶身份資訊,在後端微服務例項之間轉了幾個圈後,微服務無法確保是否可以接受這個請求了,因此,需要在每個請求裡攜帶通過驗證的使用者身份資訊,這就需要採取JWT(JSON WEB TOKEN), JWT能使用HMACSHA256進行簽名,或者使用RSA進行公有/私有鍵值對簽名,可以通過URL,POST引數或者在HTTP header傳送,因為資料量小,傳輸速度也很快,由此避免了各個微服務多次查詢資料庫以搞清楚當前請求的身份資訊。

總結:

瞭解了SpringCloud架構以後,遷移之路也就明細了:

整個核心是服務註冊和發現,因此首先開始應用服務註冊,但是服務註冊中心容易變成單點風險,談不上高可用性,一旦這個單點崩潰,全域性奔潰,那麼準備兩套註冊中心,引入配置伺服器,在兩套註冊中心之間進行切換變得非常重要,由於配置伺服器一旦修改,需要通知很多元件,因此需要引入非同步通訊,由此需要Spring Cloud Bus。

第一步:註冊中心

第二步:配置伺服器

第三步:Spring Cloud bus通訊匯流排

第四步是資料庫的切分,使得每個微服務只有一兩個資料庫。

第五步是切入基於事件的事務架構,比如EventSourcing等等。

第六步是安裝上底座:Docker化和Kubernetes排程Paas平臺化。

相關文章