目錄java
前言node
1、微服務介紹mysql
1.什麼是微服務nginx
2. 微服務由來git
3. 爲何須要微服務?github
3.1 早期的單體架構帶來的問題web
3.2 微服務與單體架構區別redis
3.3 微服務與SOA區別算法
4. 微服務本質spring
5. 什麼樣的項目適合微服務
6. 微服務折分與設計
6.1 微服務設計原則
7. 微服務優點與缺點
7.1 特性
7.2 特色
7.3 缺點
8. 微服務開發框架
9. Sprint cloud 和 Sprint boot區別
2、微服務實踐先知
1. 客戶端如何訪問這些服務?(API Gateway)
2. 服務之間如何通訊?(服務調用)
3. 這麼多服務怎麼查找?(服務發現)
4. 服務掛了怎麼辦?
5. 微服務須要考慮的問題
3、微服務重要部件
1. 微服務基本能力
2. 服務註冊中心
2.1 zookeeper服務註冊和發現
3. 負載均衡
3.1 負載均衡的常見策略
4. 容錯
4.1 容錯策略
5. 熔斷
6. 限流和降級
7. SLA
8. API網關
9. 多級緩存
10. 超時和重試
11. 線程池隔離
12. 降級和限流
13. 網關監控和統計
前言
到底什麼是微服務?爲何要用微服務?微服務主要來作一些什麼?微服務有哪些優點?什麼樣的服務屬於微服務?本文全部資料來源網絡,我只是整理一下,總結一下。僅供參考。
1、微服務介紹
1.什麼是微服務
在介紹微服務時,首先得先理解什麼是微服務,顧名思義,微服務得從兩個方面去理解,什麼是"微"、什麼是"服務",
微,狹義來說就是體積小、著名的"2 pizza 團隊"很好的詮釋了這一解釋(2 pizza 團隊最先是亞馬遜 CEO Bezos提出來的,意思是說單個服務的設計,全部參與人從設計、開發、測試、運維全部人加起來 只須要2個披薩就夠了 )。 而所謂服務,必定要區別於系統,服務一個或者一組相對較小且獨立的功能單元,是用戶能夠感知最小功能集。
2. 微服務由來
微服務最先由Martin Fowler與James Lewis於2014年共同提出,微服務架構風格是一種使用一套小服務來開發單個應用的方式途徑,每一個服務運行在本身的進程中,並使用輕量級機制通訊,一般是HTTP API,這些服務基於業務能力構建,並可以經過自動化部署機制來獨立部署,這些服務使用不一樣的編程語言實現,以及不一樣數據存儲技術,並保持最低限度的集中式管理。
3. 爲何須要微服務?
在傳統的IT行業軟件大多都是各類獨立系統的堆砌,這些系統的問題總結來講就是擴展性差,可靠性不高,維護成本高。到後面引入了SOA服務化,可是,因爲 SOA 早期均使用了總線模式,這種總線模式是與某種技術棧強綁定的,好比:J2EE。這致使不少企業的遺留系統很難對接,切換時間太長,成本過高,新系統穩定性的收斂也須要一些時間。最終 SOA 看起來很美,但卻成爲了企業級奢侈品,中小公司都望而生畏。
3.1 早期的單體架構帶來的問題
單體架構在規模比較小的狀況下工做狀況良好,可是隨着系統規模的擴大,它暴露出來的問題也愈來愈多,主要有如下幾點:
1.複雜性逐漸變高
好比有的項目有幾十萬行代碼,各個模塊之間區別比較模糊,邏輯比較混亂,代碼越多複雜性越高,越難解決遇到的問題。
2.技術債務逐漸上升
公司的人員流動是再正常不過的事情,有的員工在離職以前,疏於代碼質量的自我管束,致使留下來不少坑,因爲單體項目代碼量龐大的驚人,留下的坑很難被發覺,這就給新來的員工帶來很大的煩惱,人員流動越大所留下的坑越多,也就是所謂的技術債務愈來愈多。
3.部署速度逐漸變慢
這個就很好理解了,單體架構模塊很是多,代碼量很是龐大,致使部署項目所花費的時間愈來愈多,曾經有的項目啓動就要一二十分鐘,這是多麼恐怖的事情啊,啓動幾回項目一天的時間就過去了,留給開發者開發的時間就很是少了。
4.阻礙技術創新
好比之前的某個項目使用struts2寫的,因爲各個模塊之間有着千絲萬縷的聯繫,代碼量大,邏輯不夠清楚,若是如今想用spring mvc來重構這個項目將是很是困難的,付出的成本將很是大,因此更多的時候公司不得不硬着頭皮繼續使用老的struts架構,這就阻礙了技術的創新。
5.沒法按需伸縮
好比說電影模塊是CPU密集型的模塊,而訂單模塊是IO密集型的模塊,假如咱們要提高訂單模塊的性能,好比加大內存、增長硬盤,可是因爲全部的模塊都在一個架構下,所以咱們在擴展訂單模塊的性能時不得不考慮其它模塊的因素,由於咱們不能由於擴展某個模塊的性能而損害其它模塊的性能,從而沒法按需進行伸縮。
3.2 微服務與單體架構區別
單體架構全部的模塊全都耦合在一塊,代碼量大,維護困難,微服務每一個模塊就至關於一個單獨的項目,代碼量明顯減小,遇到問題也相對來講比較好解決。
單體架構全部的模塊都共用一個數據庫,存儲方式比較單一,微服務每一個模塊均可以使用不一樣的存儲方式(好比有的用redis,有的用mysql等),數據庫也是單個模塊對應本身的數據庫。
單體架構全部的模塊開發所使用的技術同樣,微服務每一個模塊均可以使用不一樣的開發技術,開發模式更靈活。
3.3 微服務與SOA區別
微服務,從本質意義上看,仍是 SOA 架構。但內涵有所不一樣,微服務並不綁定某種特殊的技術,在一個微服務的系統中,能夠有 Java 編寫的服務,也能夠有 Python編寫的服務,他們是靠Restful架構風格統一成一個系統的。因此微服務自己與具體技術實現無關,擴展性強。
4. 微服務本質
微服務,關鍵其實不只僅是微服務自己,而是系統要提供一套基礎的架構,這種架構使得微服務能夠獨立的部署、運行、升級,不只如此,這個系統架構還讓微服務與微服務之間在結構上「鬆耦合」,而在功能上則表現爲一個統一的總體。這種所謂的「統一的總體」表現出來的是統一風格的界面,統一的權限管理,統一的安全策略,統一的上線過程,統一的日誌和審計方法,統一的調度方式,統一的訪問入口等等。
微服務的目的是有效的拆分應用,實現敏捷開發和部署 。
微服務提倡的理念團隊間應該是 inter-operate, not integrate 。inter-operate是定義好系統的邊界和接口,在一個團隊內全棧,讓團隊自治,緣由就是由於若是團隊按照這樣的方式組建,將溝通的成本維持在系統內部,每一個子系統就會更加內聚,彼此的依賴耦合能變弱,跨系統的溝通成本也就能下降。
5. 什麼樣的項目適合微服務
微服務能夠按照業務功能自己的獨立性來劃分,若是系統提供的業務是很是底層的,如:操做系統內核、存儲系統、網絡系統、數據庫系統等等,這類系統都偏底層,功能和功能之間有着緊密的配合關係,若是強制拆分爲較小的服務單元,會讓集成工做量急劇上升,而且這種人爲的切割沒法帶來業務上的真正的隔離,因此沒法作到獨立部署和運行,也就不適合作成微服務了。
能不能作成微服務,取決於四個要素:
小:微服務體積小,2 pizza 團隊。
獨:可以獨立的部署和運行。
輕:使用輕量級的通訊機制和架構。
鬆:爲服務之間是鬆耦合的。
6. 微服務折分與設計
從單體式結構轉向微服務架構中會持續碰到服務邊界劃分的問題:好比,咱們有user 服務來提供用戶的基礎信息,那麼用戶的頭像和圖片等是應該單獨劃分爲一個新的service更好仍是應該合併到user服務裏呢?若是服務的粒度劃分的過粗,那就回到了單體式的老路;若是過細,那服務間調用的開銷就變得不可忽視了,管理難度也會指數級增長。目前爲止尚未一個能夠稱之爲服務邊界劃分的標準,只能根據不一樣的業務系統加以調節。
拆分的大原則是當一塊業務不依賴或極少依賴其它服務,有獨立的業務語義,爲超過2個的其餘服務或客戶端提供數據,那麼它就應該被拆分紅一個獨立的服務模塊。
6.1 微服務設計原則
單一職責原則
意思是每一個微服務只須要實現本身的業務邏輯就能夠了,好比訂單管理模塊,它只須要處理訂單的業務邏輯就能夠了,其它的沒必要考慮。
服務自治原則
意思是每一個微服務從開發、測試、運維等都是獨立的,包括存儲的數據庫也都是獨立的,本身就有一套完整的流程,咱們徹底能夠把它當成一個項目來對待。沒必要依賴於其它模塊。
輕量級通訊原則
首先是通訊的語言很是的輕量,第二,該通訊方式須要是跨語言、跨平臺的,之因此要跨平臺、跨語言就是爲了讓每一個微服務都有足夠的獨立性,能夠不受技術的鉗制。
接口明確原則
因爲微服務之間可能存在着調用關係,爲了儘可能避免之後因爲某個微服務的接口變化而致使其它微服務都作調整,在設計之初就要考慮到全部狀況,讓接口儘可能作的更通用,更靈活,從而儘可能避免其它模塊也作調整。
7. 微服務優點與缺點
7.1 特性
每一個微服務可獨立運行在本身的進程裏;
一系列獨立運行的微服務共同構建起了整個系統;
每一個服務爲獨立的業務開發,一個微服務通常完成某個特定的功能,好比:訂單管理,用戶管理等;
微服務之間經過一些輕量級的通訊機制進行通訊,例如經過REST API或者RPC的方式進行調用。
7.2 特色
易於開發和維護
因爲微服務單個模塊就至關於一個項目,開發這個模塊咱們就只需關心這個模塊的邏輯便可,代碼量和邏輯複雜度都會下降,從而易於開發和維護。
啓動較快
這是相對單個微服務來說的,相比於啓動單體架構的整個項目,啓動某個模塊的服務速度明顯是要快不少的。
局部修改容易部署
在開發中發現了一個問題,若是是單體架構的話,咱們就須要從新發布並啓動整個項目,很是耗時間,可是微服務則不一樣,哪一個模塊出現了bug咱們只須要解決那個模塊的bug就能夠了,解決完bug以後,咱們只須要重啓這個模塊的服務便可,部署相對簡單,沒必要重啓整個項目從而大大節約時間。
技術棧不受限
好比訂單微服務和電影微服務原來都是用java寫的,如今咱們想把電影微服務改爲nodeJs技術,這是徹底能夠的,並且因爲所關注的只是電影的邏輯而已,所以技術更換的成本也就會少不少。
按需伸縮
咱們上面說了單體架構在想擴展某個模塊的性能時不得不考慮到其它模塊的性能會不會受影響,對於咱們微服務來說,徹底不是問題,電影模塊經過什麼方式來提高性能沒必要考慮其它模塊的狀況。
7.3 缺點
運維要求較高
對於單體架構來說,咱們只須要維護好這一個項目就能夠了,可是對於微服務架構來說,因爲項目是由多個微服務構成的,每一個模塊出現問題都會形成整個項目運行出現異常,想要知道是哪一個模塊形成的問題每每是不容易的,由於咱們沒法一步一步經過debug的方式來跟蹤,這就對運維人員提出了很高的要求。
分佈式的複雜性
對於單體架構來說,咱們能夠不使用分佈式,可是對於微服務架構來講,分佈式幾乎是必會用的技術,因爲分佈式自己的複雜性,致使微服務架構也變得複雜起來。
接口調整成本高
好比,用戶微服務是要被訂單微服務和電影微服務所調用的,一旦用戶微服務的接口發生大的變更,那麼全部依賴它的微服務都要作相應的調整,因爲微服務可能很是多,那麼調整接口所形成的成本將會明顯提升。
重複勞動
對於單體架構來說,若是某段業務被多個模塊所共同使用,咱們即可以抽象成一個工具類,被全部模塊直接調用,可是微服務卻沒法這樣作,由於這個微服務的工具類是不能被其它微服務所直接調用的,從而咱們便不得不在每一個微服務上都建這麼一個工具類,從而致使代碼的重複。
8. 微服務開發框架
目前微服務的開發框架,最經常使用的有如下四個:
Spring Cloud:http://projects.spring.io/spring-cloud(如今很是流行的微服務架構)
Dubbo:http://dubbo.io
Dropwizard:http://www.dropwizard.io (關注單個微服務的開發)
Consul、etcd&etc.(微服務的模塊)
9. Sprint cloud 和 Sprint boot區別
Spring Boot:
旨在簡化建立產品級的Spring應用和服務,簡化了配置文件,使用嵌入式web服務器,含有諸多開箱即用微服務功能,能夠和spring cloud聯合部署。
Spring Cloud:
微服務工具包,爲開發者提供了在分佈式系統的配置管理、服務發現、斷路器、智能路由、微代理、控制總線等開發工具包。
具體區別能夠點擊:https://blog.csdn.net/Soinice/article/details/83793722
2、微服務實踐先知
1. 客戶端如何訪問這些服務?(API Gateway)
傳統的開發方式,全部的服務都是本地的,UI能夠直接調用,如今按功能拆分紅獨立的服務,跑在獨立的通常都在獨立的虛擬機上的 Java進程了。客戶端UI如何訪問他的?後臺有N個服務,前臺就須要記住管理N個服務,一個服務下線/更新/升級,前臺就要從新部署,這明顯不符合咱們拆分的理念,特別當前臺是移動應用的時候,一般業務變化的節奏更快。另外,N個小服務的調用也是一個不小的網絡開銷。還有通常微服務在系統內部,一般是無狀態的,用戶登陸信息和權限管理最好有一個統一的地方維護管理(OAuth)。
因此,通常在後臺N個服務和UI之間會有一個代理或者叫API Gateway,他的做用包括
提供統一服務入口,讓微服務對前臺透明
聚合後臺的服務,節省流量,提高性能
提供安全,過濾,流控等API管理功能
個人理解其實這個API Gateway能夠有不少廣義的實現辦法,能夠是一個軟硬一體的盒子,也能夠是一個簡單的MVC框架,甚至是一個Node.js的服務端。他們最重要的做用是爲前臺(一般是移動應用)提供後臺服務的聚合,提供一個統一的服務出口,解除他們之間的耦合,不過API Gateway也有可能成爲單點故障點或者性能的瓶頸。
2. 服務之間如何通訊?(服務調用)
由於全部的微服務都是獨立的Java進程跑在獨立的虛擬機上,因此服務間的通行就是IPC(inter process communication),已經有不少成熟的方案。如今基本最通用的有兩種方式。這幾種方式,展開來說均可以寫本書,並且你們通常都比較熟悉細節了, 就不展開講了。
REST(JAX-RS,Spring Boot)
RPC(Thrift, Dubbo)
異步消息調用(Kafka, Notify)
通常同步調用比較簡單,一致性強,可是容易出調用問題,性能體驗上也會差些,特別是調用層次多的時候。RESTful和RPC的比較也是一個頗有意思的話題。通常REST基於HTTP,更容易實現,更容易被接受,服務端實現技術也更靈活些,各個語言都能支持,同時能跨客戶端,對客戶端沒有特殊的要求,只要封裝了HTTP的SDK就能調用,因此相對使用的廣一些。RPC也有本身的優勢,傳輸協議更高效,安全更可控,特別在一個公司內部,若是有統一個的開發規範和統一的服務框架時,他的開發效率優點更明顯些。就看各自的技術積累實際條件,本身的選擇了。
而異步消息的方式在分佈式系統中有特別普遍的應用,他既能減低調用服務之間的耦合,又能成爲調用之間的緩衝,確保消息積壓不會沖垮被調用方,同時能保證調用方的服務體驗,繼續幹本身該乾的活,不至於被後臺性能拖慢。不過須要付出的代價是一致性的減弱,須要接受數據最終一致性;還有就是後臺服務通常要 實現冪等性,由於消息發送出於性能的考慮通常會有重複(保證消息的被收到且僅收到一次對性能是很大的考驗);最後就是必須引入一個獨立的broker,若是公司內部沒有技術積累,對broker分佈式管理也是一個很大的挑戰。
3. 這麼多服務怎麼查找?(服務發現)
在微服務架構中,通常每個服務都是有多個拷貝,來作負載均衡。一個服務隨時可能下線,也可能應對臨時訪問壓力增長新的服務節點。服務之間如何相互感知?服務如何管理?這就是服務發現的問題了。通常有兩類作法,也各有優缺點。基本都是經過zookeeper等相似技術作服務註冊信息的分佈式管理。當服務上線時,服務提供者將本身的服務信息註冊到ZK(或相似框架),並經過心跳維持長連接,實時更新連接信息。服務調用者經過ZK尋址,根據可定製算法,找到一個服務,還能夠將服務信息緩存在本地以提升性能。當服務下線時,ZK會發通知給服務客戶端。
客戶端作:
優勢是架構簡單,擴展靈活,只對服務註冊器依賴。缺點是客戶端要維護全部調用服務的地址,有技術難度,通常大公司都有成熟的內部框架支持,好比Dubbo。
服務端作:
優勢是簡單,全部服務對於前臺調用方透明,通常在小公司在雲服務上部署的應用採用的比較多。
4. 服務掛了怎麼辦?
分佈式最大的特性就是網絡是不可靠的。經過微服務拆分能下降這個風險,不過若是沒有特別的保障,結局確定是噩夢。咱們剛遇到一個線上故障就是一個很不起眼的SQL計數功能,在訪問量上升時,致使數據庫load彪高,影響了所在應用的性能,從而影響全部調用這個應用服務的前臺應用。因此當咱們的系統是由一系列的服務調用鏈組成的時候,咱們必須確保任一環節出問題都不至於影響總體鏈路。相應的手段有不少:
重試機制
限流
熔斷機制
負載均衡
降級(本地緩存) 這些方法基本上都很明確通用,就不詳細說明了。好比Netflix的Hystrix:https://github.com/Netflix/Hystrix
5. 微服務須要考慮的問題
這裏有一個圖很是好的總結微服務架構須要考慮的問題,包括
API Gateway
服務間調用
服務發現
服務容錯
服務部署
數據調用
3、微服務重要部件
1. 微服務基本能力
2. 服務註冊中心
服務之間須要建立一種服務發現機制,用於幫助服務之間互相感知彼此的存在。服務啓動時會將自身的服務信息註冊到註冊中心,並訂閱本身須要消費的服務。
服務註冊中心是服務發現的核心。它保存了各個可用服務實例的網絡地址(IPAddress和Port)。服務註冊中心必需要有高可用性和實時更新功能。上面提到的 Netflix Eureka 就是一個服務註冊中心。它提供了服務註冊和查詢服務信息的REST API。服務經過使用POST請求註冊本身的IPAddress和Port。每30秒發送一個PUT請求刷新註冊信息。經過DELETE請求註銷服務。客戶端經過GET請求獲取可用的服務實例信息。 Netflix的高可用(Netflix achieves high availability )是經過在Amazon EC2運行多個實例來實現的,每個Eureka服務都有一個彈性IP Address。當Eureka服務啓動時,有DNS服務器動態的分配。Eureka客戶端經過查詢 DNS來獲取Eureka的網絡地址(IP Address和Port)。通常狀況下,都是返回和客戶端在同一個可用區Eureka服務器地址。 其餘可以做爲服務註冊中心的有:
etcd:高可用,分佈式,強一致性的,key-value,Kubernetes和Cloud Foundry都是使用了etcd。
consul:一個用於discovering和configuring的工具。它提供了容許客戶端註冊和發現服務的API。Consul能夠進行服務健康檢查,以肯定服務的可用性。
zookeeper:在分佈式應用中被普遍使用,高性能的協調服務。 Apache Zookeeper 最初爲Hadoop的一個子項目,但如今是一個頂級項目。
2.1 zookeeper服務註冊和發現
簡單來說,zookeeper能夠充當一個服務註冊表(Service Registry),讓多個服務提供者造成一個集羣,讓服務消費者經過服務註冊表獲取具體的服務訪問地址(ip+端口)去訪問具體的服務提供者。以下圖所示:
具體來講,zookeeper就是個分佈式文件系統,每當一個服務提供者部署後都要將本身的服務註冊到zookeeper的某一路徑上: /{service}/{version}/{ip:port},好比咱們的HelloWorldService部署到兩臺機器,那麼zookeeper上就會建立兩條目錄:
/HelloWorldService/1.0.0/100.19.20.01:16888
/HelloWorldService/1.0.0/100.19.20.02:16888
zookeeper提供了「心跳檢測」功能,它會定時向各個服務提供者發送一個請求(實際上創建的是一個 socket 長鏈接),若是長期沒有響應,服務中心就認爲該服務提供者已經「掛了」,並將其剔除,好比100.19.20.02這臺機器若是宕機了,那麼zookeeper上的路徑就會只剩/HelloWorldService/1.0.0/100.19.20.01:16888。
服務消費者會去監聽相應路徑(/HelloWorldService/1.0.0),一旦路徑上的數據有任務變化(增長或減小),zookeeper都會通知服務消費方服務提供者地址列表已經發生改變,從而進行更新。
更爲重要的是zookeeper 與生俱來的容錯容災能力(好比leader選舉),能夠確保服務註冊表的高可用性。
3. 負載均衡
服務高可用的保證手段,爲了保證高可用,每個微服務都須要部署多個服務實例來提供服務。此時客戶端進行服務的負載均衡。
3.1 負載均衡的常見策略
3.1.1 隨機
把來自網絡的請求隨機分配給內部中的多個服務器。
3.1.2 輪詢
每個來自網絡中的請求,輪流分配給內部的服務器,從1到N而後從新開始。此種負載均衡算法適合服務器組內部的服務器都具備相同的配置而且平均服務請求相對均衡的狀況。
3.1.3 加權輪詢
根據服務器的不一樣處理能力,給每一個服務器分配不一樣的權值,使其可以接受相應權值數的服務請求。例如:服務器A的權值被設計成1,B的權值是3,C的權值是6,則服務器A、B、C將分別接受到10%、30%、60%的服務請求。此種均衡算法能確保高性能的服務器獲得更多的使用率,避免低性能的服務器負載太重。
3.1.4 IP Hash
這種方式經過生成請求源IP的哈希值,並經過這個哈希值來找到正確的真實服務器。這意味着對於同一主機來講他對應的服務器老是相同。使用這種方式,你不須要保存任何源IP。可是須要注意,這種方式可能致使服務器負載不平衡。
3.1.5 最少鏈接數
客戶端的每一次請求服務在服務器停留的時間可能會有較大的差別,隨着工做時間加長,若是採用簡單的輪循或隨機均衡算法,每一臺服務器上的鏈接進程可能會產生極大的不一樣,並無達到真正的負載均衡。最少鏈接數均衡算法對內部中需負載的每一臺服務器都有一個數據記錄,記錄當前該服務器正在處理的鏈接數量,當有新的服務鏈接請求時,將把當前請求分配給鏈接數最少的服務器,使均衡更加符合實際狀況,負載更加均衡。此種均衡算法適合長時處理的請求服務,如FTP。
4. 容錯
容錯,這個詞的理解,直面意思就是能夠容下錯誤,不讓錯誤再次擴張,讓這個錯誤產生的影響在一個固定的邊界以內,「千里之堤毀於蟻穴」咱們用容錯的方式就是讓這種蟻穴不要變大。那麼咱們常見的降級,限流,熔斷器,超時重試等等都是容錯的方法。
在調用服務集羣時,若是一個微服務調用異常,如超時,鏈接異常,網絡異常等,則根據容錯策略進行服務容錯。目前支持的服務容錯策略有快速失敗,失效切換。若是連續失敗屢次則直接熔斷,再也不發起調用。這樣能夠避免一個服務異常拖垮全部依賴於他的服務。
4.1 容錯策略
4.1.1 快速失敗
服務只發起一次待用,失敗當即報錯。一般用於非冪等下性的寫操做。
4.1.2 失效切換
服務發起調用,當出現失敗後,重試其餘服務器。一般用於讀操做,但重試會帶來更長時間的延遲。重試的次數一般是能夠設置的。
4.1.3 失敗安全
失敗安全, 當服務調用出現異常時,直接忽略。一般用於寫入日誌等操做。
4.1.4 失敗自動恢復
當服務調用出現異常時,記錄失敗請求,定時重發。一般用於消息通知。
4.1.5 forking Cluster
並行調用多個服務器,只要有一個成功,即返回。一般用於實時性較高的讀操做。能夠經過forks=n來設置最大並行數。
4.1.6 廣播調用
廣播調用全部提供者,逐個調用,任何一臺失敗則失敗。一般用於通知全部提供者更新緩存或日誌等本地資源信息。
5. 熔斷
熔斷技術能夠說是一種「智能化的容錯」,當調用知足失敗次數,失敗比例就會觸發熔斷器打開,有程序自動切斷當前的RPC調用,來防止錯誤進一步擴大。實現一個熔斷器主要是考慮三種模式,關閉,打開,半開。各個狀態的轉換以下圖。
咱們在處理異常的時候,要根據具體的業務狀況來決定處理方式,好比咱們調用商品接口,對方只是臨時作了降級處理,那麼做爲網關調用就要切到可替換的服務上來執行或者獲取託底數據,給用戶友好提示。還有要區分異常的類型,好比依賴的服務崩潰了,這個可能須要花費比較久的時間來解決。也多是因爲服務器負載臨時太高致使超時。做爲熔斷器應該可以甄別這種異常類型,從而根據具體的錯誤類型調整熔斷策略。增長手動設置,在失敗的服務恢復時間不肯定的狀況下,管理員能夠手動強制切換熔斷狀態。最後,熔斷器的使用場景是調用可能失敗的遠程服務程序或者共享資源。若是是本地緩存本地私有資源,使用熔斷器則會增長系統的額外開銷。還要注意,熔斷器不能做爲應用程序中業務邏輯的異常處理替代品。
有一些異常比較頑固,忽然發生,沒法預測,並且很難恢復,而且還會致使級聯失敗(舉個例子,假設一個服務集羣的負載很是高,若是這時候集羣的一部分掛掉了,還佔了很大一部分資源,整個集羣都有可能遭殃)。若是咱們這時仍是不斷進行重試的話,結果大多都是失敗的。所以,此時咱們的應用須要當即進入失敗狀態(fast-fail),並採起合適的方法進行恢復。
咱們能夠用狀態機來實現CircuitBreaker,它有如下三種狀態:
關閉( Closed ):默認狀況下Circuit Breaker是關閉的,此時容許操做執行。CircuitBreaker內部記錄着最近失敗的次數,若是對應的操做執行失敗,次數就會續一次。若是在某個時間段內,失敗次數(或者失敗比率)達到閾值,CircuitBreaker會轉換到開啓( Open )狀態。在開啓狀態中,Circuit Breaker會啓用一個超時計時器,設這個計時器的目的是給集羣相應的時間來恢復故障。當計時器時間到的時候,CircuitBreaker會轉換到半開啓( Half-Open )狀態。
開啓( Open ):在此狀態下,執行對應的操做將會當即失敗而且當即拋出異常。
半開啓( Half-Open ):在此狀態下,Circuit Breaker會容許執行必定數量的操做。若是全部操做所有成功,CircuitBreaker就會假定故障已經恢復,它就會轉換到關閉狀態,而且重置失敗次數。若是其中 任意一次 操做失敗了,Circuit Breaker就會認爲故障仍然存在,因此它會轉換到開啓狀態並再次開啓計時器(再給系統一些時間使其從失敗中恢復)
6. 限流和降級
保證核心服務的穩定性。爲了保證核心服務的穩定性,隨着訪問量的不斷增長,須要爲系統可以處理的服務數量設置一個極限閥值,超過這個閥值的請求則直接拒絕。同時,爲了保證核心服務的可用,能夠對否些非核心服務進行降級,經過限制服務的最大訪問量進行限流,經過管理控制檯對單個微服務進行人工降級。
7. SLA
SLA:Service-LevelAgreement的縮寫,意思是服務等級協議。 是關於網絡服務供應商和客戶間的一份合同,其中定義了服務類型、服務質量和客戶付款等術語。 典型的SLA包括如下項目:
分配給客戶的最小帶寬;
客戶帶寬極限;
能同時服務的客戶數目;
在可能影響用戶行爲的網絡變化以前的通知安排;
撥入訪問可用性;
運用統計學;
服務供應商支持的最小網絡利用性能,如99.9%有效工做時間或天天最多爲1分鐘的停機時間;
各種客戶的流量優先權;
客戶技術支持和服務;
懲罰規定,爲服務供應商不能知足 SLA需求所指定。
8. API網關
這裏說的網關是指API網關,直面意思是將全部API調用統一接入到API網關層,有網關層統一接入和輸出。一個網關的基本功能有:統一接入、安全防禦、協議適配、流量管控、長短連接支持、容錯能力。有了網關以後,各個API服務提供團隊能夠專一於本身的的業務邏輯處理,而API網關更專一於安全、流量、路由等問題。
9. 多級緩存
最簡單的緩存就是查一次數據庫而後將數據寫入緩存好比redis中並設置過時時間。由於有過時失效所以咱們要關注下緩存的穿透率,這個穿透率的計算公式,好比查詢方法queryOrder(調用次數1000/1s)裏面嵌套查詢DB方法queryProductFromDb(調用次數300/s),那麼redis的穿透率就是300/1000,在這種使用緩存的方式下,是要重視穿透率的,穿透率大了說明緩存的效果很差。還有一種使用緩存的方式就是將緩存持久化,也就是不設置過時時間,這個就會面臨一個數據更新的問題。通常有兩種辦法,一個是利用時間戳,查詢默認以redis爲主,每次設置數據的時候放入一個時間戳,每次讀取數據的時候用系統當前時間和上次設置的這個時間戳作對比,好比超過5分鐘,那麼就再查一次數據庫。這樣能夠保證redis裏面永遠有數據,通常是對DB的一種容錯方法。還有一個就是真正的讓redis作爲DB使用。就是圖裏面畫的經過訂閱數據庫的binlog經過數據異構系統將數據推送給緩存,同時將將緩存設置爲多級。能夠經過使用jvmcache做爲應用內的一級緩存,通常是體積小,訪問頻率大的更適合這種jvmcache方式,將一套redis做爲二級remote緩存,另外最外層三級redis做爲持久化緩存。
10. 超時和重試
超時與重試機制也是容錯的一種方法,凡是發生RPC調用的地方,好比讀取redis,db,mq等,由於網絡故障或者是所依賴的服務故障,長時間不能返回結果,就會致使線程增長,加大cpu負載,甚至致使雪崩。因此對每個RPC調用都要設置超時時間。對於強依賴RPC調用資源的狀況,還要有重試機制,可是重試的次數建議1-2次,另外若是有重試,那麼超時時間就要相應的調小,好比重試1次,那麼一共是發生2次調用。若是超時時間配置的是2s,那麼客戶端就要等待4s才能返回。所以重試+超時的方式,超時時間要調小。這裏也再談一下一次PRC調用的時間都消耗在哪些環節,一次正常的調用統計的耗時主要包括: ①調用端RPC框架執行時間 + ②網絡發送時間 + ③服務端RPC框架執行時間 + ④服務端業務代碼時間。調用方和服務方都有各自的性能監控,好比調用方tp99是500ms,服務方tp99是100ms,找了網絡組的同事確認網絡沒有問題。那麼時間都花在什麼地方了呢,兩種緣由,客戶端調用方,還有一個緣由是網絡發生TCP重傳。因此要注意這兩點。
11. 線程池隔離
在抗量這個環節,Servlet3異步的時候,有提到過線程隔離。線程隔離的之間優點就是防止級聯故障,甚至是雪崩。當網關調用N多個接口服務的時候,咱們要對每一個接口進行線程隔離。好比,咱們有調用訂單、商品、用戶。那麼訂單的業務不可以影響到商品和用戶的請求處理。若是不作線程隔離,當訪問訂單服務出現網絡故障致使延時,線程積壓最終致使整個服務CPU負載滿。就是咱們說的服務所有不可用了,有多少機器都會被此刻的請求塞滿。那麼有了線程隔離就會使得咱們的網關能保證局部問題不會影響全局。
12. 降級和限流
關於降級限流的方法業界都已經有很成熟的方法了,好比FAILBACK機制,限流的方法令牌桶,漏桶,信號量等。這裏談一下咱們的一些經驗,降級通常都是由統一配置中心的降級開關來實現的,那麼當有不少個接口來自同一個提供方,這個提供方的系統或這機器所在機房網絡出現了問題,咱們就要有一個統一的降級開關,否則就要一個接口一個接口的來降級。也就是要對業務類型有一個大閘刀。還有就是 降級切記暴力降級,什麼是暴力降級的,好比把論壇功能降調,結果用戶顯示一個大白板,咱們要實現緩存住一些數據,也就是有託底數據。限流通常分爲分佈式限流和單機限流,若是實現分佈式限流的話就要一個公共的後端存儲服務好比redis,在大nginx節點上利用lua讀取redis配置信息。咱們如今的限流都是單機限流,並無實施分佈式限流。
13. 網關監控和統計
API網關是一個串行的調用,那麼每一步發生的異常要記錄下來,統一存儲到一個地方好比elasticserach中,便於後續對調用異常的分析。鑑於公司docker申請都是統一分配,並且分配以前docker上已經存在3個agent了,再也不容許增長。咱們本身實現了一個agent程序,來負責採集服務器上面的日誌輸出,而後發送到kafka集羣,再消費到elasticserach中,經過web查詢。如今作的追蹤功能還比較簡單,這塊還須要繼續豐富。