歡迎光臨
每天分享高質量文章

微服務的接入層設計與動靜資源隔離

這個系列是微服務高併發設計,所以我們先從最外層的接入層入手,看都有什麼樣的策略保證高併發。
接入層的架構畫一個簡圖來講包括下麵的部分。

接下來我們依次解析各個部分以及可以做的最佳化。


一、資料中心之外:DNS、HttpDNS、GSLB

當我們要訪問一個網站的服務的時候,首先訪問的肯定是一個域名,然後由DNS,將域名解析為IP地址。
我們首先先透過DNS訪問資料中心中的物件儲存上的靜態資源為例子,看一看整個過程。
我們建議將例如檔案、圖片、影片、音訊等靜態資源放在物件儲存中,直接透過CDN下發,而非放在伺服器上,和動態資源系結在一起。
假設全國有多個資料中心,託管在多個運營商,每個資料中心三個可用區Available Zone,物件儲存透過跨可用區部署,實現高可用性,在每個資料中心中,都至少部署兩個內部負載均衡器,內部負載均衡器後面對接多個物件儲存的前置服務proxy-server。

1、當一個客戶端要訪問object.yourcompany.com的時候,需要將域名轉換為IP地址進行訪問,所以他要請求本地的resolver幫忙。
2、本地的resolver看本地的快取是否有這個記錄呢?如果有則直接使用。
3、如果本地無快取,則需要請求本地的Name Server。
4、本地的Name Server一般部署在客戶的資料中心或者客戶所在的運營商的網路中,本地Name Server看本地是否有快取,如果有則傳回。
5、如果本地沒有,本地Name Server需要從Root Name Server開始查起,Root Name Server會將.com Name Server的地址傳回給本地Name Server。
6、本地的Name Server接著訪問.com的Name Server,他會將你們公司的yourcompany.com的Name Server給本地Name Server。
7、本地的Name Server接著訪問yourcompany.com的Name Server,按說這一步就應該傳回真實要訪問的IP地址。
對於不需要做全域性負載均衡的簡單應用來講,yourcompany.com的Name Server可以直接將object.yourcompany.com這個域名解析為一個或者多個IP地址,然後客戶端可以透過多個IP地址,進行簡單的輪詢,實現簡單的負載均衡即可。
但是對於複雜的應用,尤其是跨地域跨運營商的大型應用,則需要更加複雜的全域性負載均衡機制,因而需要專門的裝置或者伺服器來做這件事情,這就是GSLB,全域性負載均衡器。
從yourcompany.com的Name Server中,一般是透過配置CNAME的方式,給object.yourcompany.com起一個別名,例如object.vip.yourcomany.com,然後告訴本地Name Server,讓他去請求GSLB去解析這個域名,則GSLB就可以在解析這個域名的過程中,透過自己的策略實現負載均衡。
圖中畫了兩層的GSLB,是因為分運營商和分地域,我們希望將屬於不同運營商的客戶,訪問相同運營商機房中的資源,這樣不用跨運營商訪問,有利於提高吞吐量,減少時延。
8、第一層GSLB透過檢視請求他的本地Name Server所在的運營商,就知道了使用者所在的運營商,假設是移動,然後透過CNAME的方式,透過另一個別名object.yd.yourcompany.com,告訴本地Name Server去請求第二層的GSLB。
9、第二層的GSLB透過檢視請求他的本地Name Server所在的地址,就知道了使用者所在的地理位置,然後將距離使用者位置比較近的Region的裡面的內部負載均衡SLB的地址共六個傳回給本地Name Server。
10、本地Name Server將結果傳回給resolver。
11、resolver將結果快取後,傳回給客戶端。
12、客戶端開始訪問屬於相同運營商的距離較近的Region1中的物件儲存,當然客戶端得到了六個IP地址,他可以透過負載均衡的方式,隨機或者輪詢選擇一個可用區進行訪問,物件儲存一般會有三份備份,從而可以實現對儲存讀寫的負載均衡。
從上面的過程可以看出,基於DNS域名的GSLB實現全域性的負載均衡,可是現在跨運營商和跨地域的流量排程,但是由於不同運營商的DNS快取策略不同,會造成GSLB的工作實效。
有的使用者的DNS會將域名解析的請求轉發給其他的運營商的DNS進行解析,導致到GSLB的時候,錯誤的判斷了使用者所在的運營商。
有的運營商的DNS出口會做NAT,導致GSLB判斷錯誤使用者所在的運營商。
所以不同於傳統的DNS,有另一種機制稱為httpDNS,可以在使用者的手機App裡面嵌入SDK,透過http的方式訪問一個httpDNS伺服器,由於手機App可以精確的獲得自己的IP地址,可以將IP地址傳給httpDNS伺服器,httpDNS伺服器完全由應用的服務商提供,可以實現完全自主的全網流量排程。


