SpringCloud源碼系列 : (一) SpringCloud的前世今生

單機架構 VS 微服務架構 哪個是21世紀的Web領域的趨勢 ?

答案: 微服務架構是單機架構的未來, 但不是銀彈多用於增長型業務!

如果你是一位軟件行業從業者,尤其是從事服務器端或者後臺系統軟件開發,相信近年來一定被層出不窮的商業名詞所包圍:NoSQL、Big Data、Web-scale、Sharding、Eventual consistency、ACID、CAP理論、雲服務、MapReduce和Real-time等,所有這些其實都圍繞著如何構建高效存儲與數據處理這一核心主題。

過去十年,在數據庫領域與分佈式系統方面湧現了許多引人矚目的進展,由此深刻地影響了如何構建上層應用系統。分析這些激動人心的變化背後,你會發現有以下幾個非常重要的驅動因素: 互聯網公司,包括Google、Yahoo! 、Amazon、Facebook、LinkedIn、Microsoft,以及Twitter等,它們每天都在面對海量數據和負載,迫使其不斷創新,並改進支撐系統以更有效地處理這種量級的數據。

商業方面因素,如敏捷開發、測試驅動和對市場機會做出快速反應等,都要求儘量縮短產品開發週期,因此係統中的數據模型也要足夠靈活以方便調整。

硬件方面,CPU主頻增長日趨緩慢,而多核系統成為新常態,網絡速度則依舊保持快速發展,這就意味著並行分佈式系統將會成為業界主流。

SpringCloud源碼系列 : (一) SpringCloud的前世今生

先有SpringCloud 還是先有 微服務 ?

答案: 先有微服務後有SpringCloud !

2014年3月25日 敏捷開發教父 Martin Fowler 在 Microservices 一文中 對於 Microservice Architecture 進行了條理清晰的論述, 向世人展示了進可攻退可守的微服務架構思想, 奠定了後來者對 微服務的認知.

SpringCloud源碼系列 : (一) SpringCloud的前世今生

早期 SpringCloud & Angel 系列基於Spring Boot 1.2.x, 而1.2版本最早誕生於 2014年12月11日,也就是說至少晚了8個月多! 其中很多設計思想也來源於前者! (數據來源: github) 又一個活生生的學術界驅動工業界的例子. 所以大家有空還是要關注一下 學術界大牛們的新作.才能保證走在技術最前沿.

微服務的定義

筆者通過翻閱 Martin Fowler 發表的文章 Microservices , 將微服務理念梳理為以下 7 點

  • 通過服務進行組件化: 組件是獨立可替換和可升級的軟件單元。微服務架構將使用庫,但是它們將自己的軟件組成組件的主要方式是分解成服務。我們將庫定義為鏈接到程序並使用內存中函數調用進行調用的組件,而服務則是進程外組件,它們通過某種機制(例如Web服務請求或遠程過程調用)進行通信。
  • 分散治理: 集中治理的後果之一是傾向於在單一技術平臺上實現標準化。經驗表明,這種方法是束手無策的-並非每個問題都是釘子,也不是每個解決方案都是錘子。我們更喜歡使用正確的工具來完成工作,而整體式應用程序可以在一定程度上利用不同的語言,但這並不常見。
  • 分散數據管理: 數據管理的分散化以多種不同的方式呈現。從最抽象的角度講,這意味著系統的世界概念模型將有所不同。在大型企業中進行集成時,這是一個常見問題,客戶的銷售視圖將與支持視圖不同。在銷售視圖中被稱為客戶的某些內容可能根本不會出現在支持視圖中。那些具有相同屬性的屬性可能具有不同的語義,並且(更差的)公共屬性具有不同的語義。
  • 智能端點和啞管道: 在不同流程之間建立通信結構時,我們已經看到了許多產品和方法,這些產品和方法強調在通信機制本身中投入大量智慧。一個很好的例子是企業服務總線(ESB),其中ESB產品通常包括用於消息路由,編排,轉換和應用業務規則的複雜工具。
  • 基礎設施自動化: 我們希望儘可能地放心我們的軟件正在運行,因此我們運行了許多自動化測試。升級工作軟件的渠道意味著我們可以自動部署 到每個新環境。
  • 失敗設計: 使用服務作為組件的結果是,需要對應用程序進行設計,以便它們可以容忍服務故障。由於供應商不可用,任何服務呼叫都可能失敗,客戶必須儘可能優雅地響應此請求。與單片設計相比,這是一個缺點,因為它引入了額外的處理複雜性。結果是微服務團隊不斷反思服務故障如何影響用戶體驗。Netflix的Simian Army 在工作日內導致服務甚至數據中心發生故障,以測試應用程序的彈性和監視能力。
  • 進化設計: 每當您嘗試將軟件系統分解為組件時,您都會面臨如何劃分各個部分的決定-我們決定對應用程序進行分割的原則是什麼?組件的關鍵屬性是獨立替換和可升級性的概念[13] -這意味著我們尋找可以想象重寫組件而不影響其協作者的觀點。實際上,許多微服務組通過明確期望許多服務將被廢棄而不是長期發展而將其進一步發展。

