作者:費偉偉
上海華瑞銀行數(shù)字銀行開發(fā)中心
架構(gòu)設(shè)計關(guān)注點
架構(gòu)師在進(jìn)行架構(gòu)設(shè)計的時候除了業(yè)務(wù)功能架構(gòu)還需要關(guān)注技術(shù)架構(gòu)的高性能向楼、高可用和可擴(kuò)展囤屹,對于系統(tǒng)技術(shù)架構(gòu)來說主要的復(fù)雜度都是來源于對高性能亿卤、高可用和可擴(kuò)展性的要求驱敲,一旦系統(tǒng)涉及到高性能完箩、高可用赐俗、可擴(kuò)展其中一條,那么在制定技術(shù)架構(gòu)的時候就要進(jìn)行這方面技術(shù)架構(gòu)的考慮弊知。
高性能
1)單機(jī)復(fù)雜度
- 多進(jìn)程:多進(jìn)程雖然要求每個任務(wù)都有獨立的內(nèi)存空間阻逮,進(jìn)程間互不相關(guān),但從使用角度來看秩彤,多個任務(wù)之間能夠在運(yùn)行過程中通訊才能讓設(shè)計更加靈活叔扼。否則兩個進(jìn)程在運(yùn)行過程中不能通訊會導(dǎo)致效率低而且設(shè)計更加復(fù)雜。為了解決這個問題漫雷,大拿們就設(shè)計出了解決方案:操作系統(tǒng)進(jìn)程管道瓜富、消息隊列、信號量降盹、共享存儲等与柑。
- 多線程:在一個進(jìn)程內(nèi)部為了也支持并行任務(wù),很多架構(gòu)設(shè)計又使用了多線程,但這些多線程都共享一份進(jìn)程數(shù)據(jù)价捧,所以為了保證數(shù)據(jù)的正確性丑念,又出現(xiàn)了互斥鎖機(jī)制,我們常見的JDK中的JUC就是一個為了解決線程間數(shù)據(jù)共享的package结蟋。
2)集群復(fù)雜度
目前大部分系統(tǒng)的交易量通過單機(jī)性能都沒辦法支撐脯倚,必須采用機(jī)器集群的方式來達(dá)到高性能。
橫向擴(kuò)展集群:橫向擴(kuò)展集群需要有一個負(fù)載均衡來進(jìn)行流量分發(fā)嵌屎,常見的負(fù)載分發(fā)方式就是增加一個流量分配器挠将,可能是一個硬件網(wǎng)絡(luò)設(shè)備F5,可能是一個軟件網(wǎng)絡(luò)設(shè)備LVS编整,也可能是負(fù)載均衡軟件Nginx舔稀,也有可能是自己開發(fā)的路由網(wǎng)關(guān)。一個具備流量負(fù)載均衡的分配器掌测,需要具備多樣的分配算法内贮,是采用輪詢算法、權(quán)重分配汞斧、還是按照ip hash夜郁。
-
縱向擴(kuò)展集群:縱向擴(kuò)展指的是功能層面的拆分形成的集群,通過負(fù)載均衡增加機(jī)器節(jié)點可以解決單機(jī)器節(jié)點處理性能的瓶頸問題粘勒,但是如果業(yè)務(wù)本身非常復(fù)雜竞端,那么單純的增加機(jī)器其實是無法實現(xiàn)成倍線性的性能提升。為了解決單體應(yīng)用的性能問題就是進(jìn)行服務(wù)拆分庙睡,把一個單體應(yīng)用按照服務(wù)領(lǐng)域進(jìn)行合理的拆分后部署事富。拆分服務(wù)后的優(yōu)勢有以下幾點:
a. 簡單的系統(tǒng)更容易做到高性能,代碼架構(gòu)邏輯簡單更容易進(jìn)行優(yōu)化乘陪;
b. 可以針對單個任務(wù)進(jìn)行擴(kuò)展统台,更細(xì)粒度的針對單獨的性能瓶頸服務(wù)進(jìn)行橫向擴(kuò)容,更有針對性的性能優(yōu)化啡邑;
高可用
保證系統(tǒng)高可用的核心思路就是實現(xiàn)冗余贱勃,實現(xiàn)計算、存儲谤逼、網(wǎng)絡(luò) 3方面的冗余來保證高可用贵扰。
計算高可用:計算高可用主要是依靠對服務(wù)器增加冗余節(jié)點來保證,這里需要考慮計算高可用方案流部,在保證應(yīng)用無狀態(tài)的前提下可以是簡單的使用負(fù)載均衡器進(jìn)行軟負(fù)載戚绕,也可以是1主N備、N主N備贵涵。一般的應(yīng)用節(jié)點只要保證計算無狀態(tài)那么就可以采用簡單高效的負(fù)載均衡多節(jié)點方案列肢,如果系統(tǒng)要保證數(shù)據(jù)一致性那么高可用方案就要采用1主N從或者N主N從方案恰画,例如Mysql主從方案、redis cluster方案等瓷马。
-
存儲高可用:對于需要存儲數(shù)據(jù)的系統(tǒng)來說拴还,整個系統(tǒng)的高可用設(shè)計關(guān)鍵點和難點就在于存儲高可用。存儲與計算相比欧聘,本質(zhì)上的區(qū)別在于片林,將數(shù)據(jù)從一臺機(jī)器搬到另一臺機(jī)器,需要經(jīng)過線路進(jìn)行傳輸怀骤,線路傳輸?shù)乃俣仁呛撩爰墑e的费封,雖然毫秒時間很短,但是對于高可用系統(tǒng)來水蒋伦,這就會造成數(shù)據(jù)不一致的情況弓摘。除了物理傳輸速度限制,傳輸線路本身也可能存在可用性問題痕届,導(dǎo)致線路中斷韧献,并且線路故障一般少則十幾分鐘,長則幾個小時研叫。在傳輸線路中斷的情況下锤窑,就意味著存儲無法進(jìn)行同步,在這段時間內(nèi)整個系統(tǒng)的數(shù)據(jù)是不一致的嚷炉。
分布式領(lǐng)域的CAP定理渊啰,從理論上論證了存儲高可用的復(fù)雜性,CAP定理說的是存儲高可用不可能同時滿足“一致性申屹、可用性绘证、分區(qū)容錯性”,最多滿足其中兩個独柑,這就要求我們在做架構(gòu)設(shè)計的時候要進(jìn)行取舍迈窟。
-
高可用決策算法:無論計算高可用還是存儲高可用,保證高可用的基礎(chǔ)都是狀態(tài)決策忌栅,即系統(tǒng)要能判斷當(dāng)前的狀態(tài)是正常還是異常,如果出現(xiàn)了異常就要采取行動來保證高可用曲稼。
a. 獨裁制:獨裁制決策指的是存在一個獨立的決策主體索绪,負(fù)責(zé)收集信息然后進(jìn)行決策,所有冗余的個體贫悄,都將自身的狀態(tài)信息發(fā)送給決策者瑞驱。
monkey 2019-08-18 10.35.00獨裁制決策方式不會出現(xiàn)決策混亂的問題,因為只有一個決策者窄坦,但問題也正是在于只有一個決策者唤反。當(dāng)決策者本身故障時凳寺,整個系統(tǒng)就無法實現(xiàn)準(zhǔn)確的決策,也就存在了管理節(jié)點的單點問題彤侍。
b. 協(xié)商制:協(xié)商制指的是兩個獨立的個體通過交流信息肠缨,然后根據(jù)規(guī)則進(jìn)行決策,最常用的協(xié)商式?jīng)Q策就是主備決策盏阶。
兩臺服務(wù)器同時以備機(jī)身份啟動晒奕,兩臺服務(wù)器建立通訊,其中一臺服務(wù)器根據(jù)一定的主備決策算法作出決策成為主機(jī)名斟,另一臺保持備機(jī)身份脑慧。協(xié)商式?jīng)Q策架構(gòu)不復(fù)雜,規(guī)則也不復(fù)雜砰盐,難點在于闷袒,如果兩臺服務(wù)器之間的信息交換出現(xiàn)問題,比如網(wǎng)絡(luò)中斷岩梳,此時的狀態(tài)決策就會成為問題霜运。
如果備機(jī)在連接中斷的情況下認(rèn)為主機(jī)故障,那么備機(jī)需要升級為主機(jī)蒋腮,但實際上此時主機(jī)并沒有故障淘捡,那么系統(tǒng)就會出現(xiàn)兩個主機(jī),這樣會存在節(jié)點管理混亂出現(xiàn)問題池摧。
monkey 2019-08-18 10.32.32
備機(jī)如果在連接中斷的情況下不認(rèn)為主機(jī)有故障焦除,則此時如果主機(jī)真的發(fā)生故障,那么系統(tǒng)就沒有主機(jī)了作彤,這樣會導(dǎo)致集群出現(xiàn)無主的局面膘魄。
為了解決上面提到的這兩種情況,一般我們會通過增加更多的連接竭讳,3連接是常用的方式创葡,但這也不能保證絕對的沒問題。
c. 民主制:民主制決策指的是多個獨立的個體通過投票的方式來進(jìn)行狀態(tài)決策绢慢,ZK采用的就是選舉leader的方式灿渴。
民主制決策和協(xié)商制決策比較類似,其基礎(chǔ)都是獨立的個體之間交換信息胰舆,每個個體作出自己的決策骚露,然后按照多數(shù)取勝的規(guī)則來確定最終的狀態(tài),選舉算法為了保證公平和理性一般都很復(fù)雜缚窿,例如ZK的Paxos就非常復(fù)雜棘幸。除了復(fù)雜的算法,民主制決策還有個缺陷就是腦裂倦零。腦裂的根本原因就是误续,原來統(tǒng)一的集群因為連接中斷吨悍,造成了兩個獨立分隔的子集群,每個子集群獨立進(jìn)行選舉蹋嵌,于是選出了兩個主機(jī)育瓜,這就產(chǎn)生了腦裂。
如圖所示欣尼,產(chǎn)生了兩個子集群爆雹,一個子集群的主機(jī)是2,另一個集群的主機(jī)是5愕鼓,這時系統(tǒng)出現(xiàn)了兩個主機(jī)依然違背了系統(tǒng)的設(shè)計原則钙态,兩個主節(jié)點都會各自作出決策,整個系統(tǒng)狀態(tài)就會混亂菇晃。為了解決腦裂的問題册倒,民主式?jīng)Q策的系統(tǒng)一般會采用投票節(jié)點數(shù)必須超過系統(tǒng)總節(jié)點數(shù)一半的規(guī)則來處理,因此節(jié)點4和節(jié)點5沒有超過一半磺送,則不能進(jìn)行選舉驻子,因此最后選出的節(jié)點2作為主節(jié)點,但是在極端情況下估灿,節(jié)點1崇呵,2,3真的都掛了馅袁,那么就算節(jié)點4域慷,5還是正常的也無法提供服務(wù),這也是該方案唯一的缺陷汗销,不過觸發(fā)該問題的可能性較低犹褒。
可擴(kuò)展
設(shè)計一個系統(tǒng)架構(gòu)一方面要保證系統(tǒng)的高性能和高可用,還有一方面也是需要非常重要的弛针,那就是可擴(kuò)展性叠骑。系統(tǒng)保證可擴(kuò)展性是非常困難的,擴(kuò)展性的設(shè)計是一件很復(fù)雜的事情削茁,而且沒有通用的標(biāo)準(zhǔn)可以簡單套上去宙枷,更多的是依靠架構(gòu)師的經(jīng)驗和直覺。
架構(gòu)設(shè)計考慮擴(kuò)展性的目的就是為了應(yīng)對需求變更付材,常見的應(yīng)對需求變化的方案有兩種:
第一種應(yīng)對變化的常見方案是將變化封裝在一個變化層朦拖,將不變的部分封裝在一個獨立的穩(wěn)定層。無論是變化層依賴穩(wěn)定層厌衔,還是穩(wěn)定層依賴變化層都是可以的,需要根據(jù)具體場景來設(shè)計捍岳。
如果系統(tǒng)需要支持XML富寿、JSON睬隶、PB三種接入方式,那么最終的架構(gòu)就是圖中的形式1.
如果系統(tǒng)需要同時支持Mysql页徐、Oracle苏潜、DB2三種數(shù)據(jù)庫存儲方式,那么最終架構(gòu)就是圖中的形式2.
可擴(kuò)展性涉及的難點在于需要拆分出變化層和穩(wěn)定層变勇,對于哪些屬于變化層恤左,哪些屬于穩(wěn)定層,很多時候并不是像前面介紹的例子那么簡單那么明確搀绣,這時候就要依靠對業(yè)務(wù)的理解和架構(gòu)設(shè)計經(jīng)驗設(shè)計出變化層和穩(wěn)定層飞袋,這時候可以考慮采用DDD的設(shè)計思想進(jìn)行變化層和穩(wěn)定層的設(shè)計。
在變化層和穩(wěn)定層之間需要提煉出一個抽象層链患,抽象層的接口要保證穩(wěn)定巧鸭,具體實現(xiàn)層可以根據(jù)具體業(yè)務(wù)進(jìn)行定制開發(fā),當(dāng)加入新功能時麻捻,只需要增加新的實現(xiàn)纲仍,無需修改其他層次。
架構(gòu)設(shè)計流程
識別復(fù)雜度
架構(gòu)設(shè)計第一步就是識別系統(tǒng)復(fù)雜度贸毕,所以在我們設(shè)計架構(gòu)時郑叠,首先就要分析系統(tǒng)的復(fù)雜性,只有分析出系統(tǒng)的復(fù)雜性明棍,后續(xù)的架構(gòu)設(shè)計方案才不會偏離方向乡革。
如果一個系統(tǒng)的復(fù)雜度本來是業(yè)務(wù)邏輯太復(fù)雜,功能耦合嚴(yán)重击蹲,架構(gòu)師卻設(shè)計了一個TPS達(dá)到5w的高性能架構(gòu)署拟,即使這個架構(gòu)最終的性能再優(yōu)秀也沒有意義,因為架構(gòu)沒有解決正確的復(fù)雜性問題歌豺。
架構(gòu)的復(fù)雜度主要來源于高性能推穷、高可用、可擴(kuò)展這3個方面类咧,但架構(gòu)師在具體判斷復(fù)雜性的時候馒铃,不能生搬硬套,認(rèn)為任何時候架構(gòu)設(shè)計都必須同時滿足這3方面要求痕惋。實際上大部分場景下区宇,復(fù)雜度只有其中的某一個,少數(shù)情況下包含其中兩個值戳,如果真的出現(xiàn)同時需要解決3個復(fù)雜性议谷,也必須排個優(yōu)先級。
為了避免過度設(shè)計堕虹,正確的做法是將主要的復(fù)雜度問題列出來卧晓,然后根據(jù)業(yè)務(wù)芬首,技術(shù),團(tuán)隊等綜合情況進(jìn)行排序逼裆,優(yōu)先解決當(dāng)前面臨的最主要問題的復(fù)雜度問題郁稍。對于按照復(fù)雜度優(yōu)先級解決的方式,存在一個普遍的擔(dān)憂胜宇,如果按照優(yōu)先級來解決復(fù)雜問題耀怜,可能會出現(xiàn)解決了優(yōu)先級排在前面的復(fù)雜度后,解決后續(xù)復(fù)雜度的方案需要將已經(jīng)落地的方案推到重來桐愉。這個擔(dān)憂理論上是可能的财破,但現(xiàn)實中幾乎不可能出現(xiàn)。
識別復(fù)雜度對架構(gòu)師來說是一個挑戰(zhàn)仅财,因為原始業(yè)務(wù)需求里并沒有哪個地方會說明復(fù)雜度在哪狈究,需要架構(gòu)時在理解需求的基礎(chǔ)上進(jìn)行分析。
設(shè)計備選方案
有經(jīng)驗的架構(gòu)師需要對目前主流的技術(shù)非常熟悉盏求,對已經(jīng)經(jīng)過驗證的架構(gòu)模式爛熟于心抖锥,然后根據(jù)自己對業(yè)務(wù)的理解,挑選合適的架構(gòu)模式進(jìn)行組合碎罚,再對組合后的方案進(jìn)行修改和調(diào)整磅废。
技術(shù)經(jīng)過這么多年的發(fā)展,新技術(shù)層出不窮荆烈,但是經(jīng)過時間考驗拯勉,已經(jīng)被各種場景驗證過的成熟技術(shù)其實更多,已經(jīng)形成了一些架構(gòu)套路憔购。例如高可用的主備方案宫峦、集群方案、高性能負(fù)載均衡玫鸟、多路復(fù)用导绷、可擴(kuò)展的分層、插件化等技術(shù)屎飘,在我們明確了目標(biāo)后妥曲,按圖索驥就能夠找到可選的解決方案。只有當(dāng)這種方式完全無法滿足需求的時候钦购,才會考慮逆行方案的創(chuàng)新檐盟,而事實上方案的創(chuàng)新絕大部分情況下也都是基于已有的成熟技術(shù)。
架構(gòu)師需要設(shè)計多套備選方案押桃,但方案數(shù)量可以說是無窮無盡的葵萎,架構(gòu)師也不可能窮舉所有方案,可以按照以下方式進(jìn)行執(zhí)行:
- 備選方案的數(shù)量以3-5個最佳,少于3個方案可能是因為思維狹隘陌宿,經(jīng)驗不足锡足,考慮不周全波丰;多于5個則需要耗費大量的精力和時間壳坪,并且方案之間的差別可能并不明顯。
- 備選方案的差異要比較明顯掰烟,例如主備方案和集群方案差異就很明顯爽蝴,或者同樣是主備方案,用ZK做主備決策和用keepalived做主備決策的差異就很明顯纫骑,但是用ZK做主備策略蝎亚,一個檢測周期是1分鐘,一個檢測周期是5分鐘先馆,這就不是架構(gòu)上的差異发框,而只是實現(xiàn)細(xì)節(jié)上的差異。
- 備選方案的技術(shù)不要只局限于已經(jīng)熟悉的技術(shù)煤墙。設(shè)計架構(gòu)時梅惯,架構(gòu)師需要將視野放寬,考慮更多可能性仿野。很多架構(gòu)師積累了一些成功經(jīng)驗铣减,出于快速完成任務(wù)和降低風(fēng)險的目的,可能就不自覺的傾向于使用一些熟悉的技術(shù)脚作,對于新的技術(shù)有所擔(dān)心葫哗。
評估方案
評估和選擇備選方案中最好的方案那就必須經(jīng)過嚴(yán)格的方案評估。具體的操作方式為球涛,列出我們需要關(guān)注的屬性點劣针,然后分別從這些屬性的圍堵去評估每個方案,再綜合挑選適合當(dāng)時情況的最優(yōu)方案亿扁。
常見的方案屬性點有:性能捺典、可用性、硬件成本魏烫、項目投入辣苏、復(fù)雜度、安全性哄褒、可擴(kuò)展性稀蟋、用戶體驗等。在評估這些屬性點時呐赡,需要遵循架構(gòu)設(shè)計原則退客,合適原則、簡單原則、演進(jìn)原則萌狂,避免貪大求全档玻,基本上某個屬性能夠滿足一定時期內(nèi)業(yè)務(wù)發(fā)展就可以了。
假如做一個購物網(wǎng)站茫藏,現(xiàn)在的TPS是1000误趴,如果我們預(yù)期一年內(nèi)能夠發(fā)展到TPS2000,在評估方案性能時务傲,只要能超過2000的都是合適方案凉当,而不是說淘寶網(wǎng)站TPS是每秒10w,我們的購物網(wǎng)站也要按照淘寶的標(biāo)準(zhǔn)來設(shè)計售葡。
有的架構(gòu)師會說看杭,如果我們業(yè)務(wù)發(fā)展迅速,業(yè)務(wù)一年翻了10倍挟伙,TPS從1000到1w楼雹,那豈不是到時候要重新做方案。
這種情況存在尖阔,但是發(fā)生的概率太小贮缅,如果每次都考慮這些小概率事件,那么會導(dǎo)致方案過度設(shè)計诺祸,投入浪費携悯。考慮這個問題的時候遵循演進(jìn)原則避免過度設(shè)計筷笨、一步到位的想法憔鬼。這樣設(shè)計出的架構(gòu),就算真的出現(xiàn)極端情況胃夏,業(yè)務(wù)飛速發(fā)展轴或,那就算重新做方案和系統(tǒng)重構(gòu),代價也是可以接受的仰禀,那時候業(yè)務(wù)快速發(fā)展照雁,錢已經(jīng)不是問題,公司會不惜一切成本投入資源做重構(gòu)答恶。
可以參考這個表格進(jìn)行對設(shè)計出的備選方案進(jìn)行環(huán)評:
架構(gòu)屬性 | 方案1 | 方案2 | 方案3 |
---|---|---|---|
性能 | |||
復(fù)雜度 | |||
硬件成本 | |||
可運(yùn)維性 | |||
可靠性 | |||
人力投入 | |||
用戶體驗 |
詳細(xì)方案設(shè)計
選擇好了方案后就到了最后的詳細(xì)方案設(shè)計階段饺蚊,有了前面的鋪墊這個階段就最簡單了。本篇中主要講述的是技術(shù)架構(gòu)設(shè)計部分悬嗓,在一個技術(shù)方案中還有很大的篇幅是業(yè)務(wù)架構(gòu)污呼,業(yè)務(wù)架構(gòu)的設(shè)計比技術(shù)架構(gòu)要簡單,業(yè)務(wù)架構(gòu)的設(shè)計更多的還是依賴架構(gòu)師對業(yè)務(wù)的熟悉和對周邊系統(tǒng)的了解包竹。業(yè)務(wù)架構(gòu)上的變化不會那么大燕酷,并且學(xué)習(xí)門檻比較低籍凝,技術(shù)架構(gòu)的學(xué)習(xí)需要依賴長期的學(xué)習(xí)和不斷的實踐才能提升。
詳細(xì)方案設(shè)計基本就是按照公司的模版將前面選出的備選方案按照方案模版對號入座做一定的詳細(xì)描述就可以了苗缩。
總結(jié)
本篇文章主要介紹了架構(gòu)設(shè)計中架構(gòu)師需要關(guān)注高性能饵蒂、高可用、可擴(kuò)展這幾個關(guān)注點酱讶,對于每個關(guān)注點需要注意的內(nèi)容都做了介紹退盯,也講述了架構(gòu)設(shè)計的流程,識別復(fù)雜度浴麻、設(shè)計備選方案得问、評估方案到最后的詳細(xì)方案設(shè)計。本篇更多的還是介紹架構(gòu)設(shè)計流程的方法論软免,更多的還是要在實際項目中不斷積累經(jīng)驗,不斷使用該套流程去驗證這套架構(gòu)設(shè)計流程方法論焚挠。