二、資料中心之外:CDN

對於靜態資源來講,其實在真實的訪問機房內的物件儲存之前,在最最接近使用者的地方,可以先透過CDN進行快取,這也是高併發應用的一個總體的思路,能接近客戶,儘量接近客戶。
CDN廠商的改寫範圍往往更廣,在每個運營商,每個地區都有自己的POP點,所以總有更加靠近使用者的相同運營商和相近地點的CDN節點就近獲取靜態資料,避免了跨運營商和跨地域的訪問。
在使用了CDN之後,使用者訪問資源的時候,和上面的過程類似,但是不同的是,DNS解析的時候,會將域名的解析權交給CDN廠商的DNS伺服器,而CDN廠商的DNS伺服器可以透過CDN廠商的GSLB,找到最最接近客戶的POP點,將資料傳回給使用者。

當CDN中沒有找到快取資料的時候,則需要到真正的伺服器中去拿,這個稱為回源,僅僅非常少數的流量需要回源,大大減少了伺服器的壓力。


三、資料中心邊界與核心:邊界路由、核心交換、等價路由

如果真的需要回源,或者訪問的壓根就不是靜態資源,而是動態資源,則需要進入資料中心了。
剛才第一節中說到,最終GSLB傳回了6個IP地址,都是內部負載均衡SLB的IP地址,說明這6個IP地址都是公網可以訪問的,那麼公網如何知道這些IP地址的呢?
這就要看機房的結構了。

一個機房一般會有邊界路由器、核心交換機,每個AZ有匯聚交換機,6個SLB是在AZ裡面的,所以他們的IP地址是透過iBGP協議告知邊界路由器的。
當使用者從六個IP裡面選擇了一個IP地址進行訪問的時候,可以透過公網上面的路由,找到機房的邊界路由器,邊界路由器知道當時這個路由是從哪個AZ裡面給他的,於是就透過核心交換一層,將請求轉發給某一個AZ,這個AZ的匯聚交換機會將請求轉發給這個SLB。
如果一個AZ出現了問題,是否可以讓對某個公網IP的訪問給另一個AZ呢?當然是可以的,在核心路由和核心交換之間,可以做ECMP等價路由。當然也可以在邊界路由上將外部地址NAT稱為內部的一個VIP地址,透過等價路由實現跨AZ的流量分擔。


四、資料中心可用區中:負載均衡SLB、LVS、HAProxy

進入一個可用區AZ之後,首先到達的是負載均衡SLB,可以購買商用的SLB,也可以自己搭建,例如透過LVS實現基本的負載均衡功能。
LVS的效能比較好,很多工作透過核心模組ipvs完成。

LVS可使用keepalived實現雙機熱備,也可以透過OSPF使用等價路由的方式,在多個LVS之間進行流量分擔,往往作為統一的負載均衡入口,承載大的流量。

有時候需要更加複雜的4層和7層負載均衡,則會在LVS後面加上HAProxy叢集,也即將LVS匯入的流量,分發到一大批HAProxy上,這些HAProxy可以根據不同的應用或者租戶進行隔離,每個租戶獨享單獨的HAProxy,但是所有的租戶共享LVS叢集。
如果有雲環境,則HAProxy可以部署在虛擬機器裡面,可以根據流量的情況和租戶的請求進行動態的建立和刪除。

五、資料中心可用區中:接入層Nginx、接入層快取