沒接觸過微服務的小夥伴看完暈倒了過去, 過一會醒來瘋狂撓頭, 這知識不過腦子啊 !

輕點,注意髮量哈

其實每一個點對應的都是一種微服務場景的解決方案。 而這些解決方案可能是 Spring 官方提供,有可能是 別的公司提供. 或者兩者都有...

SpringCloud源碼系列 : (一) SpringCloud的前世今生

微服務之我見

筆者才畢業時那會業內流行 Dubbo , 只要涉及到有點難度的項目 別管併發,數據量怎麼樣, 都一律上 Dubbo 生產者消費者分離, 和今天小夥伴們使用 SpringCloud 的熱情如出一轍, 但是那時候 微服務這個概念並不是很火熱 !

Dubbo 官方定義: Apache Dubbo |ˈdʌbəʊ| 是一款高性能、輕量級的開源Java RPC框架,它提供了三大核心能力:面向接口的遠程方法調用,智能容錯和負載均衡,以及服務自動註冊和發現。

SpringCloud源碼系列 : (一) SpringCloud的前世今生

SpringCloud 官方定義: SpringCloud基於SpringBoot為開發人員提供了組件,以快速構建分佈式系統中的一些常見模式(例如,配置中心,服務發現,斷路器,智能路由,微代理,控制總線,一次性令牌,全局鎖,領導選舉,分佈式會話,群集狀態)。分佈式系統的協調導致樣板式樣,並且使用Spring Cloud開發人員可以快速站起來實現這些樣板的服務和應用程序。它們可以在任何分佈式環境中正常工作,包括開發人員自己的筆記本電腦,裸機數據中心以及Cloud Foundry等託管平臺。

SpringCloud源碼系列 : (一) SpringCloud的前世今生

那麼 Dubbo 和 SpringCloud 有什麼區別呢?

從技術棧上來看

<code> dubbo:zookeeper+dubbo+springmvc/springboot
通信方式:rpc
註冊中心:zookeeper,nacos
配置中心:diamond(淘寶開發)

spring cloud:spring+Netflix
通信方式:http restful
註冊中心:eureka,consul,nacos                
配置中心:config
斷路器:hystrix
網關:zuul,gateway
分佈式追蹤系統:sleuth+zipkin/<code>
SpringCloud源碼系列 : (一) SpringCloud的前世今生

誠然 Dubbo 已經跟不上目前 微服務思想的發展了, 我們在做微服務的時候 首選 SpringCloud.那 SpringCloud 有那麼多組合我們選哪個好呢?

SpringCloud 組合大PK

SpringCloud 有哪些主流組合呢?

  • SpringCloud-Alibaba Sentinel:把流量作為切入點,從流量控制、熔斷降級、系統負載保護等多個維度保護服務的穩定性。 Nacos:一個更易於構建雲原生應用的動態服務發現、配置管理和服務管理平臺。 RocketMQ:一款開源的分佈式消息系統,基於高可用分佈式集群技術,提供低延時的、高可靠的消息發佈與訂閱服務。 Dubbo:Apache Dubbo™ 是一款高性能 Java RPC 框架。 Seata:阿里巴巴開源產品,一個易於使用的高性能微服務分佈式事務解決方案。 Alibaba Cloud ACM:一款在分佈式架構環境中對應用配置進行集中管理和推送的應用配置中心產品。 Alibaba Cloud OSS: 阿里雲對象存儲服務(Object Storage Service,簡稱 OSS),是阿里雲提供的海量、安全、低成本、高可靠的雲存儲服務。您可以在任何應用、任何時間、任何地點存儲和訪問任意類型的數據。
    Alibaba Cloud SchedulerX: 阿里中間件團隊開發的一款分佈式任務調度產品,提供秒級、精準、高可靠、高可用的定時(基於 Cron 表達式)任務調度服務。 Alibaba Cloud SMS: 覆蓋全球的短信服務,友好、高效、智能的互聯化通訊能力,幫助企業迅速搭建客戶觸達通道。
  • SpringCloud-Netflix Eureka :服務註冊和發現,它提供了一個服務註冊中心、服務發現的客戶端,還有一個方便的查看所有註冊的服務的界面。 所有的服務使用Eureka的服務發現客戶端來將自己註冊到Eureka的服務器上。 Zuul : 網關,所有的客戶端請求通過這個網關訪問後臺的服務。它可以使用一定的路由配置來判斷某一個URL由哪個服務來處理。並從Eureka獲取註冊的服務來轉發請求。 Ribbon :即負載均衡,Zuul網關將一個請求發送給某一個服務的應用的時候,如果一個服務啟動了多個實例,就會通過Ribbon來通過一定的負載均衡策略來發送給某一個服務實例。 Feign :服務客戶端,服務之間如果需要相互訪問,可以使用RestTemplate,也可以使用Feign客戶端訪問。它默認會使用Ribbon來實現負載均衡。 Hystrix : 監控和斷路器。我們只需要在服務接口上添加Hystrix標籤,就可以實現對這個接口的監控和斷路器功能。 Hystrix Dashboard : 監控面板,它提供了一個界面,可以監控各個服務上的服務調用所消耗的時間等。 Turbine : 監控聚合,使用Hystrix監控,我們需要打開每一個服務實例的監控信息來查看。而Turbine可以幫助我們把所有的服務實例的監控信息聚合到一個地方統一查看。

