負載均衡知識總結
參考:
微信公眾號:架構師之路
一分鍾了解負載均衡的一切
什么是負載均衡
負載均衡(Load Balance)是分布式系統架構設計中必須考慮的因素之一,它通常是指,將請求/數據【均勻】分攤到多個操作單元上執行,負載均衡的關鍵在於【均勻】。
常見的負載均衡方案

常見互聯網分布式架構如上,分為客戶端層、反向代理nginx層、站點層、服務層、數據層。可以看到,每一個下游都有多個上游調用,只需要做到,每一個上游都均勻訪問每一個下游,就能實現“將請求/數據【均勻】分攤到多個操作單元上執行”。
【客戶端層->反向代理層】的負載均衡

【客戶端層】到【反向代理層】的負載均衡,是通過“DNS輪詢”實現的:DNS-server對於一個域名配置了多個解析ip,每次DNS解析請求來訪問DNS-server,會輪詢返回這些ip,保證每個ip的解析概率是相同的。這些ip就是nginx的外網ip,以做到每台nginx的請求分配也是均衡的。
【反向代理層->站點層】的負載均衡

【反向代理層】到【站點層】的負載均衡,是通過“nginx”實現的。通過修改nginx.conf,可以實現多種負載均衡策略:
1)請求輪詢:和DNS輪詢類似,請求依次路由到各個web-server
2)最少連接路由:哪個web-server的連接少,路由到哪個web-server
3)ip哈希:按照訪問用戶的ip哈希值來路由web-server,只要用戶的ip分布是均勻的,請求理論上也是均勻的,ip哈希均衡方法可以做到,同一個用戶的請求固定落到同一台web-server上,此策略適合有狀態服務,例如session(58沈劍備注:可以這么做,但強烈不建議這么做,站點層無狀態是分布式架構設計的基本原則之一,session最好放到數據層存儲)
4)…
【站點層->服務層】的負載均衡

【站點層】到【服務層】的負載均衡,是通過“服務連接池”實現的。
上游連接池會建立與下游服務多個連接,每次請求會“隨機”選取連接來訪問下游服務。
上一篇文章《RPC-client實現細節》中有詳細的負載均衡、故障轉移、超時處理的細節描述,歡迎點擊link查閱,此處不再展開。
【數據層】的負載均衡
在數據量很大的情況下,由於數據層(db,cache)涉及數據的水平切分,所以數據層的負載均衡更為復雜一些,它分為“數據的均衡”,與“請求的均衡”。
數據的均衡是指:水平切分后的每個服務(db,cache),數據量是差不多的。
請求的均衡是指:水平切分后的每個服務(db,cache),請求量是差不多的。
業內常見的水平切分方式有這么幾種:
一、按照range水平切分

每一個數據服務,存儲一定范圍的數據,上圖為例:
user0服務,存儲uid范圍1-1kw
user1服務,存儲uid范圍1kw-2kw
這個方案的好處是:
(1)規則簡單,service只需判斷一下uid范圍就能路由到對應的存儲服務
(2)數據均衡性較好
(3)比較容易擴展,可以隨時加一個uid[2kw,3kw]的數據服務
不足是:
(1)請求的負載不一定均衡,一般來說,新注冊的用戶會比老用戶更活躍,大range的服務請求壓力會更大
二、按照id哈希水平切分

