系統(tǒng)為什么拆分?
系統(tǒng)做大了,并發(fā)量無(wú)法扛得住,如何做?
業(yè)務(wù)做復(fù)雜了,單個(gè)應(yīng)用中不能個(gè)性化,如何做?
模塊和邏輯對(duì)各類(lèi)資源開(kāi)銷(xiāo)非常特殊,如何做?
。。。。。。
拆分、拆分、再拆分。
由 全世界用一個(gè)系統(tǒng)表達(dá)全世界所有的企業(yè)和公司的業(yè)務(wù)開(kāi)始,注定系統(tǒng)做大后必然拆分的走向,也就是一個(gè)大力士無(wú)法完成成千上萬(wàn)群眾所能做到的一件大事,高集 成度的硬件和軟件解決方案,為傳統(tǒng)企業(yè)提供較為完善的解決方案,并在這種程度上是可以節(jié)約成本,高端機(jī)和高端存儲(chǔ)的解決方案,當(dāng)達(dá)到一個(gè)成本的交叉點(diǎn)后,隨著數(shù)據(jù)量以及并發(fā)量的不斷上升,其解決方案的成本也會(huì)隨之直線上漲。
如何拆分?拆分后有什么后果,是其中一個(gè)問(wèn)題?
首先我們看看應(yīng)用一般是如何拆分的:
1、應(yīng)用一般的企業(yè)內(nèi)部都是按照業(yè)務(wù)增長(zhǎng)方式比較多,所以隨著業(yè)務(wù)的增加,將系統(tǒng)進(jìn)行拆分的是比較多的,也就是將一個(gè)較大的系統(tǒng)拆分為多個(gè)小的系統(tǒng)。
2、在一些企業(yè)中,不愿意將系統(tǒng)拆分為小系統(tǒng)(原因后面說(shuō)明),而是將所有的內(nèi)容部署在一起,依賴(lài)于集群分發(fā)到多個(gè)節(jié)點(diǎn)上去做負(fù)載均衡,這樣來(lái)完成一種切割,前序兩種也就是應(yīng)用系統(tǒng)級(jí)別的縱橫向切割。
3、 獨(dú)立工具、模塊、服務(wù)的獨(dú)立化和集群化,基于SOA服務(wù)的企業(yè)級(jí)應(yīng)用,很多模塊經(jīng)過(guò)抽象后,并非子系統(tǒng),而是一個(gè)獨(dú)立的服務(wù)系統(tǒng),不參與業(yè)務(wù),只參與一個(gè)技術(shù)級(jí)別的功能服務(wù),如MQ、JMS、MemCached等,我們經(jīng)常也管這一類(lèi)叫做中間件,也就是平臺(tái)沒(méi)有提供自己來(lái)做或第三方提供的中間件(當(dāng)然中間 件也包含應(yīng)用服務(wù)器)。
4、數(shù)據(jù)庫(kù)拆分,數(shù)據(jù)庫(kù)拆分是也是因?yàn)閴毫ι仙约按鎯?chǔ)容量的需求,最終在成本上認(rèn)為拆分是必然的走勢(shì);數(shù)據(jù)庫(kù)拆分有多重規(guī)則存在。
5、由于上述各類(lèi)拆分導(dǎo)致的運(yùn)維的困難,在數(shù)以萬(wàn)計(jì)的計(jì)算機(jī)集群下,如何動(dòng)態(tài)資源分配和拆分以及拋開(kāi)分布式的內(nèi)部細(xì)節(jié)來(lái)編程,如何自動(dòng)化運(yùn)維系統(tǒng)就是大型計(jì)算機(jī)集群下需要考慮的問(wèn)題-云存儲(chǔ)與云計(jì)算。
我們拆分中面臨哪些問(wèn)題?(這些內(nèi)容在后面的文章中說(shuō)明,本文不再闡述)
1、負(fù)載均衡器的問(wèn)題。
2、不同系統(tǒng)之間的通信問(wèn)題。
3、數(shù)據(jù)寫(xiě)入和查找的問(wèn)題。
4、跨數(shù)據(jù)庫(kù)事務(wù)問(wèn)題。
5、跨數(shù)據(jù)庫(kù)序列問(wèn)題。
6、不同應(yīng)用的本地緩存問(wèn)題。
7、系統(tǒng)之間的直接依賴(lài)和間接依賴(lài)問(wèn)題。
8、獨(dú)立模塊面臨的單點(diǎn)問(wèn)題。
9、各類(lèi)批量分組、切換、擴(kuò)展的問(wèn)題。
10、統(tǒng)一監(jiān)控和恢復(fù)問(wèn)題。
本 文我們暫時(shí)不討論關(guān)于云存儲(chǔ)方面的問(wèn)題,先引入話題,不過(guò)每項(xiàng)技術(shù)的產(chǎn)生都是為了解決某些特定的問(wèn)題而存在,所以云也并非萬(wàn)能的,后面的文章我們會(huì)介紹一 些基于純java開(kāi)發(fā)的hadoop相關(guān)架構(gòu)和模塊(如:MapReduce、Hbase、Hive、HDFS、Pig等子系統(tǒng),說(shuō)明當(dāng)今海量信息的互聯(lián) 網(wǎng)中大象的崛起)。
1、系統(tǒng)按照業(yè)務(wù)拆分:
首先看下企業(yè)中拆分為小系統(tǒng)的過(guò)程中的過(guò)程和遇到的問(wèn)題,在大多數(shù)企業(yè)中,選擇高端企業(yè)的解決方案,因?yàn)橐慌_(tái)兩臺(tái)小型機(jī)一般的企業(yè)都沒(méi)有問(wèn)題,除非是做的項(xiàng)目的確太小了,這類(lèi)系統(tǒng)的訪問(wèn)量大概每天保持在幾十萬(wàn)左右高的有一百多萬(wàn)的,不過(guò)為什么要拆分,一般有以下原因
a.隨著業(yè)務(wù)的發(fā)展,模塊之間的耦合性越來(lái)越強(qiáng)
b.開(kāi)發(fā)人員越來(lái)越多,相互之間代碼版本也難以管理
c.系統(tǒng)啟動(dòng)加載PermGen的時(shí)間也會(huì)很長(zhǎng)并且需要很大的PermGen,更加重要的原因是JVM在CMSGC出來(lái)之前管理大內(nèi)存是有問(wèn)題的
d.尤其是發(fā)生Full GC時(shí)候在大內(nèi)存的JVM上暫停時(shí)間是相當(dāng)?shù)拈L(zhǎng),長(zhǎng)得讓人無(wú)法接受.
e.在單個(gè)機(jī)器上硬件廠商做得集成度越高,算法就越來(lái)越復(fù)雜,尤其是CPU的個(gè)數(shù)始終有限,這樣就導(dǎo)致的是單位時(shí)間內(nèi)處理的請(qǐng)求數(shù)也就受到限制,拆分水平擴(kuò)展是非常容易的.
f.一個(gè)大系統(tǒng)由多個(gè)開(kāi)發(fā)商完成,多個(gè)開(kāi)發(fā)商都有自己的主打產(chǎn)品,為自己節(jié)約成本,將各個(gè)產(chǎn)品以集成的方法完成一個(gè)大系統(tǒng)的業(yè)務(wù)過(guò)程。
等等原因。
那 么系統(tǒng)拆分這樣的系統(tǒng)拆分有什么技巧嗎,可以說(shuō)原因就算是技巧,也就是在什么時(shí)候再拆分,一般系統(tǒng)我們能不拆分就不拆分,因?yàn)椴鸱钟杏泻芏嗦闊┮ッ鎸?duì), 面臨的第一個(gè)困難就是以前一個(gè)工程內(nèi)部的系統(tǒng),相互之間的調(diào)用就可以直接調(diào)用到,現(xiàn)在很麻煩,要兩邊來(lái)做接口,接口還得聯(lián)調(diào),聯(lián)調(diào)是一件比較惡心的事情,尤其是兩個(gè)廠商之間來(lái)聯(lián)調(diào)。
所以拆分應(yīng)當(dāng)具有的最基本條件是高內(nèi)聚、 低耦合的條件,也就是說(shuō),這個(gè)系統(tǒng)和外部系統(tǒng)的調(diào)用模塊對(duì)于整個(gè)系統(tǒng)的模塊來(lái)講是比較少的,而不是大部分模塊都是在和外部系統(tǒng)交互,除了專(zhuān)門(mén)用于處理系統(tǒng)交互的系統(tǒng)外,這樣的拆分設(shè)計(jì)是肯定不合理的,因?yàn)橥ㄐ诺拇鷥r(jià)遠(yuǎn)遠(yuǎn)大于本地JVM的代價(jià)。
開(kāi) 發(fā)人員越來(lái)越多,從最初的一個(gè)人,幾個(gè)人,到幾十人,幾百人甚至上千人,在一個(gè)工程中來(lái)寫(xiě)代碼是很恐怖的事情,誰(shuí)改了沒(méi)法查出來(lái),無(wú)法定位,很亂,所以拆 分在一定程度上可以將版本控制的粒度細(xì)化一下,但是并不代表拆分后就沒(méi)有版本問(wèn)題;隨著產(chǎn)品不斷模塊化和抽象化,在大多數(shù)的應(yīng)用中,獨(dú)立的子系統(tǒng)就會(huì)成為一個(gè)獨(dú)立的行業(yè)產(chǎn)品,可以基于配置模式的適用于大部分的地區(qū)工廠或者企業(yè)的應(yīng)用,也可以通過(guò)一個(gè)頂層版本分發(fā)出來(lái)的多個(gè)地區(qū)化個(gè)性化版本(可能有兩層結(jié) 構(gòu));也就是在節(jié)約大部分共享勞動(dòng)力的基礎(chǔ)上如何做到個(gè)性化平臺(tái),這也是行業(yè)軟件中非常盛行的,不過(guò)這樣將絕大部分程序員控制在一個(gè)小匣子里面了,幾乎沒(méi)有發(fā)揮的空間。
上面也說(shuō)了,系統(tǒng)可能由幾十人、幾百人甚至于上千人去 寫(xiě),如果大家都寫(xiě)一個(gè)工程,代碼量可想而知,系統(tǒng)初始化需要加載代碼段到PermGen,這塊空間將不可預(yù)知的大小發(fā)展,并且隨著業(yè)務(wù)的復(fù)雜性,需要的引 入的第三方技術(shù)越來(lái)越多,第三發(fā)包的class同樣會(huì)占用PermGen的空間,不用多說(shuō),這塊空間的大小是不可預(yù)知的。
當(dāng) 發(fā)生Full GC的時(shí)候,遍歷整個(gè)內(nèi)存,在沒(méi)有CMS GC出來(lái)之前,或者現(xiàn)在G 1的出現(xiàn),F(xiàn)ull GC對(duì)于幾十G上百G的大內(nèi)存是一件非常痛苦的事情,延遲時(shí)間可以打到十幾秒甚至于上百秒(這里在16個(gè)4 core的CPU使用了并行GC,時(shí)間是應(yīng)用暫停時(shí)間),這是不可以接受的,雖然CMS GC已經(jīng)可以在較短的暫停時(shí)間內(nèi)回收掉大內(nèi)存(只是暫停時(shí)間減少,但是回收時(shí)間可能會(huì)更加長(zhǎng)),不過(guò)在它目前解決的主要問(wèn)題是這個(gè),同時(shí)由于大內(nèi)存部署邏輯節(jié)點(diǎn)的個(gè)數(shù)減少,使得負(fù)載均衡器的負(fù)載目標(biāo)成倍減少,這樣可以讓同樣的負(fù)載均衡器支撐起更加龐大的后臺(tái)訪問(wèn)集群;不過(guò)大部分早期的系統(tǒng)還沒(méi)有看到CMS GC的誕生,更加沒(méi)有想到G1會(huì)出現(xiàn)(其實(shí)早在N多年前,論文就出來(lái)了,只是一直沒(méi)有實(shí)現(xiàn)而已),所以一直都還是在沿用比較老的拆分方法,不過(guò)拆分始終是 有它的好處的,不僅僅是因?yàn)镚C的問(wèn)題,在傳統(tǒng)企業(yè)中一般的負(fù)載均衡器也足以支撐,不會(huì)面臨更大的問(wèn)題。
對(duì) 于集成度較高的,通過(guò)芯片等方式來(lái)完成高性能的服務(wù)方法,對(duì)于傳統(tǒng)軟件來(lái)講是非常好的,因?yàn)橥ㄟ^(guò)硬件完成的,一般情況下比軟件完成的速度要快(所謂通過(guò)硬 件完成除了通過(guò)集成電路增加各類(lèi)特殊指令外,還有就是基于芯片或底層語(yǔ)言實(shí)現(xiàn)使之效能更高而且封裝操作),不過(guò)遇到的問(wèn)題就是隨著集成度的高度集中,算法越來(lái)越復(fù)雜,導(dǎo)致了內(nèi)部的諸多沖突,水平擴(kuò)展性受到了嚴(yán)重的限制,所以幾乎沒(méi)有多少算法的拆分,是一個(gè)必然的發(fā)展趨勢(shì)。
多 個(gè)開(kāi)發(fā)商完成了一個(gè)自己的系統(tǒng),開(kāi)發(fā)商為了產(chǎn)品化系統(tǒng),并且由于系統(tǒng)的復(fù)雜性,以及提升開(kāi)發(fā)商在行業(yè)內(nèi)部的積淀,所以就需要不斷完善產(chǎn)品,不斷版本化,以 及本地化的不斷改善;這個(gè)目的是好的,不過(guò)一定要做好版本的事情,以及一個(gè)大型的行業(yè)軟件的頂層架構(gòu)以及繼承關(guān)系,否則不如不做,部分軟件廠商可能只考慮到前者,也就是產(chǎn)品化,不過(guò)代碼頂層架構(gòu)幾乎沒(méi)有,只有業(yè)務(wù)架構(gòu),產(chǎn)品化和本地化代碼更加是隨心所欲,軟件五花八門(mén),就像貼補(bǔ)丁一樣,誰(shuí)要做本地就加一個(gè) else if,甚至于有直接對(duì)地區(qū)判定的硬代碼,很無(wú)語(yǔ)的做法,我個(gè)人認(rèn)為這樣做不如直接拿一個(gè)模板來(lái)改出來(lái)一個(gè)系統(tǒng),就不要做什么版本,因?yàn)檫@樣的版本的代碼是越來(lái)越爛,面對(duì)這種代碼唯一的辦法就是重構(gòu),如果不想重構(gòu)就永遠(yuǎn)下去吧,不面臨改變終究會(huì)被淘汰掉;這種情況也面臨在系統(tǒng)底層版本升級(jí)上,包括JDK的升 級(jí),如果只是考慮到成本和風(fēng)險(xiǎn)的話應(yīng)該說(shuō)真的永遠(yuǎn)都無(wú)法升級(jí),沒(méi)有做不到的升級(jí),關(guān)鍵是否愿意去做,越晚去升級(jí),所帶來(lái)的成本代價(jià)是越高的,類(lèi)似國(guó)際上有多少大型軟件的底層版本也是在不斷的升級(jí)中,而上層的代碼由于繁雜而不斷的重構(gòu),雖然說(shuō)不一定要時(shí)時(shí)刻刻重構(gòu),這樣程序員也會(huì)很累,并且也體現(xiàn)不出他們的 價(jià)值,因?yàn)槌商炀褪歉拇a,但是該重構(gòu)就應(yīng)該要去重構(gòu)。
負(fù)載均衡,首先負(fù)載均衡可以是硬件也可以是軟件,硬件在一定程度上支撐不上去的時(shí)候就要考慮通過(guò)軟件的負(fù)載均衡來(lái)解決了(硬件一般情況下比軟件要快速,但是它本身設(shè)計(jì)的復(fù)雜性導(dǎo)致了在一定場(chǎng)景下不如軟件的擴(kuò)展性好),系統(tǒng)在拆分后不論是分布到各個(gè)機(jī)器上還是在一個(gè)機(jī)器上虛擬出來(lái)多個(gè)節(jié)點(diǎn)都是需要,將其負(fù)載均衡的,按照URL和端口+虛擬目錄名稱(chēng)進(jìn)行負(fù)載,負(fù)載均衡器需要 知道這些內(nèi)容,也需要知道那個(gè)session訪問(wèn)了那臺(tái)機(jī)器,中間負(fù)載均衡器會(huì)采用一些特殊的算法來(lái)解決一些問(wèn)題,這里簡(jiǎn)單介紹到這里,在下一篇文章中會(huì) 介紹下負(fù)載均衡的大致原理和作用。
負(fù)載均衡器并不簡(jiǎn)單承擔(dān)這個(gè)問(wèn)題,在負(fù)載均衡器中一般還會(huì)有很多算法存在,如負(fù)載均衡器比較經(jīng)典的算法就是一致性hash算法,或者輪訓(xùn)檢測(cè);而在有限的線程下,為了得到更大的連接訪問(wèn),異步IO的訪問(wèn)策略應(yīng)運(yùn)而生,著名的Nginx到目前為止都是全世界大型互聯(lián)網(wǎng)前端負(fù)載均衡的設(shè)計(jì)藍(lán)圖的標(biāo)準(zhǔn),其QPS極限情況可以打到30000-50000左右,內(nèi)部還存在各種模式來(lái)支持不同的情況(NAT、DR、RUN),當(dāng)然還有很多類(lèi)似的負(fù)載均衡設(shè)備(設(shè)計(jì)上有些差別)。
2、系統(tǒng)水平拆分:系統(tǒng)水平拆分即同一個(gè)子系統(tǒng),或者整個(gè)系統(tǒng)部署在多個(gè)node上,這些node可以是多個(gè)主機(jī)或同一個(gè)主機(jī)上的多個(gè)軟件節(jié)點(diǎn);但是這些節(jié)點(diǎn)目前來(lái)講即使應(yīng)用拆分得再細(xì),在分布式系統(tǒng)上的這種低端機(jī)器也不可能扛得住高并發(fā)的訪問(wèn),一般這類(lèi)低端服務(wù)器代碼調(diào)解得較好等各種情況下,服務(wù)器的QPS一般都是保持在200以?xún)?nèi)的(這是以16個(gè)CPU來(lái)處理,一個(gè)請(qǐng)求在80ms內(nèi)處理完成請(qǐng)求分派,業(yè)務(wù)處理和數(shù)據(jù)請(qǐng)求,反饋結(jié)果等過(guò)程已經(jīng)是非??焖俚牧耍芏鄷r(shí)候一個(gè)SQL都會(huì)超過(guò)這個(gè)時(shí)間),當(dāng)然單用幾個(gè)字節(jié)去做壓力測(cè)試,反饋幾個(gè)字節(jié),并且中間幾乎沒(méi)有IO方面的額請(qǐng)求(如數(shù)據(jù)庫(kù)、文件、遠(yuǎn)程方法調(diào)用等),那么這個(gè)QPS你可能會(huì)上千,甚至于在好的機(jī)器上可以上萬(wàn)也有可能。
也就是系統(tǒng)真正運(yùn)行的時(shí)候,前端的用的并發(fā)量都是有限的,而且很多時(shí)候代碼不好的時(shí)候,一般應(yīng)用的QPS還會(huì)更低;面對(duì)高并發(fā),在這種情況下,我們唯一可以做的就是加機(jī)器,也就是水平擴(kuò)展,它的分發(fā)也是依賴(lài)于負(fù)載均衡設(shè)備,加機(jī)器的過(guò)程就好比是工廠里面的請(qǐng)很多工人來(lái)做同一件事情一樣,相對(duì)來(lái)講第一種拆分就是請(qǐng)不同的人來(lái)做不同的事情,不要讓一個(gè)人從頭做到尾部,那樣會(huì)搞得很累,而且對(duì)人的要求也很高。
這種拆分沒(méi)有什么太高的要求,只要負(fù)載均衡設(shè)備可以支撐就可以,為了讓負(fù)載均衡可以支撐更大的壓力,那么就盡量讓節(jié)點(diǎn)數(shù)量減少,那么就希望在同一臺(tái)實(shí)體機(jī)器上盡量一個(gè)節(jié)點(diǎn)(通過(guò)對(duì)實(shí)體機(jī)器進(jìn)行虛擬化可以在某些情況下節(jié)約成本,并將物理機(jī)本身的性能發(fā)揮到一個(gè)極限,并可以將一個(gè)比較好一點(diǎn)的機(jī)器分?jǐn)偨o多個(gè)訪問(wèn)量較低的系統(tǒng),不過(guò)虛擬化本身也會(huì)產(chǎn)生很多開(kāi)銷(xiāo),在這些方面需要綜合權(quán)衡一下好壞),可惜目前來(lái)講Oracle的Hotspot VM還不足以支撐大型的非常好的實(shí)時(shí)系統(tǒng)(我們很多時(shí)候不得不在同一個(gè)大內(nèi)存機(jī)器上部署多個(gè)小的JVM節(jié)點(diǎn)),尤其面對(duì)幾種場(chǎng)景顯得力不從心:
1、大內(nèi)存的管理(包括GC、內(nèi)存分析、跟蹤等都沒(méi)有完善的體系和解決方案)。
2、做實(shí)時(shí)應(yīng)用不適合,實(shí)時(shí)應(yīng)用的延遲一般是毫秒級(jí)別(如2ms響應(yīng),最慢也不能有十多毫秒的響應(yīng),當(dāng)然這種不包含IO操作,只是做一些內(nèi)存處理和反饋,并且數(shù)據(jù)量不大),而java在正常情況下,如果一旦發(fā)生GC,即使并行GC,而且僅僅只針對(duì)Yong空間做GC,也需要一段延遲(在一個(gè)16CPU的機(jī)器上,配置了并行GC,發(fā)生YGC的時(shí)候(Yong的大小大概為330M左右),延遲大概為10ms-15ms左右,發(fā)生Full GC的時(shí)候(Heap大小為1.5G),延遲大概為30ms-40ms左右),如果是更大的內(nèi)存,就更加蠻了,因?yàn)榛厥盏臅r(shí)間很多時(shí)候取決于內(nèi)存的大小,增加一倍的內(nèi)存,并不代表回收時(shí)間只增加一倍,因?yàn)殡S著內(nèi)存的增加,回收過(guò)程中產(chǎn)生的開(kāi)銷(xiāo)和沖突也變化,所以?xún)?nèi)存增加一倍,時(shí)間不一定只增加一倍,曾經(jīng)在96G的JVM內(nèi)存上,采用16CPU進(jìn)行全局GC,大概需要3分多鐘,也就是說(shuō)這3分多鐘外部是無(wú)法訪問(wèn)的,在實(shí)時(shí)應(yīng)用面前這就是垃圾。
3、做緩存不適合,分代垃圾回收考慮的是絕大部分對(duì)象都應(yīng)該死掉,而Old會(huì)采用全局GC,即使是CMS也會(huì)有各種問(wèn)題;很多時(shí)候我們?cè)诰彺娴臅r(shí)候,數(shù)據(jù)初始化就會(huì)裝載進(jìn)去,而很少甚至于不用去做GC,至少可以說(shuō)99%的內(nèi)存是不需要考慮GC的;而且做緩存的服務(wù)器內(nèi)存都是大內(nèi)存,也就是沒(méi)有地方讓自己來(lái)操控可存放不做GC的內(nèi)容,但是程序員發(fā)現(xiàn)這部分內(nèi)容占據(jù)了絕大部分內(nèi)存而自己卻無(wú)法控制它。
4、目前不支持半長(zhǎng)命對(duì)象,也就是要么是長(zhǎng)命鬼、要么是短命鬼,但是很多非常規(guī)應(yīng)用中,有很多半長(zhǎng)命對(duì)象,采用不同的算法,會(huì)提高更好的性能,如一些page cache數(shù)據(jù),在內(nèi)存中啟用LRU策略,這些隊(duì)列的數(shù)據(jù),不能說(shuō)他們的壽命很長(zhǎng),也不能說(shuō)他們的壽命很短,但是LRU本身在使用的過(guò)程中,不想受到類(lèi)似Yong和Old之間的這種晉升策略,因?yàn)榉旁贓den中覺(jué)得命太短,來(lái)回倒騰,有很多還是會(huì)到Old中(具體有多少進(jìn)入old要看應(yīng)用場(chǎng)景),進(jìn)入old它又并不是什么太長(zhǎng)命的東西,隨時(shí)可能就掛掉了,真是無(wú)奈啊。
其實(shí)還有很多JVM不方便去做的服務(wù)器方面的特殊應(yīng)用,不過(guò)隨著JVM的發(fā)展已經(jīng)比以前有了很大的飛躍,而且越來(lái)越多的硬件廠商和學(xué)術(shù)界的頂尖高手在為java的發(fā)展而努力,所以我很期待java能解決掉這些問(wèn)題。
3、 獨(dú)立工具、模塊、服務(wù)的獨(dú)立化和集群化
其實(shí)這種拆分和第一種拆分有相似之處,幾乎可以算是一樣的拆分模式,不過(guò)說(shuō)到工具化、模塊化、服務(wù)化、集群化,這種屬于更為專(zhuān)業(yè)的拆分,第一種拆分的依據(jù)是系統(tǒng)各項(xiàng)壓力上來(lái),為考慮擴(kuò)展性,而不得不拆分系統(tǒng),而將很多高內(nèi)聚、低耦合的系統(tǒng)拆分出來(lái),也就是模塊成為了子系統(tǒng)。
而這種拆分是一種技術(shù)獨(dú)立性拆分,將很多較為復(fù)雜,不好解決的技術(shù)以及工具特征獨(dú)立出來(lái),虛擬化為一種服務(wù)模式,為外部提供服務(wù),你可以將它理解為一個(gè)傳統(tǒng)的子系統(tǒng),不過(guò)它是屬于很多系統(tǒng)里面都需要的一個(gè)公共子系統(tǒng),而前者僅僅一般只為自己的兄弟模塊提供相應(yīng)的服務(wù)以及一些自己的對(duì)外用戶(hù)服務(wù);比如:將郵件系統(tǒng)獨(dú)立、短信系統(tǒng)獨(dú)立就是為很多應(yīng)用服務(wù),大家都可以使用,將通信技術(shù)獨(dú)立、將分布式緩存獨(dú)立、將配置管理獨(dú)立、將版本管理獨(dú)立就是屬于技術(shù)上的獨(dú)立進(jìn)而逐步個(gè)性化成為一種服務(wù)。
第一種和這種拆分方法沒(méi)有明顯的區(qū)別,可以說(shuō)這種拆分的思想是受第一種拆分的影響或者說(shuō)基于它來(lái)做的,它的目的是以一個(gè)個(gè)體或者集群為外部提供一種公共服務(wù);當(dāng)一個(gè)企業(yè)或者一個(gè)大的互聯(lián)網(wǎng)公司,將這些公共服務(wù)開(kāi)放出來(lái)后,形成一種全局的數(shù)據(jù)、技術(shù)的服務(wù)平臺(tái)。
4、數(shù)據(jù)庫(kù)拆分
這個(gè)話題扯得有點(diǎn)大了,因?yàn)閿?shù)據(jù)庫(kù)拆分這個(gè)拆分方法的確太多,本文也不能完全說(shuō)明數(shù)據(jù)庫(kù)的拆分方法,只是概要性的提及一些內(nèi)容。
首先,前端有壓力,數(shù)據(jù)庫(kù)自然也有,而且數(shù)據(jù)庫(kù)壓力肯定比前端壓力會(huì)更多(當(dāng)然前端可以采用很多緩存技術(shù)來(lái)環(huán)節(jié)數(shù)據(jù)庫(kù)的壓力),數(shù)據(jù)庫(kù)的復(fù)雜性比前端要更多,因?yàn)樗菙?shù)據(jù)的核心,需要對(duì)數(shù)據(jù)庫(kù)的安全、一致性等做保障,在很多處理上它都是采用磁盤(pán)IO操作,而普通的sata盤(pán)是很爛的,sas盤(pán)可能會(huì)稍微好一些,這些盤(pán)上做幾個(gè)KB的IOPS測(cè)試,一般只能達(dá)到180的IOPS就很不錯(cuò)了,當(dāng)然根據(jù)磁盤(pán)本身的尺寸和轉(zhuǎn)速會(huì)有所區(qū)別;在早期的技術(shù)上,我們大部分的都是采用高端存儲(chǔ),如:EMC、IBM這類(lèi)公司就是專(zhuān)門(mén)做高端存儲(chǔ)的,其IOPS可以達(dá)到萬(wàn)級(jí)別,其實(shí)其原理也是在普通存儲(chǔ)級(jí)別上做了很多類(lèi)似多存儲(chǔ)控制器、鏡像、cache等技術(shù)來(lái)解決很多問(wèn)題,但是其價(jià)格非常昂貴,小型機(jī)+EMC的解決方案相信是諸多企業(yè)的絕佳解決方案,因?yàn)楦静挥脫?dān)心性能、穩(wěn)定性和存儲(chǔ)空間,但是在數(shù)據(jù)量達(dá)到非常大的時(shí)候,他們也會(huì)顯得力不從心,此時(shí)在這種解決方案下也不得不去拆分,拆分過(guò)程中出現(xiàn)的問(wèn)題就需要技術(shù)人員來(lái)解決,付出的成本將是指數(shù)級(jí)的上升,而不是平衡上升的;SSD的出現(xiàn)雖然顛覆了傳統(tǒng)的磁盤(pán)存取效率(主要是隨機(jī)存取效率,順序讀寫(xiě)優(yōu)勢(shì)并不大),不過(guò)目前還有很多問(wèn)題存在,最近Intel也稱(chēng)其發(fā)生過(guò)丟失數(shù)據(jù)的問(wèn)題,而且SSD目前的成本非常高,不過(guò)我們可以看到它的來(lái)臨是傳統(tǒng)磁盤(pán)開(kāi)始被取代的標(biāo)志。
好,OK,隨著磁盤(pán)性能提高,但是容量還是和以前差不多,而且更加貴,所以就當(dāng)前來(lái)講我們絕大部分還是用傳統(tǒng)磁盤(pán)來(lái)解決,在這種一塊磁盤(pán)做一百多的IOPS的情況下(注意一個(gè)SQL并不代表只做一次IO,具體做多少次IO和實(shí)際的應(yīng)用場(chǎng)景、實(shí)際的優(yōu)化方案、以及SQL的寫(xiě)法所決定;而一個(gè)業(yè)務(wù)請(qǐng)求也一般會(huì)做多個(gè)SQL操作),我們?nèi)绾翁岣邤?shù)據(jù)庫(kù)的性能呢?和上面一樣,在很多時(shí)候我們先選擇的是小機(jī)+高端存儲(chǔ)的解決方案;但是隨著復(fù)雜性的增加,成本開(kāi)始補(bǔ)課預(yù)測(cè),所以為了接觸這種耦合性,我們需要一種高可擴(kuò)展的分布式技術(shù)來(lái)解決,在多個(gè)分布式的機(jī)器上來(lái)解決這些問(wèn)題。
首先,這種可以認(rèn)為是一種分區(qū)技術(shù)在分布式上的一種實(shí)現(xiàn),也就是將原有分區(qū)的技術(shù)應(yīng)用在多臺(tái)機(jī)器上,按照一種規(guī)則拆分到多臺(tái)計(jì)算機(jī)上,如果跨機(jī)器查找也就是原來(lái)的跨分區(qū)查找,顯然性能不如在單個(gè)機(jī)器上查找快速,所以如何設(shè)計(jì)分區(qū)成為一個(gè)性能關(guān)鍵,而不是僅僅為了拆分而拆分;另外拆分之前要有預(yù)算,計(jì)算所需要的TPS、QPS等負(fù)載情況,拆分到多少個(gè)機(jī)器上可以承受得起這樣的訪問(wèn)量,一般最少需要預(yù)留一半的余量才可以預(yù)防突發(fā)性事件,如果需要未來(lái)幾年都不受到拆分上的干擾,那么就可以預(yù)留更多;因?yàn)檫@種數(shù)據(jù)庫(kù)拆分的代價(jià)是很高的。
在早期的數(shù)據(jù)庫(kù)拆分中,有主備讀寫(xiě)分離,ORACLE RAC多實(shí)例運(yùn)算,不過(guò)面對(duì)越來(lái)越龐大的系統(tǒng),他們都顯得力不從心了,當(dāng)然讀寫(xiě)分離還是可以和現(xiàn)有的人工拆分所兼容,人工拆分主要是為了得到更好的水平擴(kuò)展。
首先我們來(lái)看看傳統(tǒng)應(yīng)用中的range分區(qū),如果用在分布式上,就是放在多個(gè)主機(jī)上的多個(gè)庫(kù)上的多個(gè)表,這種用于自動(dòng)增長(zhǎng)列或時(shí)間上比較多,如剛開(kāi)始可以將1-1億的數(shù)據(jù)一般可以用多久,選擇多少個(gè)機(jī)器來(lái)做,每臺(tái)機(jī)器可以存放多少數(shù)據(jù),而這種拆分Insert操作始終落在最后一臺(tái)機(jī)器的最后一個(gè)表的最后一個(gè)block上,而且在剛開(kāi)始使用的時(shí)候,后面所有的機(jī)器的所有的表都是空的,沒(méi)有任何用處,顯得非常的浪費(fèi),也就是沒(méi)有數(shù)據(jù)的機(jī)器一直都是閑著的;這個(gè)問(wèn)題比較好解決,你可以用一個(gè)無(wú)窮大來(lái)代表最后一臺(tái)機(jī)器,當(dāng)覺(jué)得應(yīng)該加機(jī)器的時(shí)候,再將最后前一臺(tái)機(jī)器的上限控制住,不過(guò)前一個(gè)問(wèn)題是沒(méi)辦法搞定的,所以這種方法是用在insert壓力并不是很大的情況,每秒要是有幾千個(gè)insert這樣做肯定是不行的,其余的update、delete等如果有最近訪問(wèn)熱點(diǎn),那么最后一臺(tái)機(jī)器也必將成為熱點(diǎn)訪問(wèn)區(qū)域,一般最近訪問(wèn)的都是熱點(diǎn),不過(guò)這種思路最容易讓人接受,而且最容易做出來(lái)。
那么在大部分應(yīng)用中我們?yōu)榱丝紤]負(fù)載較為均衡,所以我們選擇hash算法,但是絕對(duì)不是一致性hash算法,因?yàn)橐恢滦詇ash在擴(kuò)展時(shí)會(huì)導(dǎo)致數(shù)據(jù)不一致,一些數(shù)學(xué)模型可以解決,但是非常復(fù)雜而且也會(huì)存在數(shù)據(jù)版本的問(wèn)題;hash算法最簡(jiǎn)單的就是求模,如將一個(gè)表拆分為100個(gè)表,那么按照絕大部分情況按照某個(gè)編號(hào)去求模得到的是0-99之間的數(shù)據(jù),這一百個(gè)表編號(hào)為0-99,分別對(duì)應(yīng)存儲(chǔ)即可,無(wú)論是自動(dòng)增長(zhǎng)還是非自動(dòng)增長(zhǎng)也不太可能落在同一個(gè)表上面去;而對(duì)于某些熱點(diǎn)用戶(hù),如果按照用戶(hù)拆分,這些熱點(diǎn)用戶(hù)的訪問(wèn)就會(huì)被反復(fù)訪問(wèn)到同一個(gè)表,比如類(lèi)似微博這種東西,也許某個(gè)熱門(mén)人物的他的好友個(gè)數(shù)就會(huì)非常多,可能會(huì)導(dǎo)致某個(gè)表非常大,所以為了緩解這種問(wèn)題,我們會(huì)再做二次hash;而對(duì)于一些非數(shù)字類(lèi)的數(shù)據(jù),我們一般會(huì)采取對(duì)其前幾個(gè)字符的ascii或者h(yuǎn)ash值等取出來(lái)做操作,具體看實(shí)際情況而定;那么hash算法就是完美的嗎?當(dāng)然不是,它最痛苦的就是拆分,一旦拆分將會(huì)面臨各種問(wèn)題,應(yīng)用要重啟,配置要修改,數(shù)據(jù)要遷移;雖然用了一些手段來(lái)解決,但是這些手段一般都是需要提前預(yù)估出來(lái)的,比如hash算法一般都是2的次方拆分法則,因?yàn)閿?shù)據(jù)庫(kù)都會(huì)有備庫(kù),而且很多時(shí)候會(huì)有多個(gè)備庫(kù),所以如果做2倍數(shù)拆分的時(shí)候,可以直接將一個(gè)備份庫(kù)上的數(shù)據(jù)拿上來(lái)用,如原來(lái)拆分規(guī)則為100,現(xiàn)在變成200,按照100求模=1的機(jī)器的主庫(kù)數(shù)據(jù)和200求模等于1的都還在這個(gè)上面,只是有一部分和200求模會(huì)變成101(理論上可以認(rèn)為是一半),備庫(kù)也是這樣,所以在乘以2以后這個(gè)備庫(kù)變成主庫(kù)后,數(shù)據(jù)是完全可以路由到的,剩余的工作就只需要將原有主庫(kù)上和200求模等于101的數(shù)據(jù)刪掉,以將這部分空間節(jié)約出來(lái),而原有備庫(kù)替換成的主庫(kù)上和200求模等于1的數(shù)據(jù)刪掉,刪掉的這個(gè)過(guò)程是痛苦的,時(shí)間長(zhǎng),資源多,全是IO操作,而且還有各種鎖,性能影響極大;試圖想到我可以直接把他干掉,幾乎不影響性能就除非需要?jiǎng)h掉的數(shù)據(jù)是一個(gè)獨(dú)立的邏輯單位,在同一個(gè)表上能想到的就是分區(qū),也就是它如果是一個(gè)分區(qū)你就可以直接把他很快的drop掉或truncate掉,這種必須要有提前的預(yù)案才可以,否則這些都是空想;所以這種基于hash的拆分一般不要隨便拆分,代價(jià)是很大的,因?yàn)檫@個(gè)上面的每個(gè)節(jié)點(diǎn)都需要做切割,甚至于只有一個(gè)備庫(kù)的需要做遷移,要盡量少做,壓力來(lái)了也得做,所以需要預(yù)估未來(lái)幾年幾乎不太可能做這樣的事情,這個(gè)估算是根據(jù)業(yè)務(wù)的發(fā)展速度和趨勢(shì)來(lái)決定的。
剩下是一種很常規(guī)但是很少用到的拆分,就是基于位圖的拆分,也就是認(rèn)為的講某個(gè)字段(這個(gè)字段的值是可以被列舉的),某些值放在某個(gè)放在某個(gè)表里面,也就是表的個(gè)數(shù)是被定義好的,拆分的個(gè)數(shù)收到值的個(gè)數(shù)的限制,除非和其他字段再進(jìn)行二次組合;雖然它本身用途不多,但是如果以range或hash作為前提它也有可能是有用途的。
上面闡述了幾種基本的拆分方法,都有各自有優(yōu)缺點(diǎn),為了更好的解決問(wèn)題,我們考慮得失,會(huì)考慮使用他們進(jìn)行組合,組合的方法根據(jù)實(shí)際情況而定,如我們?cè)谝恍?shù)字列上,既想考慮擴(kuò)展性,又想考慮負(fù)載均衡,那么在可接收的條件下,那么我們將range-hash或hash-range,至于是那一種要看具體情況,我們簡(jiǎn)單說(shuō)下range-hash,它在做range的時(shí)候,每個(gè)hash值就面對(duì)多個(gè)主機(jī)目標(biāo),在這部分主機(jī)目標(biāo)內(nèi)部做相應(yīng)的hash負(fù)載均衡,如果出現(xiàn)熱點(diǎn),在這個(gè)range內(nèi)部做二次拆分,其他的range是不需要的,如果負(fù)載較低,可以合并一些數(shù)據(jù),range拆分的條件只是負(fù)責(zé)某個(gè)數(shù)據(jù)段的數(shù)據(jù)太多,較為均衡的分布數(shù)據(jù),多個(gè)range如果以后不是怎么用了,可以將多個(gè)range的數(shù)據(jù)進(jìn)行再次合并(這個(gè)代價(jià)相對(duì)較大,因?yàn)槊總€(gè)range下面的hash規(guī)則可以是不一樣的,但是如果只要2的多少次方來(lái)完成這個(gè)動(dòng)作,就不會(huì)出現(xiàn)太大的問(wèn)題);而面對(duì)字符串的數(shù)據(jù),或者不是自動(dòng)增長(zhǎng)類(lèi)的數(shù)據(jù),range沒(méi)有辦法,因?yàn)榉秶豢深A(yù)知,雖然可以通過(guò)ascii來(lái)取,我們的范圍也可以用正無(wú)窮和負(fù)無(wú)窮來(lái)代表,但是我們無(wú)法保證數(shù)據(jù)的均衡的,所以建議還是先做hash,而在拆分的過(guò)程中,為了使得應(yīng)用不停需要設(shè)置一個(gè)版本號(hào),也就是拆分過(guò)程中,的時(shí)間戳標(biāo)記,所有在這個(gè)時(shí)間點(diǎn)以后的數(shù)據(jù)都在新的分布式規(guī)則中,老的數(shù)據(jù)讀取的時(shí)候在老的規(guī)則中,然后可以遷移數(shù)據(jù),但是遷移過(guò)程中性能是很低的,遷移完成后就將中間規(guī)則去掉就完成了整個(gè)的拆分過(guò)程,這個(gè)拆分過(guò)程就不局限于必須是2倍拆分了。
有關(guān)組合條件有很多,可以根據(jù)自己的應(yīng)用場(chǎng)景去選取不同的組合方法,使得它的性能最佳,盡量少出現(xiàn)跨庫(kù)跨表的操作,如果是按照非拆分字段進(jìn)行查詢(xún),要么做二級(jí)拆分,要么就是做索引表,索引表也可以是拆分的表,也就是先查索引表然后再?gòu)乃饕淼玫降闹鞅淼姆直碜侄稳フ抑鞅韮?nèi)容(但是由于索引表的結(jié)構(gòu)完全又開(kāi)發(fā)人員自己定義,所以索引表的維護(hù)完全是程序來(lái)控制,一致性需要開(kāi)發(fā)人員來(lái)保證)。
如上,拆分解決了很多問(wèn)題,也帶來(lái)了很多新問(wèn)題,如維護(hù)成本極度上升,需要大量外圍軟件來(lái)支持,否則發(fā)生任何問(wèn)題將無(wú)從下手;其二,開(kāi)發(fā)人員要編寫(xiě)很多的代碼來(lái)處理路由規(guī)則信息和分布式的一致性數(shù)據(jù)的問(wèn)題;切分和數(shù)據(jù)庫(kù)切換過(guò)程中,一次要切換一大堆機(jī)器,應(yīng)用重啟時(shí)間很長(zhǎng);動(dòng)態(tài)擴(kuò)展要實(shí)現(xiàn)就需要非常復(fù)雜的代價(jià)。
為了解決第一個(gè)問(wèn)題,公司需要較好的基層架構(gòu)的人員,來(lái)編寫(xiě)很多外圍的類(lèi)似分布式一致性監(jiān)控、問(wèn)題跟蹤處理等工具軟件,并且這些軟件要可持續(xù)的,否則經(jīng)常換成本永遠(yuǎn)無(wú)法控制,只要基層做好了,以后這些成本就會(huì)越來(lái)越少了,或者這些成本在同等的業(yè)務(wù)水平下會(huì)越來(lái)越少。
為了解決第二個(gè)問(wèn)題,讓開(kāi)發(fā)來(lái)編寫(xiě)路由等信息肯定是不合理的,一個(gè)是很多開(kāi)發(fā)人員水平有限,數(shù)據(jù)是業(yè)務(wù)關(guān)鍵,路由更加保護(hù)這數(shù)據(jù)存儲(chǔ)在哪里,所以要是代碼寫(xiě)得不好就死定了;于是我們需要獨(dú)立中間件,這個(gè)中間件可以只是保留在應(yīng)用中的一個(gè)算法,也可以是一個(gè)獨(dú)立的服務(wù)模式,服務(wù)模式為了保證其不是單點(diǎn)問(wèn)題以及訪問(wèn)壓力過(guò)大,需要優(yōu)化的是提供服務(wù)應(yīng)當(dāng)是一個(gè)集群,而所有訪問(wèn)它的應(yīng)用系統(tǒng)應(yīng)當(dāng)做一定算法的本地緩存來(lái)處理;這又回到我們上一章節(jié)說(shuō)的應(yīng)用系統(tǒng)的拆分了。
為了解決第三個(gè)問(wèn)題,切換要讓?xiě)?yīng)用不知道,那么就要讓?xiě)?yīng)用感覺(jué)不到IP、PORT、庫(kù)名稱(chēng)的變化,那么就必須將這些東西抽象出來(lái),抽象為如上所示的獨(dú)立服務(wù)模式或本地配置,當(dāng)一個(gè)統(tǒng)一的配置被修改后,將會(huì)通知相關(guān)的應(yīng)用系統(tǒng)進(jìn)行修改,并一致性將多套機(jī)器全部一次性切換完成。
為了解決第四個(gè)問(wèn)題,我們想了很多拆分的動(dòng)態(tài)擴(kuò)展性,但是算法十分復(fù)雜,就增加第二個(gè)中間件的復(fù)雜性,并且面臨各種風(fēng)險(xiǎn),所以傳統(tǒng)RDBMS的拆分再次受到水平擴(kuò)展的限制,人為介入太多,主要原因就是先獨(dú)立做數(shù)據(jù)庫(kù),再做上層管理,是一個(gè)從下到上的過(guò)程,也就是有問(wèn)題貼補(bǔ)丁的過(guò)程,而并非從一個(gè)站在高處把控一切的思想;于是為了解決更多的特殊的問(wèn)題,如數(shù)據(jù)量超級(jí)大,而且增量也很多,讀的訪問(wèn)非常多的情況,nosql這種低耦合的拆分技術(shù)出現(xiàn)了,也是云計(jì)算來(lái)臨的基礎(chǔ)(現(xiàn)在云計(jì)算這個(gè)詞匯徹底被用亂了,尤其是中國(guó),太過(guò)分了,這么好歌東西,在國(guó)內(nèi)就被到處使用,用著當(dāng)招牌,對(duì)此我表示無(wú)語(yǔ)),關(guān)于這部分不是本文的重點(diǎn),最后一章節(jié)會(huì)簡(jiǎn)單提及一些bigtable的思路和原理,以及其開(kāi)源版本的實(shí)現(xiàn)HBase的大概的架構(gòu)模式。
Nosql技術(shù)概述:
谷歌是一家偉大的互聯(lián)網(wǎng)公司,其引領(lǐng)著互聯(lián)網(wǎng)時(shí)代的發(fā)展,bigtable的經(jīng)典一直在世界各大互聯(lián)網(wǎng)公司所效仿,后來(lái)還有多個(gè)升級(jí)版本,但是大家還是喜歡叫他bigtable;谷歌取名字很奇怪,就是直截了當(dāng),bigtable就是大表,什么樣的表的是大表,每個(gè)幾十億、幾百億、幾千億什么的,不是大表,谷歌的架構(gòu)可以承受萬(wàn)億級(jí)別的數(shù)量,它的MapReduce也是一個(gè)非常簡(jiǎn)單的名詞,也就是先做Map處理(也就是將需要分析的目標(biāo)中將需要分析的有效數(shù)據(jù)提取出來(lái)并組織為K-V結(jié)構(gòu)),而Reduce就負(fù)責(zé)將這些K-V數(shù)據(jù)進(jìn)行處理;Apache也是一家偉大的公司,開(kāi)源社區(qū)的大拿,在java界更加孕育了非常多的經(jīng)典,它的Hadoop架構(gòu)就是仿照谷歌的架構(gòu)來(lái)完成的,這套架構(gòu)完全是java編寫(xiě)的,這個(gè)公司也有自己的特點(diǎn),就是很多名字都是動(dòng)物的名字,hadoop號(hào)稱(chēng)就是大象的崛起,呵呵,這個(gè)hadoop架構(gòu)里頭有什么:pig、zookeeper就是什么豬、公園什么的意思,整個(gè)就是動(dòng)物園,他們不需要多么玄的名字,就是純屬喜歡什么就用用什么,甚至于某些食物的名字或某個(gè)親人的名字。
Hadoop雖然還不可以和谷歌的架構(gòu)抗衡(基本差一個(gè)到兩個(gè)數(shù)量級(jí)),但是對(duì)于絕大部分的應(yīng)用是絕對(duì)沒(méi)有問(wèn)題,在分布式運(yùn)算上,它的MapReduce架構(gòu)可以支撐4000臺(tái)(在雅虎)的機(jī)器同時(shí)進(jìn)行分布式運(yùn)算;對(duì)于線上應(yīng)用就是其子模塊的HBase架構(gòu),全世界最大的是960臺(tái)(也是在雅虎)。
HBase算是nosql中的一種,每一種nosql都是為了解決某些特殊的問(wèn)題而存在,因?yàn)榍懊婵吹椒植际降牟鸱址椒ㄓ泻芏喾N,nosql也不可能解決所有的問(wèn)題,HBase總體來(lái)講需要配合的子系統(tǒng)有多個(gè)Region Server、Zookeeper、Master、HDFS來(lái)配合,其中HDFS為存儲(chǔ)引擎,所有和hadoop相關(guān)的內(nèi)容不論是不是HBase都基本是存在這個(gè)上面的,少部分內(nèi)容是存儲(chǔ)在本地文件(如MapReduce中Map后的中間結(jié)果可能會(huì)用本地文件來(lái)存儲(chǔ),因?yàn)橛猛旰笾虚g數(shù)據(jù)就沒(méi)有用了,沒(méi)有必要放在HDFS上面);Zookeeper就是公園,管理這些動(dòng)物,哪里出事或者門(mén)票都是它說(shuō)了算,在這里如果誰(shuí)宕機(jī)了(那個(gè)Region server宕機(jī)了),它要知道,然后告訴Master(管理者)去處理這些問(wèn)題,Master宕機(jī)了就會(huì)啟動(dòng)備用的Master,客戶(hù)端要請(qǐng)求首先就就是從Zookeeper請(qǐng)求,Zookeeper從Master哪里得到數(shù)據(jù)分布信息后,反饋給客戶(hù)端,客戶(hù)端會(huì)緩存主分布信息,然后開(kāi)始訪問(wèn),如果訪問(wèn)不到就再次請(qǐng)求Zookeeper,所以Zookeeper必須是多臺(tái)機(jī)器才能保證穩(wěn)定性。
也就是客戶(hù)端最終訪問(wèn)的Region Server(其實(shí)這里可以看得出來(lái)它是基于范圍,但是這個(gè)范圍絕對(duì)不是基于某個(gè)自動(dòng)增長(zhǎng)列什么的,而是基于數(shù)據(jù)的字節(jié)碼匹配,可以放中文、數(shù)字什么的都可以,但是放進(jìn)去前都需要轉(zhuǎn)換為二進(jìn)制,所以轉(zhuǎn)換的過(guò)程完全是業(yè)務(wù)層自己定義的),這個(gè)東西你就可以理解為一個(gè)JVM節(jié)點(diǎn),數(shù)據(jù)cache在內(nèi)存的是memstore,內(nèi)部存儲(chǔ)很多storefile,以hfile為單位,對(duì)文件進(jìn)行讀寫(xiě);memstore一般都是64M兩個(gè)之間來(lái)回寫(xiě),一個(gè)寫(xiě)滿就flush,另一個(gè)也在寫(xiě),如果另一個(gè)寫(xiě)滿了,這個(gè)flush還未完成,就要鎖住兩個(gè)部分。
Region Server負(fù)責(zé)和HDFS通信,其另一個(gè)需要做的就是HLog的編寫(xiě),Hlog一般是數(shù)據(jù)實(shí)時(shí)寫(xiě)的,但是也可以不是實(shí)時(shí)寫(xiě)的;HBase數(shù)據(jù)的版本個(gè)數(shù)等方面都是可以設(shè)置的,并且可以保證單個(gè)操作的一致性;Master在初始化的時(shí)候,就會(huì)從HDFS上去獲取字典Meta信息,所以這些內(nèi)容都是存儲(chǔ)在HDFS上的。
OK,這部分并不是本文的重點(diǎn),本文重點(diǎn)在于拆分,這里攜帶闡述了下HBase,但是它也有很多問(wèn)題,相信問(wèn)題最多的就是他是用java做的,對(duì)于后端的實(shí)時(shí)應(yīng)用一旦發(fā)生GC就有很多的問(wèn)題,尤其是我們前面也簡(jiǎn)單說(shuō)了下GC對(duì)于這種半長(zhǎng)命的鬼東西是很有問(wèn)題的;其次是雖然ZK可以發(fā)現(xiàn)宕機(jī),但是時(shí)間很長(zhǎng),這個(gè)心跳時(shí)間設(shè)置太短可能會(huì)是一種假死,心跳時(shí)間太長(zhǎng)就宕機(jī)很多也不會(huì)被人發(fā)現(xiàn),總之還有很多問(wèn)題,但是在JVM進(jìn)步的同時(shí),我們相信這些問(wèn)題都可以得到解決,OK,本文就寫(xiě)到這里,后續(xù)會(huì)參數(shù)拆分后各種問(wèn)題的一些常見(jiàn)的解決方法。
聯(lián)系客服