1、概念
微服務(wù)架構(gòu)是一種架構(gòu)模式,它提倡將單一應(yīng)用程序劃分成一組小的服務(wù),服務(wù)之間互相協(xié)調(diào),配合為用戶提供最終價值。每個服務(wù)運行在其獨立的進程中,服務(wù)與服務(wù)間采用輕量級的通信機制互相溝通(通常基于HTTP的RESTFUL API)
2、微服務(wù)框架
image.png

Dubbo 是 SOA 時代的產(chǎn)物,它的關(guān)注點主要在于服務(wù)的調(diào)用,流量分發(fā)、流量監(jiān)控和熔斷。而 Spring Cloud 誕生于微服務(wù)架構(gòu)時代,考慮的是微服務(wù)治理的方方面面.
Dubbo 是阿里巴巴公司一個開源的高性能服務(wù)框架,致力于提供高性能和透明化的 RPC 遠程服務(wù)調(diào)用方案,以及 SOA 服務(wù)治理方案,使得應(yīng)用可通過高性能 RPC 實現(xiàn)服務(wù)的輸出、輸入功能和 Spring 框架無縫集成。Dubbo 包含遠程通訊、集群容錯和自動發(fā)現(xiàn)三個核心部分。
3、SpringCloud核心( springcloud(一):大話Spring Cloud - 純潔的微笑博客 )
- Spring Cloud Netflix:各項服務(wù)依賴與它,與各種Netflix OSS組件集成,組成微服務(wù)的核心。
- Netflix Eureka:服務(wù)中心,云端服務(wù)發(fā)現(xiàn),一個基于 REST 的服務(wù),用于定位服務(wù),以實現(xiàn)云端中間層服務(wù)發(fā)現(xiàn)和故障轉(zhuǎn)移。
- Netflix Hystrix:熔斷器,容錯管理工具,旨在通過熔斷機制控制服務(wù)和第三方庫的節(jié)點,從而對延遲和故障提供更強大的容錯能力。
- Netflix Zuul:Zuul 是在云平臺上提供動態(tài)路由,監(jiān)控,彈性,安全等邊緣服務(wù)的框架。Zuul 相當于是設(shè)備和 Netflix 流應(yīng)用的 Web 網(wǎng)站后端所有請求的前門。
- Netflix Archaius:配置管理API,包含一系列配置管理API,提供動態(tài)類型化屬性、線程安全配置操作、輪詢框架、回調(diào)機制等功能。
- Spring Cloud Config:俗稱的配置中心,配置管理工具包,讓你可以把配置放到遠程服務(wù)器,集中化管理集群配置,目前支持本地存儲、Git以及Subversion。
- Spring Cloud Bus:事件、消息總線,用于在集群(例如,配置變化事件)中傳播狀態(tài)變化,可與Spring Cloud Config聯(lián)合實現(xiàn)熱部署。
- Ribbon:是一個客戶端負載均衡器,主要功能是提供客戶端的軟件負載均衡算法,將Netflix的中間層服務(wù)連接在一起。Ribbon工作時分為兩步:第一步先選擇 Eureka Server, 它優(yōu)先選擇在同一個Zone且負載較少的Server;第二步再根據(jù)用戶指定的策略,在從Server取到的服務(wù)注冊列表中選擇一個地址。
-
Feign:是一個聲明式的web service客戶端,它使得編寫web service客戶端更為容易。創(chuàng)建接口,為接口添加注解,即可使用Feign。image.pngimage.png
a、外部或者內(nèi)部的非Spring Cloud項目都統(tǒng)一通過API網(wǎng)關(guān)(Zuul)來訪問內(nèi)部服務(wù)
b、網(wǎng)關(guān)接收到請求后,從注冊中心(Eureka)獲取可用服務(wù)
c、由Ribbon進行均衡負載后,分發(fā)到后端的具體實例
d、微服務(wù)之間通過Feign進行通信處理業(yè)務(wù)
e、Hystrix負責處理服務(wù)超時熔斷
f、Turbine監(jiān)控服務(wù)間的調(diào)用和熔斷相關(guān)指標
4、Eureka
image.png

Eureka由兩個組件組成:Eureka服務(wù)器和Eureka客戶端。Eureka服務(wù)器用作服務(wù)注冊服務(wù)器。Eureka客戶端是一個java客戶端,用來簡化與服務(wù)器的交互、作為輪詢負載均衡器,并提供服務(wù)的故障切換支持。
- Eureka Server:提供服務(wù)注冊和發(fā)現(xiàn)
- Service Provider:服務(wù)提供方,將自身服務(wù)注冊到Eureka,從而使服務(wù)消費方能夠找到
- Service Consumer:服務(wù)消費方,從Eureka獲取注冊服務(wù)列表,從而能夠消費服務(wù)
4.1 Eureka和Zookeeper對比
一個分布式系統(tǒng)不可能同時滿足C(一致性)、A(可用性)、和P(分區(qū)容錯性)。由于分區(qū)容錯性P在分布式系統(tǒng)中必須要保證的,因此我們只能在A和C之間進行權(quán)衡。
- Zoopkeeper保證CP: zk會出現(xiàn)這樣的一種情況,當master節(jié)點因網(wǎng)路故障與其他節(jié)點失去聯(lián)系時,剩余的節(jié)點會重新進行l(wèi)eader選舉。問題在于,選舉leader的時間太長,30~120s,且選舉期間整個zk集群是都是不可用的,這就導(dǎo)致在選舉期間注冊服務(wù)癱瘓。
- Eureka保證AP: Eureka各個節(jié)點都是平等的,幾個節(jié)點掛掉不影響正常節(jié)點的工作,剩余的節(jié)點依然可以提供注冊和查詢服務(wù)。Eureka的客戶端在向某個Eureka注冊時如果發(fā)現(xiàn)連接失敗,則會自動切換至其他的節(jié)點,只要有一臺Eureka還在,就能保證注冊服務(wù)可用(保證可用性),只不過查到的信息可能不是最新的(不保證一致性)。

4.2 Eureka自我保護機制
如果在15分鐘內(nèi)超過85%的節(jié)點都沒有正常的心跳,那么Eureka就認為客戶端與注冊中心出現(xiàn)了網(wǎng)絡(luò)故障,Eureka不再從注冊列表中移除因為長時間沒收到心跳而應(yīng)該過期的服務(wù),Eureka仍然能夠接受新服務(wù)的注冊和查詢請求,但是不會被同步到其它節(jié)點上(即保證當前節(jié)點依然可用),當網(wǎng)絡(luò)穩(wěn)定時,當前實例新的注冊信息會被同步到其它節(jié)點中。
4.3 Eureka工作流程
a. Eureka Server 啟動成功,等待服務(wù)端注冊。在啟動過程中如果配置了集群,集群之間定時通過 Replicate 同步注冊表,每個 Eureka Server 都存在獨立完整的服務(wù)注冊表信息;
b. Eureka Client 啟動時根據(jù)配置的 Eureka Server 地址去注冊中心注冊服務(wù);
c. Eureka Client 會每 30s 向 Eureka Server 發(fā)送一次心跳請求,證明客戶端服務(wù)正常;
d. 當 Eureka Server 90s 內(nèi)沒有收到 Eureka Client 的心跳,注冊中心則認為該節(jié)點失效,會注銷該實例;
e. 單位時間內(nèi) Eureka Server 統(tǒng)計到有大量的 Eureka Client 沒有上送心跳,則認為可能為網(wǎng)絡(luò)異常,進入自我保護機制,不再剔除沒有上送心跳的客戶端;
f. 當 Eureka Client 心跳請求恢復(fù)正常之后,Eureka Server 自動退出自我保護模式;
g. Eureka Client 定時全量或者增量從注冊中心獲取服務(wù)注冊表,并且將獲取到的信息緩存到本地;
h. 服務(wù)調(diào)用時,Eureka Client 會先從本地緩存找尋調(diào)取的服務(wù)。如果獲取不到,先從注冊中心刷新注冊表,再同步到本地緩存;
i. Eureka Client 獲取到目標服務(wù)器信息,發(fā)起服務(wù)調(diào)用;
j. Eureka Client 程序關(guān)閉時向 Eureka Server 發(fā)送取消請求,Eureka Server 將實例從注冊表中刪除;
5、CAP和Base