每一個數據服務,存儲某個key值hash后的部分數據,上圖為例:
user0服務,存儲偶數uid數據
user1服務,存儲奇數uid數據
這個方案的好處是:
(1)規則簡單,service只需對uid進行hash能路由到對應的存儲服務
(2)數據均衡性較好
(3)請求均勻性較好
不足是:
(1)不容易擴展,擴展一個數據服務,hash方法改變時候,可能需要進行數據遷移
總結
負載均衡(Load Balance)是分布式系統架構設計中必須考慮的因素之一,它通常是指,將請求/數據【均勻】分攤到多個操作單元上執行,負載均衡的關鍵在於【均勻】。
(1)【客戶端層】到【反向代理層】的負載均衡,是通過“DNS輪詢”實現的
(2)【反向代理層】到【站點層】的負載均衡,是通過“nginx”實現的
(3)【站點層】到【服務層】的負載均衡,是通過“服務連接池”實現的
(4)【數據層】的負載均衡,要考慮“數據的均衡”與“請求的均衡”兩個點,常見的方式有“按照范圍水平切分”與“hash水平切分”
lvs為何不能完全替代DNS輪詢
上一篇文章“一分鍾了解負載均衡的一切”引起了不少同學的關注,評論中大家爭論的比較多的一個技術點是接入層負載均衡技術,部分同學持這樣的觀點:
1)nginx前端加入lvs和keepalived可以替代“DNS輪詢”
2)F5能搞定接入層高可用、擴展性、負載均衡,可以替代“DNS輪詢”
“DNS輪詢”究竟是不是過時的技術,是不是可以被其他方案替代,接入層架構技術演進,是本文將要細致討論的內容。
一、問題域
nginx、lvs、keepalived、f5、DNS輪詢,每每提到這些技術,往往討論的是接入層的這樣幾個問題:
1)可用性:任何一台機器掛了,服務受不受影響
2)擴展性:能否通過增加機器,擴充系統的性能
3)反向代理+負載均衡:請求是否均勻分攤到后端的操作單元執行
二、上面那些名詞都是干嘛的
由於每個技術人的背景和知識域不同,上面那些名詞縮寫(運維的同學再熟悉不過了),還是花1分鍾簡單說明一下(詳細請自行“百度”):
1)nginx:一個高性能的web-server和實施反向代理的軟件
2)lvs:Linux Virtual Server,使用集群技術,實現在linux操作系統層面的一個高性能、高可用、負載均衡服務器
3)keepalived:一款用來檢測服務狀態存活性的軟件,常用來做高可用
4)f5:一個高性能、高可用、負載均衡的硬件設備(聽上去和lvs功能差不多?)
5)DNS輪詢:通過在DNS-server上對一個域名設置多個ip解析,來擴充web-server性能及實施負載均衡的技術
三、接入層技術演進
【裸奔時代(0)單機架構】

裸奔時代的架構圖如上:
1)瀏覽器通過DNS-server,域名解析到ip
2)瀏覽器通過ip訪問web-server
缺點:
1)非高可用,web-server掛了整個系統就掛了
2)擴展性差,當吞吐量達到web-server上限時,無法擴容
注:單機不涉及負載均衡的問題
【簡易擴容方案(1)DNS輪詢】
假設tomcat的吞吐量是1000次每秒,當系統總吞吐量達到3000時,如何擴容是首先要解決的問題,DNS輪詢是一個很容易想到的方案:

此時的架構圖如上:
1)多部署幾份web-server,1個tomcat抗1000,部署3個tomcat就能抗3000
2)在DNS-server層面,域名每次解析到不同的ip
優點:
1)零成本:在DNS-server上多配幾個ip即可,功能也不收費
2)部署簡單:多部署幾個web-server即可,原系統架構不需要做任何改造
3)負載均衡:變成了多機,但負載基本是均衡的
缺點:
1)非高可用:DNS-server只負責域名解析ip,這個ip對應的服務是否可用,DNS-server是不保證的,假設有一個web-server掛了,部分服務會受到影響
2)擴容非實時:DNS解析有一個生效周期
3)暴露了太多的外網ip
【簡易擴容方案(2)nginx】
tomcat的性能較差,但nginx作為反向代理的性能就強多了,假設線上跑到1w,就比tomcat高了10倍,可以利用這個特性來做擴容:

此時的架構圖如上:
1)站點層與瀏覽器層之間加入了一個反向代理層,利用高性能的nginx來做反向代理
2)nginx將http請求分發給后端多個web-server
優點:
1)DNS-server不需要動
2)負載均衡:通過nginx來保證
3)只暴露一個外網ip,nginx->tomcat之間使用內網訪問
4)擴容實時:nginx內部可控,隨時增加web-server隨時實時擴容
5)能夠保證站點層的可用性:任何一台tomcat掛了,nginx可以將流量遷移到其他tomcat
缺點:
1)時延增加+架構更復雜了:中間多加了一個反向代理層
2)反向代理層成了單點,非高可用:tomcat掛了不影響服務,nginx掛了怎么辦?
【高可用方案(3)keepalived】
為了解決高可用的問題,keepalived出場了(之前的文章“使用shadow-master保證系統可用性”詳細介紹過):