兩者的優缺點: SpringCloud 是一項標準而不是一門技術, 你可以在它們互相兼容的前提下同時使用兩大陣營的組件, 兩者最大的不同在於, Netflix 的服務通信基於 Feign 組件傾向於 HTTP RestFul, 而 Alibaba 的服務通信 基於 Dubbo 組件 的 RPC 調用, 從這裡不難看出來, 它們的基本盤分別是 SpringBoot 與 Dubbo, 如果你的項目基於 SpringBoot 就首選 Netflix , 如果你的項目基於 Dubbo 就首選 Alibaba 這樣對於重構系統來說會減少很多工作量, 從社區的角度看, 大家都知道 2018-12-12日,Netflix宣佈Spring Cloud Netflix 除了 Eureka 其它組件都進入維護狀態(不會推出新功能), 但不等於 Netflix 就毫無希望, 最近 Netflix 推出了 PRE 3.0 M1 對 Eureka 進行迭代, 而 Alibaba 這個後起之秀的 GitHub Fork 數為 3.8 K 而 Netflix 為 2K 近乎兩倍, 對擁有國內 70% 市場的 Netflix 來說 進入維護狀態的 組件可以, 用別的組件來替代就可以, 而如果使用了 Alibaba 就被被捆綁銷售了 一堆自己的技術以及阿里雲的東西 ... 技術選型上面沒有銀彈, 選擇最適合項目的技術即可 !

SpringCloud源碼系列 : (一) SpringCloud的前世今生

SpringCloud-Alibaba 太香了 , 我選 SpringCloud-Netflix !

推薦 SpringCloud-Netflix組合

  1. 服務註冊與發現組件:Eureka,Zookeeper,Consul,Nacos等。Eureka基於REST風格的。
  2. 服務調用組件:Hystrix(熔斷降級,在出現依賴服務失效的情況下,通過隔離 系統依賴服務 的方式,防止服務級聯失敗,同時提供失敗回滾機制,使系統能夠更快地從異常中恢復),Ribbon(客戶端負載均衡,用於提供客戶端的軟件負載均衡算法,提供了一系列完善的配置項:連接超時、重試等),OpenFeign(優雅的封裝Ribbon,是一個聲明式RESTful網絡請求客戶端,它使編寫Web服務客戶端變得更加方便和快捷)。
  3. 網關:路由和過濾。Zuul,Gateway。
  4. 配置中心:提供了配置集中管理,動態刷新配置的功能;配置通過Git或者其它方式來存儲。
  5. 消息組件:Spring Cloud Stream(對分佈式消息進行抽象,包括髮布訂閱、分組消費等功能,實現了微服務之間的異步通信)和Spring Cloud Bus(主要提供服務間的事件通信,如刷新配置)
  6. 安全控制組件:Spring Cloud Security 基於OAuth2.0開放網絡的安全標準,提供了單點登錄、資源授權和令牌管理等功能。
  7. 鏈路追蹤組件:Spring Cloud Sleuth(收集調用鏈路上的數據),Zipkin(對Sleuth收集的信息,進行存儲,統計,展示)

SpringCloud-Netflix 中的微服務理念

SpringCloud源碼系列 : (一) SpringCloud的前世今生

SpringCloud-Netflix 組件源碼簡析

Eureka

註冊中心 (場景: 服務註冊與服務發現, 可以理解為 IM服務器)

SpringCloud源碼系列 : (一) SpringCloud的前世今生

  • Eureka Server: 同步複製 Eureka Client 元信息用於微服務註冊發現 , 支持多實例
  • Service Provider: 通過 Eureka Server 進行微服務註冊, 心跳續約, 下線通知, 支持多實例
  • Service Consumer: 通過 Eureka Server 發現微服務註冊信息, 支持多實例