- Partition tolerance(分區(qū)容錯):區(qū)間通信可能失敗
- Consistency(一致性):寫操作之后的讀操作,必須返回該值
- Availability(可用性):只要收到用戶的請求,服務(wù)器就必須給出回應(yīng)
一般來說,分區(qū)容錯無法避免,因此可以認為 CAP 的 P 總是成立,C跟A不能同時存在。
BASE 理論是對 CAP 理論的延伸,核心思想是即使無法做到強一致性(Strong Consistency,CAP 的一致性就是強一致性),但應(yīng)用可以采用適合的方式達到最終一致性(Eventual Consitency)。
-
基本可用(Basically Available)
基本可用是指分布式系統(tǒng)在出現(xiàn)故障的時候,允許損失部分可用性,即保證核心可用。
電商大促時,為了應(yīng)對訪問量激增,部分用戶可能會被引導(dǎo)到降級頁面,服務(wù)層也可能只提供降級服務(wù)。這就是損失部分可用性的體現(xiàn)。 -
軟狀態(tài)(Soft State)
軟狀態(tài)是指允許系統(tǒng)存在中間狀態(tài),而該中間狀態(tài)不會影響系統(tǒng)整體可用性。分布式存儲中一般一份數(shù)據(jù)至少會有三個副本,允許不同節(jié)點間副本同步的延時就是軟狀態(tài)的體現(xiàn)。mysql replication 的異步復(fù)制也是一種體現(xiàn)。 -
最終一致性(Eventual Consistency)
最終一致性是指系統(tǒng)中的所有數(shù)據(jù)副本經(jīng)過一定時間后,最終能夠達到一致的狀態(tài)。弱一致性和強一致性相反,最終一致性是弱一致性的一種特殊情況。
6、熔斷器Hystrix
image.png