此時:
1)做兩台nginx組成一個集群,分別部署上keepalived,設置成相同的虛IP,保證nginx的高可用
2)當一台nginx掛了,keepalived能夠探測到,並將流量自動遷移到另一台nginx上,整個過程對調用方透明

優點:
1)解決了高可用的問題
缺點:
1)資源利用率只有50%
2)nginx仍然是接入單點,如果接入吞吐量超過的nginx的性能上限怎么辦,例如qps達到了50000咧?
【scale up擴容方案(4)lvs/f5】
nginx畢竟是軟件,性能比tomcat好,但總有個上限,超出了上限,還是扛不住。
lvs就不一樣了,它實施在操作系統層面;f5的性能又更好了,它實施在硬件層面;它們性能比nginx好很多,例如每秒可以抗10w,這樣可以利用他們來擴容,常見的架構圖如下:

此時:
1)如果通過nginx可以擴展多個tomcat一樣,可以通過lvs來擴展多個nginx
2)通過keepalived+VIP的方案可以保證可用性
99.9999%的公司到這一步基本就能解決接入層高可用、擴展性、負載均衡的問題。
這就完美了嘛?還有潛在問題么?
好吧,不管是使用lvs還是f5,這些都是scale up的方案,根本上,lvs/f5還是會有性能上限,假設每秒能處理10w的請求,一天也只能處理80億的請求(10w秒吞吐量*8w秒),那萬一系統的日PV超過80億怎么辦呢?(好吧,沒幾個公司要考慮這個問題)
【scale out擴容方案(5)DNS輪詢】
如之前文章所述,水平擴展,才是解決性能問題的根本方案,能夠通過加機器擴充性能的方案才具備最好的擴展性。
facebook,google,baidu的PV是不是超過80億呢,它們的域名只對應一個ip么,終點又是起點,還是得通過DNS輪詢來進行擴容:

此時:
1)通過DNS輪詢來線性擴展入口lvs層的性能
2)通過keepalived來保證高可用
3)通過lvs來擴展多個nginx
4)通過nginx來做負載均衡,業務七層路由
四、結論
聊了這么多,稍微做一個簡要的總結:
1)接入層架構要考慮的問題域為:高可用、擴展性、反向代理+擴展均衡
2)nginx、keepalived、lvs、f5可以很好的解決高可用、擴展性、反向代理+擴展均衡的問題
3)水平擴展scale out是解決擴展性問題的根本方案,DNS輪詢是不能完全被nginx/lvs/f5所替代的
末了,上一篇文章有同學留言問58到家采用什么方案,58到家目前部署在阿里雲上,前端購買了SLB服務(可以先粗暴的認為是一個lvs+keepalived的高可用負載均衡服務),后端是nginx+tomcat。
五、挖坑
接入層講了這么多,下一章,准備講講服務層“異構服務的負載均”(牛逼的機器應該分配更多的流量,如何做到?)。
如何實施異構服務器的負載均衡及過載保護?
零、需求緣起
第一篇文章“一分鍾了解負載均衡”和大家share了互聯網架構中反向代理層、站點層、服務層、數據層的常用負載均衡方法。
第二篇文章“lvs為何不能完全代替DNS輪詢”和大家share了互聯網接入層負載均衡需要解決的問題及架構演進。
在這兩篇文章中,都強調了“負載均衡是指,將請求/數據【均勻】分攤到多個操作單元上執行,負載均衡的關鍵在於【均勻】”。
然而,后端的service有可能部署在硬件條件不同的服務器上:
1)如果對標最低配的服務器“均勻”分攤負載,高配的服務器的利用率不足;
2)如果對標最高配的服務器“均勻”分攤負載,低配的服務器可能會扛不住;
能否根據異構服務器的處理能力來動態、自適應進行負載均衡及過載保護,是本文要討論的問題。
一、service層的負載均衡通常是怎么做的

