像我這樣的菜鳥,總會有各類疑問,剛開始是對 JDK API 的疑問,對 NIO 的疑問,對 JVM 的疑問,當工做幾年後,對服務的可用性,可擴展性也有了新的疑問,什麼疑問呢?實際上是老生常談的話題:服務的擴容問題。mysql
讓咱們從最初開始。程序員
單體應用 每一個創業公司基本都是從相似 SSM 和 SSH 這種架構起來的,沒什麼好講的,基本每一個程序員都經歷過。面試
RPC 應用 當業務愈來愈大,咱們須要對服務進行水平擴容,擴容很簡單,只要保證服務是無狀態的就能夠了,以下圖:算法
當業務又愈來愈大,咱們的服務關係錯綜複雜,同時,有不少服務訪問都是不須要鏈接 DB 的,只須要鏈接緩存便可,那麼就能夠作成分離的,減小 DB 寶貴的鏈接。以下圖:sql
我相信大部分公司都是在這個階段。Dubbo 就是爲了解決這個問題而生的。數據庫
若是你的公司產品很受歡迎,業務繼續高速發展,數據愈來愈多,SQL 操做愈來愈慢,那麼數據庫就會成爲瓶頸,那麼你確定會想到分庫分表,不論經過 ID hash 或者 range 的方式均可以。以下圖:緩存
這下應該沒問題了吧。任憑你用戶再多,併發再高,我只要無限擴容數據庫,無限擴容應用,就能夠了。架構
這也是本文的標題,分庫分表就能解決無限擴容嗎?併發
實際上,像上面的架構,並不能解決。微服務
其實,這個問題和 RPC 的問題有點相似:數據庫鏈接過多!!!
一般,咱們的 RPC 應用因爲是使用中間件進行訪問數據庫,應用其實是不知道到底要訪問哪一個數據庫的,訪問數據庫的規則由中間件決定,例如 sharding JDBC。這就致使,這個應用必須和全部的數據庫鏈接,就像咱們上面的架構圖同樣,一個 RPC 應用須要和 3 個 mysql 鏈接,若是是 30 個 RPC 應用,每一個 RPC 的數據庫鏈接池大小是 8 ,每一個 mysql 須要維護 240 個鏈接,咱們知道,mysql 默認鏈接數是 100,最大鏈接數是 16384,也就是說,假設每一個應用的鏈接池大小是 8 ,超過 2048 個應用就沒法再繼續鏈接了,也就沒法繼續擴容了。
注意,因爲每一個物理庫有不少邏輯庫,再加上微服務運動如火如荼, 2048 並無看起來那麼大。
也許你說,我能夠經過前面加一個 proxy 來解決鏈接數的問題,實際上,代理的性能也會成爲問題,爲何?代理的鏈接數也是不能超過 16384 的,若是併發超過 16384,變成 163840,那麼 proxy 也解決不了問題。
怎麼辦?讓咱們再看看上面的架構圖:
咱們發現,問題是出在 「每一個 RPC 應用都要連全部的庫」,致使擴容應用的同時,每一個數據庫鏈接數就要增長。就算增長數據庫,也不能解決鏈接數的問題。
那怎麼辦呢?
單元化,聽起來高大上,一般在一些 XXX 大會上,分享 「關於兩地三中心」,「三地五中心」,「異地多活」 等等牛逼的名詞的時候,單元化也會一塊兒出現。
這裏咱們不討論那麼牛逼的,就只說 「數據庫鏈接數過多」 的問題。
實際上,思路很簡單:咱們不讓應用鏈接全部的數據庫就能夠了。
假設咱們根據 range 分紅了 10 個庫,如今有 10 個應用,咱們讓每一個應用只連一個庫,當應用增多變成 20 個,數據庫的鏈接不夠用了,咱們就將 10 個庫分紅 20 個庫,這樣,不管你應用擴容到多少個,均可以解決數據庫鏈接數過多的問題。
注意:作這件事的前提是:你必須保證,訪問你這個應用的 request 請求的數據庫必定是在這個應用的。s
換個說法,當用戶從 DNS 那裏進來的時候,就知道本身要去那個應用了,因此,規則在 DNS 以前就定好了,雖然這有點誇張,但確定在進應用以前就知道要去哪一個庫了。
因此,這一般須要一個規則,例如經過用戶 ID hash,由配置中心廣播 hash 規則。這樣,全部的組件都能保持一致的規則,從而正確的訪問到數據庫。以下圖:
到這裏,咱們終於解決了無限擴容的問題。
本文從單體應用開始,逐步講述了一個正常後臺的演進歷程,知道了分庫分表並不能解決 「無限擴容」 的問題,只有單元化才能解決這問題。而單元化則帶來更多的複雜性。可是好處不言而喻。
單元化帶來的更多的思路。
有了單元化,解決了無限擴容的問題,可是咱們尚未考慮單點的問題,即服務的可用性。要知道,咱們這裏的數據庫都是單點的。
「不積跬步,無以致千里」,但願將來的你能:有夢爲馬 隨處可棲!加油,少年!
關注公衆號:「Java 知己」,天天更新Java知識哦,期待你的到來!