- 雪崩效應(yīng):在微服務(wù)架構(gòu)中通常會有多個服務(wù)層調(diào)用,基礎(chǔ)服務(wù)的故障可能會導(dǎo)致級聯(lián)故障,進而造成整個系統(tǒng)不可用的情況,這種現(xiàn)象被稱為服務(wù)雪崩效應(yīng)。服務(wù)雪崩效應(yīng)是一種因“服務(wù)提供者”的不可用導(dǎo)致“服務(wù)消費者”的不可用,并將不可用逐漸放大的過程。
- 熔斷器(CircuitBreaker):它可以實現(xiàn)快速失敗,如果它在一段時間內(nèi)偵測到許多類似的錯誤,會強迫其以后的多個調(diào)用快速失敗,不再訪問遠程服務(wù)器,從而防止應(yīng)用程序不斷地嘗試執(zhí)行可能會失敗的操作,使得應(yīng)用程序繼續(xù)執(zhí)行而不用等待修正錯誤,或者浪費CPU時間去等到長時間的超時產(chǎn)生。熔斷器也可以使應(yīng)用程序能夠診斷錯誤是否已經(jīng)修正,如果已經(jīng)修正,應(yīng)用程序會再次嘗試調(diào)用操作。
- 服務(wù)降級:一般是從整體負荷考慮。就是當某個服務(wù)熔斷之后,服務(wù)器將不再被調(diào)用,此時客戶端可以自己準備一個本地的fallback回調(diào),返回一個缺省值。
斷路器很好理解, 當Hystrix Command請求后端服務(wù)失敗數(shù)量超過一定比例(默認50%), 斷路器會切換到開路狀態(tài)(Open). 這時所有請求會直接失敗而不會發(fā)送到后端服務(wù). 斷路器保持在開路狀態(tài)一段時間后(默認5秒), 自動切換到半開路狀態(tài)(HALF-OPEN). 這時會判斷下一次請求的返回情況, 如果請求成功, 斷路器切回閉路狀態(tài)(CLOSED), 否則重新切換到開路狀態(tài)(OPEN). Hystrix的斷路器就像我們家庭電路中的保險絲, 一旦后端服務(wù)不可用, 斷路器會直接切斷請求鏈, 避免發(fā)送大量無效請求影響系統(tǒng)吞吐量, 并且斷路器有自我檢測并恢復(fù)的能力。
Hystrix目前是有兩種隔離策略,分別是線程池隔離和信號量隔離。
- 線程池隔離
當前端發(fā)起請求過來到服務(wù)A或者B之后,服務(wù)A和服務(wù)B是通過線程池隔離的。服務(wù)A是否熔斷,是否正常都和服務(wù)B無關(guān)。
他其實是一個異步編程,用線程池將后面的服務(wù)包裹了起來,至于服務(wù)內(nèi)部tomcate的線程運行怎么樣是無關(guān)的。他適合于絕大多數(shù)的場景,對于一些超時的場景都非常好用。但是既然是通過線程池來操作的,不可避免的就是線程之間的計算開銷,以及線程上下文的切換,調(diào)度消耗。 - 信號量隔離
隔離是通過信號量來做到的。他其實是一個計數(shù)器。一個請求進來就會減少一個信號,一個請求完成就會增加一個信號。
信號量的調(diào)用時同步的,也就是說他會阻塞直到請求回來。所以他自身是不能實現(xiàn)超時的,因此這里的超時只能依靠協(xié)議的超時來做,否則是無法釋放的(比如socket超時等等)。所以當此服務(wù)不對外部服務(wù)依賴同時自身沒有大量的計算或者說經(jīng)過這個服務(wù)的時間比較短,則非常適合信號量,比如說spring cloud的zuul的gateway網(wǎng)關(guān)。
7、RPC和Restful的區(qū)別:
Restful架構(gòu)是基于Http應(yīng)用層協(xié)議的產(chǎn)物,RPC架構(gòu)是基于TCP傳輸層協(xié)議的產(chǎn)物。
Feign 是一個http請求調(diào)用的輕量級框架,以Java接口注解的方式調(diào)用Http請求,而不用像Java中通過封裝HTTP請求報文的方式直接調(diào)用。Feign通過處理注解,將請求模板化,當實際調(diào)用的時候,傳入?yún)?shù),根據(jù)參數(shù)再應(yīng)用到請求上,進而轉(zhuǎn)化成真正的請求,這種請求相對而言比較直觀。
- 從使用方面看,Http接口只關(guān)注服務(wù)提供方(服務(wù)端),對于客戶端怎么調(diào)用,調(diào)用方式怎樣并不關(guān)心,通常情況下,客戶端使用Http方式進行調(diào)用時,只要將內(nèi)容進行傳輸即可,這樣客戶端在使用時,需要更關(guān)注網(wǎng)絡(luò)方面的傳輸,比較不適用與業(yè)務(wù)方面的開發(fā);而RPC服務(wù)則需要客戶端接口與服務(wù)端保持一致,服務(wù)端提供一個方法,客戶端通過接口直接發(fā)起調(diào)用,業(yè)務(wù)開發(fā)人員僅需要關(guān)注業(yè)務(wù)方法的調(diào)用即可,不再關(guān)注網(wǎng)絡(luò)傳輸?shù)募毠?jié),在開發(fā)上更為高效。
- 從性能角度看,使用Http時,Http本身提供了豐富的狀態(tài)功能與擴展功能,但也正由于Http提供的功能過多,導(dǎo)致在網(wǎng)絡(luò)傳輸時,需要攜帶的信息更多,從性能角度上講,較為低效。而RPC服務(wù)網(wǎng)絡(luò)傳輸上僅傳輸與業(yè)務(wù)內(nèi)容相關(guān)的數(shù)據(jù),傳輸數(shù)據(jù)更小,性能更高。
-
從運維角度看,使用Http接口時,常常使用一個前端代理,來進行Http轉(zhuǎn)發(fā)代理請求的操作,需要進行擴容時,則需要去修改代理服務(wù)器的配置,較為繁瑣,也容易出錯。而使用RPC方式的微服務(wù),則只要增加一個服務(wù)節(jié)點即可,注冊中心可自動感知到節(jié)點的變化,通知調(diào)用客戶端進行負載的動態(tài)控制,更為智能,省去運維的操作。
8、RPC原理
image.png
(1). 服務(wù)消費方(client)以本地調(diào)用方式調(diào)用服務(wù);
(2). client stub接收到調(diào)用后負責將方法、參數(shù)等組裝成能夠進行網(wǎng)絡(luò)傳輸?shù)南Ⅲw;
(3). client stub找到服務(wù)地址,并將消息發(fā)送到服務(wù)端;
(4). server stub收到消息后進行解碼;
(5). server stub根據(jù)解碼結(jié)果 反射調(diào)用 本地的服務(wù);
(6). 本地服務(wù)執(zhí)行并將結(jié)果返回給server stub;
(7). server stub將返回結(jié)果打包成消息并發(fā)送至消費方;
(8). client stub接收到消息,并進行解碼;
(9). 服務(wù)消費方得到最終結(jié)果。
9、Feign原理(原文地址)