“一分鍾了解負載均衡”中提到,service層的負載均衡,一般是通過service連接池來實現的,調用方連接池會建立與下游服務多個連接,每次請求“隨機”獲取連接,來保證service訪問的均衡性。
“RPC-client實現細節”中提到,負載均衡、故障轉移、超時處理等細節也都是通過調用方連接池來實現的。
這個調用方連接池能否實現,根據service的處理能力,動態+自適應的進行負載調度呢?
二、通過“靜態權重”標識service的處理能力

調用方通過連接池組件訪問下游service,通常采用“隨機”的方式返回連接,以保證下游service訪問的均衡性。
要打破這個隨機性,最容易想到的方法,只要為每個下游service設置一個“權重”,代表service的處理能力,來調整訪問到每個service的概率,例如:
假設service-ip1,service-ip2,service-ip3的處理能力相同,可以設置weight1=1,weight2=1,weight3=1,這樣三個service連接被獲取到的概率分別就是1/3,1/3,1/3,能夠保證均衡訪問。
假設service-ip1的處理能力是service-ip2,service-ip3的處理能力的2倍,可以設置weight1=2,weight2=1,weight3=1,這樣三個service連接被獲取到的概率分別就是2/4,1/4,1/4,能夠保證處理能力強的service分別到等比的流量,不至於資源浪費。
使用nginx做反向代理與負載均衡,就有類似的機制。
這個方案的優點是:簡單,能夠快速的實現異構服務器的負載均衡。
缺點也很明顯:這個權重是固定的,無法自適應動態調整,而很多時候,服務器的處理能力是很難用一個固定的數值量化。
三、通過“動態權重”標識service的處理能力
提問:通過什么來標識一個service的處理能力呢?
回答:其實一個service能不能處理得過來,能不能響應得過來,應該由調用方說了算。調用服務,快速處理了,處理能力跟得上;調用服務,處理超時了,處理能力很有可能跟不上了。
動態權重設計
1)用一個動態權重來標識每個service的處理能力,默認初始處理能力相同,即分配給每個service的概率相等;
2)每當service成功處理一個請求,認為service處理能力足夠,權重動態+1
3)每當service超時處理一個請求,認為service處理能力可能要跟不上了,權重動態-10(權重下降會更快)
4)為了方便權重的處理,可以把權重的范圍限定為[0, 100],把權重的初始值設為60分
舉例說明:
假設service-ip1,service-ip2,service-ip3的動態權重初始值weight1=weight2=weight3=60,剛開始時,請求分配給這3台service的概率分別是60/180,60/180,60/180,即負載是均衡的。
隨着時間的推移,處理能力強的service成功處理的請求越來越多,處理能力弱的service偶爾有超時,隨着動態權重的增減,權重可能變化成了weight1=100,weight2=60,weight3=40,那么此時,請求分配給這3台service的概率分別是100/200,60/200,40/200,即處理能力強的service會被分配到更多的流量。
四、過載保護
提問:什么是過載保護?

圖示:無過載保護的負載與處理能力圖(會掉底)
回答:互聯網軟件架構設計中所指的過載保護,是指當系統負載超過一個service的處理能力時,如果service不進行自我保護,可能導致對外呈現處理能力為0,且不能自動恢復的現象。而service的過載保護,是指即使系統負載超過一個service的處理能力,service讓能保證對外提供有損的穩定服務。