<code>// 從eureka-core 包中的 AbstractInstanceRegistry 類看起

/* Handles all registry requests from eureka clients.
 *
 * 
 * Primary operations that are performed are the
 * Registers, Renewals, Cancels, Expirations, and Status Changes The
 * registry also stores only the delta operations
 * 
 * @author Karthik Ranganathan
 *
 */

private final ConcurrentHashMap>> registry
            = new ConcurrentHashMap>>();/<code>
  • 第一層的 Map , K 是應用名稱. V 是Map 多實例元信息
  • 第二層 Map 為保持更多實例信息, K 為 實例名稱, V 為實例詳細信息(註冊信息,ip地址,實例id,端口, 狀態等)
  • Eureka 通過維護 這個 ConcurrentHashMap 實現服務註冊以及發現.
  • 建議可以從 193行 public void register(InstanceInfo registrant, int leaseDuration, boolean isReplication) 微服務註冊方法看起

    Zuul

    API 網關 (場景: 動態路由, 監控, 可以理解為 快遞攬件配送)

    SpringCloud源碼系列 : (一) SpringCloud的前世今生

    • pre filters: 在調用 Origin Server 之前執行, 場景: 用於身份驗證. 記錄調試信息, 擇優選擇微服務等
    • routing filters: 調用 Origin Server 時執行, 場景: 用於請求微服務. 獲得響應等
    • post filters: 在調用 Origin Server 之後執行, 場景: 用於為響應添加標準 HTTP 頭, 收集統計信息和指標, 將響應從微服務返回給客戶端等
    • error filters: 在調用 Origin Server 過程中, 場景: 獲取錯誤信息跳轉 post filters.
    • custom filters: 在調用 Origin Server 任意場景執行, 場景: 自定義過濾需求
    <code>從 org.springframework.cloud.netflix.zuul.filters.support FilterConstants 類看起
    
    這個類中是有和 上面的Filters 相關的常量
    
    // Zuul Filter TYPE constants ----------------------------------- /** * {@link ZuulFilter#filterType()} error type. */ public static final String ERROR_TYPE = "error"; /** * {@link ZuulFilter#filterType()} post type. */ public static final String POST_TYPE = "post"; /** * {@link ZuulFilter#filterType()} pre type. */ public static final String PRE_TYPE = "pre"; /** * {@link ZuulFilter#filterType()} route type. */ public static final String ROUTE_TYPE = "route"; // OTHER constants -----------------------------------
    
    對這幾個 常量全局搜索 會找到與上述功能相同的過濾器類 PreDecorationFilter SendForwardFilter SendResponseFilter SendErrorFilter
    
    PreDecorationFilter 128行 初始化請求參數映射
    
     RequestContext ctx = RequestContext.getCurrentContext(); ...
    
    // 之後 通過轉發過濾實現上述功能 !
    
    RequestDispatcher dispatcher = ctx.getRequest().getRequestDispatcher(path);/<code>

    RestTemplate

    RestTemplate (場景: 簡化 HTTP 通信方式,統一了RESTful的標準併為 執行復雜任務提供了一種具有默認行為的簡化方法, 可以理解為 GOF中的 模板模式)

    SpringCloud源碼系列 : (一) SpringCloud的前世今生

    • HttpMessageConverter: 對象轉換器
    • ClientHttpRequestFactory: 提供了多種便捷訪問遠程Http服務的方法,能夠大大提高客戶端的編寫效率。
    • ResponseErrorHandler: 異常處理
    • ClientHttpRequestInterceptor: 請求攔截器

    Spring 核心 HTTP 消息轉換器 HttpMessageConverter Rest自描述信息: 媒體類型 (MediaType) : text/html; text/xml; application/json HTTP 協議特點: 純文本協議 ,需要自我描述

    • REST 客戶端
    • REST 服務端

    反序列化 : 文本(通信) ---> 對象(程序使用)

    序列化: 對象(程序) ----> 文本(通信)


    分析 HttpMessageConverter

    <code>// 策略接口,它指定了一個轉換器,可以將請求和響應轉換為HTTP請求和響應。 
    public interface HttpMessageConverter {
    	// 判斷當前 泛型是否可以反序列化
        boolean canRead(Class> clazz, @Nullable MediaType mediaType);
        // 判斷當前 泛型是否可以序列化
    	boolean canWrite(Class> clazz, @Nullable MediaType mediaType);
        // 當前支持的媒體類型
       	List getSupportedMediaTyp/<code> 


    分享到:


    相關文章: