由于這系列文章實在是太長侈询,所以很抱歉發(fā)錯了順序,這應該是第二篇糯耍,不過單獨來看也是可以成文的扔字。
目錄服務(ZooKeeper)
分布式系統(tǒng)是一個由很多進程組成的整體,這個整體中每個成員部分温技,都會具備一些狀態(tài),比如自己的負責模塊舵鳞,自己的負載情況震檩,對某些數(shù)據(jù)的掌握等等抛虏。而這些和其他進程相關的數(shù)據(jù),在故障恢復迂猴、擴容縮容的時候變得非常重要。
簡單的分布式系統(tǒng)沸毁,可以通過靜態(tài)的配置文件,來記錄這些數(shù)據(jù):進程之間的連接對應關系息尺,他們的IP地址和端口,等等搂誉。然而一個自動化程度高的分布式系統(tǒng),必然要求這些狀態(tài)數(shù)據(jù)都是動態(tài)保存的勒葱。這樣才能讓程序自己去做容災和負載均衡的工作。
一些程序員會專門自己編寫一個DIR服務(目錄服務)凛虽,來記錄集群中進程的運行狀態(tài)。集群中進程會和這個DIR服務產(chǎn)生自動關聯(lián)凯旋,這樣在容災、擴容至非、負載均衡的時候钠署,就可以自動根據(jù)這些DIR服務里的數(shù)據(jù),來調整請求的發(fā)送目地荒椭,從而達到繞開故障機器谐鼎、或連接到新的服務器的操作。
然而趣惠,如果我們只是用一個進程來充當這個工作狸棍。那么這個進程就成為了這個集群的“單點”——意思就是,如果這個進程故障了味悄,那么整個集群可能都無法運行的草戈。所以存放集群狀態(tài)的目錄服務,也需要是分布式的侍瑟。幸好我們有ZooKeeper這個優(yōu)秀的開源軟件唐片,它正是一個分布式的目錄服務區(qū)。
ZooKeeper可以簡單啟動奇數(shù)個進程,來形成一個小的目錄服務集群费韭。這個集群會提供給所有其他進程茧球,進行讀寫其巨大的“配置樹”的能力。這些數(shù)據(jù)不僅僅會存放在一個ZooKeeper進程中揽思,而是會根據(jù)一套非常安全的算法袜腥,讓多個進程來承載见擦。這讓ZooKeeper成為一個優(yōu)秀的分布式數(shù)據(jù)保存系統(tǒng)钉汗。
由于ZooKeeper的數(shù)據(jù)存儲結構,是一個類似文件目錄的樹狀系統(tǒng)鲤屡,所以我們常常會利用它的功能损痰,把每個進程都綁定到其中一個“分枝”上,然后通過檢查這些“分支”酒来,來進行服務器請求的轉發(fā)卢未,就能簡單的解決請求路由(由誰去做)的問題。另外還可以在這些“分支”上標記進程的負載的狀態(tài)堰汉,這樣負載均衡也很容易做了辽社。
目錄服務是分布式系統(tǒng)中最關鍵的組件之一。而ZooKeeper是一個很好的開源軟件翘鸭,正好是用來完成這個任務滴铅。
消息隊列服務(ActiveMQ汉匙、ZeroMQ噩翠、Jgroups)
兩個進程間如果要跨機器通訊邦投,我們幾乎都會用TCP/UDP這些協(xié)議。但是直接使用網(wǎng)絡API去編寫跨進程通訊屯援,是一件非常麻煩的事情蠢涝。除了要編寫大量的底層socket代碼外和二,我們還要處理諸如:如何找到要交互數(shù)據(jù)的進程,如何保障數(shù)據(jù)包的完整性不至于丟失惕它,如果通訊的對方進程掛掉了淹魄,或者進程需要重啟應該怎樣等等這一系列問題。這些問題包含了容災擴容兆蕉、負載均衡等一系列的需求缤沦。
為了解決分布式系統(tǒng)進程間通訊的問題缸废,人們總結出了一個有效的模型,就是“消息隊列”模型测萎。消息隊列模型届巩,就是把進程間的交互姆泻,抽象成對一個個消息的處理,而對于這些消息四苇,我們都有一些“隊列”方咆,也就是管道,來對消息進行暫存榆骚。每個進程都可以訪問一個或者多個隊列妓肢,從里面讀取消息(消費)或寫入消息(生產(chǎn))苫纤。由于有一個緩存的管道,我們可以放心的對進程狀態(tài)進行變化喊废。當進程起來的時候,它會自動去消費消息就可以了工闺。而消息本身的路由陆蟆,也是由存放的隊列決定的,這樣就把復雜的路由問題遍搞,變成了如何管理靜態(tài)的隊列的問題器腋。
一般的消息隊列服務纫塌,都是提供簡單的“投遞”和“收取”兩個接口措左,但是消息隊列本身的管理方式卻比較復雜避除,一般來說有兩種。一部分的消息隊列服務凉逛,提倡點對點的隊列管理方式:每對通信節(jié)點之間状飞,都有一個單獨的消息隊列书斜。這種做法的好處是不同來源的消息,可以互不影響焙糟,不會因為某個隊列的消息過多穿撮,擠占了其他隊列的消息緩存空間。而且處理消息的程序也可以自己來定義處理的優(yōu)先級——先收取枪向、多處理某個隊列咧党,而少處理另外一些隊列。
但是這種點對點的消息隊列深员,會隨著集群的增長而增加大量的隊列倦畅,這對于內存占用和運維管理都是一個復雜的事情绣的。因此更高級的消息隊列服務,開始可以讓不同的隊列共享內存空間芭概,而消息隊列的地址信息惩嘉、建立和刪除文黎,都采用自動化的手段∽兀——這些自動化往往需要依賴上文所述的“目錄服務”抓艳,來登記隊列的ID對應的物理IP和端口等信息玷或。比如很多開發(fā)者使用ZooKeeper來充當消息隊列服務的中央節(jié)點;而類似Jgropus這類軟件蔬胯,則自己維護一個集群狀態(tài)來存放各節(jié)點今昔氛濒。
另外一種消息隊列,則類似一個公共的郵箱京景。一個消息隊列服務就是一個進程骗奖,任何使用者都可以投遞或收取這個進程中的消息执桌。這樣對于消息隊列的使用更簡便,運維管理也比較方便伴逸。不過這種用法下错蝴,任何一個消息從發(fā)出到處理香椎,最少進過兩次進程間通信畜伐,其延遲是相對比較高的躺率。并且由于沒有預定的投遞悼吱、收取約束,所以也比較容易出BUG笨枯。
不管使用那種消息隊列服務馅精,在一個分布式服務器端系統(tǒng)中粱檀,進程間通訊都是必須要解決的問題茄蚯,所以作為服務器端程序員睦优,在編寫分布式系統(tǒng)代碼的時候汗盘,使用的最多的就是基于消息隊列驅動的代碼衡未,這也直接導致了EJB3.0把“消息驅動的Bean”加入到規(guī)范之中家凯。
事務系統(tǒng)
在分布式的系統(tǒng)中绊诲,事務是最難解決的技術問題之一。由于一個處理可能分布在不同的處理進程上抗俄,任何一個進程都可能出現(xiàn)故障动雹,而這個故障問題則需要導致一次回滾跟压。這種回滾大部分又涉及多個其他的進程震蒋。這是一個擴散性的多進程通訊問題。要在分布式系統(tǒng)上解決事務問題钾虐,必須具備兩個核心工具:一個是穩(wěn)定的狀態(tài)存儲系統(tǒng)笋庄;另外一個是方便可靠的廣播系統(tǒng)直砂。
事務中任何一步的狀態(tài)哆键,都必須在整個集群中可見,并且還要有容災的能力闪盔。這個需求,一般還是由集群的“目錄服務”來承擔听绳。如果我們的目錄服務足夠健壯椅挣,那么我們可以把每步事務的處理狀態(tài)塔拳,都同步寫到目錄服務上去。ZooKeeper再次在這個地方能發(fā)揮重要的作用量九。
如果事務發(fā)生了中斷荠列,需要回滾载城,那么這個過程會涉及到多個已經(jīng)執(zhí)行過的步驟诉瓦。也許這個回滾只需要在入口處回滾即可(加入那里有保存回滾所需的數(shù)據(jù)),也可能需要在各個處理節(jié)點上回滾呼寸。如果是后者,那么就需要集群中出現(xiàn)異常的節(jié)點河狐,向其他所有相關的節(jié)點廣播一個“回滾馋艺!事務ID是XXXX”這樣的消息。這個廣播的底層一般會由消息隊列服務來承載碱鳞,而類似Jgroups這樣的軟件窿给,直接提供了廣播服務。
雖然現(xiàn)在我們在討論事務系統(tǒng)禁荒,但實際上分布式系統(tǒng)經(jīng)常所需的“分布式鎖”功能角撞,也是這個系統(tǒng)可以同時完成的谒所。所謂的“分布式鎖”,也就是一種能讓各個節(jié)點先檢查后執(zhí)行的限制條件姐军。如果我們有高效而單子操作的目錄服務剖踊,那么這個鎖狀態(tài)實際上就是一種“單步事務”的狀態(tài)記錄德澈,而回滾操作則默認是“暫停操作,稍后再試”缴守。這種“鎖”的方式屡穗,比事務的處理更簡單忽肛,因此可靠性更高,所以現(xiàn)在越來越多的開發(fā)人員础废,愿意使用這種“鎖”服務评腺,而不是去實現(xiàn)一個“事務系統(tǒng)”淑掌。
自動部署工具(Docker)
由于分布式系統(tǒng)最大的需求,是在運行時(有可能需要中斷服務)來進行服務容量的變更:擴容或者縮容媒殉。而在分布式系統(tǒng)中某些節(jié)點故障的時候侥钳,也需要新的節(jié)點來恢復工作。這些如果還是像老式的服務器管理方式苦酱,通過填表疫萤、申報敢伸、進機房池颈、裝服務器、部署軟件……這一套做法每币,那效率肯定是不行琢歇。
在分布式系統(tǒng)的環(huán)境下李茫,我們一般都是采用“池”的方式來管理服務。我們預先會申請一批機器秸侣,然后在某些機器上運行服務軟件塔次,另外一些則作為備份名秀。顯然我們這一批服務器不可能只為某一個業(yè)務服務匕得,而是會提供多個不同的業(yè)務承載汁掠。那些備份的服務器,則會成為多個業(yè)務的通用備份“池”翠忠。隨著業(yè)務需求的變化秽之,一些服務器可能“退出”A服務而“加入”B服務考榨。
這種頻繁的服務變化鹦倚,依賴高度自動的軟件部署工具震叙。我們的運維人員,應該掌握這開發(fā)人員提供的部署工具乐尊,而不是厚厚的手冊匣砖,來進行這類運維操作猴鲫。一些比較有經(jīng)驗的開發(fā)團隊,會統(tǒng)一所有的業(yè)務底層框架牺弄,以期大部分的部署宜狐、配置工具抚恒,都能用一套通用的系統(tǒng)來進行管理。而開源界回溺,也有類似的嘗試,最廣為人知的莫過于RPM安裝包格式萍恕,然而RPM的打包方式還是太復雜车要,不太符合服務器端程序的部署需求翼岁。所以后來又出現(xiàn)了Chef為代表的登澜,可編程的通用部署系統(tǒng)。
在虛擬機技術出現(xiàn)之后购撼,PaaS平臺為自動部署提供了強大的支持:如果我們是按某個PaaS平臺的規(guī)范來編寫的應用迂求,可以完全把程序丟給平臺去部署揩局,其承載量計算凌盯、部署規(guī)劃驰怎,都自動完成了县忌。這方面的佼佼者是Google的AppEngine:我們可以直接用Eclipse開發(fā)一個本地的Web應用继效,然后上傳到AppEngine里面瑞信,所有的部署就完成了!AppEngine會自動的根據(jù)對這個Web應用的訪問量走芋,來進行擴容翁逞、縮容溉仑、故障恢復浊竟。
然而振定,真正有革命性的工具,是Docker的出現(xiàn)梳庆。雖然虛擬機膏执、沙箱技術早就不是什么新技術更米,但是真正使用這些技術來作為部署工具的時間卻不長征峦。Linux高效的輕量級容器技術栏笆,提供了部署上巨大的便利性——我們可以在各種庫竖伯、各種協(xié)作軟件的環(huán)境下打包我們的應用程序因宇,然后隨意的部署在任何一個Linux系統(tǒng)上察滑。
為了管理大量的分布式服務器端進程户盯,我們確實需要花很多功夫,其優(yōu)化其部署管理的工作吗伤。統(tǒng)一服務器端進程的運行規(guī)范足淆,是實現(xiàn)自動化部署管理的基本條件。我們可以根據(jù)“操作系統(tǒng)”作為規(guī)范礁阁,采用Docker技術巧号;也可以根據(jù)“Web應用”作為規(guī)范,采用某些PaaS平臺技術姥闭;或者自己定義一些更具體的規(guī)范丹鸿,自己開發(fā)完整的分布式計算平臺。
日志服務(log4j)
服務器端的日志棚品,一直是一個既重要又容易被忽視的問題靠欢。很多團隊在剛開始的時候,僅僅把日志視為開發(fā)調試南片、排除BUG的輔助工具掺涛。但是很快會發(fā)現(xiàn)疼进,在服務運營起來之后,日志幾乎是服務器端系統(tǒng)减拭,在運行時可以用來了解程序情況的唯一有效手段。
盡管我們有各種profile工具可霎,但是這些工具大部分都不適合在正式運營的服務上開啟,因為會嚴重降低其運行性能绢记。所以我們更多的時候需要根據(jù)日志來分析。盡管日志從本質上护赊,就是一行行的文本信息抽高,但是由于其具有很大的靈活性,所以會很受開發(fā)和運維人員的重視。
日志本身從概念上莹桅,是一個很模糊的東西。你可以隨便打開一個文件,然后寫入一些信息。但是現(xiàn)代的服務器系統(tǒng)杭抠,一般都會對日志做一些標準化的需求規(guī)范:日志必須是一行一行的,這樣比較方便日后的統(tǒng)計分析忿墅;每行日志文本,都應該有一些統(tǒng)一的頭部棍弄,比如日期時間就是基本的需求颁虐;日志的輸出應該是分等級的儒陨,比如fatal/error/warning/info/debug/trace等等车海,程序可以在運行時調整輸出的等級喘沿,以便可以節(jié)省日志打印的消耗留量;日志的頭部一般還需要一些類似用戶ID或者IP地址之類的頭信息忆绰,用于快速查找定位過濾某一批日志記錄,或者有一些其他的用于過濾縮小日志查看范圍的字段,這叫做染色功能;日志文件還需要有“回滾”功能侈沪,也就是保持固定大小的多個文件歼秽,避免長期運行后呻惕,把硬盤寫滿。
由于有上述的各種需求柑营,所以開源界提供了很多游戲的日志組件庫,比如大名鼎鼎的log4j,以及成員眾多的log4X家族庫,這些都是應用廣泛而飽受好評的工具摆尝。
不過對比日志的打印功能,日志的搜集和統(tǒng)計功能卻往往比較容易被忽視视哑。作為分布式系統(tǒng)的程序員跪呈,肯定是希望能從一個集中節(jié)點误阻,能搜集統(tǒng)計到整個集群日志情況寻定。而有一些日志的統(tǒng)計結果唐含,甚至希望能在很短時間內反復獲取,用來監(jiān)控整個集群的健康情況桐腌。要做到這一點,就必須有一個分布式的文件系統(tǒng)遭殉,用來存放源源不斷到達的日志(這些日志往往通過UDP協(xié)議發(fā)送過來)蛔糯。而在這個文件系統(tǒng)上,則需要有一個類似Map Reduce架構的統(tǒng)計系統(tǒng),這樣才能對海量的日志信息翅溺,進行快速的統(tǒng)計以及報警。有一些開發(fā)者會直接使用Hadoop系統(tǒng),有一些則用Kafka來作為日志存儲系統(tǒng),上面再搭建自己的統(tǒng)計程序。
日志服務是分布式運維的儀表盤色洞、潛望鏡奈搜。如果沒有一個可靠的日志服務,整個系統(tǒng)的運行狀況可能會是失控的鞋真。所以無論你的分布式系統(tǒng)節(jié)點是多還是少,必須花費重要的精力和專門的開發(fā)時間闸昨,去建立一個對日志進行自動化統(tǒng)計分析的系統(tǒng)嵌牺。
本系列2:分布式本質論:維服務震缭、協(xié)程手趣、云
往期精彩內容回看: