1. 程式人生 > >關於大型網站技術演進的思考(三)--儲存的瓶頸(3)

關於大型網站技術演進的思考(三)--儲存的瓶頸(3)

  儲存的瓶頸寫到現在就要進入到深水區了,如果我們所做的網站已經到了做資料庫垂直拆分和水平拆分的階段,那麼此時我們所面臨的技術難度的挑戰也會大大增強。

  這裡我們先回顧下資料庫的垂直拆分和水平拆分的定義:

  垂直拆分:把一個數據庫中不同業務單元的資料分到不同的資料庫裡。

  水平拆分:是根據一定的規則把同一業務單元的資料拆分到多個數據庫裡。

  垂直拆分是一個粗粒度的拆分資料,它主要是將原來在一個數據庫下的表拆分到不同的資料庫裡,水平拆分粒度比垂直拆分要更細點,它是將一張表拆到不同資料庫裡,粒度的粗細也會導致實現技術的難度的也不一樣,很明顯水平拆分的技術難度要遠大於垂直拆分的技術難度。難度意味著投入的成本的增加以及我們需要承擔的風險的加大,我們做系統開發一定要有個清晰的認識:能用簡單的方案解決問題,就一定要毫不猶豫的捨棄複雜的方案,當系統需要使用高難度技術的時候,我們一定要讓自己感受到這是迫不得已的

  我是以java工程師應聘進了我現在的公司,所以在我轉到專職前端前,我也做過不少java的應用開發,當時我在公司的前輩告訴我,我們公司的資料庫建模很簡單,怎麼個簡單法了,資料庫的表之間都沒有外來鍵,資料庫不準寫觸發器,可以寫寫儲存過程,但是儲存過程決不能用於處理生產業務邏輯,而只能是一些輔助工作,例如匯入匯出寫資料啊,後面聽說就算是資料庫做到了讀寫分離,資料之間同步也最好是用java程式做,也不要使用儲存過程,除非迫不得已。開始我還不太理解這些做法,這種不理解不是指我質疑了公司的做法,而是我在想如果一個數據庫我們就用了這麼一點功能,那還不如讓資料庫公司為咋們定製個閹割版算了,不過在我學習了hadoop之後我有點理解這個背後的深意了,其實作為儲存資料的資料庫,它和我們開發出的程式的本質是一樣的那就是:儲存和計算,那麼當資料庫作為一個業務系統的儲存介質時候,那麼它的儲存對業務系統的重要性要遠遠大於它所能承擔的計算功能,當資料庫作為網際網路系統的儲存介質時候,如果這個網際網路系統成長迅速,那麼這個時候我們對資料庫儲存的要求就會越來越高,最後估計我們都想把資料庫的計算特性給閹割掉,當然資料庫基本的增刪改查我們是不能捨棄的,因為它們是資料庫和外界溝通的入口,我們如果接觸過具有海量資料的資料庫,我們會發現讓資料庫執行的單個sql語句都會變得異常簡潔和簡單,因為這個時候我們知道資料庫已經在儲存這塊承擔了太多的負擔,那麼我們能幫助資料庫的手段只能是儘量降低它運算的壓力

  回到關於資料庫垂直拆分和水平拆分的問題,假如我們的資料庫設計按照我們公司業務資料庫為藍本的話,那麼資料庫進行了水平拆分我們會碰到什麼樣的問題了?為了回答這個問題我就要比較下拆分前和拆分後會給呼叫資料庫的程式帶來怎樣的不同,不同主要是兩點:

  第一點:被拆出的表和原庫的其他表有關聯查詢即使用join查詢的操作需要進行改變;

  第二點:某些增刪改(注意:一般業務庫設計很少使用物理刪除,因為這個操作十分危險,這裡的刪往往是邏輯刪除,一般做法就是更新下記錄的狀態,本質是一個更新操作)牽涉到拆分的表和原庫其他表共同完成,那麼該操作的事務性就會被打破,如果處理不好,假如碰到操作失敗,業務無法做到回滾,這會對業務操作的安全性帶來極大的風險。

  關於解決第一點的問題還是相對比較簡單的,方式方法也很多,下面我來講講我所知道的一些方法,具體如下:

  方法一:在垂直拆表時候,我們先梳理下使用到join操作sql查詢,梳理的維度是以被拆分出的表為原點,如果是弱依賴的join表我們改寫下sql查詢語句,如果是強依賴的join表則隨拆分表一起拆分,這個方法很簡單也很可控,但是這個技術方案存在一個問題,就是讓拆分粒度變大,拆分的業務規則被幹擾,這麼拆分很容易犯一個問題就是一個數據庫裡總會存在這樣一些表,就是很多資料庫都會和它關聯,我們很難拆解這些關聯關係,當我們無法理清時候就會把該表做冗餘,即不同資料庫存在雷同表,隨著業務增長,這種表的資料同步就成為了資料庫的一個軟肋,最終它會演變為整個資料庫系統的短板甚至是全系統的短板。

  方法二:我們拆表的準則還是按業務按需求在資料庫層面進行,等資料庫拆好後,再改寫原來受到影響的join查詢語句,這裡我要說明的是查詢語句修改的成本很低,因為查詢操作是個只讀操作,它不會改變任何底層的東西,如果資料表跨庫,我們可以把join查詢拆分為多次查詢,最後將查詢結果在記憶體中歸納和合並,其實我們如果主動拆庫,絕不會把換個不同的資料庫產品建立新庫,肯定是使用相同資料庫,同類型的資料庫基本都支援跨庫查詢,不過跨庫查詢聽說效率不咋地,我們可以有選擇的使用。這種方案也有個致命的缺點,我們做資料庫垂直拆分絕不可能一次到位,一般都是多次迭代,而該方案的影響面很大,關聯方過多,每次拆表幾乎要檢查所有相關的sql語句,這會導致系統不斷累積不可預知的風險。

  以下三段內容是方法三:

      不管是方法一還是方法二,都有一個很根本的缺陷就是資料庫和上層業務操作耦合度很高,每次資料庫的變遷都導致業務開發跟隨做大量的同步工作,這樣的後果就是資源浪費,做服務的人不能天天被資料庫牽著鼻子走,這樣業務系統的日常維護和業務擴充套件會很存問題,那麼我們一定要有一個服務和資料庫解耦方案,那麼這裡我們就得借鑑ORM技術了。(這裡我要說明下,方法一和方法二我都是以修改sql闡述的,在現實開發裡很多系統會使用ORM技術,網際網路一般用ibatis和mybatis這種半ORM的產品,因為它們可以直接寫sql和資料庫最為親近,如果使用hibernate則就不同了,但是hibernate雖然大部分不是直接寫sql,但是它只不過是對資料庫操作做了一層對映,本質手段是一致,所以上文的sql可以算是一種指代,它也包括ORM裡的對映技術)

       傳統的ORM技術例如hibernate還有mybatis都是針對單庫進行的,並不能幫我們解決垂直拆分的問題,因此我們必須自己開發一套解決跨庫操作的ORM系統,這裡我只針對查詢的ORM談談自己的看法(講到這裡是不是有些人會有種似成相識的感覺,這個不是和分散式系統很像嗎)。

       其實具體怎麼重構有問題的sql不是我想討論的問題,因為這是個技術手段或者說是一個技術上的技巧問題,我這裡重點講講這個ORM與服務層介面的互動,對於服務層而言,服務層最怕的就是被資料庫牽著鼻子走,因為當資料庫要進行重大改變時候,服務層總是想方設法讓自己不要發生變化,對於資料庫層而言服務層的建議都應該是合理,資料庫層要把服務層當做自己的需求方,這樣雙方才能齊心協力完成這件重要的工作,那麼服務層一般是怎樣和資料庫層互動的呢?

       從傳統的ORM技術我們可以找到答案,具體的方式有兩種:

       第一種:以hibernate為代表的,hibernate框架有一套自己的查詢語言就是hql,它類似於sql,自定義一套查詢語言看起來很酷,也非常靈活,但是實現難度非常之高,因為這種做法相當於我們要自己編寫一套新的程式語言,如果這個語言設計不好,使用者又理解不深入,最後往往會事與願違,就像hibernate的hql,我們經常令可直接使用sql也不願意使用hql,這其中的緣由用過的人一定很好理解的。

      第二種:就是資料層給服務層提供呼叫方法,每個方法對應一個具體的資料庫操作,就算底層資料庫發生重大變遷,只要提供給服務端的方法定義不變,那麼資料庫的變遷對服務層影響度也會最低。

      前面我提到技術難度是我們選擇技術的一個重要指標,相比之下第二種方案將會是我們的首選。

      垂直拆分資料庫還會帶來另一個問題就是對事務的影響,垂直拆分資料庫會導致原來的事務機制變成了分散式事務,解決分散式事務問題是非常難的,特別是如果我們想使用業界推出的解決分散式事務方案,那麼要自己實現個分散式事務就更難了,不過這裡我要說明一下,我這裡說的更難是和我寫本文有關,我本篇文章之所以現在才寫是因為我想先研究下業界推出的分散式解決方案,但是這些方案的原理看得我很沮喪,我就想如果我們直接用方案的介面實現了它,因為還是不懂他的很多原理,那麼這些方案其實就是不可控方案,說不定使用過多就會給系統埋下定時炸彈,因此這裡我就只提提這些方案,有興趣的童鞋可以去研究下:

  一、X/OPEN組織推出的分散式事務規範XA,其中還包括該組織定義的分散式事務處理模型X/OPEN

  二、大型網站一致性理論CAP/BASE

  三、 PAXOS協議。

  這裡特別要提的是PAXOS協議,我以前寫過好幾篇關於zookeeper的文章,zookeeper框架有一個特性就是它本身是一個分散式檔案系統,當我們往zookeeper寫資料時候,zookeeper叢集能保證我們的寫操作的可靠性,這個可靠性和我們使用執行緒安全來控制寫資料一樣,絕對不會讓寫操作出錯,之所以zookeeper能做到這點,是因為zookeeper內部有一個類似PAXOS協議的協議,這個協議類似一個選舉方案,它能保證寫入操作的原子性。

  其實事務也是和執行緒安全技術類似,只不過事務是要保證一個業務操作的原子性問題,當然事務還要有個特點就是回滾機制即業務操作失敗,事務可以保證系統恢復到業務操作前的狀態,回滾機制的本質其實是維護業務操作的狀態性,具體點我這裡列舉個例子:當系統將要執行一個業務操作時候,我們首先為業務系統定義一個初始狀態,業務執行操作時候我們可以定義一個執行狀態,操作成功就是一個成功狀態,操作失敗就是一個操作失敗狀態,如果業務操作是失敗狀態,我們可以讓業務回滾到初始狀態,更進一步如果執行狀態超時也可以將整個業務狀態回退到初始狀態,其實所有事務回滾機制的本質基本都是如此。記得不久前,在群裡有個群友就問大家如何實現分散式事務,他想要知道的分散式事務是有沒有一種技術能像我們操作資料庫或者是jdbc那樣一個commit,一個rollback就搞定,但是現實中的分散式事務比commit和rollback複雜的多,不可能簡單的讓我們寫幾個標記就能實現分散式事務,當然業界是有方案的,就是我上面提到的,如果有人真想知道可以自己研究下,不過我本人現在還是不太懂上面這些技術的原理和思想。

  其實當時我馬上給那位群友一個解答,我說我們開發時候是經常碰到分散式事務,但是我們解決分散式事務大多數從業務角度來解決的,而沒去選擇純技術手段,因為技術手段太複雜難以控制。這個答案可能不會令提問者滿意,但是我現在還是堅持這個觀點,這個觀點符合我提到的原則,當技術方案難度過高,我們就不要輕易選擇使用它,因為這麼做是很危險的,今天我就舉個例子吧,這樣可能更有說服力。我現在做的系統很多業務操作經常要和其他系統共同完成,其他系統有我們公司自己的系統,也有其他企業的系統,這裡我還是把業務操作比作一輛在高速公路的汽車,那麼每個系統就是高速公路上的一個收費站,業務每到一個收費站,該系統的資料庫就會在對應的資料庫的某張表裡某條記錄上記錄一個狀態,當汽車跑完全程,各個收費站就會相互通知,告訴大家任務完成,最終將所有的狀態置為已完成,如果失敗,就廢掉這輛汽車,收費站之間也會相互通知,讓所有的記錄狀態迴歸到初始狀態,就當從來沒有這輛汽車來過。這個做法的原理就是使用了事務回滾的本質,狀態的變遷和回退,這個做法在業務系統開發裡也有個專有術語就是工作流。其實大多數問如何實現分散式事務如何實現的問題的本質就是想解決事務的回滾問題,我們其實不要被這個分散式事務的名字給嚇住了,其實有很多不起眼的技術手段和業務手段都能達到相同的目的。

  晚上11點了,看來本文今天寫不完了,今天就到此為止,最後我要總結下本文的內容,具體如下:

1. 大型網站解決儲存瓶頸的問題,我們要找準儲存這個關鍵點,因為資料庫其實是儲存和運算的組合體,但是在我們這個場景下,儲存是第一位的,當儲存是瓶頸時候我們要狠下心來儘量多的拋棄資料的計算特點,所以上文中我提出我們資料庫就不要濫用計算功能了例如觸發器、儲存過程等等。

2. 資料庫剝離計算功能不代表不要資料的計算功能,因為沒有資料的計算功能資料庫也就沒價值了,那麼我們要將資料庫的計算功能進行遷移,遷移到程式裡面,一般大型系統程式和資料庫都是分開部署到不同伺服器上,因此程式裡處理資料計算就不會影響到資料庫所在伺服器的效能,就可以讓安裝資料庫的伺服器專心服務於儲存。

3. 我們要盡一切可能的把資料庫的變化對服務層的影響降到最低,最好是資料庫做拆分後,現有業務不要任何的更改,那麼我們就得設計一個全新的資料訪問層,這個資料訪問層將資料庫和服務層進行解耦,任何資料庫的變化都由資料訪問層消化,資料訪問層對外介面要高度統一,不要輕易改變。

4. 如果我們設計了資料訪問層來解決資料庫拆分的問題,資料訪問層加上資料庫其實就組合出了一個分散式資料庫的解決方案,由此可見拆分資料庫的難度是很高的,因為資料庫將擁有分散式的特性,而分散式開發就意味開發難度的增加。

5. 對於分散式事務的處理,我們儘量要從具體問題具體分析,不要一感覺這個事務操作本質是分散式事務就去尋找通用的分散式事務技術手段,這樣的想法其實是迴避困難的思想,結果可能會是把問題搞得更加複雜。

  好了,今天就寫到這裡吧,祝大家晚安,生活愉快!

相關推薦

關於大型網站技術演進思考--儲存瓶頸3

  儲存的瓶頸寫到現在就要進入到深水區了,如果我們所做的網站已經到了做資料庫垂直拆分和水平拆分的階段,那麼此時我們所面臨的技術難度的挑戰也會大大增強。   這裡我們先回顧下資料庫的垂直拆分和水平拆分的定義:   垂直拆分:把一個數據庫中不同業務單元的資料分到不同的資料庫裡。   水平拆分:是根據一定的規

關於大型網站技術演進思考儲存瓶頸3

儲存的瓶頸寫到現在就要進入到深水區了,如果我們所做的網站已經到了做資料庫垂直拆分和水平拆分的階段,那麼此時我們所面臨的技術難度的挑戰也會大大增強。 這裡我們先回顧下資料庫的垂直拆分和水平拆分的定義: 垂直拆分:把一個數據庫中不同業務單元的資料分到不同的資料庫裡。