圖示:有過載保護的負載與處理能力圖(不會掉底)
提問:如何進行過載保護?
回答:最簡易的方式,服務端設定一個負載閾值,超過這個閾值的請求壓過來,全部拋棄。這個方式不是特別優雅。
五、如何借助“動態權重”來實施過載保護
動態權重是用來標識每個service的處理能力的一個值,它是RPC-client客戶端連接池層面的一個東東。服務端處理超時,客戶端RPC-client連接池都能夠知道,這里只要實施一些策略,就能夠對“疑似過載”的服務器進行降壓,而不用服務器“拋棄請求”這么粗暴的實施過載保護。
應該實施一些什么樣的策略呢,例如:
1)如果某一個service的連接上,連續3個請求都超時,即連續-10分三次,客戶端就可以認為,服務器慢慢的要處理不過來了,得給這個service緩一小口氣,於是設定策略:接下來的若干時間內,例如1秒(或者接下來的若干個請求),請求不再分配給這個service;
2)如果某一個service的動態權重,降為了0(像連續10個請求超時,中間休息了3次還超時),客戶端就可以認為,服務器完全處理不過來了,得給這個service喘一大口氣,於是設定策略:接下來的若干時間內,例如1分鍾(為什么是1分鍾,根據經驗,此時service一般在發生fullGC,差不多1分鍾能回過神來),請求不再分配給這個service;
3)可以有更復雜的保護策略…
這樣的話,不但能借助“動態權重”來實施動態自適應的異構服務器負載均衡,還能在客戶端層面更優雅的實施過載保護,在某個下游service快要響應不過來的時候,給其喘息的機會。
需要注意的是:要防止客戶端的過載保護引起service的雪崩,如果“整體負載”已經超過了“service集群”的處理能力,怎么轉移請求也是處理不過來的,還得通過拋棄請求來實施自我保護。
六、總結
1)service的負載均衡、故障轉移、超時處理通常是RPC-client連接池層面來實施的
2)異構服務器負載均衡,最簡單的方式是靜態權重法,缺點是無法自適應動態調整
3)動態權重法,可以動態的根據service的處理能力來分配負載,需要有連接池層面的微小改動
4)過載保護,是在負載過高時,service為了保護自己,保證一定處理能力的一種自救方法
5)動態權重法,還可以用做service的過載保護
單點系統架構的可用性與性能優化
一、需求緣起
明明架構要求高可用,為何系統中還會存在單點?
回答:單點master的設計,會大大簡化系統設計,何況有時候避免不了單點
在哪些場景中會存在單點?先來看一下一個典型互聯網高可用架構。

典型互聯網高可用架構:
(1)客戶端層,這一層是瀏覽器或者APP,第一步先訪問DNS-server,由域名拿到nginx的外網IP
(2)負載均衡層,nginx是整個服務端的入口,負責反向代理與負載均衡工作
(3)站點層,web-server層,典型的是tomcat或者apache
(4)服務層,service層,典型的是dubbo或者thrift等提供RPC調用的后端服務
(5)數據層,包含cache和db,典型的是主從復制讀寫分離的db架構
在這個互聯網架構中,站點層、服務層、數據庫的從庫都可以通過冗余的方式來保證高可用,但至少
(1)nginx層是一個潛在的單點
(2)數據庫寫庫master也是一個潛在的單點
再舉一個GFS(Google File System)架構的例子。

GFS的系統架構里主要有這么幾種角色:
(1)client,就是發起文件讀寫的調用端
(2)master,這是一個單點服務,它有全局事業,掌握文件元信息
(3)chunk-server,實際存儲文件額服務器
這個系統里,master也是一個單點的服務,Map-reduce系統里也有類似的全局協調的master單點角色。
系統架構設計中,像nginx,db-master,gfs-master這樣的單點服務,會存在什么問題,有什么方案來優化呢,這是本文要討論的問題。
二、單點架構存在的問題
單點系統一般來說存在兩個很大的問題:
(1)非高可用:既然是單點,master一旦發生故障,服務就會受到影響
(2)性能瓶頸:既然是單點,不具備良好的擴展性,服務性能總有一個上限,這個單點的性能上限往往就是整個系統的性能上限
接下來,就看看有什么優化手段可以優化上面提到的兩個問題
三、shadow-master解決單點高可用問題
shadow-master是一種很常見的解決單點高可用問題的技術方案。
“影子master”,顧名思義,服務正常時,它只是單點master的一個影子,在master出現故障時,shadow-master會自動變成master,繼續提供服務。
shadow-master它能夠解決高可用的問題,並且故障的轉移是自動的,不需要人工介入,但不足是它使服務資源的利用率降為了50%,業內經常使用keepalived+vip的方式實現這類單點的高可用。