Feign 整體框架非常小巧,在處理請求轉(zhuǎn)換和消息解析的過程中,基本上沒什么時間消耗。真正影響性能的,是處理Http請求的環(huán)節(jié)??梢酝ㄟ^拓展該接口,使用Apache HttpClient 或者OkHttp3等基于連接池的高性能Http客戶端。
/**
* feign請求攔截器
* 所有用feign發(fā)出的請求的攔截器,注意是feign作為客戶端發(fā)出請求的,而不是服務(wù)端
*/
@Configuration
public class FeignRequestInterceptor implements RequestInterceptor {
@Override
public void apply(RequestTemplate requestTemplate) {
//這里可以添加feign請求的全局參數(shù)
requestTemplate.header("msClientId", "8888");
}
}
10、API網(wǎng)關(guān)
API Gateway是一個服務(wù)器,也可以說是進入系統(tǒng)的唯一節(jié)點。這跟面向?qū)ο笤O(shè)計模式中的Facade模式很像。API Gateway封裝內(nèi)部系統(tǒng)的架構(gòu),并且提供API給各個客戶端。它還可能有其他功能,如授權(quán)、監(jiān)控、負載均衡、緩存、請求分片和管理、靜態(tài)響應(yīng)處理等。下圖展示了一個適應(yīng)當前架構(gòu)的API Gateway。
API Gateway負責請求轉(zhuǎn)發(fā)、合成和協(xié)議轉(zhuǎn)換。所有來自客戶端的請求都要先經(jīng)過API Gateway,然后路由這些請求到對應(yīng)的微服務(wù)。API Gateway將經(jīng)常通過調(diào)用多個微服務(wù)來處理一個請求以及聚合多個服務(wù)的結(jié)果。它可以在web協(xié)議與內(nèi)部使用的非Web友好型協(xié)議間進行轉(zhuǎn)換,如HTTP協(xié)議、WebSocket協(xié)議。
- 請求轉(zhuǎn)發(fā):服務(wù)轉(zhuǎn)發(fā)主要是對客戶端的請求安裝微服務(wù)的負載轉(zhuǎn)發(fā)到不同的服務(wù)上
- 響應(yīng)合并:把業(yè)務(wù)上需要調(diào)用多個服務(wù)接口才能完成的工作合并成一次調(diào)用對外統(tǒng)一提供服務(wù)。
- 協(xié)議轉(zhuǎn)換:重點是支持SOAP,JMS,Rest間的協(xié)議轉(zhuǎn)換。
- 數(shù)據(jù)轉(zhuǎn)換:重點是支持XML和Json之間的報文格式轉(zhuǎn)換能力(可選)
-
安全認證:
a. 基于Token的客戶端訪問控制和安全策略
b. 傳輸數(shù)據(jù)和報文加密,到服務(wù)端解密,需要在客戶端有獨立的SDK代理包
c. 基于Https的傳輸加密,客戶端和服務(wù)端數(shù)字證書支持
d. 基于OAuth2.0的服務(wù)安全認證(授權(quán)碼,客戶端,密碼模式等)
11、服務(wù)跟蹤(starter-sleuth)
隨著微服務(wù)數(shù)量不斷增長,需要跟蹤一個請求從一個微服務(wù)到下一個微服務(wù)的傳播過程, Spring Cloud Sleuth 正是解決這個問題,它在日志中引入唯一ID,以保證微服務(wù)調(diào)用之間的一致性,這樣你就能跟蹤某個請求是如何從一個微服務(wù)傳遞到下一個。
a. 為了實現(xiàn)請求跟蹤,當請求發(fā)送到分布式系統(tǒng)的入口端點時,只需要服務(wù)跟蹤框架為該請求創(chuàng)建一個唯一的跟蹤標識,同時在分布式系統(tǒng)內(nèi)部流轉(zhuǎn)的時候,框架始終保持傳遞該唯一標識,直到返回給請求方為止,這個唯一標識就是Trace ID。通過Trace ID的記錄,我們就能將所有請求過程日志關(guān)聯(lián)起來。
b. 為了統(tǒng)計各處理單元的時間延遲,當請求達到各個服務(wù)組件時,或是處理邏輯到達某個狀態(tài)時,也通過一個唯一標識來標記它的開始、具體過程以及結(jié)束,該標識就是我們前文中提到的Span ID,對于每個Span來說,它必須有開始和結(jié)束兩個節(jié)點,通過記錄開始Span和結(jié)束Span的時間戳,就能統(tǒng)計出該Span的時間延遲,除了時間戳記錄之外,它還可以包含一些其他元數(shù)據(jù),比如:事件名稱、請求信息等。
c. 在Spring Boot應(yīng)用中,通過在工程中引入spring-cloud-starter-sleuth依賴之后, 它會自動的為當前應(yīng)用構(gòu)建起各通信通道的跟蹤機制,比如:
- 通過諸如RabbitMQ、Kafka(或者其他任何Spring Cloud Stream綁定器實現(xiàn)的消息中間件)傳遞的請求。
- 通過Zuul代理傳遞的請求。
- 通過RestTemplate發(fā)起的請求。
12、Ribbon
-
服務(wù)器端負載均衡 Nginx
nginx 是客戶端所有請求統(tǒng)一交給 nginx,由 nginx 進行實現(xiàn)負載均衡請求轉(zhuǎn)發(fā),屬于服務(wù)器端負載均衡。
既請求由 nginx 服務(wù)器端進行轉(zhuǎn)發(fā)。 -
客戶端負載均衡 Ribbon
Ribbon 是從 eureka 注冊中心服務(wù)器端上獲取服務(wù)注冊信息列表,緩存到本地,然后在本地實現(xiàn)輪詢負載均衡策略。在客戶端實現(xiàn)負載均衡。
應(yīng)用場景的區(qū)別
Nginx 適合于服務(wù)器端實現(xiàn)負載均衡 比如 Tomcat ,Ribbon 適合與在微服務(wù)中 RPC 遠程調(diào)用實現(xiàn)本地服務(wù)負載均衡,比如 Dubbo、SpringCloud 中都是采用本地負載均衡。
spring cloud的Netflix中提供了兩個組件實現(xiàn)軟負載均衡調(diào)用:ribbon和feign。
Ribbon
是一個基于 HTTP 和 TCP 客戶端的負載均衡器
它可以在客戶端配置 ribbonServerList(服務(wù)端列表),然后輪詢請求以實現(xiàn)均衡負載。Feign
Spring Cloud Netflix 的微服務(wù)都是以 HTTP 接口的形式暴露的,所以可以用 Apache 的 HttpClient 或 Spring 的 RestTemplate 去調(diào)用,而 Feign 是一個使用起來更加方便的 HTTP 客戶端,使用起來就像是調(diào)用自身工程的方法,而感覺不到是調(diào)用遠程方法。


