來源:公眾號 作者: Java知音
鏈接:https://mp.weixin.qq.com/s/1Wz2g5_9OedSvtRwIpdv1Q
1. 分布式架構(gòu)的演進
在軟件行業(yè),一個應用服務隨著功能越來越復雜,用戶量越來越大,尤其是互聯(lián)網(wǎng)行業(yè)流量爆發(fā)式的增長,導致我們需要不斷的重構(gòu)應用的結(jié)構(gòu)來支撐龐大的用戶量,最終從一個簡單的系統(tǒng)主鍵演變成了一個非常復雜的可以支撐高并發(fā)的高可用的分布式架構(gòu),但是一個系統(tǒng)再復雜也是不斷演變來的,所以從另一方面來說,其實是業(yè)務(問題)推動了技術(shù)的發(fā)展。
2. 傳統(tǒng)的單體應用
在早期,我們開發(fā)的都是單體應用,也就是一個系統(tǒng)所有的模塊都在一個服務上:
這種傳統(tǒng)的應用開發(fā)和運維都非常簡單,隨著用戶量的增加,我們發(fā)現(xiàn)應用程序的壓力越來越大,于是我們會選擇對應用進行集群部署:
當然因為選擇了集群,我們就需要考慮服務分發(fā)的問題,所以需要有負載均衡服務器,比如我們最常用的 nginx,還有 lvs,HaProxy 等,硬件層面也可以選擇 F5 來實現(xiàn)負載均衡等等。
當然,在使用了集群之后,我們還需要考慮 session 共享的問題,所以相比較單機架構(gòu)會稍微復雜一點點,那么到這里我們應用進行了擴展了,這時候發(fā)現(xiàn)數(shù)據(jù)庫又到瓶頸了,所以數(shù)據(jù)庫又需要進行擴展。
數(shù)據(jù)庫的擴展可以有兩種主流方式:
讀寫分離
通過讀寫分離以及在某些場景用分布式存儲系統(tǒng)替換關(guān)系型數(shù)據(jù)庫的方式,能夠降低主庫的壓力,解決數(shù)據(jù)存儲方面的問題,不過隨著業(yè)務的發(fā)展,主庫依然會遇到瓶頸。
分庫分表
當采用讀寫分離之后,如果再次遇到瓶頸,那么就可以采用垂直拆分的方式來實現(xiàn),垂直拆分的意思是把數(shù)據(jù)庫中不同的業(yè)務數(shù)據(jù)拆分到不同的數(shù)據(jù)庫中。但是這樣有些熱門模塊依然遲早會遇到瓶頸,于是可以更進一步采用水平拆分,水平拆分就是把同一個表的數(shù)據(jù)拆分到不同的數(shù)據(jù)庫中。
垂直拆分還比較容易處理,畢竟同一個模塊的數(shù)據(jù)還是在一起,水平拆分就會比較復雜了,比如說用戶表拆成了兩張,存在不同的數(shù)據(jù)庫中,那么存的時候到底該存的哪個庫,取的時候又該到哪個庫去查詢,所以水平拆分需要考慮以下問題:
- 插入和查詢的路由問題,需要根據(jù)某一個條件來決定當前數(shù)據(jù)應該分到哪個庫。
- 主鍵的處理,主鍵不能采用自增主鍵的形式,因為不同的庫采用自增主鍵會有沖突。
- 如果某些查詢需要到兩個庫去查詢,會比較難處理。
數(shù)據(jù)庫的拆分可以使用當前比較流行的 Sharding JDBC 或者 MyCat 來實現(xiàn),這時候的架構(gòu)大致就會如下圖所示:
當然,為了進一步優(yōu)化,可以視情況加入緩存層,或者使用消息隊列等技術(shù)來削峰等優(yōu)化措施。
3. 分布式架構(gòu)
分布式架構(gòu)是指位于網(wǎng)絡(luò)計算機上的各個組件(系統(tǒng))僅通過傳遞消息來通信和協(xié)調(diào)目標系統(tǒng),分布式系統(tǒng)其實也可以認為是一種去中心化的實現(xiàn)思路,對于用戶來說是無感知的。
4. 分布式架構(gòu)的意義
從單機單用戶到單機多用戶,再到現(xiàn)在的網(wǎng)絡(luò)時代,應用系統(tǒng)發(fā)生了很多的變化,為什么單體架構(gòu)會逐漸滿足不了需求轉(zhuǎn)而要采用分布式架構(gòu)呢?
原因主要有以下幾點:
- 升級單機處理能力的性價比越來越低。
- 單機處理能力存在瓶頸,一臺服務器的處理能力始終是會有上限的。
- 對于穩(wěn)定性和可用性的要求,單機環(huán)境下無法提供,一旦單機應用掛了,整個系統(tǒng)就全部掛了,而分布式架構(gòu)則不會存在這個問題,某一個模塊不可用并不會導致整個系統(tǒng)的不可用。
5. SOA 架構(gòu)
SOA 全稱為 Service Oriented Architecture,即面向服務架構(gòu)。SOA 是一種架構(gòu)理念。它的提出主要是解決服務之間的耦合問題。
SOA 對服務之間的解耦是一種比較粗粒度的劃分,比如我們的電商網(wǎng)站按服務可以拆分為:用戶模塊,訂單模塊,商品模塊等。SOA 其本質(zhì)上是服務的集合,然后服務間一般會通過 ESB 總線來進行通信。比如之前比較常用的 webservice 就是一種 SOA 架構(gòu)的實現(xiàn)。
6. 微服務架構(gòu)
微服務架構(gòu)在 SOA 架構(gòu)的基礎(chǔ)上做了進一步的細化,微服務架構(gòu)和 SOA 架構(gòu)并沒有本質(zhì)上的區(qū)別,都是為了服務的解耦,只不過微服務架構(gòu)更加關(guān)注服務的粒度,比如上面提到的用戶模塊我們還可以進一步拆分成更細粒度的服務。
隨著微服務架構(gòu)的普及,原本一個單體應用可能會被拆分成幾十個甚至更多的服務,從應用的壓力上來說,我們把壓力進行了分流,但是原本一個服務變成了多個服務對開發(fā)者和運維者來說也帶來了極大的挑戰(zhàn),這也就隨之衍生了一些技術(shù)組件,比如服務與與服務之間如何通信?單個服務如果是集群如何實現(xiàn)負載均衡?配置如何進行統(tǒng)一管理?適合實現(xiàn)分流?如何實現(xiàn)監(jiān)控等。
6.1 注冊中心
各個微服務相互之間需要進行調(diào)用,那么服務與服務之間又是如何知道對方的調(diào)用信息(如 ip,端口,路由等),最簡單最直接的辦法就是每個服務都維護一個其他需要調(diào)用的服務地址信息,但是這樣會給開發(fā)和運維帶來相當大的工作量,當我們有某一個服務 A 的地址信息發(fā)生變更,那么只要調(diào)用了 A 服務的其他所有服務都要隨之修改。而且假如 A 服務宕機了,其他服務也無法發(fā)現(xiàn),當然,也可以做大發(fā)現(xiàn),但是這會相當麻煩,而且每個服務都要重復實現(xiàn)這個功能,這會導致非常繁瑣和重復的工作,所以微服務常用組件中就有了注冊中心。
注冊中心是微服務架構(gòu)中一個核心的基礎(chǔ)服務,主要用來管理所有的微服務,并且注冊中心需要實現(xiàn)服務上線和下線的感知。
也就是說我們所有的微服務都將自己的地址信息注冊到注冊中心,然后其他調(diào)用者只需要維護注冊中心的地址即可,當一個服務下線的時候,注冊中心也會及時將該服務剔除。
常用的注冊中心有:Eureka,consul,Nacos,其他的還有 Zookeeper,Redis 等也可以實現(xiàn)注冊中心。
6.2 遠程通信協(xié)議
微服務之間各個服務可能會非常頻繁的調(diào)用,所以我們一定需要一款高效便捷的通訊協(xié)議來完成遠程通信。
為什么使用 rpc 而不直接使用 http
回答這個問題之前我們先來回答另一個問題,微服務之間能不能直接使用 http 來進行通信?答案是肯定的,但是直接使用 http 來作為遠程通信會有以下問題:
- 請求和返回參數(shù)需要自己封裝,過程比較繁瑣。
- http 協(xié)議是基于 tcp 協(xié)議實現(xiàn)的,每次連接和斷開需要三次握手和四次揮手,這過程會帶來一定的網(wǎng)絡(luò)開銷。
基于上面兩個問題,我們需要另一種更加高效便捷的通信方式來完成微服務之間的通信,這就是 rpc 通信。
RPC(Remote Procedure Call)遠程過程調(diào)用,它是一種通過網(wǎng)絡(luò)從遠程計算機程序上請求服務,而不需要了解底層網(wǎng)絡(luò)技術(shù)的協(xié)議,達到調(diào)用遠程服務就像調(diào)用本地方法一樣,也就是調(diào)用者并不知道這個方法會具體去調(diào)用哪個服務。
不過需要強調(diào)的是 RPC 并不是一種協(xié)議,這一點和 http 是有本質(zhì)區(qū)別的,rpc 只是一種技術(shù)名詞,其底層實現(xiàn)也可以使用 http 協(xié)議,也可以基于 tcp 協(xié)議自己去進行改造。
RPC 主要是用來解決兩個問題:
- 處理分布式架構(gòu)中各個微服務之間的通訊問題。
- 遠程調(diào)用時,調(diào)用者就像調(diào)用本地方法一樣方便。
常用的分布式服務之間遠程通訊組件有:feign,openfeign,dubbo 等。
6.3 負載均衡
提到負載均衡大家的第一反應就是 nginx,一般我們使用 http 通訊時大部分都會使用 nginx 作為負載均衡來處理,那么我們的微服務能否直接使用 nginx 來進行負載呢?
答案是可以的,但是我們?yōu)槭裁床恢苯邮褂?nginx 作為服務轉(zhuǎn)發(fā)呢?我個人覺得主要有以下三個考慮:
- nginx 主要是一款基于 http 來進行的 七層負載(當然其也能實現(xiàn)四層負載),而我們的微服務通信之間不一定會基于 http 協(xié)議。
- 如果使用了 nginx,等于是微服務之間又多引入了一個單點,我們還需要考慮 nginx 轉(zhuǎn)發(fā)的問題,還需要對其進行配置調(diào)優(yōu)等。
- 微服務使用了注冊中心來進行統(tǒng)一管理服務的上線和下線,而如果使用 nginx 那么就需要使用 openresty 結(jié)合 lua 腳本才能實現(xiàn)從注冊中心獲取服務。
也就是說直接使用 nginx 來進行負載的話,技術(shù)上是可行的,但是卻可能會引入一些新的問題,所以微服務之間的負載均衡并沒有直接選擇使用 nginx,而是重新開發(fā)了負載均衡組件。
常用的分布式服務之間負載均衡組件有:ribbon 等。
6.4 配置中心
假如我們某一個模塊部署了幾十甚至上百個集群部署,那么如果每個服務都單獨使用自己的配置文件的話,一旦修改某一個配置,那么我們需要同時修改即使甚至上百個服務的配置,這是一個苦力活,所以我們就需要考慮讓這些服務共用同一套配置,這樣只要修改這一套配置,所有服務都能能生效。
配置中心主要就是用來解決這個問題,為了解決這個問題,配置中心需要具備以下能力:
- 提供配置文件的管理界面(dashboard),這樣使用者可以直接通過訪問 dashboard 來實現(xiàn)可視化配置。
- 配置中心配置修改之后,需要能及時通知到對應服務,讓對應服務修改最新配置。
常用的分布式服務之間負載均衡組件有:apollo,nacos,Spring Cloud config,disconf,diamond,Zookeeper 等。
6.5 服務降級/熔斷
引入微服務我們的目的就是為了讓每一個微服務都成為一個獨立的單元,我們可以對每一個服務進行獨立擴展,實現(xiàn)高可用,假如現(xiàn)在有一個服務 A 因為一下子并發(fā)量過高導致請求堆積,那么就會造成越來越多的請求阻塞,最終造成雪崩效應導致服務 A 宕機,最終可能會導致整個微服務架構(gòu)不可用,所以為了保證高可用用,微服務需要提供一種降級和熔斷措施。
降級也可以分為主動降級和被動降級,主動降級就是在高峰期比如我關(guān)閉一些非核心功能,如:評論,留言等功能。
而熔斷一般指的是某一個方法或者接口負載過高,或者說因為網(wǎng)絡(luò)都動等原因造成響應超時或者失敗等,那么這時候應該主動觸發(fā)熔斷,也就是對后續(xù)請求不再處理而是直接返回,當然這也要視具體業(yè)務來決定采用何種熔斷措施。
常用的分布式服務之間降級/熔斷組件有:Hystrix 和 Sentinel 等。
6.6 服務網(wǎng)關(guān)
微服務架構(gòu)是由單體服務架構(gòu)發(fā)展而來,一般我們一個一個微服務架構(gòu)其實是一個大的應用系統(tǒng),那么必然這一個大的系統(tǒng)有公共部分,比如:統(tǒng)一授權(quán),統(tǒng)一路由,統(tǒng)一記錄日志,也可以進行全局的限流措施等。
不過微服務網(wǎng)關(guān)并不是必須的,這些工作也可以放到每個服務中進行處理。
常用的微服務網(wǎng)關(guān)組件有:Zuul,Spring Cloud GatWay。
7. 這么多分布式組件該如何選擇
分布式架構(gòu)中主要有六大組件,而每個組件又有不同的實現(xiàn),看起來技術(shù)五花八門,感覺需要學的東西非常多,但是上面介紹了這么多分布式組件。
其實其主要就是三大類型:Spring Cloud Netflix,Spring Cloud 官方,Spring Cloud Alibaba,下面我們對這些分布式組件進行歸納分類,這樣大家在學習的時候就可以進行有目的的針對性學習:
Spring Cloud Netflix 是由 Netflix(美國奈飛)公司開源的一套分布式組件,這套組件應該也是大家比較熟悉的一套分布式組件,不過其只有 1.0 版本開源,2.0 之后就不再開源了,Spring Cloud 官方自己也提供了部分組件,而且基于 Feign 的基礎(chǔ)上改造成了 Open Feign。
另外一套比較完整的分布式組件就是 Spring Cloud Alibaba,這是由阿里巴巴開源的的一套分布式組件,這套組件中的 dubbo 大家應該也是比較熟悉的,除了這兩套組件外,其他的也有一些可以用來作為分布式組件,比如 Zookeeper,Consul 等,配置中心像 apollo 是攜程開源的,用的也比較多,所以大家學習的時候可以對同類組件進行了解,并對比其特性,然后選擇一套適合自己系統(tǒng)的組件使用。
除了上面的六大分布式組件外,分布式架構(gòu)中還會涉及到另外兩個比較大的問題:
7.1 分布式消息
分布式消息一般就使用消息隊列,比如 Rabbit MQ,Rocket MQ(阿里巴巴體系),kafka 等。
7.2 分布式事務
分布式事務的話,Spring Cloud Alibaba 也提供了一個組件 seata 來實現(xiàn)。
另外分布式系統(tǒng)當中還涉及到鏈路監(jiān)控相關(guān)問題,這方面可以選擇 sleuth + zipkin,pinponit,skywalking等等。所以說分布式架構(gòu)解決了單體架構(gòu)一些問題的同時,也帶來了一些問題,但是技術(shù)總是在向前發(fā)展的,比如現(xiàn)在號稱為了微服務而生的 Kubernetes(k8s),又有號稱是下一代微服務架構(gòu)的 Service Mesh等。
一門技術(shù)的誕生總是為了解決一些問題,所以還是那句話:業(yè)務才是推動技術(shù)發(fā)展的根本原因。 只有隨著業(yè)務的發(fā)展出現(xiàn)了問題,才會去解決問題,才有更好的促進新技術(shù)的誕生。比如現(xiàn)在流行的 docker,也是為了解決微服務過多導致部署困難問題,任何一門技術(shù)能得到發(fā)展,它一定是解決了當前的痛點,否則我們?yōu)槭裁匆褂盟??假如互?lián)網(wǎng)沒有興起,并發(fā)量始終很低,那么微服務也不會興起,直接使用傳統(tǒng)的單點應用反而更簡單直接。
總結(jié)
本文主要講述了從單點應用到分布式架構(gòu)的發(fā)展歷程,并且描述了微服務當中為什么會誕生出一批組件,其根本原因就是為了解決微服務所帶來的的挑戰(zhàn)和問題,在文中最后對當前流行的分布式架構(gòu)組件進行了分類整理,幫助大家梳理思路,這樣就可以做到有目的的進行針對性的學習,希望通過本文能讓大家對微服務相關(guān)組件有一個清晰的學習思路。