承載量是分布式系統(tǒng)存在的原因
當(dāng)一個(gè)互聯(lián)網(wǎng)業(yè)務(wù)獲得大眾歡迎的時(shí)候,最顯著碰到的技術(shù)問(wèn)題化漆,就是服務(wù)器非常繁忙估脆。當(dāng)每天有1000萬(wàn)個(gè)用戶訪問(wèn)你的網(wǎng)站時(shí),無(wú)論你使用什么樣的服務(wù)器硬件座云,都不可能只用一臺(tái)機(jī)器就承載的了疙赠。因此付材,在互聯(lián)網(wǎng)程序員解決服務(wù)器端問(wèn)題的時(shí)候,必須要考慮如何使用多臺(tái)服務(wù)器圃阳,為同一種互聯(lián)網(wǎng)應(yīng)用提供服務(wù)厌衔,這就是所謂“分布式系統(tǒng)”的來(lái)源。
然而捍岳,大量用戶訪問(wèn)同一個(gè)互聯(lián)網(wǎng)業(yè)務(wù)富寿,所造成的問(wèn)題并不簡(jiǎn)單。從表面上看锣夹,要能滿足很多用戶來(lái)自互聯(lián)網(wǎng)的請(qǐng)求页徐,最基本的需求就是所謂性能需求:用戶反應(yīng)網(wǎng)頁(yè)打開(kāi)很慢,或者網(wǎng)游中的動(dòng)作很卡等等银萍。而這些對(duì)于“服務(wù)速度”的要求变勇,實(shí)際上包含的部分卻是以下幾個(gè):高吞吐、高并發(fā)贴唇、低延遲和負(fù)載均衡搀绣。
高吞吐,意味著你的系統(tǒng)戳气,可以同時(shí)承載大量的用戶使用链患。這里關(guān)注的整個(gè)系統(tǒng)能同時(shí)服務(wù)的用戶數(shù)。這個(gè)吞吐量肯定是不可能用單臺(tái)服務(wù)器解決的瓶您,因此需要多臺(tái)服務(wù)器協(xié)作麻捻,才能達(dá)到所需要的吞吐量。而在多臺(tái)服務(wù)器的協(xié)作中览闰,如何才能有效的利用這些服務(wù)器芯肤,不致于其中某一部分服務(wù)器成為瓶頸巷折,從而影響整個(gè)系統(tǒng)的處理能力压鉴,這就是一個(gè)分布式系統(tǒng),在架構(gòu)上需要仔細(xì)權(quán)衡的問(wèn)題锻拘。
高并發(fā)是高吞吐的一個(gè)延伸需求油吭。當(dāng)我們?cè)诔休d海量用戶的時(shí)候,我們當(dāng)然希望每個(gè)服務(wù)器都能盡其所能的工作署拟,而不要出現(xiàn)無(wú)謂的消耗和等待的情況婉宰。然而,軟件系統(tǒng)并不是簡(jiǎn)單的設(shè)計(jì)推穷,就能對(duì)同時(shí)處理多個(gè)任務(wù)心包,做到“盡量多”的處理。很多時(shí)候馒铃,我們的程序會(huì)因?yàn)橐x擇處理哪個(gè)任務(wù)蟹腾,而導(dǎo)致額外的消耗痕惋。這也是分布式系統(tǒng)解決的問(wèn)題。
低延遲對(duì)于人數(shù)稀少的服務(wù)來(lái)說(shuō)不算什么問(wèn)題娃殖。然而值戳,如果我們需要在大量用戶訪問(wèn)的時(shí)候,也能很快的返回計(jì)算結(jié)果炉爆,這就要困難的多堕虹。因?yàn)槌舜罅坑脩粼L問(wèn)可能造成請(qǐng)求在排隊(duì)外,還有可能因?yàn)榕抨?duì)的長(zhǎng)度太長(zhǎng)芬首,導(dǎo)致內(nèi)存耗盡赴捞、帶寬占滿等空間性的問(wèn)題。如果因?yàn)榕抨?duì)失敗而采取重試的策略郁稍,則整個(gè)延遲會(huì)變的更高螟炫。所以分布式系統(tǒng)會(huì)采用很多請(qǐng)求分揀和分發(fā)的做法,盡快的讓更多的服務(wù)器來(lái)出來(lái)用戶的請(qǐng)求艺晴。但是昼钻,由于一個(gè)數(shù)量龐大的分布式系統(tǒng),必然需要把用戶的請(qǐng)求經(jīng)過(guò)多次的分發(fā)封寞,整個(gè)延遲可能會(huì)因?yàn)檫@些分發(fā)和轉(zhuǎn)交的操作然评,變得更高,所以分布式系統(tǒng)除了分發(fā)請(qǐng)求外狈究,還要盡量想辦法減少分發(fā)的層次數(shù)碗淌,以便讓請(qǐng)求能盡快的得到處理。
由于互聯(lián)網(wǎng)業(yè)務(wù)的用戶來(lái)自全世界抖锥,因此在物理空間上可能來(lái)自各種不同延遲的網(wǎng)絡(luò)和線路亿眠,在時(shí)間上也可能來(lái)自不同的時(shí)區(qū),所以要有效的應(yīng)對(duì)這種用戶來(lái)源的復(fù)雜性磅废,就需要把多個(gè)服務(wù)器部署在不同的空間來(lái)提供服務(wù)纳像。同時(shí),我們也需要讓同時(shí)發(fā)生的請(qǐng)求拯勉,有效的讓多個(gè)不同服務(wù)器承載竟趾。所謂的負(fù)載均衡,就是分布式系統(tǒng)與生俱來(lái)需要完成的功課宫峦。
由于分布式系統(tǒng)岔帽,幾乎是解決互聯(lián)網(wǎng)業(yè)務(wù)承載量問(wèn)題,的最基本方法导绷,所以作為一個(gè)服務(wù)器端程序員犀勒,掌握分布式系統(tǒng)技術(shù)就變得異常重要了。然而,分布式系統(tǒng)的問(wèn)題贾费,并非是學(xué)會(huì)用幾個(gè)框架和使用幾個(gè)庫(kù)枚碗,就能輕易解決的,因?yàn)楫?dāng)一個(gè)程序在一個(gè)電腦上運(yùn)行铸本,變成了又無(wú)數(shù)個(gè)電腦上同時(shí)協(xié)同運(yùn)行肮雨,在開(kāi)發(fā)、運(yùn)維上都會(huì)帶來(lái)很大的差別箱玷。
分布式系統(tǒng)提高承載量的基本手段
分層模型(路由怨规、代理)
使用多態(tài)服務(wù)器來(lái)協(xié)同完成計(jì)算任務(wù),最簡(jiǎn)單的思路就是锡足,讓每個(gè)服務(wù)器都能完成全部的請(qǐng)求波丰,然后把請(qǐng)求隨機(jī)的發(fā)給任何一個(gè)服務(wù)器處理。最早期的互聯(lián)網(wǎng)應(yīng)用中舶得,DNS輪詢就是這樣的做法:當(dāng)用戶輸入一個(gè)域名試圖訪問(wèn)某個(gè)網(wǎng)站掰烟,這個(gè)域名會(huì)被解釋成多個(gè)IP地址中的一個(gè),隨后這個(gè)網(wǎng)站的訪問(wèn)請(qǐng)求沐批,就被發(fā)往對(duì)應(yīng)IP的服務(wù)器了纫骑,這樣多個(gè)服務(wù)器(多個(gè)IP地址)就能一起解決處理大量的用戶請(qǐng)求。
然而九孩,單純的請(qǐng)求隨機(jī)轉(zhuǎn)發(fā)先馆,并不能解決一切問(wèn)題。比如我們很多互聯(lián)網(wǎng)業(yè)務(wù)躺彬,都是需要用戶登錄的煤墙。在登錄某一個(gè)服務(wù)器后,用戶會(huì)發(fā)起多個(gè)請(qǐng)求宪拥,如果我們把這些請(qǐng)求隨機(jī)的轉(zhuǎn)發(fā)到不同的服務(wù)器上仿野,那么用戶登錄的狀態(tài)就會(huì)丟失,造成一些請(qǐng)求處理失敗她君。簡(jiǎn)單的依靠一層服務(wù)轉(zhuǎn)發(fā)是不夠的脚作,所以我們會(huì)增加一批服務(wù)器,這些服務(wù)器會(huì)根據(jù)用戶的Cookie犁河,或者用戶的登錄憑據(jù)鳖枕,來(lái)再次轉(zhuǎn)發(fā)給后面具體處理業(yè)務(wù)的服務(wù)器魄梯。
除了登錄的需求外桨螺,我們還發(fā)現(xiàn),很多數(shù)據(jù)是需要數(shù)據(jù)庫(kù)來(lái)處理的酿秸,而我們的這些數(shù)據(jù)往往都只能集中到一個(gè)數(shù)據(jù)庫(kù)中灭翔,否則在查詢的時(shí)候就會(huì)丟失其他服務(wù)器上存放的數(shù)據(jù)結(jié)果。所以往往我們還會(huì)把數(shù)據(jù)庫(kù)單獨(dú)出來(lái)成為一批專用的服務(wù)器。
至此肝箱,我們就會(huì)發(fā)現(xiàn)哄褒,一個(gè)典型的三層結(jié)構(gòu)出現(xiàn)了:接入、邏輯煌张、存儲(chǔ)呐赡。然而,這種三層結(jié)果骏融,并不就能包醫(yī)百病链嘀。例如,當(dāng)我們需要讓用戶在線互動(dòng)(網(wǎng)游就是典型) 档玻,那么分割在不同邏輯服務(wù)器上的在線狀態(tài)數(shù)據(jù)怀泊,是無(wú)法知道對(duì)方的,這樣我們就需要專門(mén)做一個(gè)類似互動(dòng)服務(wù)器的專門(mén)系統(tǒng)误趴,讓用戶登錄的時(shí)候霹琼,也同時(shí)記錄一份數(shù)據(jù)到它那里,表明某個(gè)用戶登錄在某個(gè)服務(wù)器上凉当,而所有的互動(dòng)操作枣申,要先經(jīng)過(guò)這個(gè)互動(dòng)服務(wù)器,才能正確的把消息轉(zhuǎn)發(fā)到目標(biāo)用戶的服務(wù)器上看杭。
又例如糯而,當(dāng)我們?cè)谑褂镁W(wǎng)上論壇(BBS)系統(tǒng)的時(shí)候,我們發(fā)的文章泊窘,不可能只寫(xiě)入一個(gè)數(shù)據(jù)庫(kù)里熄驼,因?yàn)樘嗳说拈喿x請(qǐng)求會(huì)拖死這個(gè)數(shù)據(jù)庫(kù)。我們常常會(huì)按論壇板塊來(lái)寫(xiě)入不同的數(shù)據(jù)庫(kù)烘豹,又或者是同時(shí)寫(xiě)入多個(gè)數(shù)據(jù)庫(kù)瓜贾。這樣把文章數(shù)據(jù)分別存放到不同的服務(wù)器上,才能應(yīng)對(duì)大量的操作請(qǐng)求携悯。然而祭芦,用戶在讀取文章的時(shí)候,就需要有一個(gè)專門(mén)的程序憔鬼,去查找具體文章在哪一個(gè)服務(wù)器上龟劲,這時(shí)候我們就要架設(shè)一個(gè)專門(mén)的代理層,把所有的文章請(qǐng)求先轉(zhuǎn)交給它轴或,由它按照我們預(yù)設(shè)的存儲(chǔ)計(jì)劃昌跌,去找對(duì)應(yīng)的數(shù)據(jù)庫(kù)獲取數(shù)據(jù)。
根據(jù)上面的例子來(lái)看照雁,分布式系統(tǒng)雖然具有三層典型的結(jié)構(gòu)蚕愤,但是實(shí)際上往往不止有三層,而是根據(jù)業(yè)務(wù)需求,會(huì)設(shè)計(jì)成多個(gè)層次的萍诱。為了把請(qǐng)求轉(zhuǎn)交給正確的進(jìn)程處理悬嗓,我們而設(shè)計(jì)很多專門(mén)用于轉(zhuǎn)發(fā)請(qǐng)求的進(jìn)程和服務(wù)器。這些進(jìn)程我們常常以Proxy或者Router來(lái)命名裕坊,一個(gè)多層結(jié)構(gòu)常常會(huì)具備各種各樣的Proxy進(jìn)程包竹。這些代理進(jìn)程,很多時(shí)候都是通過(guò)TCP來(lái)連接前后兩端籍凝。然而映企,TCP雖然簡(jiǎn)單,但是卻會(huì)有故障后不容易恢復(fù)的問(wèn)題静浴。而且TCP的網(wǎng)絡(luò)編程堰氓,也是有點(diǎn)復(fù)雜的∑幌恚——所以双絮,人們?cè)O(shè)計(jì)出更好進(jìn)程間通訊機(jī)制:消息隊(duì)列。
盡管通過(guò)各種Proxy或者Router進(jìn)程能組建出強(qiáng)大的分布式系統(tǒng)得问,但是其管理的復(fù)雜性也是非常高的囤攀。所以人們?cè)诜謱幽J降幕A(chǔ)上,想出了更多的方法宫纬,來(lái)讓這種分層模式的程序變得更簡(jiǎn)單高效的方法焚挠。
并發(fā)模型(多線程、異步)
當(dāng)我們?cè)诰帉?xiě)服務(wù)器端程序是漓骚,我們會(huì)明確的知道蝌衔,大部分的程序,都是會(huì)處理同時(shí)到達(dá)的多個(gè)請(qǐng)求的蝌蹂。因此我們不能好像HelloWorld那么簡(jiǎn)單的噩斟,從一個(gè)簡(jiǎn)單的輸入計(jì)算出輸出來(lái)。因?yàn)槲覀儠?huì)同時(shí)獲得很多個(gè)輸入孤个,需要返回很多個(gè)輸出剃允。在這些處理的過(guò)程中,往往我們還會(huì)碰到需要“等待”或“阻塞”的情況齐鲤,比如我們的程序要等待數(shù)據(jù)庫(kù)處理結(jié)果斥废,等待向另外一個(gè)進(jìn)程請(qǐng)求結(jié)果等等……如果我們把請(qǐng)求一個(gè)挨著一個(gè)的處理,那么這些空閑的等待時(shí)間將白白浪費(fèi)给郊,造成用戶的響應(yīng)延時(shí)增加牡肉,以及整體系統(tǒng)的吞吐量極度下降。
所以在如何同時(shí)處理多個(gè)請(qǐng)求的問(wèn)題上丑罪,業(yè)界有2個(gè)典型的方案荚板。一種是多線程凤壁,一種是異步吩屹。在早期的系統(tǒng)中跪另,多線程或多進(jìn)程是最常用的技術(shù)。這種技術(shù)的代碼編寫(xiě)起來(lái)比較簡(jiǎn)單煤搜,因?yàn)槊總€(gè)線程中的代碼都肯定是按先后順序執(zhí)行的免绿。但是由于同時(shí)運(yùn)行著多個(gè)線程鸠窗,所以你無(wú)法保障多個(gè)線程之間的代碼的先后順序橘茉。這對(duì)于需要處理同一個(gè)數(shù)據(jù)的邏輯來(lái)說(shuō),是一個(gè)非常嚴(yán)重的問(wèn)題诵盼,最簡(jiǎn)單的例子就是顯示某個(gè)新聞的閱讀量迹卢。兩個(gè)++操作同時(shí)運(yùn)行辽故,有可能結(jié)果只加了1,而不是2腐碱。所以多線程下誊垢,我們常常要加很多數(shù)據(jù)的鎖,而這些鎖又反過(guò)來(lái)可能導(dǎo)致線程的死鎖症见。
因此異步回調(diào)模型在隨后比多線程更加流行喂走,除了多線程的死鎖問(wèn)題外,異步還能解決多線程下谋作,線程反復(fù)切換導(dǎo)致不必要的開(kāi)銷的問(wèn)題:每個(gè)線程都需要一個(gè)獨(dú)立的椨蟪Γ空間,在多線程并行運(yùn)行的時(shí)候遵蚜,這些棧的數(shù)據(jù)可能需要來(lái)回的拷貝帖池,這額外消耗了CPU。同時(shí)由于每個(gè)線程都需要占用椏跃唬空間碘裕,所以在大量線程存在的時(shí)候,內(nèi)存的消耗也是巨大的攒钳。而異步回調(diào)模型則能很好的解決這些問(wèn)題帮孔,不過(guò)異步回調(diào)更像是“手工版”的并行處理,需要開(kāi)發(fā)者自己去實(shí)現(xiàn)如何“并行”的問(wèn)題不撑。
異步回調(diào)基于非阻塞的I/O操作(網(wǎng)絡(luò)和文件)文兢,這樣我們就不用在調(diào)用讀寫(xiě)函數(shù)的時(shí)候“卡”在那一句函數(shù)調(diào)用,而是立刻返回“有無(wú)數(shù)據(jù)”的結(jié)果焕檬。而Linux的epoll技術(shù)姆坚,則利用底層內(nèi)核的機(jī)制,讓我們可以快速的“查找”到有數(shù)據(jù)可以讀寫(xiě)的連接\文件实愚。由于每個(gè)操作都是非阻塞的兼呵,所以我們的程序可以只用一個(gè)進(jìn)程兔辅,就處理大量并發(fā)的請(qǐng)求。因?yàn)橹挥幸粋€(gè)進(jìn)程击喂,所以所有的數(shù)據(jù)處理维苔,其順序都是固定的,不可能出現(xiàn)多線程中懂昂,兩個(gè)函數(shù)的語(yǔ)句交錯(cuò)執(zhí)行的情況介时,因此也不需要各種“鎖”。從這個(gè)角度看凌彬,異步非阻塞的技術(shù)沸柔,是大大簡(jiǎn)化了開(kāi)發(fā)的過(guò)程。由于只有一個(gè)線程铲敛,也不需要有線程切換之類的開(kāi)銷褐澎,所以異步非阻塞成為很多對(duì)吞吐量、并發(fā)有較高要求的系統(tǒng)首選伐蒋。
int?epoll_create(int?size)工三;//創(chuàng)建一個(gè)epoll的句柄,size用來(lái)告訴內(nèi)核這個(gè)監(jiān)聽(tīng)的數(shù)目一共有多大
int?epoll_ctl(int?epfd,?int?op,?int?fd,?struct?epoll_event *event)咽弦;
int?epoll_wait(int?epfd,?struct?epoll_event * events,?int?maxevents,?int?timeout);
緩沖技術(shù)
在互聯(lián)網(wǎng)服務(wù)中徒蟆,大部分的用戶交互,都是需要立刻返回結(jié)果的型型,所以對(duì)于延遲有一定的要求段审。而類似網(wǎng)絡(luò)游戲之類服務(wù),延遲更是要求縮短到幾十毫秒以內(nèi)闹蒜。所以為了降低延遲寺枉,緩沖是互聯(lián)網(wǎng)服務(wù)中最常見(jiàn)的技術(shù)之一。
早期的WEB系統(tǒng)中绷落,如果每個(gè)HTTP請(qǐng)求的處理姥闪,都去數(shù)據(jù)庫(kù)(MySQL)讀寫(xiě)一次,那么數(shù)據(jù)庫(kù)很快就會(huì)因?yàn)檫B接數(shù)占滿而停止響應(yīng)砌烁。因?yàn)橐话愕臄?shù)據(jù)庫(kù)筐喳,支持的連接數(shù)都只有幾百,而WEB的應(yīng)用的并發(fā)請(qǐng)求函喉,輕松能到幾千避归。這也是很多設(shè)計(jì)不良的網(wǎng)站人一多就卡死的最直接原因。為了盡量減少對(duì)數(shù)據(jù)庫(kù)的連接和訪問(wèn)管呵,人們?cè)O(shè)計(jì)了很多緩沖系統(tǒng)——把從數(shù)據(jù)庫(kù)中查詢的結(jié)果存放到更快的設(shè)施上梳毙,如果沒(méi)有相關(guān)聯(lián)的修改,就直接從這里讀捐下。
最典型的WEB應(yīng)用緩沖系統(tǒng)是Memcache账锹。由于PHP本身的線程結(jié)構(gòu)萌业,是不帶狀態(tài)的。早期PHP本身甚至連操作“堆”內(nèi)存的方法都沒(méi)有奸柬,所以那些持久的狀態(tài)生年,就一定要存放到另外一個(gè)進(jìn)程里。而Memcache就是一個(gè)簡(jiǎn)單可靠的存放臨時(shí)狀態(tài)的開(kāi)源軟件鸟缕。很多PHP應(yīng)用現(xiàn)在的處理邏輯晶框,都是先從數(shù)據(jù)庫(kù)讀取數(shù)據(jù)排抬,然后寫(xiě)入Memcache懂从;當(dāng)下次請(qǐng)求來(lái)的時(shí)候,先嘗試從Memcache里面讀取數(shù)據(jù)蹲蒲,這樣就有可能大大減少對(duì)數(shù)據(jù)庫(kù)的訪問(wèn)番甩。
然而Memcache本身是一個(gè)獨(dú)立的服務(wù)器進(jìn)程,這個(gè)進(jìn)程自身并不帶特別的集群功能届搁。也就是說(shuō)這些Memcache進(jìn)程缘薛,并不能直接組建成一個(gè)統(tǒng)一的集群。如果一個(gè)Memcache不夠用卡睦,我們就要手工用代碼去分配宴胧,哪些數(shù)據(jù)應(yīng)該去哪個(gè)Memcache進(jìn)程”矶停——這對(duì)于真正的大型分布式網(wǎng)站來(lái)說(shuō)恕齐,管理一個(gè)這樣的緩沖系統(tǒng),是一個(gè)很繁瑣的工作瞬逊。
因此人們開(kāi)始考慮設(shè)計(jì)一些更高效的緩沖系統(tǒng):從性能上來(lái)說(shuō)显歧,Memcache的每筆請(qǐng)求,都要經(jīng)過(guò)網(wǎng)絡(luò)傳輸确镊,才能去拉取內(nèi)存中的數(shù)據(jù)士骤。這無(wú)疑是有一點(diǎn)浪費(fèi)的,因?yàn)檎?qǐng)求者本身的內(nèi)存蕾域,也是可以存放數(shù)據(jù)的拷肌。——這就是促成了很多利用請(qǐng)求方內(nèi)存的緩沖算法和技術(shù)旨巷,其中最簡(jiǎn)單的就是使用LRU算法巨缘,把數(shù)據(jù)放在一個(gè)哈希表結(jié)構(gòu)的堆內(nèi)存中。
而Memcache的不具備集群功能契沫,也是一個(gè)用戶的痛點(diǎn)带猴。于是很多人開(kāi)始設(shè)計(jì),如何讓數(shù)據(jù)緩存分不到不同的機(jī)器上懈万。最簡(jiǎn)單的思路是所謂讀寫(xiě)分離拴清,也就是緩存每次寫(xiě)靶病,都寫(xiě)到多個(gè)緩沖進(jìn)程上記錄,而讀則可以隨機(jī)讀任何一個(gè)進(jìn)程口予。在業(yè)務(wù)數(shù)據(jù)有明顯的讀寫(xiě)不平衡差距上娄周,效果是非常好的。
然而沪停,并不是所有的業(yè)務(wù)都能簡(jiǎn)單的用讀寫(xiě)分離來(lái)解決問(wèn)題煤辨,比如一些在線互動(dòng)的互聯(lián)網(wǎng)業(yè)務(wù),比如社區(qū)木张、游戲众辨。這些業(yè)務(wù)的數(shù)據(jù)讀寫(xiě)頻率并沒(méi)很大的差異,而且也要求很高的延遲舷礼。因此人們又再想辦法鹃彻,把本地內(nèi)存和遠(yuǎn)端進(jìn)程的內(nèi)存緩存結(jié)合起來(lái)使用,讓數(shù)據(jù)具備兩級(jí)緩存妻献。同時(shí)蛛株,一個(gè)數(shù)據(jù)不在同時(shí)的復(fù)制存在所有的緩存進(jìn)程上,而是按一定規(guī)律分布在多個(gè)進(jìn)程上育拨〗髀模——這種分布規(guī)律使用的算法,最流行的就是所謂“一致性哈习旧ィ”笋粟。這種算法的好處是,當(dāng)某一個(gè)進(jìn)程失效掛掉锹引,不需要把整個(gè)集群中所有的緩存數(shù)據(jù)矗钟,都重新修改一次位置。你可以想象一下嫌变,如果我們的數(shù)據(jù)緩存分布吨艇,是用簡(jiǎn)單的以數(shù)據(jù)的ID對(duì)進(jìn)程數(shù)取模,那么一旦進(jìn)程數(shù)變化腾啥,每個(gè)數(shù)據(jù)存放的進(jìn)程位置都可能變化东涡,這對(duì)于服務(wù)器的故障容忍是不利的倘待。
Orcale公司旗下有一款叫Coherence的產(chǎn)品疮跑,是在緩存系統(tǒng)上設(shè)計(jì)比較好的。這個(gè)產(chǎn)品是一個(gè)商業(yè)產(chǎn)品凸舵,支持利用本地內(nèi)存緩存和遠(yuǎn)程進(jìn)程緩存協(xié)作祖娘。集群進(jìn)程是完全自管理的,還支持在數(shù)據(jù)緩存所在進(jìn)程啊奄,進(jìn)行用戶定義的計(jì)算(處理器功能)渐苏,這就不僅僅是緩存了掀潮,還是一個(gè)分布式的計(jì)算系統(tǒng)。
存儲(chǔ)技術(shù)(NoSQL)
相信CAP理論大家已經(jīng)耳熟能詳琼富,然而在互聯(lián)發(fā)展的早期仪吧,大家都還在使用MySQL的時(shí)候,如何讓數(shù)據(jù)庫(kù)存放更多的數(shù)據(jù)鞠眉,承載更多的連接薯鼠,很多團(tuán)隊(duì)都是絞盡腦汁。甚至于有很多業(yè)務(wù)械蹋,主要的數(shù)據(jù)存儲(chǔ)方式是文件出皇,數(shù)據(jù)庫(kù)反而變成是輔助的設(shè)施了。
然而朝蜘,當(dāng)NoSQL興起恶迈,大家突然發(fā)現(xiàn)涩金,其實(shí)很多互聯(lián)網(wǎng)業(yè)務(wù)谱醇,其數(shù)據(jù)格式是如此的簡(jiǎn)單,很多時(shí)候根部不需要關(guān)系型數(shù)據(jù)庫(kù)那種復(fù)雜的表格步做。對(duì)于索引的要求往往也只是根據(jù)主索引搜索副渴。而更復(fù)雜的全文搜索,本身數(shù)據(jù)庫(kù)也做不到全度。所以現(xiàn)在相當(dāng)多的高并發(fā)的互聯(lián)網(wǎng)業(yè)務(wù)煮剧,首選NoSQL來(lái)做存儲(chǔ)設(shè)施。最早的NoSQL數(shù)據(jù)庫(kù)有MangoDB等将鸵,現(xiàn)在最流行的似乎就是Redis了勉盅。甚至有些團(tuán)隊(duì),把Redis也當(dāng)成緩沖系統(tǒng)的一部分顶掉,實(shí)際上也是認(rèn)可Redis的性能優(yōu)勢(shì)草娜。
NoSQL除了更快、承載量更大以外痒筒,更重要的特點(diǎn)是宰闰,這種數(shù)據(jù)存儲(chǔ)方式,只能按照一條索引來(lái)檢索和寫(xiě)入簿透。這樣的需求約束移袍,帶來(lái)了分布上的好處,我們可以按這條主索引老充,來(lái)定義數(shù)據(jù)存放的進(jìn)程(服務(wù)器)葡盗。這樣一個(gè)數(shù)據(jù)庫(kù)的數(shù)據(jù),就能很方便的存放在不同的服務(wù)器上啡浊。在分布式系統(tǒng)的必然趨勢(shì)下觅够,數(shù)據(jù)存儲(chǔ)層終于也找到了分布的方法路狮。
分布式系統(tǒng)在可管理性上造成的問(wèn)題
分布式系統(tǒng)并不是簡(jiǎn)單的把一堆服務(wù)器一起運(yùn)行起來(lái)就能滿足需求的。對(duì)比單機(jī)或少量服務(wù)器的集群蔚约,有一些特別需要解決的問(wèn)題等待著我們奄妨。
硬件故障率
所謂分布式系統(tǒng),肯定就不是只有一臺(tái)服務(wù)器苹祟。假設(shè)一臺(tái)服務(wù)器的平均故障時(shí)間是1%砸抛,那么當(dāng)你有100臺(tái)服務(wù)器的時(shí)候,那就幾乎總有一臺(tái)是在故障的树枫。雖然這個(gè)比方不一定很準(zhǔn)確直焙,但是,當(dāng)你的系統(tǒng)所涉及的硬件越來(lái)越多砂轻,硬件的故障也會(huì)從偶然事件變成一個(gè)必然事件奔誓。一般我們?cè)趯?xiě)功能代碼的時(shí)候,是不會(huì)考慮到硬件故障的時(shí)候應(yīng)該怎么辦的搔涝。而如果在編寫(xiě)分布式系統(tǒng)的時(shí)候厨喂,就一定需要面對(duì)這個(gè)問(wèn)題了。否則庄呈,很可能只有一臺(tái)服務(wù)器出故障蜕煌,整個(gè)數(shù)百臺(tái)服務(wù)器的集群都工作不正常了。
除了服務(wù)器自己的內(nèi)存诬留、硬盤(pán)等故障斜纪,服務(wù)器之間的網(wǎng)絡(luò)線路故障更加常見(jiàn)。而且這種故障還有可能是偶發(fā)的文兑,或者是會(huì)自動(dòng)恢復(fù)的盒刚。面對(duì)這種問(wèn)題,如果只是簡(jiǎn)單的把“出現(xiàn)故障”的機(jī)器剔除出去绿贞,那還是不夠的因块。因?yàn)榫W(wǎng)絡(luò)可能過(guò)一會(huì)兒就又恢復(fù)了,而你的集群可能因?yàn)檫@一下的臨時(shí)故障樟蠕,丟失了過(guò)半的處理能力贮聂。
如何讓分布式系統(tǒng),在各種可能隨時(shí)出現(xiàn)故障的情況下寨辩,盡量的自動(dòng)維護(hù)和維持對(duì)外服務(wù)吓懈,成為了編寫(xiě)程序就要考慮的問(wèn)題。由于要考慮到這種故障的情況靡狞,所以我們?cè)谠O(shè)計(jì)架構(gòu)的時(shí)候耻警,也要有意識(shí)的預(yù)設(shè)一些冗余、自我維護(hù)的功能。這些都不是產(chǎn)品上的業(yè)務(wù)需求甘穿,完全就是技術(shù)上的功能需求腮恩。能否在這方面提出對(duì)的需求,然后正確的實(shí)現(xiàn)温兼,是服務(wù)器端程序員最重要的職責(zé)之一秸滴。
資源利用率優(yōu)化
在分布式系統(tǒng)的集群,包含了很多個(gè)服務(wù)器募判,當(dāng)這樣一個(gè)集群的硬件承載能力到達(dá)極限的時(shí)候荡含,最自然的想法就是增加更多的硬件。然而届垫,一個(gè)軟件系統(tǒng)不是那么容易就可以通過(guò)“增加”硬件來(lái)提高承載性能的释液。因?yàn)檐浖诙鄠€(gè)服務(wù)器上的工作,是需要有復(fù)雜細(xì)致的協(xié)調(diào)工作装处。在對(duì)一個(gè)集群擴(kuò)容的時(shí)候误债,我們往往會(huì)要停掉整個(gè)集群的服務(wù),然后修改各種配置妄迁,最后才能重新啟動(dòng)一個(gè)加入了新的服務(wù)器的集群寝蹈。
由于在每個(gè)服務(wù)器的內(nèi)存里,都可能會(huì)有一些用戶使用的數(shù)據(jù)判族,所以如果冒然在運(yùn)行的時(shí)候躺盛,就試圖修改集群中提供服務(wù)的配置,很可能會(huì)造成內(nèi)存數(shù)據(jù)的丟失和錯(cuò)誤形帮。因此,運(yùn)行時(shí)擴(kuò)容在對(duì)無(wú)狀態(tài)的服務(wù)上周叮,是比較容易的辩撑,比如增加一些Web服務(wù)器。但如果是在有狀態(tài)的服務(wù)上仿耽,比如網(wǎng)絡(luò)游戲合冀,幾乎是不可能進(jìn)行簡(jiǎn)單的運(yùn)行時(shí)擴(kuò)容的。
分布式集群除了擴(kuò)容项贺,還有縮容的需求君躺。當(dāng)用戶人數(shù)下降,服務(wù)器硬件資源出現(xiàn)空閑的時(shí)候开缎,我們往往需要這些空閑的資源能利用起來(lái)棕叫,放到另外一些新的服務(wù)集群里去∞壬荆縮容和集群中有故障需要容災(zāi)有一定類似之處俺泣,區(qū)別是縮容的時(shí)間點(diǎn)和目標(biāo)是可預(yù)期的。
由于分布式集群中的擴(kuò)容、縮容伏钠,以及希望盡量能在線操作横漏,這導(dǎo)致了非常復(fù)雜的技術(shù)問(wèn)題需要處理,比如集群中互相關(guān)聯(lián)的配置如何正確高效的修改熟掂、如何對(duì)有狀態(tài)的進(jìn)程進(jìn)行操作缎浇、如何在擴(kuò)容縮容的過(guò)程中保證集群中節(jié)點(diǎn)之間通信的正常。作為服務(wù)器端程序員赴肚,會(huì)需要花費(fèi)大量的經(jīng)歷华畏,來(lái)對(duì)多個(gè)進(jìn)程的集群狀態(tài)變化,造成的一系列問(wèn)題進(jìn)行專門(mén)的開(kāi)發(fā)尊蚁。
軟件服務(wù)內(nèi)容更新
現(xiàn)在都流行用敏捷開(kāi)發(fā)模式中的“迭代”亡笑,來(lái)表示一個(gè)服務(wù)不斷的更新程序,滿足新的需求横朋,修正BUG仑乌。如果我們僅僅管理一臺(tái)服務(wù)器,那么更新這一臺(tái)服務(wù)器上的程序琴锭,是非常簡(jiǎn)單的:只要把軟件包拷貝過(guò)去晰甚,然后修改下配置就好。但是如果你要對(duì)成百上千的服務(wù)器去做同樣的操作决帖,就不可能每臺(tái)服務(wù)器登錄上去處理厕九。
服務(wù)器端的程序批量安裝部署工具,是每個(gè)分布式系統(tǒng)開(kāi)發(fā)者都需要的地回。然而扁远,我們的安裝工作除了拷貝二進(jìn)制文件和配置文件外,還會(huì)有很多其他的操作刻像。比如打開(kāi)防火墻畅买、建立共享內(nèi)存文件、修改數(shù)據(jù)庫(kù)表結(jié)構(gòu)细睡、改寫(xiě)一些數(shù)據(jù)文件等等……甚至有一些還要在服務(wù)器上安裝新的軟件谷羞。
如果我們?cè)陂_(kāi)發(fā)服務(wù)器端程序的時(shí)候,就考慮到軟件更新溜徙、版本升級(jí)的問(wèn)題湃缎,那么我們對(duì)于配置文件、命令行參數(shù)蠢壹、系統(tǒng)變量的使用嗓违,就會(huì)預(yù)先做一定的規(guī)劃,這能讓安裝部署的工具運(yùn)行更快知残,可靠性更高靠瞎。
除了安裝部署的過(guò)程比庄,還有一個(gè)重要的問(wèn)題,就是不同版本間數(shù)據(jù)的問(wèn)題乏盐。我們?cè)谏?jí)版本的時(shí)候佳窑,舊版本程序生成的一些持久化數(shù)據(jù),一般都是舊的數(shù)據(jù)格式的父能;而我們升級(jí)版本中如果涉及修改了數(shù)據(jù)格式神凑,比如數(shù)據(jù)表結(jié)果,那么這些舊格式的數(shù)據(jù)何吝,都要轉(zhuǎn)換改寫(xiě)成新版本的數(shù)據(jù)格式才行溉委。這導(dǎo)致了我們?cè)谠O(shè)計(jì)數(shù)據(jù)結(jié)構(gòu)的時(shí)候,就要考慮清楚這些表格的結(jié)構(gòu)爱榕,是用最簡(jiǎn)單直接的表達(dá)方式瓣喊,來(lái)讓將來(lái)的修改更簡(jiǎn)單;還是一早就預(yù)計(jì)到修改的范圍黔酥,專門(mén)預(yù)設(shè)一些字段藻三,或者使用其他形式存放數(shù)據(jù)。
除了持久化數(shù)據(jù)以外跪者,如果存在客戶端程序(如受擊APP)棵帽,這些客戶端程序的升級(jí)往往不能和服務(wù)器同步,如果升級(jí)的內(nèi)容包含了通信協(xié)議的修改渣玲,這就造成了我們必須為不同的版本部署不同的服務(wù)器端系統(tǒng)的問(wèn)題逗概。為了避免同時(shí)維護(hù)多套服務(wù)器,我們?cè)谲浖_(kāi)發(fā)的時(shí)候忘衍,往往傾向于所謂“版本兼容”的協(xié)議定義方式逾苫。而怎樣設(shè)計(jì)的協(xié)議才能有很好的兼容性,又是服務(wù)器端程序需要仔細(xì)考慮的問(wèn)題淑履。
數(shù)據(jù)統(tǒng)計(jì)和決策
一般來(lái)說(shuō)隶垮,分布式系統(tǒng)的日志數(shù)據(jù),都是被集中到一起秘噪,然后統(tǒng)一進(jìn)行統(tǒng)計(jì)的。然而勉耀,當(dāng)集群的規(guī)模到一定程度的時(shí)候指煎,這些日志的數(shù)據(jù)量會(huì)變得非常恐怖便斥。很多時(shí)候至壤,統(tǒng)計(jì)一天的日志量,要消耗計(jì)算機(jī)運(yùn)行一天以上的時(shí)間枢纠。所以像街,日志統(tǒng)計(jì)這項(xiàng)工作,也變成一門(mén)非常專業(yè)的活動(dòng)。
經(jīng)典的分布式統(tǒng)計(jì)模型镰绎,有Google的Map Reduce模型脓斩。這種模型既有靈活性,也能利用大量服務(wù)器進(jìn)行統(tǒng)計(jì)工作畴栖。但是缺點(diǎn)是易用性往往不夠好随静,因?yàn)檫@些數(shù)據(jù)的統(tǒng)計(jì)和我們常見(jiàn)的SQL數(shù)據(jù)表統(tǒng)計(jì)有非常大的差異,所以我們最后還是常常把數(shù)據(jù)丟到MySQL里面去做更細(xì)層面的統(tǒng)計(jì)吗讶。
由于分布式系統(tǒng)日志數(shù)量的龐大燎猛,以及日志復(fù)雜程度的提高。我們變得必須要掌握類似Map Reduce技術(shù)照皆,才能真正的對(duì)分布式系統(tǒng)進(jìn)行數(shù)據(jù)統(tǒng)計(jì)重绷。而且我們還需要想辦法提高統(tǒng)計(jì)工作的工作效率。
解決分布式系統(tǒng)可管理性的基本手段
目錄服務(wù)(ZooKeeper)
分布式系統(tǒng)是一個(gè)由很多進(jìn)程組成的整體膜毁,這個(gè)整體中每個(gè)成員部分昭卓,都會(huì)具備一些狀態(tài),比如自己的負(fù)責(zé)模塊爽茴,自己的負(fù)載情況葬凳,對(duì)某些數(shù)據(jù)的掌握等等。而這些和其他進(jìn)程相關(guān)的數(shù)據(jù)室奏,在故障恢復(fù)火焰、擴(kuò)容縮容的時(shí)候變得非常重要。
簡(jiǎn)單的分布式系統(tǒng)胧沫,可以通過(guò)靜態(tài)的配置文件昌简,來(lái)記錄這些數(shù)據(jù):進(jìn)程之間的連接對(duì)應(yīng)關(guān)系,他們的IP地址和端口绒怨,等等纯赎。然而一個(gè)自動(dòng)化程度高的分布式系統(tǒng),必然要求這些狀態(tài)數(shù)據(jù)都是動(dòng)態(tài)保存的南蹂。這樣才能讓程序自己去做容災(zāi)和負(fù)載均衡的工作犬金。
一些程序員會(huì)專門(mén)自己編寫(xiě)一個(gè)DIR服務(wù)(目錄服務(wù)),來(lái)記錄集群中進(jìn)程的運(yùn)行狀態(tài)六剥。集群中進(jìn)程會(huì)和這個(gè)DIR服務(wù)產(chǎn)生自動(dòng)關(guān)聯(lián)晚顷,這樣在容災(zāi)、擴(kuò)容疗疟、負(fù)載均衡的時(shí)候该默,就可以自動(dòng)根據(jù)這些DIR服務(wù)里的數(shù)據(jù),來(lái)調(diào)整請(qǐng)求的發(fā)送目地策彤,從而達(dá)到繞開(kāi)故障機(jī)器栓袖、或連接到新的服務(wù)器的操作匣摘。
然而酌予,如果我們只是用一個(gè)進(jìn)程來(lái)充當(dāng)這個(gè)工作檬果。那么這個(gè)進(jìn)程就成為了這個(gè)集群的“單點(diǎn)”——意思就是拄轻,如果這個(gè)進(jìn)程故障了秋忙,那么整個(gè)集群可能都無(wú)法運(yùn)行的个榕。所以存放集群狀態(tài)的目錄服務(wù)萤厅,也需要是分布式的入录。幸好我們有ZooKeeper這個(gè)優(yōu)秀的開(kāi)源軟件来涨,它正是一個(gè)分布式的目錄服務(wù)區(qū)塔橡。
ZooKeeper可以簡(jiǎn)單啟動(dòng)奇數(shù)個(gè)進(jìn)程梅割,來(lái)形成一個(gè)小的目錄服務(wù)集群。這個(gè)集群會(huì)提供給所有其他進(jìn)程葛家,進(jìn)行讀寫(xiě)其巨大的“配置樹(shù)”的能力户辞。這些數(shù)據(jù)不僅僅會(huì)存放在一個(gè)ZooKeeper進(jìn)程中,而是會(huì)根據(jù)一套非常安全的算法癞谒,讓多個(gè)進(jìn)程來(lái)承載底燎。這讓ZooKeeper成為一個(gè)優(yōu)秀的分布式數(shù)據(jù)保存系統(tǒng)。
由于ZooKeeper的數(shù)據(jù)存儲(chǔ)結(jié)構(gòu)弹砚,是一個(gè)類似文件目錄的樹(shù)狀系統(tǒng)双仍,所以我們常常會(huì)利用它的功能,把每個(gè)進(jìn)程都綁定到其中一個(gè)“分枝”上桌吃,然后通過(guò)檢查這些“分支”朱沃,來(lái)進(jìn)行服務(wù)器請(qǐng)求的轉(zhuǎn)發(fā),就能簡(jiǎn)單的解決請(qǐng)求路由(由誰(shuí)去做)的問(wèn)題茅诱。另外還可以在這些“分支”上標(biāo)記進(jìn)程的負(fù)載的狀態(tài)逗物,這樣負(fù)載均衡也很容易做了。
目錄服務(wù)是分布式系統(tǒng)中最關(guān)鍵的組件之一瑟俭。而ZooKeeper是一個(gè)很好的開(kāi)源軟件翎卓,正好是用來(lái)完成這個(gè)任務(wù)。
消息隊(duì)列服務(wù)(ActiveMQ摆寄、ZeroMQ失暴、Jgroups)
兩個(gè)進(jìn)程間如果要跨機(jī)器通訊,我們幾乎都會(huì)用TCP/UDP這些協(xié)議微饥。但是直接使用網(wǎng)絡(luò)API去編寫(xiě)跨進(jìn)程通訊锐帜,是一件非常麻煩的事情。除了要編寫(xiě)大量的底層socket代碼外畜号,我們還要處理諸如:如何找到要交互數(shù)據(jù)的進(jìn)程,如何保障數(shù)據(jù)包的完整性不至于丟失允瞧,如果通訊的對(duì)方進(jìn)程掛掉了简软,或者進(jìn)程需要重啟應(yīng)該怎樣等等這一系列問(wèn)題蛮拔。這些問(wèn)題包含了容災(zāi)擴(kuò)容、負(fù)載均衡等一系列的需求痹升。
為了解決分布式系統(tǒng)進(jìn)程間通訊的問(wèn)題建炫,人們總結(jié)出了一個(gè)有效的模型,就是“消息隊(duì)列”模型疼蛾。消息隊(duì)列模型肛跌,就是把進(jìn)程間的交互,抽象成對(duì)一個(gè)個(gè)消息的處理察郁,而對(duì)于這些消息衍慎,我們都有一些“隊(duì)列”,也就是管道皮钠,來(lái)對(duì)消息進(jìn)行暫存稳捆。每個(gè)進(jìn)程都可以訪問(wèn)一個(gè)或者多個(gè)隊(duì)列,從里面讀取消息(消費(fèi))或?qū)懭胂ⅲㄉa(chǎn))麦轰。由于有一個(gè)緩存的管道乔夯,我們可以放心的對(duì)進(jìn)程狀態(tài)進(jìn)行變化。當(dāng)進(jìn)程起來(lái)的時(shí)候款侵,它會(huì)自動(dòng)去消費(fèi)消息就可以了末荐。而消息本身的路由,也是由存放的隊(duì)列決定的新锈,這樣就把復(fù)雜的路由問(wèn)題甲脏,變成了如何管理靜態(tài)的隊(duì)列的問(wèn)題。
一般的消息隊(duì)列服務(wù)壕鹉,都是提供簡(jiǎn)單的“投遞”和“收取”兩個(gè)接口剃幌,但是消息隊(duì)列本身的管理方式卻比較復(fù)雜,一般來(lái)說(shuō)有兩種晾浴。一部分的消息隊(duì)列服務(wù)负乡,提倡點(diǎn)對(duì)點(diǎn)的隊(duì)列管理方式:每對(duì)通信節(jié)點(diǎn)之間,都有一個(gè)單獨(dú)的消息隊(duì)列脊凰。這種做法的好處是不同來(lái)源的消息抖棘,可以互不影響,不會(huì)因?yàn)槟硞€(gè)隊(duì)列的消息過(guò)多狸涌,擠占了其他隊(duì)列的消息緩存空間切省。而且處理消息的程序也可以自己來(lái)定義處理的優(yōu)先級(jí)——先收取、多處理某個(gè)隊(duì)列帕胆,而少處理另外一些隊(duì)列朝捆。
但是這種點(diǎn)對(duì)點(diǎn)的消息隊(duì)列,會(huì)隨著集群的增長(zhǎng)而增加大量的隊(duì)列懒豹,這對(duì)于內(nèi)存占用和運(yùn)維管理都是一個(gè)復(fù)雜的事情芙盘。因此更高級(jí)的消息隊(duì)列服務(wù)驯用,開(kāi)始可以讓不同的隊(duì)列共享內(nèi)存空間,而消息隊(duì)列的地址信息儒老、建立和刪除蝴乔,都采用自動(dòng)化的手段⊥苑——這些自動(dòng)化往往需要依賴上文所述的“目錄服務(wù)”薇正,來(lái)登記隊(duì)列的ID對(duì)應(yīng)的物理IP和端口等信息。比如很多開(kāi)發(fā)者使用ZooKeeper來(lái)充當(dāng)消息隊(duì)列服務(wù)的中央節(jié)點(diǎn)囚衔;而類似Jgropus這類軟件挖腰,則自己維護(hù)一個(gè)集群狀態(tài)來(lái)存放各節(jié)點(diǎn)今昔。
另外一種消息隊(duì)列佳魔,則類似一個(gè)公共的郵箱曙聂。一個(gè)消息隊(duì)列服務(wù)就是一個(gè)進(jìn)程,任何使用者都可以投遞或收取這個(gè)進(jìn)程中的消息鞠鲜。這樣對(duì)于消息隊(duì)列的使用更簡(jiǎn)便宁脊,運(yùn)維管理也比較方便。不過(guò)這種用法下贤姆,任何一個(gè)消息從發(fā)出到處理榆苞,最少進(jìn)過(guò)兩次進(jìn)程間通信,其延遲是相對(duì)比較高的霞捡。并且由于沒(méi)有預(yù)定的投遞坐漏、收取約束,所以也比較容易出BUG碧信。
不管使用那種消息隊(duì)列服務(wù)赊琳,在一個(gè)分布式服務(wù)器端系統(tǒng)中,進(jìn)程間通訊都是必須要解決的問(wèn)題砰碴,所以作為服務(wù)器端程序員躏筏,在編寫(xiě)分布式系統(tǒng)代碼的時(shí)候,使用的最多的就是基于消息隊(duì)列驅(qū)動(dòng)的代碼呈枉,這也直接導(dǎo)致了EJB3.0把“消息驅(qū)動(dòng)的Bean”加入到規(guī)范之中趁尼。
事務(wù)系統(tǒng)
在分布式的系統(tǒng)中,事務(wù)是最難解決的技術(shù)問(wèn)題之一猖辫。由于一個(gè)處理可能分布在不同的處理進(jìn)程上酥泞,任何一個(gè)進(jìn)程都可能出現(xiàn)故障,而這個(gè)故障問(wèn)題則需要導(dǎo)致一次回滾啃憎。這種回滾大部分又涉及多個(gè)其他的進(jìn)程芝囤。這是一個(gè)擴(kuò)散性的多進(jìn)程通訊問(wèn)題。要在分布式系統(tǒng)上解決事務(wù)問(wèn)題,必須具備兩個(gè)核心工具:一個(gè)是穩(wěn)定的狀態(tài)存儲(chǔ)系統(tǒng)凡人;另外一個(gè)是方便可靠的廣播系統(tǒng)名党。
事務(wù)中任何一步的狀態(tài),都必須在整個(gè)集群中可見(jiàn)挠轴,并且還要有容災(zāi)的能力。這個(gè)需求耳幢,一般還是由集群的“目錄服務(wù)”來(lái)承擔(dān)岸晦。如果我們的目錄服務(wù)足夠健壯,那么我們可以把每步事務(wù)的處理狀態(tài)睛藻,都同步寫(xiě)到目錄服務(wù)上去启上。ZooKeeper再次在這個(gè)地方能發(fā)揮重要的作用。
如果事務(wù)發(fā)生了中斷店印,需要回滾冈在,那么這個(gè)過(guò)程會(huì)涉及到多個(gè)已經(jīng)執(zhí)行過(guò)的步驟。也許這個(gè)回滾只需要在入口處回滾即可(加入那里有保存回滾所需的數(shù)據(jù))按摘,也可能需要在各個(gè)處理節(jié)點(diǎn)上回滾包券。如果是后者,那么就需要集群中出現(xiàn)異常的節(jié)點(diǎn)炫贤,向其他所有相關(guān)的節(jié)點(diǎn)廣播一個(gè)“回滾溅固!事務(wù)ID是XXXX”這樣的消息。這個(gè)廣播的底層一般會(huì)由消息隊(duì)列服務(wù)來(lái)承載兰珍,而類似Jgroups這樣的軟件侍郭,直接提供了廣播服務(wù)。
雖然現(xiàn)在我們?cè)谟懻撌聞?wù)系統(tǒng)掠河,但實(shí)際上分布式系統(tǒng)經(jīng)常所需的“分布式鎖”功能亮元,也是這個(gè)系統(tǒng)可以同時(shí)完成的。所謂的“分布式鎖”唠摹,也就是一種能讓各個(gè)節(jié)點(diǎn)先檢查后執(zhí)行的限制條件爆捞。如果我們有高效而單子操作的目錄服務(wù),那么這個(gè)鎖狀態(tài)實(shí)際上就是一種“單步事務(wù)”的狀態(tài)記錄跃闹,而回滾操作則默認(rèn)是“暫停操作嵌削,稍后再試”。這種“鎖”的方式望艺,比事務(wù)的處理更簡(jiǎn)單苛秕,因此可靠性更高,所以現(xiàn)在越來(lái)越多的開(kāi)發(fā)人員找默,愿意使用這種“鎖”服務(wù)艇劫,而不是去實(shí)現(xiàn)一個(gè)“事務(wù)系統(tǒng)”。
自動(dòng)部署工具(Docker)
由于分布式系統(tǒng)最大的需求惩激,是在運(yùn)行時(shí)(有可能需要中斷服務(wù))來(lái)進(jìn)行服務(wù)容量的變更:擴(kuò)容或者縮容店煞。而在分布式系統(tǒng)中某些節(jié)點(diǎn)故障的時(shí)候蟹演,也需要新的節(jié)點(diǎn)來(lái)恢復(fù)工作。這些如果還是像老式的服務(wù)器管理方式顷蟀,通過(guò)填表酒请、申報(bào)、進(jìn)機(jī)房鸣个、裝服務(wù)器羞反、部署軟件……這一套做法,那效率肯定是不行囤萤。
在分布式系統(tǒng)的環(huán)境下昼窗,我們一般都是采用“池”的方式來(lái)管理服務(wù)。我們預(yù)先會(huì)申請(qǐng)一批機(jī)器涛舍,然后在某些機(jī)器上運(yùn)行服務(wù)軟件澄惊,另外一些則作為備份。顯然我們這一批服務(wù)器不可能只為某一個(gè)業(yè)務(wù)服務(wù)富雅,而是會(huì)提供多個(gè)不同的業(yè)務(wù)承載掸驱。那些備份的服務(wù)器,則會(huì)成為多個(gè)業(yè)務(wù)的通用備份“池”吹榴。隨著業(yè)務(wù)需求的變化亭敢,一些服務(wù)器可能“退出”A服務(wù)而“加入”B服務(wù)。
這種頻繁的服務(wù)變化图筹,依賴高度自動(dòng)的軟件部署工具帅刀。我們的運(yùn)維人員,應(yīng)該掌握這開(kāi)發(fā)人員提供的部署工具远剩,而不是厚厚的手冊(cè)扣溺,來(lái)進(jìn)行這類運(yùn)維操作。一些比較有經(jīng)驗(yàn)的開(kāi)發(fā)團(tuán)隊(duì)瓜晤,會(huì)統(tǒng)一所有的業(yè)務(wù)底層框架锥余,以期大部分的部署、配置工具痢掠,都能用一套通用的系統(tǒng)來(lái)進(jìn)行管理驱犹。而開(kāi)源界,也有類似的嘗試足画,最廣為人知的莫過(guò)于RPM安裝包格式雄驹,然而RPM的打包方式還是太復(fù)雜,不太符合服務(wù)器端程序的部署需求淹辞。所以后來(lái)又出現(xiàn)了Chef為代表的医舆,可編程的通用部署系統(tǒng)。
然而,當(dāng)NoSQL興起蔬将,大家突然發(fā)現(xiàn)爷速,其實(shí)很多互聯(lián)網(wǎng)業(yè)務(wù),其數(shù)據(jù)格式是如此的簡(jiǎn)單霞怀,很多時(shí)候根部不需要關(guān)系型數(shù)據(jù)庫(kù)那種復(fù)雜的表格惫东。對(duì)于索引的要求往往也只是根據(jù)主索引搜索。而更復(fù)雜的全文搜索里烦,本身數(shù)據(jù)庫(kù)也做不到凿蒜。所以現(xiàn)在相當(dāng)多的高并發(fā)的互聯(lián)網(wǎng)業(yè)務(wù),首選NoSQL來(lái)做存儲(chǔ)設(shè)施胁黑。最早的NoSQL數(shù)據(jù)庫(kù)有MangoDB等,現(xiàn)在最流行的似乎就是Redis了州泊。甚至有些團(tuán)隊(duì)丧蘸,把Redis也當(dāng)成緩沖系統(tǒng)的一部分,實(shí)際上也是認(rèn)可Redis的性能優(yōu)勢(shì)遥皂。
NoSQL除了更快力喷、承載量更大以外,更重要的特點(diǎn)是演训,這種數(shù)據(jù)存儲(chǔ)方式弟孟,只能按照一條索引來(lái)檢索和寫(xiě)入。這樣的需求約束样悟,帶來(lái)了分布上的好處拂募,我們可以按這條主索引,來(lái)定義數(shù)據(jù)存放的進(jìn)程(服務(wù)器)窟她。這樣一個(gè)數(shù)據(jù)庫(kù)的數(shù)據(jù)陈症,就能很方便的存放在不同的服務(wù)器上。在分布式系統(tǒng)的必然趨勢(shì)下震糖,數(shù)據(jù)存儲(chǔ)層終于也找到了分布的方法录肯。
為了管理大量的分布式服務(wù)器端進(jìn)程,我們確實(shí)需要花很多功夫吊说,其優(yōu)化其部署管理的工作论咏。統(tǒng)一服務(wù)器端進(jìn)程的運(yùn)行規(guī)范,是實(shí)現(xiàn)自動(dòng)化部署管理的基本條件颁井。我們可以根據(jù)“操作系統(tǒng)”作為規(guī)范厅贪,采用Docker技術(shù);也可以根據(jù)“Web應(yīng)用”作為規(guī)范蚤蔓,采用某些PaaS平臺(tái)技術(shù)卦溢;或者自己定義一些更具體的規(guī)范,自己開(kāi)發(fā)完整的分布式計(jì)算平臺(tái)。
日志服務(wù)(log4j)
服務(wù)器端的日志单寂,一直是一個(gè)既重要又容易被忽視的問(wèn)題贬芥。很多團(tuán)隊(duì)在剛開(kāi)始的時(shí)候,僅僅把日志視為開(kāi)發(fā)調(diào)試宣决、排除BUG的輔助工具蘸劈。但是很快會(huì)發(fā)現(xiàn),在服務(wù)運(yùn)營(yíng)起來(lái)之后尊沸,日志幾乎是服務(wù)器端系統(tǒng)威沫,在運(yùn)行時(shí)可以用來(lái)了解程序情況的唯一有效手段。
盡管我們有各種profile工具洼专,但是這些工具大部分都不適合在正式運(yùn)營(yíng)的服務(wù)上開(kāi)啟棒掠,因?yàn)闀?huì)嚴(yán)重降低其運(yùn)行性能。所以我們更多的時(shí)候需要根據(jù)日志來(lái)分析屁商。盡管日志從本質(zhì)上烟很,就是一行行的文本信息,但是由于其具有很大的靈活性蜡镶,所以會(huì)很受開(kāi)發(fā)和運(yùn)維人員的重視雾袱。
日志本身從概念上,是一個(gè)很模糊的東西官还。你可以隨便打開(kāi)一個(gè)文件芹橡,然后寫(xiě)入一些信息。但是現(xiàn)代的服務(wù)器系統(tǒng)望伦,一般都會(huì)對(duì)日志做一些標(biāo)準(zhǔn)化的需求規(guī)范:日志必須是一行一行的林说,這樣比較方便日后的統(tǒng)計(jì)分析;每行日志文本屡谐,都應(yīng)該有一些統(tǒng)一的頭部述么,比如日期時(shí)間就是基本的需求;日志的輸出應(yīng)該是分等級(jí)的愕掏,比如fatal/error/warning/info/debug/trace等等度秘,程序可以在運(yùn)行時(shí)調(diào)整輸出的等級(jí),以便可以節(jié)省日志打印的消耗饵撑;日志的頭部一般還需要一些類似用戶ID或者IP地址之類的頭信息剑梳,用于快速查找定位過(guò)濾某一批日志記錄,或者有一些其他的用于過(guò)濾縮小日志查看范圍的字段滑潘,這叫做染色功能垢乙;日志文件還需要有“回滾”功能,也就是保持固定大小的多個(gè)文件语卤,避免長(zhǎng)期運(yùn)行后追逮,把硬盤(pán)寫(xiě)滿酪刀。
由于有上述的各種需求,所以開(kāi)源界提供了很多游戲的日志組件庫(kù)钮孵,比如大名鼎鼎的log4j骂倘,以及成員眾多的log4X家族庫(kù),這些都是應(yīng)用廣泛而飽受好評(píng)的工具巴席。
不過(guò)對(duì)比日志的打印功能历涝,日志的搜集和統(tǒng)計(jì)功能卻往往比較容易被忽視。作為分布式系統(tǒng)的程序員漾唉,肯定是希望能從一個(gè)集中節(jié)點(diǎn)荧库,能搜集統(tǒng)計(jì)到整個(gè)集群日志情況。而有一些日志的統(tǒng)計(jì)結(jié)果赵刑,甚至希望能在很短時(shí)間內(nèi)反復(fù)獲取分衫,用來(lái)監(jiān)控整個(gè)集群的健康情況。要做到這一點(diǎn)般此,就必須有一個(gè)分布式的文件系統(tǒng)丐箩,用來(lái)存放源源不斷到達(dá)的日志(這些日志往往通過(guò)UDP協(xié)議發(fā)送過(guò)來(lái))。而在這個(gè)文件系統(tǒng)上恤煞,則需要有一個(gè)類似Map Reduce架構(gòu)的統(tǒng)計(jì)系統(tǒng),這樣才能對(duì)海量的日志信息施籍,進(jìn)行快速的統(tǒng)計(jì)以及報(bào)警居扒。有一些開(kāi)發(fā)者會(huì)直接使用Hadoop系統(tǒng),有一些則用Kafka來(lái)作為日志存儲(chǔ)系統(tǒng)丑慎,上面再搭建自己的統(tǒng)計(jì)程序喜喂。
日志服務(wù)是分布式運(yùn)維的儀表盤(pán)、潛望鏡竿裂。如果沒(méi)有一個(gè)可靠的日志服務(wù)玉吁,整個(gè)系統(tǒng)的運(yùn)行狀況可能會(huì)是失控的。所以無(wú)論你的分布式系統(tǒng)節(jié)點(diǎn)是多還是少腻异,必須花費(fèi)重要的精力和專門(mén)的開(kāi)發(fā)時(shí)間进副,去建立一個(gè)對(duì)日志進(jìn)行自動(dòng)化統(tǒng)計(jì)分析的系統(tǒng)。
分布式系統(tǒng)在開(kāi)發(fā)效率上造成的問(wèn)題和解決思路
根據(jù)上文所述悔常,分布式系統(tǒng)在業(yè)務(wù)需求的功能以為影斑,還需要增加額外很多非功能的需求。這些非功能需求机打,往往都是為了一個(gè)多進(jìn)程系統(tǒng)能穩(wěn)定可靠運(yùn)行而去設(shè)計(jì)和實(shí)現(xiàn)的矫户。這些“額外”的工作,一般都會(huì)讓你的代碼更加復(fù)雜残邀,如果沒(méi)有很好的工具皆辽,就會(huì)讓你的開(kāi)發(fā)效率嚴(yán)重下降柑蛇。
微服務(wù)框架:EJB、WebService
當(dāng)我們?cè)谟懻摲?wù)器端軟件分布的時(shí)候驱闷,服務(wù)進(jìn)程之間的通信就難免了耻台。然而服務(wù)進(jìn)程間的通訊,并不是簡(jiǎn)單的收發(fā)消息就能完成的遗嗽。這里還涉及了消息的路由粘我、編碼解碼、服務(wù)狀態(tài)的讀寫(xiě)等等痹换。如果整個(gè)流程都由自己開(kāi)發(fā)征字,那就太累人了。
所以業(yè)界很早就推出了各種分布式的服務(wù)器端開(kāi)發(fā)框架娇豫,最著名的就是“EJB”——企業(yè)JavaBean匙姜。但凡冠以“企業(yè)”的技術(shù),往往都是分布式下所需的部分冯痢,而EJB這種技術(shù)氮昧,也是一種分布式對(duì)象調(diào)用的技術(shù)。我們?nèi)绻枰尪鄠€(gè)進(jìn)程合作完成任務(wù)浦楣,則需要把任務(wù)分解到多個(gè)“類”上袖肥,然后這些“類”的對(duì)象就會(huì)在各個(gè)進(jìn)程容器中存活,從而協(xié)作提供服務(wù)振劳。這個(gè)過(guò)程很“面向?qū)ο蟆弊底椤C總€(gè)對(duì)象都是一個(gè)“微服務(wù)”,可以提供某些分布式的功能历恐。
而另外一些系統(tǒng)寸癌,則走向?qū)W習(xí)互聯(lián)網(wǎng)的基本模型:HTTP。所以就有了各種的WebService框架弱贼,從開(kāi)源的到商業(yè)軟件蒸苇,都有各自的WebService實(shí)現(xiàn)。這種模型吮旅,把復(fù)雜的路由溪烤、編解碼等操作,簡(jiǎn)化成常見(jiàn)的一次HTTP操作鸟辅,是一種非常有效的抽象氛什。開(kāi)發(fā)人員開(kāi)發(fā)和部署多個(gè)WebService到Web服務(wù)器上,就完成了分布式系統(tǒng)的搭建匪凉。
不管我們是學(xué)習(xí)EJB還是WebService枪眉,實(shí)際上我們都需要簡(jiǎn)化分布式調(diào)用的復(fù)雜程度。而分布式調(diào)用的復(fù)雜之處再层,就是因?yàn)樾枰讶轂?zāi)贸铜、擴(kuò)容堡纬、負(fù)載均衡等功能,融合到跨進(jìn)程調(diào)用里蒿秦。所以使用一套通用的代碼烤镐,來(lái)為所有的跨進(jìn)程通訊(調(diào)用),統(tǒng)一的實(shí)現(xiàn)容災(zāi)棍鳖、擴(kuò)容炮叶、負(fù)載均衡、過(guò)載保護(hù)渡处、狀態(tài)緩存命中等等非功能性需求镜悉,能大大簡(jiǎn)化整個(gè)分布式系統(tǒng)的復(fù)雜性。
一般我們的微服務(wù)框架医瘫,都會(huì)在路由階段侣肄,對(duì)整個(gè)集群所有節(jié)點(diǎn)的狀態(tài)進(jìn)行觀察,如哪些地址上運(yùn)行了哪些服務(wù)的進(jìn)程醇份,這些服務(wù)進(jìn)程的負(fù)載狀況如何稼锅,是否可用,然后對(duì)于有狀態(tài)的服務(wù)僚纷,還會(huì)使用類似一致性哈希的算法矩距,去盡量試圖提高緩存的命中率。當(dāng)集群中的節(jié)點(diǎn)狀態(tài)發(fā)生變化的時(shí)候怖竭,微服務(wù)框架下的所有節(jié)點(diǎn)剩晴,都能盡快的獲得這個(gè)變化的情況,從新根據(jù)當(dāng)前狀態(tài)侵状,重新規(guī)劃以后的服務(wù)路由方向,從而實(shí)現(xiàn)自動(dòng)化的路由選擇毅整,避開(kāi)那些負(fù)載過(guò)高或者失效的節(jié)點(diǎn)趣兄。
有一些微服務(wù)框架,還提供了類似IDL轉(zhuǎn)換成“骨架”悼嫉、“樁”代碼的工具艇潭,這樣在編寫(xiě)遠(yuǎn)程調(diào)用程序的時(shí)候,完全無(wú)需編寫(xiě)那些復(fù)雜的網(wǎng)絡(luò)相關(guān)的代碼戏蔑,所有的傳輸層蹋凝、編碼層代碼都自動(dòng)的編寫(xiě)好了。這方面EJB总棵、Facebook的Thrift鳍寂,Google gRPC都具備這種能力。在具備代碼生成能力的框架下情龄,我們編寫(xiě)一個(gè)分布式下可用的功能模塊(可能是一個(gè)函數(shù)或者是一個(gè)類)迄汛,就好像編寫(xiě)一個(gè)本地的函數(shù)那樣簡(jiǎn)單捍壤。這絕對(duì)是分布式系統(tǒng)下非常重要的效率提升。
異步編程工具:協(xié)程鞍爱、Futrue鹃觉、Lamda
在分布式系統(tǒng)中編程,你不可避免的會(huì)碰到大量的“回調(diào)”型API睹逃。因?yàn)榉植际较到y(tǒng)涉及非常多的網(wǎng)絡(luò)通信盗扇。任何一個(gè)業(yè)務(wù)命令,都可能被分解到多個(gè)進(jìn)程沉填,通過(guò)多次網(wǎng)絡(luò)通信來(lái)組合完成疗隶。由于異步非阻塞的編程模型大行其道,所以我們的代碼也往往動(dòng)不動(dòng)就要碰到“回調(diào)函數(shù)”拜轨。然而抽减,回調(diào)這種異步編程模型,是一種非常不利于代碼閱讀的編程方法橄碾。因?yàn)槟銦o(wú)法從頭到尾的閱讀代碼卵沉,去了解一個(gè)業(yè)務(wù)任務(wù),是怎樣被逐步的完成的法牲。屬于一個(gè)業(yè)務(wù)任務(wù)的代碼史汗,由于多次的非阻塞回調(diào),從而被分割成很多個(gè)回調(diào)函數(shù)拒垃,在代碼的各處被串接起來(lái)停撞。
更有甚者,我們有時(shí)候會(huì)選擇使用“觀察者模式”悼瓮,我們會(huì)在一個(gè)地方注冊(cè)大量的“事件-響應(yīng)函數(shù)”戈毒,然后在所有需要回調(diào)的地方,都發(fā)出一個(gè)事件横堡÷袷校——這樣的代碼,比單純的注冊(cè)回調(diào)函數(shù)更難理解命贴。因?yàn)槭录?duì)應(yīng)的響應(yīng)函數(shù)道宅,通常在發(fā)出事件處是無(wú)法找到的。這些函數(shù)永遠(yuǎn)都會(huì)放在另外的一些文件里胸蛛,而且有時(shí)候這些函數(shù)還會(huì)在運(yùn)行時(shí)改變污茵。而事件名字本身,也往往是匪夷所思難以理解的葬项,因?yàn)楫?dāng)你的程序需要成千上百的事件的時(shí)候泞当,起一個(gè)容易理解名符其實(shí)的名字,幾乎是不可能的民珍。
為了解決回調(diào)函數(shù)這種對(duì)于代碼可讀性的破壞作用零蓉,人們發(fā)明了很多不同的改進(jìn)方法笤受。其中最著名的是“協(xié)程”。我們以前常常習(xí)慣于用多線程來(lái)解決問(wèn)題敌蜂,所以非常熟悉以同步的方式去寫(xiě)代碼箩兽。協(xié)程正是延續(xù)了我們的這一習(xí)慣,但不同于多線程的是章喉,協(xié)程并不會(huì)“同時(shí)”運(yùn)行汗贫,它只是在需要阻塞的地方,用Yield()切換出去執(zhí)行其他協(xié)程秸脱,然后當(dāng)阻塞結(jié)束后落包,用Resume()回到剛剛切換的位置繼續(xù)往下執(zhí)行。這相當(dāng)于我們可以把回調(diào)函數(shù)的內(nèi)容摊唇,接到Y(jié)ield()調(diào)用的后面咐蝇。這種編寫(xiě)代碼的方法,非常類似于同步的寫(xiě)法巷查,讓代碼變得非常易讀涮俄。但是唯一的缺點(diǎn)是僧凤,Resume()的代碼還是需要在所謂“主線程”中運(yùn)行浅浮。用戶必須自己從阻塞恢復(fù)的時(shí)候暴浦,去調(diào)用Resume()。協(xié)程另外一個(gè)缺點(diǎn)崇败,是需要做棧保存盅称,在切換到其他協(xié)程之后,棧上的臨時(shí)變量后室,也都需要額外占用空間缩膝,這限制了協(xié)程代碼的寫(xiě)法,讓開(kāi)發(fā)者不能用太大的臨時(shí)變量岸霹。
而另外一種改善回調(diào)函數(shù)的寫(xiě)法逞盆,往往叫做Future/Promise模型。這種寫(xiě)法的基本思路松申,就是“一次性把所有回調(diào)寫(xiě)到一起”。這是一個(gè)非常實(shí)用的編程模型俯逾,它沒(méi)有讓你去徹底干掉回調(diào)贸桶,而是讓你可以把回調(diào)從分散各處,集中到一個(gè)地方桌肴。在同一段代碼中皇筛,你可以清晰的看到各個(gè)異步的步驟是如何串接、或者并行執(zhí)行的坠七。
最后說(shuō)一下lamda模型水醋,這種寫(xiě)法流行于js語(yǔ)言的廣泛應(yīng)用旗笔。由于在其他語(yǔ)言中,定一個(gè)回調(diào)函數(shù)是非常費(fèi)事的:Java語(yǔ)言要設(shè)計(jì)一個(gè)接口然后做一個(gè)實(shí)現(xiàn)拄踪,簡(jiǎn)直是五星級(jí)的費(fèi)事程度蝇恶;C/C++支持函數(shù)指針,算是比較簡(jiǎn)單惶桐,但是也很容易導(dǎo)致代碼看不懂撮弧;腳本語(yǔ)言相對(duì)好一些,也要定義個(gè)函數(shù)姚糊。而直接在調(diào)用回調(diào)的地方贿衍,寫(xiě)回調(diào)函數(shù)的內(nèi)容,是最方便開(kāi)發(fā)救恨,也比較利于閱讀的贸辈。更重要的,lamda一般意味著閉包肠槽,也就是說(shuō)擎淤,這種回調(diào)函數(shù)的調(diào)用棧,是被分別保存的署浩,很多需要在異步操作中揉燃,需要建立一個(gè)類似“會(huì)話池”的狀態(tài)保存變量,在這里都是不需要的筋栋,而是可以自然生效的炊汤。這一點(diǎn)和協(xié)程有異曲同工之妙。
不管使用哪一種異步編程方式弊攘,其編碼的復(fù)雜度抢腐,都是一定比同步調(diào)用的代碼高的。所以我們?cè)诰帉?xiě)分布式服務(wù)器代碼的時(shí)候襟交,一定要仔細(xì)規(guī)劃代碼結(jié)構(gòu)迈倍,避免出現(xiàn)隨意添加功能代碼,導(dǎo)致代碼的可讀性被破壞的情況捣域。不可讀的代碼啼染,就是不可維護(hù)的代碼,而大量異步回調(diào)的服務(wù)器端代碼焕梅,是更容易出現(xiàn)這種情況的迹鹅。
云服務(wù)模型:IaaS/PaaS/SaaS
在復(fù)雜的分布式系統(tǒng)開(kāi)發(fā)和使用過(guò)程中,如何對(duì)大量服務(wù)器和進(jìn)程的運(yùn)維贞言,一直是一個(gè)貫穿其中的問(wèn)題斜棚。不管是使用微服務(wù)框架、還是統(tǒng)一的部署工具、日志監(jiān)控服務(wù)弟蚀,都是因?yàn)榇罅康姆?wù)器蚤霞,要集中的管理,是非常不容易的义钉。這里背后的原因昧绣,主要是大量的硬件和網(wǎng)絡(luò),把邏輯上的計(jì)算能力断医,切割成很多小塊滞乙。
隨著計(jì)算機(jī)運(yùn)算能力的提升,出現(xiàn)的虛擬化技術(shù)鉴嗤,卻能把被分割的計(jì)算單元斩启,更智能的統(tǒng)一起來(lái)。其中最常見(jiàn)的就是IaaS技術(shù):當(dāng)我們可以用一個(gè)服務(wù)器硬件醉锅,運(yùn)行多個(gè)虛擬的服務(wù)器操作系統(tǒng)的時(shí)候兔簇,我們需要維護(hù)的硬件數(shù)量就會(huì)成倍的下降。
而PaaS技術(shù)的流行硬耍,讓我們可以為某一種特定的編程模型垄琐,統(tǒng)一的進(jìn)行系統(tǒng)運(yùn)行環(huán)境的部署維護(hù)。而不需要再一臺(tái)臺(tái)服務(wù)器的去裝操作系統(tǒng)经柴、配置運(yùn)行容器狸窘、上傳運(yùn)行代碼和數(shù)據(jù)。在沒(méi)有統(tǒng)一的PaaS之前坯认,安裝大量的MySQL數(shù)據(jù)庫(kù)翻擒,曾經(jīng)是消耗大量時(shí)間和精力的工作。
當(dāng)我們的業(yè)務(wù)模型牛哺,成熟到可以抽象為一些固定的軟件時(shí)陋气,我們的分布式系統(tǒng)就會(huì)變得更加易用。我們的計(jì)算能力不再是代碼和庫(kù)引润,而是一個(gè)個(gè)通過(guò)網(wǎng)絡(luò)提供服務(wù)的云——SaaS巩趁,這樣使用者根本來(lái)維護(hù)、部署的工作都不需要淳附,只要申請(qǐng)一個(gè)接口议慰,填上預(yù)期的容量額度,就能直接使用了奴曙。這不僅節(jié)省了大量開(kāi)發(fā)對(duì)應(yīng)功能的事件别凹,還等于把大量的運(yùn)維工作,都交出去給SaaS的維護(hù)者——而他們做這樣的維護(hù)會(huì)更加專業(yè)缆毁。
在運(yùn)維模型的進(jìn)化上,從IaaS到PaaS到SaaS到涂,其應(yīng)用范圍也許是越來(lái)越窄脊框,但使用的便利性卻成倍的提高颁督。這也證明了,軟件勞動(dòng)的工作浇雹,也是可以通過(guò)分工沉御,向更專業(yè)化、更細(xì)分的方向去提高效率昭灵。
總結(jié)分布式系統(tǒng)問(wèn)題的解決路徑
本文轉(zhuǎn)載自 騰訊云技術(shù)社區(qū)——騰云閣 https://www.qcloud.com/community