以GFS的master為例,master正常時:
(1)client會連接正常的master,shadow-master不對外提供服務
(2)master與shadow-master之間有一種存活探測機制
(3)master與shadow-master有相同的虛IP(virtual-IP)

當發現master異常時:
shadow-master會自動頂上成為master,虛IP機制可以保證這個過程對調用方是透明的
除了GFS與MapReduce系統中的主控master,nginx亦可用類似的方式保證高可用,數據庫的主庫master(主庫)亦可用類似的方式來保證高可用,只是細節上有些地方要注意:

傳統的一主多從,讀寫分離的db架構,只能保證讀庫的高可用,是無法保證寫庫的高可用的,要想保證寫庫的高可用,也可以使用上述的shadow-master機制:

(1)兩個主庫設置相互同步的雙主模式
(2)平時只有一個主庫提供服務,言下之意,shadow-master不會往master同步數據
(3)異常時,虛IP漂移到另一個主庫,shadow-master變成主庫繼續提供服務
需要說明的是,由於數據庫的特殊性,數據同步需要時延,如果數據還沒有同步完成,流量就切到了shadow-master,可能引起小部分數據的不一致。
四、減少與單點的交互,是存在單點的系統優化的核心方向
既然知道單點存在性能上限,單點的性能(例如GFS中的master)有可能成為系統的瓶頸,那么,減少與單點的交互,便成了存在單點的系統優化的核心方向。
怎么來減少與單點的交互,這里提兩種常見的方法。
批量寫
批量寫是一種常見的提升單點性能的方式。
例如一個利用數據庫寫單點生成做“ID生成器”的例子:

(1)業務方需要ID
(2)利用數據庫寫單點的auto increament id來生成和返回ID
這是一個很常見的例子,很多公司也就是這么生成ID的,它利用了數據庫寫單點的特性,方便快捷,無額外開發成本,是一個非常帥氣的方案。
潛在的問題是:生成ID的並發上限,取決於單點數據庫的寫性能上限。
如何提升性能呢?批量寫

(1)中間加一個服務,每次從數據庫拿出100個id
(2)業務方需要ID
(3)服務直接返回100個id中的1個,100個分配完,再訪問數據庫
這樣一來,每分配100個才會寫數據庫一次,分配id的性能可以認為提升了100倍。
客戶端緩存
客戶端緩存也是一種降低與單點交互次數,提升系統整體性能的方法。
還是以GFS文件系統為例:

(1)GFS的調用客戶端client要訪問shenjian.txt,先查詢本地緩存,miss了
(2)client訪問master問說文件在哪里,master告訴client在chunk3上
(3)client把shenjian.txt存放在chunk3上記錄到本地的緩存,然后進行文件的讀寫操作
(4)未來client要訪問文件,從本地緩存中查找到對應的記錄,就不用再請求master了,可以直接訪問chunk-server。如果文件發生了轉移,chunk3返回client說“文件不在我這兒了”,client再訪問master,詢問文件所在的服務器。
根據經驗,這類緩存的命中非常非常高,可能在99.9%以上(因為文件的自動遷移是小概率事件),這樣與master的交互次數就降低了1000倍。
五、水平擴展是提升單點系統性能的好方案
無論怎么批量寫,客戶端緩存,單點畢竟是單機,還是有性能上限的。
想方設法水平擴展,消除系統單點,理論上才能夠無限的提升系統系統。
以nginx為例,如何來進行水平擴展呢?

第一步的DNS解析,只能返回一個nginx外網IP么?答案顯然是否定的,“DNS輪詢”技術支持DNS-server返回不同的nginx外網IP,這樣就能實現nginx負載均衡層的水平擴展。