關於大型網站技術演進思考--存儲的瓶頸5

做了 技術分享 表數 例子 執行 同時 設備 系統重啟 拆分 原引:http://www.cnblogs.com/sharpxiajun/p/4265853.html 上文裏我遺留了兩個問題,一個問題是數據庫做了水平拆分以後,如果我們對主鍵的設計采取一種均勻分布的策略,那麽

關於大型網站技術演進思考十四--網站靜態化處理—前後端分離—上6

  前文講到了CSI技術,這就說明網站靜態化技術的講述已經推進到了瀏覽器端了即真正到了web前端的範疇了,而時下web前端技術的前沿之一就是前後端分離技術了,那麼在這裡網站靜態化技術和前後端分離技術產生了交集,所以今天我將討論下前後端分離技術,前後端分離技術討論完後,下一篇文章我將會以網站靜態化技術的角度回過

關於大型網站技術演進思考--網站靜態化處理—動靜整合方案2

  上篇文章我簡要的介紹了下網站靜態化的演進過程,有朋友可能認為這些知識有點過於稀鬆平常了,而且網站靜態化的技術基點也不是那麼高深和難以理解,因此它和時下日新月異的web前端技術相比,就顯得不倫不類了。其實當我打算寫本系列的之前我個人覺得web前端有一個點是很多人都知道重要,但是有常常低估它作用的,那就是we