在負載均衡之後,是接入閘道器,或者API閘道器,往往需要實現很多靈活的轉發策略,這裡會選擇使用Nginx+Lua或者OpenResty做這一層。
由於Nginx本身也有負載均衡機制,有的時候會將HAProxy這一層和Nginx這一層合併,LVS後面直接跟Nginx叢集。
接入層作用一:API的聚合
使用微服務之後,後端的服務會拆分的非常的細,因而前端應用如果要獲取整個頁面的顯示,往往需要從多個服務獲取資料,將資料做一定的聚合後,方能夠顯示出來。

如果是網頁其實還好,如果你用Chrome的debug樣式下,開啟一個複雜的電商主頁的時候,你會發現這個頁面同時會發出很多的http的請求,最終聚合稱為一個頁面。
如果是APP的話,其實也沒有問題,但是會有大量的工作要在客戶端做,這樣會非常的耗電,使用者體驗非常不好,因而最好有一個地方可以將請求聚合,這就是API閘道器的職責之一。這樣對於前端APP來講,後端接是似乎是一個統一的入口,則後端的服務的拆分和聚合,灰度釋出,快取策略等全部被遮蔽了。

接入層作用二:服務發現與動態負載均衡
既然統一的入口變為了接入層,則接入層就有責任自動的發現後端拆分、聚合、擴容、縮容的服務叢集,當後端服務有所變化的時候,能夠實現健康檢查和動態的負載均衡。
對於微服務來講,服務之間也是需要做服務發現的,常見的框架是Dubbo和Spring Cloud,服務的註冊中心可以是ZooKeeper、Consul、etcd、Eureka等。
我們以Consul為例子,既然服務之間的呼叫已經註冊到Consul上,則Nginx自然也可以透過Consul來獲取後端服務的狀態,實現動態的負載均衡。
Nginx可以整合consul-template,可監聽Consul的事件, 當已註冊service串列或key/value 發生變化時, consul-template會修改配置檔案同時可執行一段shell,如nginx reload。
consul-template \    -template "/tmp/nginx.hcl:/var/nginx/nginx.conf:service nginx reload" \
consul-template樣式配置相對複雜,需要reload nginx。
另一種整合Consul的方式是nginx-upsync-module,可以同步Consul的服務串列或key/value儲存,需要重新編譯nginx,不需要reload nginx。
upstream test {
       server 127.0.0.1:11111;
       # 所有的後端服務串列會從consul拉取, 並刪除上面的佔位server
       upsync 127.0.0.1:8500/v1/catelog/service/test upsync_timeout=6m upsync_interval=500ms upsync_type=consul strong_dependency=off;
       # 備份的地址, 保證nginx不強依賴consul
       upsync_dump_path /usr/local/nginx/conf/servers/servers_test.conf;
}
還有一種方式是OpenResty+Lua,相對nginx-upsync-module, 可以加入更多自己的邏輯,init_*_by_lua階段透過http api獲取服務串列載入Nginx記憶體,並設定timer輪訓更新串列,balancer_by_lua階段讀取記憶體的串列, 設定後端伺服器。
Lua實現同樣可以不reload nginx,相比nginx-upsync-module來說更加可擴充套件。
接入層作用三:動靜資源隔離、靜態頁面快取、頁面靜態化
為什麼靜態資源需要隔離呢,靜態資源往往變化較少,但是卻往往比較大,如果每次都載入,則影響效能,浪費頻寬。其實靜態資源可以預載入,並且可以進行快取,甚至可以推送到CDN。
所以應該在接入層Nginx中配置動態資源和靜態資源的分離,將靜態資源的url匯入到Nginx的本地快取或者單獨的快取層如Varnish或者Squid,將動態的資源訪問後端的應用或者動態資源的快取。
在Nginx中,可以透過配置expires、cache-control、if-modified-since來控制瀏覽器端的快取控制。使得瀏覽器端在一段時間內,對於靜態資源,不會重覆請求服務端。這一層稱為瀏覽器端的快取。
當有的請求的確到達了接入層Nginx的時候,也不用總是去應用層獲取頁面,可以在接入層Nginx先攔截一部分熱點的請求。在這裡可以有兩層快取。一是Nginx本身的快取proxy_cache,二是快取層的Varnish或者Squid。
在使用接入層快取的時候,需要註意的是快取key的選擇,不應該包含於使用者相關的資訊,如使用者名稱、地理資訊、cookie、deviceid等,這樣相當於每個使用者單獨的一份快取,使得快取的命中率比較低。
在分離了靜態和動態資源之後,就存在組合的問題,可以透過Ajax訪問動態資源,在瀏覽器端進行組合,也可以在接入層進行組合。
如果在接入層聚合,或者Varnish進行聚合,則可以讓接入層快取定時輪詢後端的應用,當有資料修改的時候,進行動態頁面靜態化,這樣使用者訪問的資料到接入層就會被攔截,缺點是更新的速度有些慢,對於大促場景下的併發訪問高的頁面,可以進行如此的處理。
接入層作用四:動態資源快取
在動靜分離之後,靜態頁面可以很好的快取,而動態的資料還是會向後端請求,而動態頁面靜態化延時相對比較高,而且頁面數目多的時候,靜態化的工作量也比較大,因而在接入層還可以透過Redis或者Memcached,對動態資源進行快取。