DNS-server部分,一個域名可以配置多個IP,每次DNS解析請求,輪詢返回不同的IP,就能實現nginx的水平擴展,擴充負載均衡層的整體性能。
數據庫單點寫庫也是同樣的道理,在數據量很大的情況下,可以通過水平拆分,來提升寫入性能。
遺憾的是,並不是所有的業務場景都可以水平拆分,例如秒殺業務,商品的條數可能不多,數據庫的數據量不大,就不能通過水平拆分來提升秒殺系統的整體寫性能(總不能一個庫100條記錄吧?)。
六、總結
今天的話題就討論到這里,內容很多,占用大家寶貴的時間深表內疚,估計大部分都記不住,至少記住這幾個點吧:
(1)單點系統存在的問題:可用性問題,性能瓶頸問題
(2)shadow-master是一種常見的解決單點系統可用性問題的方案
(3)減少與單點的交互,是存在單點的系統優化的核心方向,常見方法有批量寫,客戶端緩存
(4)水平擴展也是提升單點系統性能的好方案
集群信息管理,架構設計中最容易遺漏的一環
准備系統性介紹“技術體系規划”了,這是第一篇。
監控平台,服務治理,調用鏈跟蹤,數據收集中心,自動化運維,自動化測試… 很多要講,卻沒想好從哪里入手。
講Z平台,可能需要提前介紹Y服務;講Y服務,可能需要提前介紹X知識。
思來想去,准備從技術體系里,最容易被遺漏,非常基礎,卻又非常重要的“集群信息管理”開始介紹。
由於基礎,可能部分同學會覺得簡單;由於大家所在公司處於不同階段,所以在實現上會介紹不同階段的公司應該如何來實現。
還是一如既往的按照“架構師之路”的思路:
-
是什么
-
什么場景,為什么會用到,存在什么問題
-
常見方案及痛點
-
不同階段公司,不同實現方案
希望大伙有收獲。
一、啥是集群?
互聯網典型分層架構如下:

-
web-server層
-
service層
-
db層與cache層
為了保證高可用,每一個站點、服務、數據庫、緩存都會冗余多個實例,組成一個分布式的系統,集群則是一個分布式的物理形態。
額,好拗口,通俗的說,集群就是一堆機器,上面部署了提供相似功能的站點,服務,數據庫,或者緩存。

