本節書摘來自華章出版社《高并發oracle資料庫系統的架構與設計》一書中的第1章,第1.1節,作者 侯松,更多章節内容可以通路雲栖社群“華章計算機”公衆号檢視
高并發這個概念并不新鮮,可以說有資料庫的地方都有可能面臨高并發的問題。在資料庫裡,高并發問題主要集中在兩個方面:讀的高并發、寫的高并發,兩者看起來都不是很複雜,然而實際情況往往是讀和寫會交織在一起,并同時呈現出高并發的問題。
這個時候,相信很多讀者都會提出一個觀點:做讀寫分離嘛。是的,這是一個不錯的主意,但隻是一個治标不治本的主意。業務系統的耦合度很高,是不可能實作業務層級的讀寫分離的。在架構設計的過程中,不能駐足于技術層面,還是需要滲透到業務層面去的。不論是業務驅動技術,還是技術驅動業務,兩者都是不能分離開考慮的,比較好的做法應該是,在兩者之間形成一種平衡,當然這是需要架構師的分析能力和溝通能力來加以驅動的。
應用架構師:“哥們!還記得上半年讓你們幫忙做的一次資料庫容量測試嗎?”
資料庫架構師:“當然!我們可是費了很大的工夫才完成的。”
應用架構師:“當時不是說我們在現有的硬體條件下,資料庫的容量足夠承受當時4倍業務壓力嗎?可是下半年我們的業務量才增長了0.5倍,怎麼就不行了呢?”
資料庫架構師:“從系統資源使用率的報告來看,cpu、記憶體、i/o、網絡上都沒有太大的壓力。但是,在業務高峰時段,cpu出現短暫沖高的現象。”
應用架構師:“沒錯!在應用端可以看到出現使用者阻塞,中間件上的連接配接持續增加,沒有得到及時釋放。”
資料庫架構師:“嗯,那是資料庫未能及時響應造成的。cpu沖高,通過監控,我們發現很多并發的會話在争用一些資源,比如資料塊、索引塊、latch和mutex。表現出很多等待事件的沖高。”
應用架構師:“我想我們遇到高并發争用的麻煩了。”
資料庫架構師:“是的。當初這套系統的設計,預期到現在這麼大的業務壓力了嗎?”
應用架構師:“誰也不會有這種先見之明吧?當初隻是一種業務的嘗試而已,誰能想到市場的反應會那麼好!從資料庫層面來看,有什麼好辦法嗎?畢竟現在的問題出在資料庫上。”
資料庫架構師:“辦法是有的,針對性地一一解決掉。但是,這總歸是治标不治本的辦法。就像治水,現在壓力我們堵住了,如果壓力再大一些呢?我需要你的幫助。”
應用架構師:“你是說業務架構的變更嗎?小變化沒有問題,但是要像網際網路公司那樣大改,肯定是不行的,我們接受不了這麼大的變化。”
資料庫架構師:“是的,變革對我們來說,成本太大,小帆船掉頭容易,航母掉頭可能就要出事情了。”
應用架構師:“我們最近在開發消息隊列,能一定程度上緩解使用者的高并發壓力。但這是以犧牲使用者體驗作為代價的,終歸不是太好的辦法。”
資料庫架構師:“我想我們可以學習大禹治水,堵不上,就疏通。先将一部分業務壓力分離出去,在子資料庫和主資料庫之間即時同步必要的資料,同時适當備援資料到子資料庫,減少資料庫之間的互動。”
應用架構師:“是個好辦法,我們現在不就是這麼在做的嗎?問題不還是在那裡嗎?”
資料庫架構師:“我想是的。因為業務熱點過于集中,在資料庫上這部分業務資料耦合度又非常高,沒有辦法做到有效拆分。”
應用架構師:“這不奇怪,我們的業務邏輯的複雜程度不是網際網路應用可以比拟的,沒辦法像他們那樣去充分地解耦。但是,我們是否可以學習他們使用廉價mysql資料庫代替oracle資料庫,這樣業務分離的成本就低了很多。”
資料庫架構師:“你确定這樣的成本會低嗎?oracle資料庫的開發人員真的會開發mysql嗎?我們的業務邏輯是很難在mysql資料庫上實作的,現在oracle資料庫幫助我們完成了大部分的資料耦合,如果使用mysql,這些都将要在應用端完成,開發成本将會增加。另外,oracle有強大的優化器機制,開發者寫得不算太好的sql,它也能包容,mysql則不然了,sql寫得不好,馬上給你顔色看,因為它的優化機制不能跟oracle相提并論。與oracle相比,mysql隻能作為一個資料容量來看待。”
應用架構師:“你說的這些我也明白,但是我們的資料庫是應該架構擴充了吧?”
資料庫架構師:“當然。雖然我們不能做到充分的資料解耦,但是一點一點地解還是可以的吧。我們現在的問題是解決高并發問題,而高并發集中的那部分業務就是我們的目标。”
應用架構師:“那部分業務很難弄哦。讀寫比例為5∶1,寫操作占比還是蠻高的,而且都交織在一起的。最大的問題是要保證較快的響應速度,否則高并發壓力就會積壓。”
資料庫架構師:“記憶體資料庫!将其作為oracle資料庫的前置緩存資料庫來加快響應速度,如果保證了快速響應,高并發壓力也就解決了。眼下oracle和sap都在記憶體資料庫上大做文章呢。”
應用架構師:“他們都是在搞olap的記憶體資料庫吧,我們的可是oltp。”
資料庫架構師:“oracle的timesten就是為了解決oltp的并發問題而研發的哦。關鍵是看我們的應用是否适應得了。”
應用架構師:“嗯,是多樣化的資料庫架構了。”
資料庫架構師:“是的,就像一套資料庫生态體系,沒有必要特别待見誰,也沒有必要特别排斥誰,關鍵是看應用的需要。不過,我們也需要反思一個問題,就是當初oracle的設計階段沒有預見性,應該從oracle内部設計先把握好,加強其處理并發的能力。是謂:‘先修内政而後縱橫。’”
看過冗長的對話,我們來總結一下吧,問題到底出在哪裡?
oracle資料庫架構設計之初,粗放設計,沒有充分把握細節;
業務資料耦合度過高,無法充分解耦,革命性的變化成本太高,不能接受;
業務邏輯比較厚重,靈活性不高;
可以接受架構創新。
以上問題,相信很多架構師和資料庫管理者們都會面臨。更多時候,我們都是無力去推動業務的,讓業務适應技術,一直都是技術人員美好的願望,卻鮮有實作。現實一點地來看,我們隻能在一定程度上去引導業務,但不能完全讓技術去适應業務,兩者需要達到一種平衡。
立足于大多數的傳統行業,來看一看應用的現狀吧。業務邏輯都是經年累月沉澱下來的,要想做出革命性的變化确實很難,除非行業革命。誰能想象一下,讓銀行去拆分核心邏輯呢?業務看似刁難的要求,也蘊藏着行業的特點,架構師是需要充分認識到這一點的。

