web架构延变
在現(xiàn)代的軟件系統(tǒng)中,幾乎所有的系統(tǒng)都使用到了數(shù)據(jù)庫,不論是關(guān)系型數(shù)據(jù),例如MySql、SQLite、Oracle、SQLServer等,還是非關(guān)系性數(shù)據(jù),例如mongoDB、redis等。本文已web系統(tǒng)為例來闡述為什么要降低數(shù)據(jù)庫的壓力,在提出具體方案之前先大致講解一下現(xiàn)在web系統(tǒng)的架構(gòu),要了解web系統(tǒng)的架構(gòu)和演變過程具體可以參考大型網(wǎng)站架構(gòu)演變和知識體系這片文章。
現(xiàn)代web系統(tǒng)的架構(gòu)
現(xiàn)在的大型web系統(tǒng)多采用分布式的架構(gòu),分布式系統(tǒng)面臨的最大挑戰(zhàn)就是如何在復(fù)雜的、并發(fā)的情況下保證數(shù)據(jù)的一致性問題。通常為了避免由于保證數(shù)據(jù)一致性問題而帶來的困難,通常情況下都是采用多個實例,單個數(shù)據(jù)源的架構(gòu)模式,簡化模式如圖。?
?
在這個架構(gòu)中,通過不斷的增加實例(webserver)可以降低應(yīng)用服務(wù)器的壓力,所以只要保證應(yīng)用代碼的質(zhì)量、應(yīng)用之間的低耦合性、可擴展性和可維護性等,應(yīng)用服務(wù)器的壓力就不再會成為整體架構(gòu)中性能瓶頸,但是隨著業(yè)務(wù)量的不斷增加增長,或者時間的積累,沉淀下來的數(shù)據(jù)變得越來越來多,隨著而來的數(shù)據(jù)庫的壓力變得越來越大,慢慢的性能的瓶頸主要集中在數(shù)據(jù)庫上。
降低數(shù)據(jù)庫壓力的方法
1.合理增加索引
表索引可以加快對表中數(shù)據(jù)的檢索速度,但是會降低表中數(shù)據(jù)的更新速度,所以增加表的索引一定控制在合理范圍內(nèi),過多的索引不但不會降低數(shù)據(jù)庫的壓力,反而可能增大數(shù)據(jù)庫的壓力,表索引的建立一般要從具體業(yè)務(wù)場景出發(fā),對于讀多寫少的場景,可以通過適當?shù)脑黾铀饕齺硖岣咝?#xff0c;對表的那些列建立索引?建立單獨索引還是建立復(fù)合索引?要根據(jù)具體的業(yè)務(wù)場景來決定,建立索引之后可以針對索引對業(yè)務(wù)邏輯中使用的SQL進行優(yōu)化,建立索引是最基礎(chǔ)的手段,這里不錯過多的介紹。
2.數(shù)據(jù)截轉(zhuǎn)
一般情況下,業(yè)務(wù)中所處理的數(shù)據(jù)的都具有一定的時間間隔,所以可以通過對業(yè)務(wù)進行梳理,將當前時間間隔之外的數(shù)據(jù)進行截轉(zhuǎn),截轉(zhuǎn)到歷史數(shù)據(jù)庫中,通過對業(yè)務(wù)進行拆分,當需要歷史數(shù)據(jù)時,可以轉(zhuǎn)到歷史數(shù)據(jù)庫中進行查詢,或者修改,通過減少當前數(shù)據(jù)庫的數(shù)據(jù)量,來減輕當前業(yè)務(wù)數(shù)據(jù)的壓力。數(shù)據(jù)截轉(zhuǎn)一般情況下是按照時間來進行,所以在業(yè)務(wù)員數(shù)據(jù)庫設(shè)計的時候就要考慮到時間這個因素。?
數(shù)據(jù)截轉(zhuǎn)可以進行間隔一段時間做一次手工的數(shù)據(jù)截轉(zhuǎn),也可以啟動一個定時器,每個一段時間進行一次數(shù)據(jù)截轉(zhuǎn),推薦的方式是準實時截轉(zhuǎn),及每天在業(yè)務(wù)量較小的時間,啟動任務(wù)實時截轉(zhuǎn)。?
數(shù)據(jù)截轉(zhuǎn)需要注意的幾個問題:(1)外鍵關(guān)聯(lián)關(guān)系(特別是有主鍵ID的關(guān)聯(lián)的)注意在截轉(zhuǎn)的歷史數(shù)據(jù)庫中的關(guān)聯(lián)關(guān)系是否正確。(2)保證生產(chǎn)庫和歷史庫的業(yè)務(wù)關(guān)聯(lián)關(guān)系,從而避免歷史庫的數(shù)據(jù)需要關(guān)聯(lián)生產(chǎn)庫中的數(shù)據(jù)。
3.增加緩存
緩存是降低數(shù)據(jù)壓力一個強有力的手段,基本是所有系統(tǒng)大型web系統(tǒng)中都會使用到,所以現(xiàn)代的大型web系統(tǒng)的架構(gòu)一般如圖。?
?
請求1到達webserver之后,首先執(zhí)行2訪問緩存,如果hit則返回,miss則執(zhí)行3訪問數(shù)據(jù)庫,在執(zhí)行4同步到緩存中,再返回。但是不是緩存并不是萬能的,緩存也有其使用的業(yè)務(wù)場景,一般在讀多寫少,數(shù)據(jù)重復(fù)查詢比較集中的場景下,緩存可以大大提高性能,緩存操作順序非常重要,不合理的操作順序,在并發(fā)場景下常常會導(dǎo)致數(shù)據(jù)的不一致,緩存的具體操作可以參考緩存架構(gòu)設(shè)計細節(jié)二三事這邊文章。
4.生成寬表,冗余數(shù)據(jù)
有些業(yè)務(wù)例如報表、數(shù)據(jù)匯總等需要數(shù)據(jù)量較多,此時可能需要進行多表聯(lián)合查詢,聯(lián)合查詢操作非常消耗數(shù)據(jù)庫的性能,所以在這種業(yè)務(wù)場景下為了避免過大的性能消耗,往往需要將查詢時的多個表按照關(guān)聯(lián)條件進行關(guān)聯(lián),生成一張含有冗余信息的包含所有表的多個字段的大寬表,這樣在進行查詢時,只在一張表中進行查詢,性能明顯得到提升。大寬表的生成是在業(yè)務(wù)流程中生成還是通過異步化任務(wù)來生成,根據(jù)具體的業(yè)務(wù)邏輯來定。
5.修改關(guān)系型數(shù)據(jù)庫為非關(guān)系性數(shù)據(jù)庫
非關(guān)系型數(shù)據(jù)庫,也就是我們通常說的NoSQL數(shù)據(jù),最常見就是key/value類型的數(shù)據(jù)庫,這類數(shù)據(jù)庫不強調(diào)表的關(guān)系,但是查詢速度非???#xff0c;所在某些具體場景下,我們應(yīng)該優(yōu)先選擇NoSQL數(shù)據(jù)庫,例如字典信息表的查詢。
6.讀寫分離
如果采用單點數(shù)據(jù)數(shù)據(jù)庫,就算對數(shù)據(jù)進行上述的相關(guān)優(yōu)化,但是由于其本身的單點性,所以隨著流量的激增,數(shù)據(jù)庫仍然會成為系統(tǒng)的瓶頸,如何對數(shù)據(jù)進行拆分來解決這個問題了,讀寫分離就是最常用的方法,讀寫分離的原理如下圖。?
?
讀寫分離技術(shù)現(xiàn)在已經(jīng)應(yīng)用的很成熟,通過將數(shù)據(jù)拆分為兩個實例,讀寫分離操作改善了數(shù)據(jù)單點的瓶頸,分攤了數(shù)據(jù)庫壓力,而且當主數(shù)據(jù)庫宕機之后可以迅速的切換到從庫,而不會導(dǎo)致業(yè)務(wù)不可用,同時也起到數(shù)據(jù)備份的作用,由于存在兩個數(shù)據(jù)實例,所以數(shù)據(jù)怎么由主庫同步到從庫、主從之間延遲引發(fā)的數(shù)據(jù)不一致問題,以及怎么來分離業(yè)務(wù)中讀和寫操作成為要解決的問題成為要解決的問題。主從同步可以參考Mysql主從架構(gòu)的復(fù)制原理及配置這篇文章,從主數(shù)據(jù)一致可以參考DB主從一致性的幾種解決方法這篇文章。
7.數(shù)據(jù)庫拆分
采用讀寫分離之后,數(shù)據(jù)庫已經(jīng)變?yōu)閮煞輰嵗?#xff0c;數(shù)據(jù)庫的壓力已經(jīng)得到分攤,如果數(shù)據(jù)庫的壓力還是過大時,這是就要從業(yè)務(wù)方面著手,將具體業(yè)務(wù)細分,將業(yè)務(wù)對應(yīng)的表分拆到不同的數(shù)據(jù)庫當中,如下圖。?
業(yè)務(wù)變動較大,同時要對系統(tǒng)內(nèi)部之間的相互調(diào)用提供接口,調(diào)用方式可以選用RPC、Restful、JMQ消息等方式。一般情況下,數(shù)據(jù)庫垂直拆分做的足夠細分的話,加上讀寫分離技術(shù),加上適當?shù)臄?shù)據(jù)截轉(zhuǎn)就可以滿足一般的大型業(yè)務(wù)系統(tǒng)對性能的需求。
8.表的垂直拆分
數(shù)據(jù)庫可以進行垂直拆分,當然也可以對數(shù)據(jù)庫中的表進行垂直拆分,對表進行拆分就是對數(shù)據(jù)拆分的再拆分,如圖。種解決方法只適用于一些特定的場景,例如對表進行垂直拆分,通過異步化調(diào)用將所有任務(wù)異步化,前提是總的任務(wù)可以進行分布的異步化操作,在實際應(yīng)用比較少,因為設(shè)計的表只要復(fù)合三范式的要求,一般是很難在進行拆分的,應(yīng)用較多是對表進行水平拆分。?
9.表的水平拆分
如果已經(jīng)做了數(shù)據(jù)庫拆分,并且進行了讀寫分離,數(shù)據(jù)壓力還是過大,主要原因就是數(shù)據(jù)庫表中的記錄太多,或者對數(shù)據(jù)進行了截轉(zhuǎn),但是對歷史數(shù)據(jù)的操作還是比較頻繁的,且隨著截轉(zhuǎn)的歷史數(shù)據(jù)越來越多,歷史數(shù)據(jù)庫的壓力也邊的也變的越來越大,這時有兩種解決方案:第一種方案就是對數(shù)據(jù)庫中的表進行垂直拆分,從而不用在截轉(zhuǎn)數(shù)據(jù),通過不斷對表進行水平拆分,保證數(shù)據(jù)數(shù)據(jù)庫中單表的記錄數(shù)保持在一個高性能合理的范圍之類,通過擴容將不同分配到不同的數(shù)據(jù)中(分庫分表)來保證數(shù)據(jù)庫的壓力,應(yīng)用在訪問時,通過分庫分表的條件進行路由,就可以取到數(shù)據(jù)。第二種就是仍舊對數(shù)據(jù)進行截轉(zhuǎn),當歷史數(shù)據(jù)信息過多從而導(dǎo)致數(shù)據(jù)庫壓力過大時,采用搜索引擎的方式來解決。相比于第一種操作第二種方案適用于讀操作上,對與寫操作,具有一定的局限性,第一種方案具有一定的通用性。對表進行水平拆分的過程如圖所示。?
?
在進行進行具體水平拆分之前,我們需要考慮這樣幾個問題
1. 制定什么樣的路由規(guī)則
2. 如何盡量避免跨庫或者跨表操作
3. 如何盡可能的避免全庫全表掃描
4. 如何保證每個庫的負載處于基本盡可能均衡的狀態(tài)
5. 如何實時跨庫訪問事物
6. 如何實時聚合操作
7. 如何保證擴容的方便性
轉(zhuǎn)載于:https://www.cnblogs.com/liangxiaofeng/p/6408103.html
總結(jié)
- 上一篇: AI资源贴
- 下一篇: 茅台19亿办医院 巨头跨界成常态