如上圖:
-
web集群,由web.1和web.2兩個實例組成
-
service集群,由service.1/service.2/service.3三個實例組成
-
db集群,由mysql-M/mysql-S1/mysql-S2三個實例組成
-
cache集群,由cache-M/cache-S兩個實例組成
與“集群”相對應的是“單機”。
畫外音:關於高可用架構,詳見文章《究竟啥才是互聯網架構“高可用”》。
畫外音:緩存如果沒有高可用要求,可能是單機架構,而不是集群。
二、集群信息
什么是集群信息?
一個集群,會包含若干信息(額,這tm算什么解釋),例如:
-
集群名稱
-
IP列表
-
二進制目錄
-
配置目錄
-
日志目錄
-
負責人列表
畫外音:集群IP列表不建議直接使用IP,而建議使用內網域名,詳見文章《小小的IP,大大的耦合》。
什么時候會用到集群信息呢?
很多場景,特別是線上操作,都會使用到各種集群信息,例如:
-
自動化上線
-
監控
-
日志清理
-
二進制與配置的備份
-
下游的調用(額,這個最典型)
這些場景,分別都是如何讀取集群信息的?
一般來說,早期會把集群信息寫在配置文件里。
例如,自動化上線,有一個配置文件,deploy.user.service.config,其內容是:
name : user.service
ip.list : ip1, ip2, ip3
bin.path : /user.service/bin/
ftp.path : ftp://192.168.0.1/USER_2_0_1_3/user.exe
自動化上線的過程,則是:
-
把可執行文件從ftp拉下來
-
讀取集群IP列表
-
讀取二進制應該部署的目錄
-
把二進制部署到線上
-
逐台重啟
畫外音:啥,還沒有實現自動化腳本部署?還處在運維ssh到線上,手動執行命令,逐台機器人肉部署的刀耕火種階段?趕緊照着這個方案,做自動化改造吧。
又例如,web-X調用下游的user服務,又有一個配置文件,web-X.config,其內容配置了:
service.name : user.service
service.ip.list : ip1, ip2, ip3
service.port : 8080
web-X調用user服務的過程,則是:
-
web-X啟動
-
web-X讀取user服務集群的IP列表與端口
-
web-X初始化user服務連接池
-
web-X拿取user服務的連接,通過RPC接口調用user服務
日志清理,服務監控,二進制備份的過程,也都與上述類似。
三、存在什么問題?
上述業務場景,對於集群信息的使用,有兩個最大的特點:
-
每個應用場景,所需集群信息都不一樣(A場景需要集群abc信息,B場景需要集群def信息)
-
每個應用場景,集群信息都寫在“自己”的配置文件里
一句話總結:集群信息管理分散化。
這里最大的問題,是耦合,當集群的信息發生變化的時候,有非常多的配置需要修改:
-
deploy.user.service.config
-
clean.log.user.service.config
-
backup.bin.user.service.config
-
monitor.config
-
web-X.config
-
…
這些配置里,user服務集群的信息都需要修改:
-
隨着研發、測試、運維人員的流動,很多配置放在哪里,逐步就被遺忘了
-
隨着時間的推移,一些配置就被改漏了
-
逐漸的,莫名其妙的問題出現了
畫外音:ca,誰痛誰知道
如何解決上述耦合的問題呢?
一句話回答:集群信息管理集中化。
四、如何集中化管理集群信息
如何集中化管理集群配置信息,不同發展階段的公司,實現的方式不一樣。
早期方案
通過全局配置文件,實現集群信息集中管理,舉例global.config如下:
[user.service]
ip.list : ip1, ip2, ip3
port : 8080
bin.path : /user.service/bin/
log.path : /user.service/log/
conf.path : /user.service/conf/
ftp.path :ftp://192.168.0.1/USER_2_0_1_3/user.exe
owner.list : shenjian, zhangsan, lisi
[passport.web]
ip.list : ip11, ip22, ip33
port : 80
bin.path : /passport.web/bin/
log.path : /passport.web/log/
conf.path : /passport.web/conf/
ftp.path :ftp://192.168.0.1/PST_1_2_3_4/passport.jar
owner.list : shenjian, zui, shuaiqi
集中維護集群信息之后:
-
任何需要讀取集群信息的場景,都從global.config里讀取
-
任何集群信息的修改,只需要修改global.config一處
-
global.config會部署到任何一台線上機器,維護和管理也很方便
畫外音:額,當然,信息太多的話,global.config也要垂直拆分
中期方案
隨着公司業務的發展,隨着技術團隊的擴充,隨着技術體系的完善,通過集群信息管理服務,來維護集群信息的訴求原來越強烈。
畫外音:慢慢的,配置太多了,通過global.config來修改配置太容易出錯了

如上圖,建立集群信息管理服務:
-
info.db :存儲集群信息
-
info.cache :緩存集群信息
-
info.service :提供集群信息訪問的RPC接口,以及HTTP接口
-
info.web :集群信息維護后台
服務的核心接口是:
Info InfoService::getInfo(String ClusterName);
Bool InfoService::setInfo(String ClusterName, String key, String value);
然后,統一通過服務來獲取與修改集群信息:
-
所有需要獲取集群信息的場景,都通過info.service提供的接口來讀取集群信息
-
所有需要修改集群信息的場景,都通過info.web來操作
長期方案
集群信息服務可以解決大部分的耦合問題,但仍然有一個不足:集群信息變更時,無法反向實時通知關注方,集群信息發生了改變。更長遠的,要引入配置中心來解決。

配置中心的細節,網上的分析很多,之前也撰文寫過,細節就不再本文展開。
五、總結
集群信息管理,是架構設計中非常容易遺漏的一環,但又是非常基礎,非常重要的基礎設施,一定要在早期規划好:
-
傳統的方式,分散化管理集群信息,容易導致耦合
-
集中管理集群信息,有全局配置,信息服務,配置中心三個階段
六、調研
調研一、對於集群信息管理,你的感受是:
-
ca,沒考慮過這個問題,一直是分散式管理
-
在使用全局配置文件
-
在使用信息管理服務
-
在使用配置中心
調研二、對於自動化運維,你的感受是:
-
ca,啥是運維,都是研發在線上亂搞
-
有專門的運維,但一直是人肉運維
-
運維在使用腳本,實現了自動化
-
運維都下崗了,在使用平台,實現了平台化