如圖1-1所示,理想情況下的應用系統架構中的子系統應該是相對比較獨立的,子系統之間關聯較少,而且互相關聯的子系統數量相對較少。實際情況往往是大相徑庭的,子系統之間存在很高的耦合性。子系統内讀寫錯綜複雜,基本上不可能實作讀寫分離。面對這樣的現實,出于成本和風險的考慮,很難做到子系統的解耦,理想情況也隻能是理想了。
業務子系統與資料庫的對應關系,如圖1-2所示。在一套完整的資料庫生态體系中,子系統和資料庫也是無法獨立開的。理想情況是若幹子系統分布在一個資料庫中,資料庫基本上是自包含的。現實仍然是殘酷的,往往是子系統和資料庫出現多對多的關系。
那麼,資料庫架構設計就需要反映這樣的業務架構,如圖1-3所示。對于某一系列的業務應用來說,是不可能通過單個資料庫來實作的。需要的是一個資料庫群,其中包含核心庫、業務應用庫,以及各種功能的庫,根據重要性做層級劃分。資料庫之間實作即時的資料同步,構成一套完整的資料庫生态體系。
做到這些是不是就解決問題了呢?當然沒有,如果解決了,也不會有以上那段對話。但是,這種架構的演化方向是正确的,将錯綜複雜的業務分為治之,如果某些業務上出現了很高的并發壓力,也不會影響到其他業務的應用,還可以将影響面控制在最小範圍内。
雖然本次在架構模組化階段沒有充分考慮到oracle資料庫的細節問題,但是也可以作為一次經驗教訓,為下次的模組化工作提供指導。可喜的是,我們也不必坐以待斃,架構的創新始終都是受歡迎的,因為這意味着資料庫的并發處理能力的提升。
從技術層面來看待以上的問題,我們可以去做好兩件事情:
oracle資料庫架構設計工作細化;
以oracle資料庫為中心,開展架構縱橫擴充。
對于現在的企業級應用系統來說,資料庫一般不會成為一套系統的瓶頸所在。資料庫出現高并發問題往往都是熱點業務集中争用造成的結果。為什麼這麼說呢?因為現在的資料庫應用中,不論是oracle資料庫,還是mysql資料庫,抑或其他新型資料庫,它們都不是一個人在戰鬥。
如圖1-4所示,在一套比較完整的應用系統架構體系中,一般可以分為四個大層級:
應用層:直接服務于最終使用者的,完成使用者行為的互動。
網絡層:背景處理的第一個層級,實作網絡路由,并通過網絡負載均衡器實作第一次負載均衡,使高并發壓力第一次得到分流。
中間件層:就是通常說的b/s架構的中間伺服器層,其接收網絡層來的使用者連接配接,并實作第二次負載均衡,所不一樣的是,網絡層是通過硬體實作負載均衡,而中間件層是通過軟體實作的。同時,其按照一定的邏輯配置連接配接資料源。
資料路由:隸屬于中間件層,是資料庫層的一個前棧,實作分布式資料存儲的路由。一般來說,若資料庫使用分布式存儲,則這個元件都是不可少的。
資料庫層:這是我們最關心的,也是最底層的結構,可分為核心資料庫層和前置資料庫層。
核心資料庫層:傳統意義上的資料庫群所在的區域,我們按照不同的功能應用,區分不同的資料庫存儲,包括核心庫、子系統庫、災備庫(可細分為遠端災備和本地災備)。如果業務擴充,則可以通過adg庫和t-1交易庫實作部分業務的分離,這兩個概念我們會在“縱橫篇”詳細介紹。
前置資料庫層:這個層級可以部署在核心資料庫層的前端,也可以平行部署。其另一種叫法是“資料庫中間層”。可以部署一些記憶體資料庫,分離高并發業務到這個區域,也可以部署一些開源的資料庫,分離邊緣化的應用于其中。
可以看到,一個完整的架構遠比我們想象得要複雜,雲的概念也是基于這個架構逐漸衍生出來的。就拿資料庫層來說吧,我們平滑地實作資料存儲的橫向和縱向的擴充,并對上一層級是透明的,那麼我們就實作了資料庫的池化,也就是說對外服務的資料庫可以視為一個,基本上實作了資料庫雲架構。
從以上架構來看,高并發的壓力經過了網絡層和中間件層的過濾,到達最底層的資料庫層,基本上都不會有壓力了,應用層、網絡層、中間件層都可以視為資料庫的保護層。當我們進行應用系統壓力測試的時候,絕大多數情況下,資料庫都是沒有太大壓力的,最容易出現問題的往往是中間件層,換而言之,在資料庫被壓垮之前中間件層已經被壓垮了。這也提醒我們隻做系統應用壓力測試是不夠的,我們還需要做資料庫的壓力測試,找到資料庫層的瓶頸所在。
這樣是不是可以就此高枕無憂了呢?當然不能,資料庫出現高并發壓力在實際應用中還是比較常見的。難道我們前面說的不對?不是的,可以看到不論是網絡層,還是中間件層,都是在分流壓力,壓力并沒有憑空消失,這些使用者會話要通路的資料分布是無法控制的,如果分布過于集中,那麼資料庫會在某一個點上出現高并發争用,也就是熱點争用,如上述談話的背景一樣。
面對高并發壓力,我們現在已經很清楚自己要做什麼了吧?就是一定程度上實作資料通路的分流工作,也就是通常所說的縱橫擴充。另一方面來看,任何的擴充都是有一個核心點的,就是我們的oracle資料庫,擴充工作在一定程度上是對其核心地位的弱化,但是核心仍然是核心,在擴充之前,必須做好oracle核心庫的設計。