所謂“當局者迷,旁觀者清”摩渺,當我迷惑于當前知識的時候儿倒,證明我正平行于或低于該知識平面高度去學習這些知識,結果只有一個——“混亂”果覆。因為自身沒有一個高層次的“綱”讓自己清晰且邏輯地“收編”和“匯總”這些知識木西,也許“知識焦慮”就這么來的。在管理層面上随静,面對矩陣型組織架構上X軸(項目經(jīng)理)與Y軸(職能經(jīng)理)平面上的矛盾八千,我會通過高層次的“目標共性”來一致性項目經(jīng)理和職能經(jīng)理的共同目標吗讶,讓“矛盾”轉(zhuǎn)化“合作”,但面對“知識學習”的時候恋捆,我卻忽略知識的“結構性”問題照皆。所以每當自己“情緒”萌生之前,我會立刻讓自己冷靜片刻沸停,盡量讓自己理性地分析對象的抽象所在膜毁。例如面對“微服務”一大堆知識焦慮的時候,我知道自身缺乏了對“微服務知識”管理和匯總的“綱”愤钾,而我目前思考得出的這個綱就是對“分布式”的一個系統(tǒng)性認知瘟滨。
為什么要“分”?
分布式的重點在于“分”能颁,而“分”就是人類普遍的正常性思維杂瘸。當我們面對一個復雜或者龐大的問題是,我們習慣性地會把它分而治之伙菊。這種“分”的技巧貫穿于我們的日常之中败玉,如“大事化小,小事化無”镜硕。如下圖所示:
“分”之前首先要做的是“識別問題”运翼,這個問題的復雜度到底需不需要分解,就算分到底需要分解到什么程度兴枯,就像我們架構一個應用系統(tǒng)的時候血淌,我們會依據(jù)各種邊界條件去考慮要不要把系統(tǒng)分解,如何分解等财剖。根據(jù)各種經(jīng)驗匯總六剥,分布式系統(tǒng)主要有兩方面的原因:
增大系統(tǒng)容量(業(yè)務復雜度);
加強系統(tǒng)可用(用戶量增長)峰伙;
“分” 和“不分”有什么不同疗疟?
活到現(xiàn)在,我覺得這個世界上最有“哲理”的一個詞叫“權衡(trade-off)”瞳氓。任何事情總有兩面策彤,從道教學角度看,這叫“取舍之道”匣摘,從經(jīng)濟學角度看店诗,這叫“機會成本”。不同選擇肯定會帶來不同的成本音榜,首先我們得會識別問題庞瘸,然后從結果成本反推方案選擇。例如面對“分”和“不分”時赠叼,我們先來看看這兩種方案的優(yōu)和劣:
以上分析都是一些“通用維度”擦囊,不同問題和場景可能還會有其他的對比維度违霞。但我覺得僅僅從文字分析可能還不夠直觀,如果我嘗試把“分”和“不分”的問題從“二維”換成“三維”可能會更加直觀和深入瞬场。
從“二維角度”只看到系統(tǒng)的“平分”买鸽,真正的分布式是存在“橫向”和“豎向”分離的事實,從以上“立體維度”可以讓我們更加清晰地認識到分布式相對單體的復雜并在未來的實踐中所需要面臨的各種各樣的問題需要去權衡贯被。
分布式系統(tǒng)的發(fā)展歷史
分布式系統(tǒng)是基于SOA(面向服務架構)方法的一種架構方式眼五,從20世紀70年代流行模塊化編程。80年代流行面向事件設計彤灶,90年代開始流行基于接口/構件設計(SOA方法的起始)看幼。回顧歷史有助于我們?nèi)忠曇暗臉嫿ɑ仙拢酉聛砜纯捶植际较到y(tǒng)的三種不同的SAO架構模式:
Pre-SOA(1990s):20世紀90年代的時候诵姜,各個服務模塊之間是直接相互調(diào)用的,從而造成了服務與服務之間的緊耦合問題苞轿;
Traditional SOA:21世紀初期為了解決服務緊耦合的問題,各大IT廠商視圖通過“中間件”把服務之間的關聯(lián)解耦(負責路由逗物、負載搬卒、協(xié)議轉(zhuǎn)換等),如ESB翎卓,但這個中間件會顯得過于臃腫和集中契邀。
Microservice:從2010年開始,為了讓架構更加輕量失暴,出現(xiàn)了微服務架構坯门,把系統(tǒng)根據(jù)業(yè)務領域分解成各個獨立的服務,并且數(shù)據(jù)庫服務等垂直組件跟著分散到不同的服務當中逗扒,做到真正的服務獨自運行古戴。從上圖可以看到,跟傳統(tǒng)SOA的不同在于服務之間的整合需要一個服務編排或服務整合“組件引擎”來組織業(yè)務矩肩。
分布式系統(tǒng)的問題總結
從分布式架構的發(fā)展歷程可以看到现恼,系統(tǒng)架構會隨著時間和發(fā)展不斷涌現(xiàn)出新的問題,從而去觸發(fā)系統(tǒng)架構模式的演變黍檩。經(jīng)過了這么多年下來的經(jīng)驗和實踐積累叉袍,前輩們大概總結出了分布式系統(tǒng)在技術上大概需要注意的問題有四大類:
① 異構系統(tǒng)不標準問題:不同系統(tǒng)之間的架構不統(tǒng)一,協(xié)議不統(tǒng)一刽酱,語言不統(tǒng)一等問題喳逛;
② 系統(tǒng)服務依賴性問題:服務調(diào)用鏈過長,多米諾骨牌效應棵里,關鍵服務的識別等問題润文;
③ 系統(tǒng)故障的概率問題:隨著資源的增加姐呐,如何確保故障時長以及故障影響面積問題;
④ 多層架構的運維問題:如何確弊Γ基礎層(LaaS)皮钠、平臺層(PaaS)、應用層(SaaS)以及接入層的問題統(tǒng)一運維問題赠法;
分布式系統(tǒng)的關鍵技術
所謂“問題觸發(fā)需求”麦轰,如果站在以上“問題”的角度出發(fā),可能更能讓自己從高維度了解砖织、分析和把握我們所面對的各種各樣的開源技術和工具(如K8S款侵,Docker、Spring Cloud等)侧纯,而不至于產(chǎn)生無從下手的“焦慮”新锈。很多時候,我們往往會被“分”出來的問題所面對的技術細節(jié)給迷惑了眶熬,而忽略了“分”之前的整體認知妹笆。缺少了對問題整體性的認知,我們是無法體會到基礎性知識的魅力和存在價值娜氏。面對以上4大類分布式系統(tǒng)問題拳缠,前輩們同樣總結出了以下4大塊分布式系統(tǒng)的關鍵技術點:
① 應用整體監(jiān)控:包括基礎層監(jiān)控、平臺(中間件)層監(jiān)控贸弥、應用層監(jiān)控(包括客戶端)窟坐;
② 資源/服務調(diào)度:包括計算資源調(diào)度、服務調(diào)度绵疲、架構調(diào)度哲鸳;
③ 狀態(tài)/數(shù)據(jù)調(diào)度:包括數(shù)據(jù)可用性、數(shù)據(jù)一致性盔憨、數(shù)據(jù)分布式徙菠;
④ 流量調(diào)度:包括服務治理、流量管控郁岩、流量管理懒豹;
作為技術人員,真心覺得自己非常容易陷入“釘子思維”驯用,主要是自身缺乏這個抽象與整體的視野高度而深陷于技術細節(jié)當中脸秽,不是說技術細節(jié)沒用,只不過連一個“主要解決什么問題”的總體性認知都沒有蝴乔,技術細節(jié)會更難以理解记餐,焦慮感油然而生。
關鍵技術一:應用整體監(jiān)控
以上提到了監(jiān)控的層面主要包括基礎層薇正、平臺層片酝、應用層的三個層面囚衔,對于一個分布式系統(tǒng)監(jiān)控工具來說,至少包含全棧監(jiān)控雕沿、(各層面)關聯(lián)分析练湿、實時告警與自動化運維以及系統(tǒng)性能分析等功能。一個完整的監(jiān)控系統(tǒng)大概如下:
監(jiān)控本身就是一件向“可控”看齊的事情审轮,但如果缺乏一定的總體性認知(例如技能分工型組織)肥哎,該運維小組可能會以監(jiān)控數(shù)據(jù)量多為考慮方向(指標),那可能會本末倒置地把原本做簡單的事情復雜化疾渣,畢竟監(jiān)控數(shù)量太多等于沒有數(shù)據(jù)一樣篡诽,不知從何入手,所以監(jiān)控還必須具備一定的大局視野榴捡。例如整個系統(tǒng)架構的分布地圖杈女,每個分布點(地圖)的關鍵程度以及每個業(yè)務流程的走向(服務調(diào)用鏈)等全局信息,才能聚合各種關鍵監(jiān)控指標吊圾,達到一個整體監(jiān)控的宏觀效果达椰。并且通過整個業(yè)務的拓撲關系快速定位異常和告警,進入更深層次的監(jiān)控明細層面去排除問題项乒。
■項目總結
作為一個從0到1到并持續(xù)做了八年(7*24小時運行)的應用系統(tǒng)啰劲,在運維層面感受最深的就是監(jiān)控數(shù)據(jù)量從單體應用(兩臺刀片機)到分布式(微服務)應用(數(shù)千萬客戶端、上千個應用節(jié)點板丽、數(shù)百個Redis實例呈枉,并對接N個外圍系統(tǒng)等)的指數(shù)增長趁尼,監(jiān)控數(shù)據(jù)種類和量的收集大得驚人埃碱。系統(tǒng)從2014年切換到微服務框架后,一致運行良好酥泞,當然砚殿,我覺得這一切的功勞歸功于我們剛開始堅持的“簡單化”與“標準化”原則。
在系統(tǒng)架構演變的初期芝囤,我們在系統(tǒng)架構的建設以及規(guī)范上我們下了很大的功夫似炎,始終保持著我們的兩大原則,各種標準化的代碼開發(fā)和日志輸出為我們后續(xù)的發(fā)展打下堅實的基礎悯姊。在2016年沒有成立專門的“運維組”之前羡藐,整個系統(tǒng)(后端)都是靠我們數(shù)個后臺同事開發(fā)并維護的,你沒有聽錯悯许,是數(shù)個仆嗦,而不是數(shù)十個。也因為這個原因先壕,讓我們避免了“監(jiān)控任務被隔離”以及“監(jiān)控數(shù)據(jù)量太多”的常見運維問題瘩扼。在我們當時數(shù)人開發(fā)兼維護的情況下谆甜,自動化維護和監(jiān)控是必不可少的手段。除了定時的關鍵和敏感指標監(jiān)控外集绰,我們會根據(jù)整個系統(tǒng)的“業(yè)務拓撲關系”做一個“關聯(lián)指標聚合”的展示頁规辱,可以從整體了解系統(tǒng)的整體概況。關鍵的聚合指標包括關鍵服務并發(fā)量栽燕、關鍵服務容器線程數(shù)罕袋、關鍵服務API耗時分布、關鍵Redis服務性能分布關鍵數(shù)據(jù)源性能分布纫谅、關鍵外圍系統(tǒng)耗時分布炫贤、關鍵業(yè)務錯誤率概況以及各種TOP10的質(zhì)量監(jiān)控等。下圖是我們運維系統(tǒng)初期的監(jiān)視一角(沒有太華麗的UI)付秕。
關鍵技術二:資源/服務調(diào)度
當單體應用被拆分后兰珍,業(yè)務場景的完成必須依賴于后端各個服務之間的調(diào)度和關聯(lián)來完成的。當然询吴,最理想的狀態(tài)就是服務之間沒有關聯(lián)(最低復雜度)掠河,直接可以滿足于業(yè)務應用的消費。這不是不可能猛计,如果系統(tǒng)和業(yè)務不復雜的話唠摹,可以把服務編排的工作直接交給客戶端去做。我們系統(tǒng)的部分功能就選擇了這樣一種折中的方案奉瘤,這樣會增加了HTTP連接性能消耗勾拉,但降低了整個系統(tǒng)服務之間調(diào)度的復雜度。
雖然我們可以通過各種方式去規(guī)避問題盗温,但作為分布式系統(tǒng)的調(diào)度問題藕赞,服務治理是不可避免的一個關鍵性問題,其主要的關鍵技術有以下幾點:
服務關鍵程度
從以上監(jiān)控層面可以看到卖局,我們會區(qū)分關鍵服務和非關鍵服務斧蜕,這種區(qū)分并非技術問題,而是業(yè)務問題砚偶。對服務關鍵程度的劃分可以讓系統(tǒng)在整體層面增加一個“層次感”批销,讓系統(tǒng)策略可以做得更加精準,如非關鍵服務降級等問題染坯。
服務依賴關系
要做到無服務依賴確實非常困難均芽,但卻是分布式系統(tǒng)設計的一個重點方向,所謂“沒有依賴就沒有傷害”单鹿。傳統(tǒng)的SOA是通過ESB來解決服務間依賴的問題掀宋,而微服務就是分布式系統(tǒng)服務依賴的最優(yōu)解上限,而服務依賴的下限就是千萬不好有閉環(huán)依賴,出現(xiàn)依賴環(huán)的設計是有問題的設計布朦。在服務依賴管理方面囤萤,我們系統(tǒng)對服務關聯(lián)做了一定的管理措施,例如是趴,我們服務的開發(fā)是分工的涛舍,如果服務A調(diào)用了服務B,而服務B具體又調(diào)用了什么服務唆途,服務A的開發(fā)小組是不得而知的富雅,所以我們在開發(fā)階段做系統(tǒng)服務依賴配置的時候(必須配置,因為我們服務之間調(diào)用強制驗證肛搬,這就是我們付出一定性能開銷的管理成本)没佑,各個小組都可以實時看到整個系統(tǒng)服務的調(diào)用依賴圖橄抹,當配置服務依賴的時候系統(tǒng)實時檢查這條服務調(diào)用鏈的深度笛洛,并達到一定的閥值是提出告警或禁止配置,當出現(xiàn)這樣的問題后可以提交給上層設計團隊去評估設計合理性饵骨。雖然我們整個系統(tǒng)都是基于微服務理念設計陶贼,但開發(fā)團隊大了啤贩,什么鳥都會有,這些額外的技術管理成本有時候也是無可奈何拜秧。
服務發(fā)現(xiàn)
有了以上的的“地圖”第一步痹屹,接下來需要對這整個系統(tǒng)地圖的服務狀態(tài)和生命周期管理的重要工具,畢竟系統(tǒng)是由各種服務組成的枉氮,分布式之所以靈活是因為其服務的動態(tài)性志衍,在系統(tǒng)運行過程中,有的服務會增加聊替,有的服務會離開楼肪,有的服務生效中,有的服務失效了等等佃牛。從管理角度淹辞,我們需要知道一個服務注冊中心來做以下幾個事:
在我們的生產(chǎn)系統(tǒng)中医舆,服務的種類俘侠、數(shù)量數(shù)量以及狀態(tài)信息是具備的,但我們并沒有對服務進行版本管理蔬将,只對服務的API進行版本管理爷速,并對服務API兼容性做了強制性的“規(guī)范”要求(只能增加輸出,不能修改或刪除輸出)霞怀。
架構版本管理
因為系統(tǒng)被拆分成各種服務單元惫东,而不同的服務單元有一定概率是不同團隊開發(fā),所以會存在服務單元版本依賴問題,超大型系統(tǒng)甚至會存在操作系統(tǒng)層面以及中間件層面不同版本的管理問題廉沮。如果使用過maven項目模型管理工具的話颓遏,就會知道pom.xml文件,它管理著各個模塊以及版本之間的關系滞时,項目的建立也是基于pom.xml之上叁幢,我們的服務同樣可以通過這種模式進行管理,但成本就會增加坪稽。目前在我們的生產(chǎn)系統(tǒng)中曼玩,并沒有這種版本管理,我們是通過規(guī)范性手段避免了這種版本管理的問題窒百,目前來說黍判,暫時沒有出現(xiàn)這種服務版本依賴性而導致回退沖突等問題。
服務生命周期管理
當我們有了服務發(fā)現(xiàn)中心這個管控工具之后篙梢,就需要對服務的狀態(tài)進行管理了顷帖,嚴格來說,服務的狀態(tài)會有一下幾種:
① Provison:代表在供應一個新的服務渤滞;
② Ready:表示啟動成功了窟她;
③ Run:表示通過了服務健康檢查;
④ Update:表示在升級中蔼水;
⑤ Rollback:表示在回滾中震糖;
⑥ Scale:表示正在伸縮中(其中包括Scale-in和Scale-out)
⑦ Destroy:表示在銷毀中
⑧ Failed:表示失敗狀態(tài)
如果需要控制好整個分布式系統(tǒng)架構,就需要對以上服務狀態(tài)進行嚴格管理趴腋,特別是在多協(xié)作團隊中吊说,這寫狀態(tài)的把控十分重要,因為服務會出現(xiàn)各種不預期(故障)和預期(上線或更新)的變化∮啪妫現(xiàn)在整個完整的地圖颁井、服務之間的依賴關系以及服務的狀態(tài)管控,整個完整分布式系統(tǒng)的管理手段會讓整個系統(tǒng)清晰起來蠢护。在我們生產(chǎn)系統(tǒng)中雅宾,對于服務的狀態(tài)并沒有這么嚴格,目前只用到“運行”葵硕、“未知”以及“異趁继В”三種狀態(tài),部分其它狀態(tài)懈凹,我們統(tǒng)一用“未知狀態(tài)”代替了蜀变。
關鍵技術三:狀態(tài)/數(shù)據(jù)調(diào)度
對于單體應用來說,并沒有太多的“可能性”介评,復雜度和維護成本自然而然不會太高库北,所以不會存在系統(tǒng)拆分后的種種新問題爬舰。因為服務拆分了,并且業(yè)務場景需要各種服務之間通過調(diào)度協(xié)助來完成的寒瓦,所以各個“點”之間的狀態(tài)就格外重要了情屹。這里的狀態(tài)(state)指的是服務自身的數(shù)據(jù)狀態(tài),而不是運行狀態(tài)(status)杂腰。一般來說屁商,我們都會通過第三方服務維護系統(tǒng)服務的數(shù)據(jù)狀態(tài),如Mysql颈墅、Redis蜡镶、ZooKeep或NFS等文件系統(tǒng),從而讓服務變成“無狀態(tài)服務”恤筛,以便于服務的靈活變更和擴展官还,甚至可以往serverless模式發(fā)展。所以很多時候毒坛,分布式系統(tǒng)架構中出現(xiàn)的問題往往都是這些存儲狀態(tài)的服務望伦,并且數(shù)據(jù)存儲節(jié)點的Scale問題也落在了這些存儲狀態(tài)服務當中。
要解決像數(shù)據(jù)存儲點這樣的單點問題煎殷,就要解決數(shù)據(jù)的復制(Replication)問題屯伞,也就是讓數(shù)據(jù)服務可以像無狀態(tài)的服務一樣在不同的設備上進行調(diào)度,而數(shù)據(jù)的復制問題又會帶來數(shù)據(jù)一致性的2問題豪直,從而帶來更多的性能問題劣摇。對于解決數(shù)據(jù)副本間的一致性問題,目前比較常見的方案是有:Master-Slave方案弓乙、Master-Master方案末融、兩階段和三階段提交方案、Paxos方案暇韧,而各種方案的優(yōu)缺點可見下圖:
在我們生產(chǎn)系統(tǒng)中勾习,核心的業(yè)務我們主要還是用到了商業(yè)的Master-Master方案(Oracle共享存儲),在非關系數(shù)據(jù)庫方面(Redis)我們幾乎都是自主研發(fā)的2PC方案組件懈玻。我們使用Redis的時候巧婶,最新版的穩(wěn)定版本好像只有2.8,并不存在目前3.0+的集群方案涂乌,所以我們自己在應用服務層寫了許多不同場景的2PC方案艺栈,為什么會很多,因為不同場景的業(yè)務不一致導致業(yè)務補償?shù)姆桨赣泻艽蟮牟煌钐龋S多的場景目前還一直穩(wěn)定運行著眼滤。當然巴席,從分工來看历涝,狀態(tài)數(shù)據(jù)調(diào)度應該由分布式存儲層(Laas)來解決,這樣對于應用層來說是透明的,就像使用單點存儲一樣簡單荧库。
關鍵技術四:流量調(diào)度
無論對單體應用還是分布式應用堰塌,流量都是需要控制的,對于單體應用而言分衫,更多只是簡單外部流量控制措施场刑,但當系統(tǒng)分解后,因為服務調(diào)度的存在蚪战,所以流程同樣需要調(diào)度牵现。
分布式系統(tǒng)可以把流量調(diào)度分為內(nèi)部調(diào)度和外部調(diào)度,內(nèi)部是因為服務編排(調(diào)用鏈)的存在邀桑,外部是因為業(yè)務被分解隔離的緣故瞎疼。對于一個流量調(diào)度器來說,其主要功能有兩點:
① 可以根據(jù)系統(tǒng)的運行情況自動地去調(diào)整流量調(diào)度壁畸,自動化地完成整個系統(tǒng)的穩(wěn)定性贼急;
② 可以彈性地計算并解決系統(tǒng)各種突發(fā)性事件,確保系統(tǒng)始終保持平穩(wěn)運行捏萍;
說白了太抓,以上功能都是為了確保系統(tǒng)的高可用和穩(wěn)定性。其實令杈,流量組件可以完成的事情可以包含如下:
服務流量:服務發(fā)現(xiàn)走敌、服務路由、服務降級逗噩、服務熔斷悔常、服務保護等;
流量控制:負載均衡给赞、流量分配机打、流量控制、異地災備(多活)等片迅;
流量管理:協(xié)議轉(zhuǎn)換残邀、請求校驗、數(shù)據(jù)緩存柑蛇、數(shù)據(jù)計算等芥挣;
如果從這些功能角度去看,這個網(wǎng)關(API Gateway)其實就跟運維系統(tǒng)一樣耻台,是一個實實在在的流量調(diào)度系統(tǒng)空免。從功能種類來說,這個API網(wǎng)關會略顯臃腫盆耽,很容易會成為“瓶頸”蹋砚。所以扼菠,作為一個能扛得住的流量的API網(wǎng)關,“高性能實現(xiàn)”坝咐、“抗大流量”循榆、“簡單的業(yè)務邏輯”以及還有“服務化設計”等幾大關鍵技術點必須得認真思考和衡量。
我們生產(chǎn)系統(tǒng)中墨坚,流量調(diào)度我們分開了三個層面來管理秧饮,總API網(wǎng)關入口,各服務網(wǎng)關入口泽篮,以及服務入口盗尸,因為我們當初考慮到網(wǎng)關作為入口的重要性,我們把以上API網(wǎng)關的部分功能(如緩存帽撑、熔斷)下放到了服務實現(xiàn)層面去實現(xiàn)了振劳。由于業(yè)務原因,我們系統(tǒng)并沒有做得很“自動化”油狂,全部靠監(jiān)控告警以及人工熔斷操作历恐。因為客戶組織復雜的組織架構原因,我們當初各種自動化容災以及降級方案都“政治性地”否定了专筷,只能把方案實現(xiàn)預留Admin API弱贼,隨時通過總控制臺人工干預。
最后的總結
越學習越發(fā)現(xiàn)磷蛹,有時候努力很重要吮旅,但方法更重要。大量的零碎知識等于沒有知識味咳,知識焦慮是必然結果庇勃。知識之間是相關聯(lián)的,有時候一篇數(shù)千字的技術文章槽驶,我會看上個把月责嚷。因為自身基礎不扎實的原因,缺乏一定的知識高度去消化掂铐,所以許多知識點我都必須深入學習才能略懂一二罕拂。今天數(shù)千字的學習總結,背后承載的學習資料可能數(shù)十萬文字的學習和研究全陨,還有大量地反思和實踐總結爆班。有時候明明知道,但又無動于衷辱姨,這顯然就是自我突破的關鍵點所在柿菩。