本文牽扯的面積可能會(huì)比較泛,或者說比較大,在這個(gè)層面很多人也有自己的見解,所以我這也僅僅是拋磚引玉,結(jié)合前面講述的一些基礎(chǔ)技術(shù),從思想中闡述更為深入的架構(gòu)思想基礎(chǔ),因?yàn)樽詈玫募軜?gòu)思想是架構(gòu)師結(jié)合實(shí)際情況思考出來最適合的架構(gòu),這里僅僅說明下一些常用的原理和思想,主要包含的內(nèi)容有(內(nèi)容很泛,所以都是簡(jiǎn)單闡述入門知識(shí),具體后續(xù)深入探討): 1、app切分集群組擴(kuò)展 2、app集群組負(fù)載均衡 3、Memcached原理 4、db cache應(yīng)用 5、db存儲(chǔ)類型以及存儲(chǔ)cache說明 6、存儲(chǔ)條帶思想 7、數(shù)據(jù)庫(kù)集群 8、數(shù)據(jù)庫(kù)分布式存儲(chǔ) 9、數(shù)據(jù)庫(kù)容災(zāi)備份以及監(jiān)控 10、nosql思想 11、無鎖分析
1、app切分集群組擴(kuò)展
應(yīng)用系統(tǒng)架構(gòu)隨著外部并發(fā)量的增加,必然導(dǎo)致的是app應(yīng)用的壓力逐漸增加,并且絕大部分app對(duì)于線程的分配能力都是有限的,但是app應(yīng)用在擴(kuò)展上是非常容易的,最基礎(chǔ)的就是一種應(yīng)用的垂直切割,其次是水平切割。
在了解app切割原理的基礎(chǔ)上先來了解一個(gè)其他的概念就是,就是Internate的路由器如何路由你請(qǐng)求的一個(gè)URL,你發(fā)送的URL并不知道路由器發(fā)送到哪里去了,最終路由到遠(yuǎn)端的服務(wù)器(互聯(lián)網(wǎng)本身就是一個(gè)云計(jì)算為基礎(chǔ)的平臺(tái)),到了遠(yuǎn)程后,它如何找到自己的應(yīng)用呢,以及應(yīng)用下具體的服務(wù)內(nèi)容呢?就是通過URL后面部分的標(biāo)識(shí)符號(hào)。也就是在云的最終技術(shù)也是各自管理各自的內(nèi)容,而云之所謂稱之為云是因?yàn)槟銦o須關(guān)心你發(fā)送的URL是如何路由到遠(yuǎn)端的服務(wù)器的,又是如何通過哪些路由器返回回來的。這里不深入討論云的概念,回到主題上是說遠(yuǎn)端的服務(wù)器每一個(gè)目標(biāo)都有自己處理的對(duì)象,或者說不同的路徑下或者不同的端口下都會(huì)有自己的處理服務(wù)。所以app系統(tǒng)切割的基本思想就是路徑。
當(dāng)一個(gè)系統(tǒng)業(yè)務(wù)十分復(fù)雜,應(yīng)用并發(fā)量很大的情況下,必然導(dǎo)致的一個(gè)步驟就是業(yè)務(wù)分解,將一個(gè)大的系統(tǒng)拆分為多個(gè)小系統(tǒng),不論是軟件本身設(shè)計(jì)的可擴(kuò)展性還是軟件性能擴(kuò)展性都會(huì)有很大的幫助,比如在各個(gè)子系統(tǒng)之間他們的業(yè)務(wù)的復(fù)雜性以及并發(fā)量都會(huì)有很大的區(qū)別,我們可以將這些小系統(tǒng)拆分到不同的集群節(jié)點(diǎn)上去,這些集群節(jié)點(diǎn)可以是由同一個(gè)主機(jī)發(fā)布出來的不同端口或者URL,或者是不同的主機(jī)發(fā)布出來的內(nèi)容,并且三者可以根據(jù)實(shí)際情況調(diào)整使得成本、軟件擴(kuò)展性、性能擴(kuò)展性達(dá)到較好的程度,總之將一個(gè)大系統(tǒng)拆分為多個(gè)小系統(tǒng)是第一個(gè)需要做的,也就是app應(yīng)用拆分,這種并不難,但是拆分的依據(jù)一定要把控好,而且還有一個(gè)總體架構(gòu),不然軟件最終會(huì)做的五花八門;在很多的應(yīng)用下都會(huì)使用,只是在這種拆分,拆分后除上述的總體設(shè)計(jì)要做好外,還需要主意的一點(diǎn)就是系統(tǒng)通信問題,子系統(tǒng)拆分后應(yīng)該是高內(nèi)聚的,但是免不了需呀通信,否則就根本不算是一個(gè)系統(tǒng)的,而且即使不是同一個(gè)系統(tǒng)也有可能因?yàn)榉?wù)需求而需要去通信,所以在通信上需要多下功夫,在不同服務(wù)器以及語言之間通信最麻煩的事情就是字符集,也是需要主意的,不過不是本文的重點(diǎn)。
在上面拆分完成后,當(dāng)某一個(gè)子系統(tǒng)的并發(fā)量非常大的時(shí)候,我就需要單獨(dú)對(duì)某一個(gè)子系統(tǒng)進(jìn)行拆分了,這種沒的選,一般不太可能通過URL來控制(除非申請(qǐng)不同的VIP或者在同一個(gè)主機(jī)上用不同的虛擬目錄來做,不過是不是有點(diǎn)挫),這種一般是通過在不同的服務(wù)端口(也稱為運(yùn)行節(jié)點(diǎn),在同一個(gè)主機(jī)上多個(gè)節(jié)點(diǎn)肯定是不同的端口的),或者發(fā)布到不同的主機(jī)上來完成;這部分拆分app應(yīng)用不會(huì)受到太大的限制;這個(gè)地方需要主意的是,當(dāng)你在app內(nèi)部做靜態(tài)內(nèi)存時(shí),就無法做到當(dāng)一個(gè)機(jī)器的內(nèi)存修改后同時(shí)修改到其他內(nèi)存中,除非你自己寫程序要么定時(shí)刷新要么相互之間傳送數(shù)據(jù),但是這兩種都會(huì)付出巨大的成本,如何解決呢,我們后面會(huì)說到的Memcached就是解決的方法。
上述兩者完成后,新的問題出現(xiàn)了,就是子系統(tǒng)之間的通信,他們不再是單機(jī)對(duì)單機(jī)的通信,而是集群組對(duì)集群組的通信,所以子系統(tǒng)中間件必然有一些非一對(duì)一的通信機(jī)制就出現(xiàn)了,以及中途產(chǎn)生的同步通信和異步通信等機(jī)制,如IBM MQ、EJB、Webservice、HttpClient、HttpInvokie、RPC、Socket甚至于借助于數(shù)據(jù)庫(kù)或者文件作為中間層等等都是通信機(jī)制的基礎(chǔ),應(yīng)用非常特殊的公司會(huì)自己寫自己的通信機(jī)制。
有了上述的集群,URL可以通過網(wǎng)絡(luò)路由到具體的服務(wù)器,但是服務(wù)器下每一個(gè)集群節(jié)點(diǎn)不可能都去申請(qǐng)一個(gè)URL吧,而且客戶也不會(huì)自己知道我第一次用URL1,下一次用URL2、再下一次用URL3來給你服務(wù)器做負(fù)載均衡吧,客戶只知道用一個(gè)URL訪問你,而且那么多的IP在互聯(lián)網(wǎng)上也會(huì)占用非常大的資源,所以很多時(shí)候,一個(gè)大網(wǎng)站后臺(tái)可能數(shù)萬的主機(jī),前端暴露的IP可能只有幾個(gè),這個(gè)可以成為VIP,他們之間有一個(gè)綁定關(guān)系,由這個(gè)VIP來負(fù)責(zé)域名的幫頂,而VIP一般會(huì)綁定在一個(gè)負(fù)載均衡器上面,由負(fù)載均衡器根據(jù)實(shí)際請(qǐng)求內(nèi)容負(fù)載到具體的主機(jī)上面去,下面第二章就是我們要寫的負(fù)載均衡基本原理。
2、app集群組負(fù)載均衡
所謂負(fù)載均衡就是負(fù)載均衡了,呵呵,也就是不讓某太機(jī)器單獨(dú)忙,也不讓某臺(tái)機(jī)器太閑,將請(qǐng)求進(jìn)行分發(fā),這就是負(fù)載均衡器設(shè)計(jì)的初衷了。
隨著發(fā)展的變化,負(fù)載均衡器需要承擔(dān)更大的作用 第一個(gè)需要做的就是請(qǐng)求解析,也就是很多不同的應(yīng)可能由一個(gè)負(fù)載均衡器來完成; 進(jìn)一步,同一個(gè)應(yīng)用發(fā)布的不同的節(jié)點(diǎn)或者不同的端口,負(fù)載均衡器可以識(shí)別出來并達(dá)到分發(fā)負(fù)載,將并發(fā)負(fù)載到很多不同的節(jié)點(diǎn)上去運(yùn)行; 再進(jìn)一步,某個(gè)客戶端請(qǐng)求第一次訪問了某個(gè)節(jié)點(diǎn)后,當(dāng)session未失效時(shí),應(yīng)當(dāng)做到繼續(xù)訪問同一臺(tái)主機(jī),這樣保證客戶在多次交互中session內(nèi)容是一致的,至少不會(huì)導(dǎo)致重新登陸等現(xiàn)象; 再進(jìn)一步,在節(jié)點(diǎn)失敗是,負(fù)載均衡器應(yīng)當(dāng)識(shí)別出來,并可以將訪問切換到其他主機(jī),在有必要的情況下需要做session復(fù)制。
負(fù)載均衡最基本的需要做到以上幾點(diǎn)內(nèi)容才算負(fù)載均衡。 負(fù)載均衡器一般需要的內(nèi)容是全局的,但是它并不關(guān)注與細(xì)節(jié),所以它主要做的事情是全局資源定位,監(jiān)控,負(fù)載均衡,切換動(dòng)作;一般會(huì)有一個(gè)單獨(dú)的管理節(jié)點(diǎn)和單獨(dú)的分發(fā)節(jié)點(diǎn),但是每一門負(fù)載均衡的機(jī)制在設(shè)計(jì)層面都會(huì)有很大的區(qū)別,所以無需一概而論。
因?yàn)樨?fù)載均衡器在所有應(yīng)用的最前端,所以我們非常關(guān)注于它的性能,有很多基于高級(jí)語言編寫的負(fù)載均衡器,甚至于你可以直接通過你的JSP、ASP、PHP等等做一個(gè)簡(jiǎn)單的控制跳轉(zhuǎn)上的負(fù)載均衡,但是他們的性能就很低了,擴(kuò)展性受到明顯的限制,Linux內(nèi)核才是負(fù)載均衡器的王道,終極方案,要深入研究和負(fù)載均衡的方案,請(qǐng)大家多多參詳Linux內(nèi)核。
目前市面上非常常用的負(fù)載均衡器是apache,它本身也可以作為WEB服務(wù)器來應(yīng)用(它的一些模塊就可以直接用于php),另外weblogic自帶的proxy+domain+managed模式也是一種負(fù)載均衡方法,不過我做過幾個(gè)版本效果不理想,主要原因還是主要是因?yàn)閷?shí)現(xiàn)的基礎(chǔ)是高級(jí)語言吧;而apache雖然性能不錯(cuò),而且大家廣受喜愛的一種東西,不過隨著互聯(lián)網(wǎng)并發(fā)量的上升,apache在很多極為高并發(fā)的系統(tǒng)中仍然受到擴(kuò)展性的限制,于是乎ngnix出現(xiàn)了,它是目前高并發(fā)網(wǎng)站應(yīng)用中最廣泛或者說在大網(wǎng)站中用得最多的負(fù)載均衡器,國(guó)內(nèi)的大網(wǎng)站基本都有它的影子,它是俄羅斯一位工程師編寫,而且是免費(fèi)的,性能極高,占用資源極少,并且支持cache以及代理,很多客戶端訪問的機(jī)制都可以配置化,安裝和使用都非常簡(jiǎn)單(要深入研究就沒那么簡(jiǎn)單),而且故障率非常低,為什么那么好,因?yàn)樗幕A(chǔ)就是unux內(nèi)核,沒有別的,當(dāng)然寫代碼一定要寫得很好才行;當(dāng)然國(guó)內(nèi)并非沒有這樣的人才存在,而且要看公司是否給這類人才一個(gè)機(jī)會(huì)去完成這樣一個(gè)東西,因?yàn)樽约簩懙目赡軙?huì)更加適合于自己,其實(shí)國(guó)內(nèi)也有很多對(duì)Unix內(nèi)核研究很深入的頂尖高手。
3、Memcached原理 這一章本身就想在數(shù)據(jù)庫(kù)后面說明的,不過由于只是簡(jiǎn)單介紹,而且后面應(yīng)該幾乎都是技術(shù),所以就這這里說明了。
一般應(yīng)用程序除了處理業(yè)務(wù)邏輯和一定的計(jì)算后,就是訪問數(shù)據(jù)庫(kù),做數(shù)據(jù)庫(kù)的存、取、事務(wù)操作,在OLAP會(huì)有更多的是在數(shù)據(jù)庫(kù)端的計(jì)算,OLAP不是本文的重點(diǎn),因?yàn)镺LAP不會(huì)涉及并發(fā)量的問題,所以更多偏重于OLTP,而且是極高并發(fā)的系統(tǒng)。
當(dāng)前端app并發(fā)達(dá)到一定程度,即將考慮的問題就是數(shù)據(jù)庫(kù)的壓力,數(shù)據(jù)庫(kù)面對(duì)的更多的數(shù)據(jù),雖然它在各方面做了非常大的優(yōu)化,不過它畢竟是存大量鎖機(jī)制和磁盤讀寫操作,來保證數(shù)據(jù)一致性和安全性,而這兩者往往是影響性能的關(guān)鍵指標(biāo),但是我們很多時(shí)候又不得不用數(shù)據(jù)庫(kù),因?yàn)樗梢蕴峁┙o我們的東西實(shí)在是太多了。
在互聯(lián)網(wǎng)應(yīng)用中有個(gè)幾乎所有網(wǎng)站都會(huì)擁有的一個(gè)共同特征那就是讀取次數(shù)非常多,而寫的次數(shù)相對(duì)比例較少(并不代表沒有寫操作),此時(shí)人們?cè)谠O(shè)計(jì)上第一個(gè)想法是讓數(shù)據(jù)庫(kù)來完成主備或者鏡像方式上的讀寫分離,不過始終會(huì)與數(shù)據(jù)庫(kù)交互,而且擴(kuò)展上會(huì)受到非常大的限制,在極高并發(fā)下,人們又對(duì)應(yīng)用做了對(duì)頁面輸出html的方式,但是最終發(fā)現(xiàn)在實(shí)施過程中會(huì)受到很多限制(尤其是ajax交互),雖然有很多軟件可以支持,此時(shí)很多人想到將數(shù)據(jù)載入到內(nèi)存中,按照某種方式刷新內(nèi)存即可,不過我們上面已經(jīng)討論,在集群下它很難做到每個(gè)被切割開的節(jié)點(diǎn)他們之間的靜態(tài)內(nèi)存是一致的,所以Memcached出現(xiàn)了。
Memcached我看網(wǎng)上寫它是分布式的,這個(gè)大家最好不要亂理解,因?yàn)閺幕镜脑O(shè)計(jì)上講,它只是將app和靜態(tài)內(nèi)存分開了,而并非真正意義上做到分布式(真正意義上的分布式應(yīng)當(dāng)自動(dòng)將多個(gè)Memcached節(jié)點(diǎn)的訪問如同訪問一個(gè)節(jié)點(diǎn)一樣簡(jiǎn)單),而一般Memcached的訪問方式還是通過程序去控制的,而多個(gè)不同節(jié)點(diǎn)劃分,也是通過人為的完成的,你可以認(rèn)為你訪問的Memcached是數(shù)據(jù)庫(kù)一樣的東西,因?yàn)樗脑L問方式類似于數(shù)據(jù)庫(kù),但是它如果命中肯定比訪問數(shù)據(jù)庫(kù)要快很多,而且可以大量減少讀的壓力,因?yàn)橐粋€(gè)大網(wǎng)站百分之八九十以上的壓力來源于讀;一個(gè)好的Memcached設(shè)計(jì)會(huì)使得讀命中率達(dá)到95%以上,而其成本只需要大內(nèi)存,并具有極大的擴(kuò)展性;根據(jù)實(shí)際系統(tǒng)的場(chǎng)景講Memcached劃分?jǐn)?shù)據(jù)的方法指定,當(dāng)命中是獲取,當(dāng)修改時(shí)先修改數(shù)據(jù)庫(kù),然后讓對(duì)應(yīng)的cached失效即可;主意解決如果它掛掉會(huì)產(chǎn)生什么問題,它的基礎(chǔ)原理是一種Key-Value方式,但是通用的東西往往不是性能最佳的東西,所以你在有必要的情況下可以適當(dāng)做下修改,淘寶網(wǎng)的tair開源技術(shù)就是一套自己完成的分布式緩存技術(shù),也是很不錯(cuò)的選擇。
4、db cache應(yīng)用 上述已經(jīng)描述到數(shù)據(jù)庫(kù)訪問會(huì)有大量的磁盤操作,這里我們說下oracle是如何緩解這些問題的,以至于它一直在數(shù)據(jù)庫(kù)領(lǐng)域處于行業(yè)界得老大哥形象出現(xiàn)。
它首先由一個(gè)SGA的全局區(qū)域,內(nèi)部的其他區(qū)域已經(jīng)在前面的文章中說明,中間對(duì)于數(shù)據(jù)層面,最重要的就是databuffer了,這個(gè)databuffer是采用基于LRU算法為基礎(chǔ)的方式來完成的所以只要有足夠大的內(nèi)存,在讀遠(yuǎn)大于寫的情況下命中率也會(huì)非常高(其實(shí)oracle做寫操作也是寫內(nèi)存的,即使你commit命令oracle也不會(huì)做磁盤寫,但是它會(huì)寫日志,當(dāng)達(dá)到一定并發(fā)量日志寫也是不可估量的,而且臟塊列表也會(huì)非常頻繁的被刷新到磁盤上,也很容易出現(xiàn)瓶頸),data buffer這也是db cache最為核心的部分,當(dāng)然還有些其他區(qū)域也有一定的cache思想。
一般來說,對(duì)于極為高并發(fā)的系統(tǒng),數(shù)據(jù)庫(kù)的cached逐漸受到限制,雖然oracle rac可以非常高效的擴(kuò)展,但是其限制最多是64節(jié)點(diǎn)的整列結(jié)構(gòu),而且在這個(gè)過程中并非沒有鎖,尤其是在集群下的全局鎖機(jī)制,這個(gè)開銷也是很大的,但是我們很多時(shí)候訪問很多數(shù)據(jù)并非需要鎖,也就是這些數(shù)據(jù)是在這段時(shí)間內(nèi)我們確定不會(huì)被修改或者說根本不會(huì)被修改甚至于說修改了一個(gè)簡(jiǎn)單臟數(shù)據(jù)的延遲讀也是無所謂的,這類數(shù)據(jù)我們沒有必要讓他來和其他需要做絕對(duì)一致性的事情套在一起,該做事務(wù)的被阻塞了,可以間接做事務(wù)的也被阻塞了,所以在更多的層面我們希望的是app端做好cache,才是更好的方案,通常app的性能會(huì)占用整個(gè)系統(tǒng)性能指標(biāo)的50%以上,而有20%在于數(shù)據(jù)庫(kù)端,另外還有設(shè)計(jì)方案、存儲(chǔ)等等其他的,以及SQL了。
在app設(shè)計(jì)cached后,數(shù)據(jù)庫(kù)更多的是做修改,讀顯得更加少,所以在app設(shè)計(jì)cached后,數(shù)據(jù)庫(kù)端的內(nèi)存可以保留,也可以節(jié)約一些出來也可以。 5、db存儲(chǔ)類型以及存儲(chǔ)cache說明 存儲(chǔ)就是指最終數(shù)據(jù)存放的位置,有些地方也叫做整列(因?yàn)楹芏鄷r(shí)候它是多個(gè)磁盤通過RAID完成的),存儲(chǔ)一般會(huì)有低端存儲(chǔ)、中端存儲(chǔ)、高端存儲(chǔ)。
存儲(chǔ)設(shè)備中最挫的就是本地硬盤了,一般都可以不認(rèn)為他是獨(dú)立的存儲(chǔ)設(shè)備;但是最終你會(huì)發(fā)現(xiàn)它在是最好的,呵呵,在分布式的架構(gòu)上,我們更加愿意選擇廉價(jià)的成本設(shè)備,并自己架構(gòu)主機(jī)來完成使得性能達(dá)到更高的程度;比如在一種順序?qū)懛浅6?、隨機(jī)讀非常多的場(chǎng)景下,我們就更加愿意選擇SSD硬盤來做存儲(chǔ),因?yàn)樗目傮w設(shè)計(jì)就非常適合這種情況。
低端存儲(chǔ)一般只有一個(gè)控制器,壞掉全部壞掉,沒有任何存儲(chǔ)cached,存磁盤操作。
中端存儲(chǔ)一般有2個(gè)控制器,可以做均衡負(fù)載,而且可以冗余保護(hù),壞掉一個(gè)性能會(huì)降低50%,并且有一定的cache設(shè)備,有些時(shí)候也會(huì)分讀cache和寫cache,IBM DS 8000屬于一種中端存儲(chǔ),不過它自稱是高端存儲(chǔ)設(shè)備,外部一般說他是偽高端設(shè)備。
高端存儲(chǔ),多個(gè)控制器相互冗余,壞掉一兩個(gè)性能影響較小,具體影響要看存儲(chǔ)成本和具體需求;EMC高端存儲(chǔ)就是非常流行的選擇,DMX3中還有一種讀cache鏡像和寫cache鏡像,在某些應(yīng)用下性能更加提升;不過高端存儲(chǔ)的成本極高,在必要的環(huán)境下才會(huì)使用,絕大部分企業(yè)會(huì)使用中端存儲(chǔ)設(shè)備。
存儲(chǔ)成本并非和性能或者說高可用性完全成正比,尤其是本身高可用性很好的情況下;所以在選擇存儲(chǔ)的時(shí)候再考慮當(dāng)前應(yīng)用下需要考慮的就是成本,主要是:數(shù)據(jù)存儲(chǔ)容量、電費(fèi)、網(wǎng)路帶寬;以及一個(gè)存儲(chǔ)在多少年后報(bào)廢等一起計(jì)算。
存儲(chǔ)的基本考量標(biāo)準(zhǔn)也是系統(tǒng)性能重點(diǎn)指標(biāo):IOPS、QPS、TPS、帶寬容量、單個(gè)請(qǐng)求響應(yīng)時(shí)間。
這些目前不做深入探討,以后我們?cè)僬f(因?yàn)樯婕皟?nèi)容非常多,而且和磁盤管理方式有關(guān)系,如下面的條帶就會(huì)對(duì)其影響),只做下簡(jiǎn)單介紹:
IOPS:磁盤陣列上每秒相應(yīng)IO次數(shù),這個(gè)IO次數(shù)不分讀寫,但是一般是OLTP系統(tǒng)中的小IO,一般用2K、4K這種來做測(cè)試(所以主意你在設(shè)計(jì)OLTP系統(tǒng)的數(shù)據(jù)庫(kù)block時(shí)為什么要小,因?yàn)樘崛∫粭l數(shù)據(jù)并不想用多次IO,而oracle提取數(shù)據(jù)的單位是block,mysql和sqlserver是頁);一般單個(gè)硬盤的IOPS會(huì)根據(jù)設(shè)計(jì)有關(guān)系,一個(gè)15k rpm 的IOPS一般是150個(gè),但是并非絕對(duì),可能會(huì)管理方式以及每個(gè)IO的大小有關(guān)系。
QPS和TPS是對(duì)IOPS的一個(gè)分解,其實(shí)本身沒這個(gè)概念,不過可以做這個(gè)來看出一個(gè)系統(tǒng)的讀寫比例以及讓系統(tǒng)以后如何設(shè)計(jì)來更好的工作。這兩個(gè)分別代表的是每秒的查詢次數(shù)、事務(wù)次數(shù);可以通過一些內(nèi)部SQL抓取等方法來實(shí)現(xiàn)。
IO帶寬:當(dāng)上述內(nèi)容完成后,就需要考慮帶寬了,當(dāng)你的IOPS可以上去后,但是帶寬上不去就悲劇了,那剛才的15k rpm來說,一般帶寬是13M/s,這里單位注意是字節(jié)(B),這里假設(shè)有120塊磁盤,那么也就是1560M/s,此時(shí)就需要通信上做一些支持,也就是要支持1G多的流量,需要光纖帶寬8Gb(這里是網(wǎng)絡(luò)上的大小,也就是二進(jìn)制大?。?,那么最少使用4塊2Gb的光纖卡;這種考慮基本在OLAP中比較多,而在OLTP系統(tǒng)中IO都是小IO,帶寬按照小IO的大小乘以IOPS已經(jīng)足夠。
響應(yīng)速度:這個(gè)因素就多了,除了上述的IOPS以及吞吐量以外,還和存儲(chǔ)cache有關(guān)系,甚至于和鎖都有關(guān)系,總之響應(yīng)速度算是一個(gè)最終結(jié)果,影響因數(shù)上面每一種都會(huì)有,具體需要根據(jù)實(shí)際系統(tǒng)來協(xié)調(diào),一般來說一個(gè)IO如果存磁盤操作最少需要10ms甚至于更多,而如果在cache中命中可能2ms左右就響應(yīng)了,也就是從單個(gè)IO來說,cache命中比正常磁盤操作要快5倍,而平均IO一般保持在10ms是比較良好的,很多時(shí)候非cache的情況下平均IO一般會(huì)達(dá)到20ms以上
6、存儲(chǔ)條帶思想 大家不要被這個(gè)詞匯所嚇到,它就是RAID0的另一種說法,其實(shí)RAID有很多種,從RAID0~RAID7每一種都有自己的特征所在,而且還有組合的,企業(yè)常用的有:RAID 10、RAID5、RAID3這幾種,本文不對(duì)磁盤陣列做詳細(xì)闡述,而只是通過條帶給帶出來一些思想。
RAID0,也就是條帶,它的思想源于負(fù)載均衡,和散列存儲(chǔ),最終在磁盤上的統(tǒng)一實(shí)現(xiàn),并將其作為磁盤組為中心,給外部調(diào)用,而無需關(guān)心磁盤的內(nèi)部細(xì)節(jié)。
它按照一定的數(shù)據(jù)順序,將數(shù)據(jù)分布逐個(gè)分布在多個(gè)磁盤上,所以看起來就像“條帶”一樣,同時(shí)不論在讀還是寫的過程中,它都將IO負(fù)載到了不同的磁盤上,使得IO的總體性能幾乎可以與磁盤數(shù)成正比,極大提高IO性能。
但是RAID0本身沒有保護(hù),也就是當(dāng)磁盤壞掉,數(shù)據(jù)就丟了,找不回來,所以后來出現(xiàn)各種各樣的RAID,根據(jù)不同的情況每一種RAID都會(huì)有自己的方式來處理,實(shí)現(xiàn)補(bǔ)充程度的冗余,還是那句話,發(fā)展到一定的冗余度將會(huì)導(dǎo)致成本直線上升,但是并不一定會(huì)帶來收益的直線上升;RAID10就是通過50%冗余完成,也就是一對(duì)一冗余完成,同一個(gè)整列下所有的數(shù)據(jù)壞掉也可以找回來,除非兩塊磁盤是相互冗余的磁盤同時(shí)壞掉;而RAID5屬于從RAID3、RAID4做一些算法改進(jìn)和性能提升上來的,其原理都是奇、偶校驗(yàn)碼原則,數(shù)據(jù)分布式按照條帶思想,冗余N+1塊磁盤,數(shù)據(jù)隨機(jī)存放在N塊磁盤上,剩余一塊做校驗(yàn)位,相對(duì)減少磁頭同步粒度,其中任意一塊磁盤壞掉,均可恢復(fù),但同一個(gè)RAID5陣列同時(shí)壞掉2塊不行。
順便提及下,ORACLE個(gè)只瘋狗什么東西都想獨(dú)霸,他的ASM就是拿出來和RAID競(jìng)爭(zhēng)的,它的管理可以基于裸機(jī),更加優(yōu)于基于操作系統(tǒng)層的調(diào)用,而在裸設(shè)備的管理上又會(huì)有很多新的講究。 7、數(shù)據(jù)庫(kù)集群 數(shù)據(jù)庫(kù)集群上,最初是通過一種操作系統(tǒng)機(jī)制HA完成,但是它在數(shù)據(jù)庫(kù)層面存在很多缺陷,相對(duì)管理數(shù)據(jù)庫(kù)來說還存在很多專業(yè)上的個(gè)性化,所以O(shè)RACLE在10g推出了ORACLE RAC(其實(shí)是9i,但是9i的集群做得很爛,所以可以認(rèn)為是10g才有的);另外10g之前的集群需要第三方的cluster軟件完成,10g后就有了oracle自己的CRS軟件,并且是免費(fèi)的,可以到官方下載。
數(shù)據(jù)庫(kù)集群除正常的app擁有的(load banlance)負(fù)載均衡、(failover)失敗切換,還有很多機(jī)制在內(nèi),包含主從關(guān)系、切換機(jī)制、以及分布式計(jì)算(網(wǎng)格計(jì)算(Grid)在ORACLE RAC中是一種最簡(jiǎn)單的實(shí)現(xiàn)方法,真正的網(wǎng)格計(jì)算是指在實(shí)際的網(wǎng)格環(huán)境下去管理網(wǎng)格下多個(gè)應(yīng)用的數(shù)據(jù)庫(kù)包括集群,他們是同一的,甚至于你無須關(guān)心網(wǎng)格下集群組之間的關(guān)系,就能非常清晰得去做操作了),這里的網(wǎng)格計(jì)算是指在一些大的統(tǒng)計(jì)下,在配置數(shù)據(jù)庫(kù)參數(shù)時(shí),將相應(yīng)的INSTANCE參數(shù)設(shè)置為集群分組,并開啟并行,在做一些大操作時(shí)就會(huì)實(shí)現(xiàn)多實(shí)例配合完成,也是通過心跳完成的。
數(shù)據(jù)庫(kù)集群的負(fù)載均衡一般是通過app端完成,這部分可能是client端的TNS配置(此時(shí)前提是通過cluster完成使用同一個(gè)service_name對(duì)應(yīng)多個(gè)SID),或者類似TNS配置在鏈接數(shù)據(jù)庫(kù)的URL中,它內(nèi)部一個(gè)重要參數(shù)就是LOAD_BALANCE等等,它可以設(shè)置為:(yes、on、true是等價(jià)的,不區(qū)分大小寫,即開啟負(fù)載均衡),相反,設(shè)置為(no、off、false)則為取消負(fù)載均衡,此時(shí)按照配置的遠(yuǎn)程主機(jī)IP或者域名的順序逐個(gè)訪問到一個(gè)可用的即可,此時(shí)一般會(huì)導(dǎo)致一臺(tái)機(jī)器忙一臺(tái)機(jī)器閑的情況,不過另一臺(tái)機(jī)器如果只是用來做備機(jī)器,當(dāng)一臺(tái)掛掉后切換過去也是可以的,一般用RAC我們也會(huì)將該參數(shù)開啟。
failover就是將數(shù)據(jù)庫(kù)的SQL切換到另一個(gè)機(jī)器上,但是事務(wù)會(huì)被回滾,具體是否切換或者如何切換要看其它參數(shù)配置,首先FAILOVER參數(shù)和上面參數(shù)的參數(shù)值一樣都是那樣設(shè)置,當(dāng)設(shè)置為開啟狀態(tài)就會(huì)進(jìn)行失敗切換,否則這個(gè)連接池的請(qǐng)求就會(huì)失??;而其它幾個(gè)參數(shù)一般是在開啟狀態(tài)下有默認(rèn)值的,自己也可以設(shè)置的哦,在FAILOVER_MODE配置中很多: 首先是TYPE參數(shù)的配置中一般有:session(失敗時(shí)候,所有內(nèi)容被中止,已經(jīng)操作的事務(wù)被回滾,創(chuàng)建新的session到另一個(gè)可用實(shí)例上)、select(設(shè)置為該參數(shù)和上面差不多,不過切換時(shí),開始被操作的事務(wù)雖然被回滾,但是如果是select語句不會(huì)被中斷,會(huì)繼續(xù)執(zhí)行),none(不做任何操作,直接回滾,也不接管,用于測(cè)試,客戶端會(huì)直接報(bào)錯(cuò)) 其次METHOD參數(shù),這個(gè)參數(shù)一般是有:basic(在發(fā)生失敗時(shí)候再在另一個(gè)實(shí)例上創(chuàng)建session回話節(jié)點(diǎn))、preconnect(預(yù)先設(shè)立回話節(jié)點(diǎn),有一定開銷,但是切換速度很快速,在主從模式下推薦)而RETRIES分別代表重試次數(shù)(默認(rèn)5)、DELAY代表每次重試時(shí)間片信息(默認(rèn)1秒)、BACKUP(備份節(jié)點(diǎn)的網(wǎng)路服務(wù)名) 集群RAC由于設(shè)計(jì)更加專業(yè)于數(shù)據(jù)庫(kù)應(yīng)用,所以他比起HA更加適用于數(shù)據(jù)庫(kù),也是眾多企業(yè)的選擇,它配合data guard(有些是extend rac是包含了這兩種功能)來完成備份,也有oracle的一直以來的終極備份方案rman來完成,不過前者更加偏重于容災(zāi),還有些關(guān)于復(fù)制以及遷移等功能不是本文重點(diǎn),不便多提及。 ORACLE RAC和相關(guān)的東西都是燒錢的東西,價(jià)格不菲,對(duì)各項(xiàng)硬件要求非常高,所以注意成本預(yù)算,如高速網(wǎng)絡(luò)以及各個(gè)INSTANCE連接共享存儲(chǔ)陣列的SAN交換機(jī)一般需要多個(gè)來冗余,心跳的交換機(jī)也需要冗余等等。 ORACLE RAC依賴于一個(gè)共享存儲(chǔ),做相應(yīng)INSTANCE和數(shù)據(jù)庫(kù)級(jí)別的管理,這也是數(shù)據(jù)庫(kù)和實(shí)例的區(qū)別了,那么它的瓶頸就在后端了,所以后端很多時(shí)候會(huì)選擇高端存儲(chǔ)來完成;另外它還有很多全局資源管理使得它的很多發(fā)展在這些瓶頸上出現(xiàn)問題,如它的節(jié)點(diǎn)一般最多支持64節(jié)點(diǎn),而隨著節(jié)點(diǎn)數(shù)量的增加,成本會(huì)直線上升,至于性能是否能直線上升呢,你應(yīng)該可以考慮下當(dāng)前的各種瓶頸在哪里,也需要和實(shí)際情況結(jié)合才好說。 8、數(shù)據(jù)庫(kù)容災(zāi)備份以及監(jiān)控 接下來一個(gè)系統(tǒng)設(shè)計(jì)應(yīng)該如何?需要做的就是容災(zāi)以及監(jiān)控運(yùn)行狀況是否良好,對(duì)于app端一般不需要容災(zāi),只需要監(jiān)控,而其一般是通過監(jiān)控內(nèi)存、CPU、磁盤使用量(主要是日志和本地緩存文件);如果監(jiān)控系統(tǒng)做得不好,那么我想很多DBA晚上睡不著(至于夜間做生產(chǎn)變更這類可以通過其他的自動(dòng)化程序完成),系統(tǒng)的發(fā)展也會(huì)受到限制,我們需要一個(gè)伸縮性很強(qiáng)的系統(tǒng)就必然會(huì)走這一步。
而數(shù)據(jù)庫(kù)容災(zāi)現(xiàn)在又很多方案,上面已經(jīng)說了,現(xiàn)在比較多的就是使用dataguard備份到一個(gè)或多個(gè)備份機(jī)器上,dataguard上有多種配置機(jī)制,來實(shí)現(xiàn)各種常用的要求,關(guān)于磁盤管理可以使用ASM來管理,數(shù)據(jù)庫(kù)也可以負(fù)責(zé)制過去,也可以異步通過程序度過去,也可以通過觸發(fā)器+dblink過去等等都可以實(shí)現(xiàn)。關(guān)鍵看實(shí)際需求。
數(shù)據(jù)庫(kù)的監(jiān)控,這個(gè)oracle也提供了系列的監(jiān)控軟件(Statspace、AWR、logmgr等等系列),不過很多時(shí)候我們需要更加精確的參數(shù)需要自己去編碼,否則就還是需要自己去查詢很多自己做報(bào)表什么的,而且很不直觀;長(zhǎng)期需要監(jiān)控的除了常用的IOPS、TPS、QPS以外,還需要關(guān)心很多如latch征用、sql parser(硬解析和軟解析的各方面指標(biāo))、cache命中率、鎖等待、內(nèi)存指標(biāo)變化、CPU指標(biāo)變化、索引、磁盤碎片等等都需要得到全方位的監(jiān)控
數(shù)據(jù)庫(kù)的管理應(yīng)當(dāng)自動(dòng)化,首先從監(jiān)控下手,完全自動(dòng)化管理和資源調(diào)配方面是一個(gè)理想,不過半自動(dòng)化也是很容易的,就是在有問題或者在一定情況下有某種方式的通知,如短信息吧。這樣DBA就不用成天盯著監(jiān)控或者后臺(tái)的某個(gè)字典表一直看了。 9、CDN思想基礎(chǔ) 后面幾個(gè)章節(jié)不是本文重點(diǎn),簡(jiǎn)單闡述下即可,在高可用性網(wǎng)站設(shè)計(jì)中,即使前端應(yīng)用增加了Memcached這類東西,不過始終不能很好的效果,要達(dá)到極佳的效果,因?yàn)楹芏鄷r(shí)候跨網(wǎng)段的開銷是非常大的,經(jīng)過的路由器越多開銷越大;其次很多時(shí)候,不愿意因?yàn)榇笪募敵觯ㄈ缫曨l下載)導(dǎo)致應(yīng)用服務(wù)器宕機(jī)的事情,這是沒有必要的,因?yàn)閼?yīng)用服務(wù)器更多關(guān)心的應(yīng)該是業(yè)務(wù)處理。
CDN的出現(xiàn)就是為了解決這個(gè)問題,也就是網(wǎng)站加速器,他需要運(yùn)營(yíng)商的配合(具體細(xì)節(jié)請(qǐng)自己查閱資料),在很多地方建立站點(diǎn),它需要做的事情就是托管DNS,通常DNS是解析域名成IP并訪問對(duì)應(yīng)IP內(nèi)容,而CDN做了一層重寫,就是通過域名解析得到的是一個(gè)CNAME,它按照提供CNAME會(huì)按照最短路徑找到對(duì)應(yīng)的CDN網(wǎng)點(diǎn),接受數(shù)據(jù),客戶端的數(shù)據(jù)接受更加快速,并且可以實(shí)現(xiàn)冗余保護(hù),另外它只是緩存在這里,可以認(rèn)為是本地的一個(gè)私服,也就是需要跨網(wǎng)段的流量都切換到本地了,這里做一個(gè)極端的假設(shè),就是跨網(wǎng)段的開銷是2,本網(wǎng)段拖數(shù)據(jù)是1,有100個(gè)請(qǐng)求時(shí),跨網(wǎng)段需要200的開銷,而本地網(wǎng)段就只需要101個(gè)開銷。
大文件下載,是通過緩存到本地的私服上,如視頻下載就很多時(shí)候這段時(shí)間大家看的都是熱播電影,就可以通過CDN來進(jìn)行網(wǎng)站加速。 10、nosql思想 根據(jù)上面的描述,我們很多時(shí)候就不想做到百分百的數(shù)據(jù)安全,或者一致性吧,比如做一個(gè)網(wǎng)站的留言板,數(shù)據(jù)有一點(diǎn)偏差也無所謂,而且數(shù)據(jù)庫(kù)的sql parser一般是很慢的,很容易達(dá)到極限,所以nosql的誕生就出現(xiàn)了,現(xiàn)在很多開源的nosql平臺(tái),它也是現(xiàn)有云存儲(chǔ)的基礎(chǔ),apache的hadoop以及谷歌的mapreduce后來做了一個(gè)Percolator,還有redis、mongodb等等,其實(shí)所謂nosql基礎(chǔ)的原理就是沒有sql,就想剛才說的Memcache一樣,只是它有存儲(chǔ)以及根據(jù)設(shè)計(jì)不同,會(huì)有一些會(huì)存在一些鎖機(jī)制,并且只是面向?qū)ο螅挥谢谛写鎯?chǔ)的、有基于列存儲(chǔ)的他們是根據(jù)實(shí)際應(yīng)用場(chǎng)景設(shè)計(jì)的一種類似于數(shù)據(jù)庫(kù)的東西,它具有極高的擴(kuò)展性和伸縮性,因?yàn)榭刂仆耆谟谀惚旧淼募軜?gòu)和設(shè)計(jì),也是我們一直所崇尚的:最好的東西肯定是最優(yōu)秀的人根據(jù)實(shí)際的場(chǎng)景所架構(gòu)出來的。
不論是哪一門,nosql它首先拋開的是sql parser的一種,但是它沒有了SQL的支持,在一些復(fù)雜操作上顯得比較困難(這些就要看具體場(chǎng)景和nosql的設(shè)計(jì)了);我們?cè)诮Y(jié)合上述幾種技術(shù)的基礎(chǔ)上如何不將Cached、nosql、RDBMS、app幾個(gè)結(jié)合起來,向后端移動(dòng),實(shí)現(xiàn)app調(diào)用完全無需關(guān)心很多調(diào)用的細(xì)節(jié),那么這就是真正的云存儲(chǔ)了,因?yàn)槭窃诜植际酱鎯?chǔ)基礎(chǔ)上以及cache管理的基礎(chǔ)上實(shí)現(xiàn)了對(duì)應(yīng)用的透明調(diào)用。
如何設(shè)計(jì)待以后專門有文章來闡述,今天只是一個(gè)開頭而已。 11、無鎖分析 通過上面的文章內(nèi)容,我們?cè)诤芏鄷r(shí)候很多不必要的信息沒有必要使用RDBMS一樣的鎖和同步等等動(dòng)作,所以所謂真正意義上的無鎖或者幾乎無鎖,就是將很多內(nèi)容抽象出來利用間接的方法來實(shí)現(xiàn)。
一般來說降低鎖的粒度有以下幾種方法: a.使用hash、range、位圖對(duì)數(shù)據(jù)進(jìn)行提前分布,讓其分框,根據(jù)實(shí)際情況而定,如果一個(gè)框只有一個(gè)線程在處理那么就幾乎可以算是無鎖了。 b.在一些特殊必要的應(yīng)用中,使用特殊的方法來控制,變通的方法來控制,如隊(duì)列中的對(duì)頭和隊(duì)尾算法,如果只有一個(gè)生產(chǎn)者和一個(gè)消費(fèi)者可以讓他們?cè)谝粋€(gè)定長(zhǎng)數(shù)組下跑圈圈即可,后者永遠(yuǎn)追不上前者,而多生產(chǎn)者多消費(fèi)者模式又該如何呢?比如多個(gè)線程做push操作,那么你只需要在多個(gè)線程以當(dāng)前隊(duì)頭下標(biāo)開始位置分配到不同的下標(biāo),幾個(gè)線程就可以無鎖操作了,那么如何分配到不同的下標(biāo)呢?用java的volatile,你可以認(rèn)為它是鎖的,不過它非常輕量級(jí)的鎖,只是在對(duì)使用volatile變量修改和讀取過程中強(qiáng)制從從新內(nèi)存中獲取,而不是寄存器,所以在計(jì)數(shù)器使用中,多個(gè)線程去同時(shí)修改這個(gè)變量并獲取到的值都是不同的;pop也是如此,這些有一定的應(yīng)用場(chǎng)景,棧也可以用變通的手段得到解決。 c.還有一些通過版本號(hào)碼、向量復(fù)制、臟塊列表等等思想來實(shí)現(xiàn),都有一些應(yīng)用場(chǎng)景和方法;以及java提供的樂觀鎖機(jī)制(適用于非常多線程調(diào)用同一段代碼,而不是循環(huán)非常多次去調(diào)用同一段代碼)。
還有很多其他的知識(shí)可以借鑒,曾經(jīng)看到過非常復(fù)雜的圖形算法,而且是多維度的,太復(fù)雜了,所以這里就不說明了。
根據(jù)上述N多知識(shí)可以看出很多知識(shí)都是相通的,無非就是分解、根據(jù)實(shí)際情況命中與解鎖,讓更快的地方替換最慢的地方,讓復(fù)雜的管理變得更加簡(jiǎn)單。
另一種無鎖是一種變通的手段,就是單線程寫操作了,也就是完全無鎖的一種機(jī)制,其實(shí)你會(huì)覺得它很慢,經(jīng)過測(cè)試發(fā)現(xiàn),如果你的操作全是或者基本是OLTP中的小IO單個(gè)線程的寫已經(jīng)可以達(dá)到非常快速度,這種非常適合于寫不多,但讀非常多的系統(tǒng),也就是讀寫分離,寫全部在內(nèi)存中完成,但是需要寫日志,讀是從多個(gè)散列主機(jī)上獲取,但是也會(huì)從這個(gè)內(nèi)存中獲取相應(yīng)數(shù)據(jù),內(nèi)存中為最新修改后得數(shù)據(jù)列,他們之間會(huì)在對(duì)應(yīng)字段上以內(nèi)存為主進(jìn)行返回,這個(gè)機(jī)器只要內(nèi)存足夠大(現(xiàn)在稍微好點(diǎn)的PC SERVER幾十G的內(nèi)存非常容易),就可以承受非常大的修改,這個(gè)數(shù)據(jù)只需要在業(yè)務(wù)量較小的時(shí)候合并到靜態(tài)數(shù)據(jù)中即可;那么當(dāng)業(yè)務(wù)進(jìn)行擴(kuò)大,單線程無法承受的時(shí)候應(yīng)該如何呢??jī)?nèi)存也寫不下了,那么此時(shí)又需要對(duì)其進(jìn)行切割分離了,在業(yè)務(wù)和邏輯表上做一定的標(biāo)識(shí)符號(hào),類似于上述說到的volatile一樣的東西,而寫操作也可以類似于讀操作一樣的分層,這就越來越像Memcache+app+RDBMS這種結(jié)構(gòu)了,只是它在Memcached有日志記錄和恢復(fù),并對(duì)于應(yīng)用來說透明化了這種分布式的調(diào)用,它將整個(gè)體系向后端移動(dòng)和抽象出來使得app的編程更加簡(jiǎn)單和方便,也就是app無需關(guān)心數(shù)據(jù)的具體位置在哪里,以及寫到哪里去了,緩存在哪里,他們?nèi)绾瓮降模@就逐步可以認(rèn)為是云存儲(chǔ)和計(jì)算了,另外其精巧的設(shè)計(jì)不得不說是非常優(yōu)秀的。 |
|