關於大型網站技術演進思考--儲存瓶頸2

  上篇裡我講到某些網站在高併發下會報出503錯誤,503錯誤的含義是指網站服務端暫時無法提供服務的含義,503還表達了網站服務端現在有問題但是以後可能會提供正常的服務,對http協議熟悉的人都知道,5開頭的響應碼錶達了服務端出現了問題,在我們開發測試時候最為常見的是500錯誤,500代表的含義是服務端程式出

關於大型網站技術演進思考十五--網站靜態化處理—前後端分離—中7

  上篇裡我講到了一種前後端分離方案,這套方案放到服務端開發人員面前比放在web前端開發人員面前或許得到的掌聲會更多,我想很多資深前端工程師看到這樣的技術方案可能會有種說不出來的矛盾心情,當我的工作逐漸走向越來越專業化的前端開發後,我就時常被這套前後端分離方案所困惑,最近我終於明白了這個困惑的本源在哪裡了,那

關於大型網站技術演進思考十七--網站靜態化處理—滿足靜態化的前後端分離9

  前後端分離的主題雖然講完了,但是前後端分離的內容並沒有結束,本篇將繼續前後端分離的問題,只不過這次前後端分離的講述將會圍繞著本系列的主題網站靜態化進行。在講本篇主題之前,我需要糾正一下前後端分離主題講述中會讓朋友們產生誤導的地方,這種誤導就是對時下流行的一些前後端分離方案(沒有使用nodejs的前後端分離

關於大型網站技術演進思考--網站靜態化處理--總述1

  在儲存瓶頸的開篇我提到像hao123這樣的導航網站只要它部署的web伺服器數量足夠,它可以承載超大規模的併發訪問量,如果是一個動態的網站,特別是使用到了資料庫的網站是很難做到通過增加web伺服器數量的方式來有效的增加網站併發訪問能力的。但是現實情況是像淘寶、京東這樣的大型動態網站在承擔高併發的情況下任然能

關於大型網站技術演進思考--儲存瓶頸6

  在講資料庫水平拆分時候,我列出了水平拆分資料庫需要解決的兩個難題,它們分別是主鍵的設計問題和單表查詢的問題,主鍵問題前文已經做了比較詳細的講述了,但是第二個問題我沒有講述,今天我將會講講如何解決資料表被水平拆分後的單表查詢問題。   要解決資料表被水平拆分後的單表查詢問題,我們首先要回到問題的源頭,我們

關於大型網站技術演進思考十六--網站靜態化處理—前後端分離—下8

  我第一次聽說nodejs技術大概是在2009年年末,不過我真正認真在網路上進一步瞭解nodejs還是在2010年年中,當時對nodejs的認識和我現在對nodejs的認識有著天壤的區別,開始想了解nodejs我只是為了感慨谷歌公司開發的V8引擎居然如此強大,它不僅僅可以作為chrome瀏覽器的javasc

關於大型網站技術演進思考十九--網站靜態化處理—web前端優化—上11

對於一個網路請求的處理,是由兩個不同型別的操作共同完成,這兩個操作是CPU的計算操作和IO操作,如果我們以處理效率角度來評判這兩個操作,CPU操作效率是光速的,而IO操作就不盡然了,計算機裡的IO操作就是對儲存資料介質的操作,計算機裡有如下幾個介質可以儲存資料,它們分別是:CPU的一級快取、二級快取、記憶

關於大型網站技術演進思考十一--網站靜態化處理—動靜分離策略3

  前文裡我講到了網站靜態化的關鍵點是動靜分離,動靜分離是讓動態網站裡的動態網頁根據一定規則把不變的資源和經常變的資源區分開來,動靜資源做好了拆分以後,我們就可以根據靜態資源的特點將其做快取操作,這就是網站靜態化處理的核心思路。由此可見,網站靜態化處理的核心就是動靜分離和快取兩大方面,上篇我簡單講述了動靜整合

關於大型網站技術演進思考--儲存瓶頸1

  前不久公司請來了位網際網路界的技術大牛跟我們做了一次大型網站架構的培訓,兩天12個小時資訊量非常大,知識的廣度和難度也非常大,培訓完後我很難完整理出全部聽到的知識,今天我換了個思路是回味這次培訓,這個思路就是通過本人目前的經驗和技術水平來思考下大型網站技術演進的過程。   首先我們要思考一個問題,什麼樣

關於大型網站技術演進思考--儲存瓶頸4

  如果資料庫需要進行水平拆分,這其實是一件很開心的事情,因為它代表公司的業務正在迅猛的增長,對於開發人員而言那就是有不盡的專案可以做,雖然會感覺很忙,但是人過的充實,心裡也踏實。   資料庫水平拆分簡單說來就是先將原資料庫裡的一張表在做垂直拆分出來放置在單獨的資料庫和單獨的表裡後更進一步的把本來是一個整體

關於大型網站技術演進思考--儲存瓶頸7

  本文開篇提個問題給大家,關係資料庫的瓶頸有哪些?我想有些朋友看到這個問題肯定會說出自己平時開發中碰到了一個跟資料庫有關的什麼什麼問題,然後如何解決的等等,這樣的答案沒問題,但是卻沒有代表性,如果出現了一個新的儲存瓶頸問題,你在那個場景的處理經驗可以套用在這個新問題上嗎?這個真的很難說。   其實不管什麼

關於大型網站技術演進思考十八--網站靜態化處理—反向代理10

  反向代理也是一種可以幫助實現網站靜態化的重要技術,今天我就來講講反向代理這個主題。那麼首先我們要了解下什麼是反向代理。和反向代理相對應的是正向代理,正向代理也就是我們常說的代理服務,正向代理是非常常見的,例如在某些公司裡我們想使用網際網路,那麼我們就得在瀏覽器裡設定一個代理伺服器,通過代理伺服器我們才能正

關於大型網站技術演進思考--儲存瓶頸5

  上文裡我遺留了兩個問題,一個問題是資料庫做了水平拆分以後,如果我們對主鍵的設計採取一種均勻分佈的策略,那麼它對於被水平拆分出的表後續的查詢操作將有何種影響,第二個問題就是水平拆分的擴容問題。這兩個問題在深入下去,本系列就越來越技術化了,可能最終很多朋友讀完後還是沒有找到解決實際問題的啟迪,而且我覺得這些問

關於大型網站技術演進思考十三--網站靜態化處理—CSI5

  講完了SSI,ESI,下面就要講講CSI了 ,CSI是瀏覽器端的動靜整合方案,當我文章發表後有朋友就問我,CSI技術是不是就是通過ajax來載入資料啊,我當時的回答只是說你的理解有點片面,那麼到底什麼是CSI技術了?這個其實要和動靜資源整合的角度來定義。   CSI技術其實是在頁面進行動靜分離後,將頁面

關於大型網站技術演進思考十二--網站靜態化處理—快取4

  上篇我補充了下SSI的知識,SSI是一個十分常見的技術,記得多年前我看到很多入口網站頁面的字尾是.shtml,那麼這就說明很多入口網站都曾經使用過SSI技術,其實現在搜狐網站也還在用shtml,如下圖所示:     由此可見SSI在網際網路的應用還是非常廣泛的。其實網際網路很多網頁如果我們按照動靜分離