接入層作用五:資源隔離
接入層的Nginx叢集不是一個,而是不同的請求可以有獨立的Nginx叢集。
例如搶券或者秒殺系統,會成為熱點中的熱點,因而應該有獨立的Nginx叢集。
接入層作用六:統一鑒權、認證、過濾
API Gateway的另一個作用是統一的認證和鑒權。
一種是基於session的,當客戶端輸入使用者名稱密碼之後,API Gateway會向後端服務提交認證和鑒權,成功後生成session,session統一放在Redis裡面,則接下來的訪問全部都帶著session進行。

另一種方式是透過統一的認證鑒權中心,分配token的方式進行。

這是一個三角形的結構,當API Gateway接收到登陸請求的時候,去認證中心請求認證和授權,如果成功則傳回token,token是一個加密過的字串,裡麵包含很多的認證資訊,接下來的訪問中,API Gateway可以驗證這個token是否有效來認證,而真正的服務可以根據token來鑒權。
接入層作用七:限流
在大促過程中,常常會遇到真實的流量遠遠大於系統測試下來的可承載流量,如果這些流量都進來,則整個系統一定垮掉,最後誰也別玩。所以長做的方式是限流。
限流是從上到下貫穿整個應用的,當然接入層作為最外面的屏障,需要做好整個系統的限流。
對於Nginx來講,限流有多種方式,可以進行連線數限制limit_conn,可以進行訪問頻率限制limit_req,可以啟用過載保護sysgurad模組。
對請求的標的URL進行限流(例如:某個URL每分鐘只允許呼叫多少次)。
對客戶端的訪問IP進行限流(例如:某個IP每分鐘只允許請求多少次)。
對於被限流的使用者,可以進行相對友好的傳回,不同的頁面的策略可以不同。
對於首頁和活動頁,是讀取比較多的,可以傳回快取中的老的頁面,或者APP定時掃清。
對於加入購物車、下單、支付等寫入請求被限流的,可以傳回等待頁面,或者傳回一個圈圈轉啊轉,如果過了一段時間還轉不出來,就可以傳回擠爆了。
對於支付結果傳回,如果被限流,需要馬上傳回錯誤頁面。
接入層作用八:灰度釋出與AB測試
在接入層,由於可以配置訪問路由,以及訪問權重,可以實現灰度釋出,或者AB測試,同時上線兩套系統,透過切入部分流量的方式,測試新上系統的穩定性或者是否更受歡迎。
本文轉載自公眾號:劉超的通俗雲端計算,點選檢視原文
Kubernetes 實戰培訓

本次培訓內容包括:Docker容器的原理與基本操作;容器網路與儲存解析;Kubernetes的架構與設計理念詳解;Kubernetes的資源物件使用說明;Kubernetes 中的開放介面CRI、CNI、CSI解析;Kubernetes監控、網路、日誌管理;容器應用的開發流程詳解等,點選識別下方二維碼加微信好友瞭解具體培訓內容

3月23日開始上課,點選閱讀原文連結即可報名。
贊(0)

分享創造快樂