拜托,面試不要再問我 SpringCloudAlibaba 底層原理
大家好,今天給大家介紹一個非常熱門的技術,同時也是面試的時候面試官特別喜歡問的一個話題,那就是 SpringCloudAlibaba 的底層原理。
現(xiàn)在大家都知道,SpringCloudAlibaba 風靡 Java 開發(fā)行業(yè),各個公司都在用這套技術,所以咱們 Java 工程師出去面試,面試官對 SpringCloudAlibaba 都搞成了面試必問選項了,但凡面試,總會有面試官問問:“兄弟,SpringCloudAlibaba 玩兒過嗎?能聊聊 SpringCloudAlibaba 的底層原理嗎?”
這個時候你要是一臉懵圈的說:“兄弟,我們玩兒的是 SpringCloud 啊,你后面加個 Alibaba 干什么?這東西什么時候跟阿里扯上鉤了?”要是面試時你這么回答,那么恭喜你,基本上面試官應該會借口肚子疼要上廁所,然后 30 分鐘就結束這場面試了。
所以說,咱們這篇文章,就是希望各位兄弟別出現(xiàn)上面那種 30 分鐘就被迫結束面試的窘迫問題。
今天我們先一步一步的來讓大家理解一下 SpringCloudAlibaba 里面都包含哪些技術組件,在系統(tǒng)里都是用來干什么的,然后再給大家分析一下這些技術底層的原理。
首先,假設你們公司有兩個系統(tǒng),咱們就假設是系統(tǒng) A 和系統(tǒng) B 吧,這倆系統(tǒng)現(xiàn)在的需求就是要讓系統(tǒng) A 可以發(fā)送一個請求給系統(tǒng) B 來實現(xiàn)系統(tǒng)間的接口調用。
咱們看下面這個圖:
現(xiàn)在有一個最大的問題,系統(tǒng) A 是部署在一臺服務器上的,系統(tǒng) B 又是部署在另外一臺服務器上的,那系統(tǒng) A 怎么可能莫名其妙的就知道系統(tǒng)B部署在哪臺機器上呢?
這就好比說,您在大馬路上走著走著,看到一個美女,回家了特別想微信聯(lián)系她一下,結果您都不知道她的微信號,沒加過好友,憑空也沒法跟美女搭訕啊!
那跟美女搭訕的正確姿勢應該是什么呢?這得有一個前提,就是您有一個中間的朋友,他認識那美女有人家的微信號,這個時候你可以找那中間的朋友要到人家微信號,再根據(jù)微信號加人家美女好友,接著就可以實現(xiàn)無縫情感溝通啦!
開個玩笑,上面僅僅是枯燥技術文章中的一個插曲,其實對于您的系統(tǒng) A 來說,這時就必須引入一個 SpringCloudAlibaba 的關鍵技術組件,叫做 Nacos。
大家請擦亮眼睛,這個 Nacos 是一個關鍵名詞,一定要記住了,他的學術定位叫做“服務注冊中心”。
這個 Nacos 就類似上面說的那個有美女微信號的第三方朋友,他是知道你的系統(tǒng)B部署在哪臺機器上的,因為系統(tǒng) B 在啟動的時候會主動向 Nacos 服務注冊中心進行服務注冊,告訴 Nacos 說自己部署在哪臺機器上,自己的機器 ip 地址是 172.86.76.251,自己的端口號是 20880。
大家看下圖:
這個時候,系統(tǒng) A 如果想要調用系統(tǒng)B的接口,就可以發(fā)送請求給 Nacos 服務注冊中心說,兄弟,能告訴我系統(tǒng) B 部署在哪臺機器上嗎?我想調用一下他的接口,這個動作有專業(yè)術語,叫做“服務發(fā)現(xiàn)”。
然后呢,Nacos 服務注冊中心絕對會很大方的把系統(tǒng) B 的微信號,奧不對,是系統(tǒng) B 的機器 ip 和端口號都告訴你的。
這時系統(tǒng) A 知道了系統(tǒng) B 的 ip 地址和端口號,就可以發(fā)送請求過去調用系統(tǒng) B 的接口了,大家請看下圖:
我們再來看下一個問題,假設系統(tǒng) B 是個大美女,然后還有多個孿生姐妹花,也就是說系統(tǒng) B 部署在了多臺服務器上,我們管這種情況叫做系統(tǒng) B 有多個服務實例部署在了多臺服務器上,然后這個時候系統(tǒng) A 想要調用系統(tǒng) B,應該怎么辦呢?
我們看下圖:
其實也很簡單,系統(tǒng) B 的每個服務實例部署了一臺機器后,他們都得對 Nacos 服務注冊中心發(fā)起服務注冊的請求,所以 Nacos 是知道系統(tǒng) B 部署的每臺機器的 ip 地址和端口號的,看下圖。
然后這個系統(tǒng) A 找 Nacos 進行服務發(fā)現(xiàn)的時候,一下子就會發(fā)現(xiàn)系統(tǒng) B 部署在了兩臺機器上,也就是說兩臺機器的 ip 地址和端口號他都會發(fā)現(xiàn)。這個時候問題就來了,系統(tǒng) A 很猶豫啊,到底調用系統(tǒng) B 的哪個機器呢?
很簡單,他可以第一次調用機器 1,第二次調用機器 2,第三次調用機器 1,第四次機器 2,以此類推,循環(huán)往復,這個過程叫做負載均衡,系統(tǒng) A 可以通過負載均衡把自己的所有請求均勻的分發(fā)給系統(tǒng) B 的每臺機器,看下圖。
那么下一個問題又來了,系統(tǒng) A 如果要想辦法去調用系統(tǒng)B的某個接口的話,就必須要跟系統(tǒng) B 建立一個網(wǎng)絡連接,然后通過這個網(wǎng)絡連接發(fā)送請求過去給系統(tǒng) B。
接著系統(tǒng) B 收到了請求,以后就會調用自己本地的某個接口的代碼,然后再把響應結果通過網(wǎng)絡連接返回給系統(tǒng) A,這個過程就叫做 RPC 遠程調用,看下圖。
其實這個 RPC 調用的過程,說白了就類似于跟人聊微信的過程,微信聊天你總得先加個好友,完了再發(fā)個消息過去,接著人家再給你回一個消息吧?
沒錯,咱們這 RPC 調用也是同理,你兩臺機器總得先建立個網(wǎng)絡連接,然后系統(tǒng) A 發(fā)個請求過去,系統(tǒng) B 本地代碼執(zhí)行一下,再返回個響應給你。
那現(xiàn)在問題來了,這個系統(tǒng) A 那里要對系統(tǒng) B 部署的多臺機器實現(xiàn)負載均衡,然后建立網(wǎng)絡連接,接著發(fā)起 RPC 調用,就是系統(tǒng) A 發(fā)個請求過去,系統(tǒng) B 執(zhí)行一下代碼返回個響應,就這套看起來很復雜的流程是誰負責搞定的呢?
簡單,就是 SpringCloudAlibaba 里的另外一個關鍵組件,Dubbo。
這個 Dubbo 就是一個 RPC 的框架,他就是專門負責幫你做負載均衡、網(wǎng)絡連接、RPC 調用這些事情的的,這是 SpringCloudAlibaba 組件體系中的第二個關鍵組件。
大家看下圖:
接著再來討論下一個問題,很多人可能知道,也可能不知道,那就是:一臺 4 核 8G 的服務器,每秒鐘可以抗多少并發(fā)請求?
有一些兄弟平時玩兒過高并發(fā)系統(tǒng),應該是知道這個數(shù)值的,那就是 4 核 8G 的服務器上部署的如果是一個 java 系統(tǒng),這個 java 系統(tǒng)連接的是 MySQL 數(shù)據(jù)庫的話,那么通常來說,這一臺服務器每秒大致可以抗 1000 以內的 QPS,如下圖,每秒 1000 請求我還特意標紅了。
這是為什么呢?原因很簡單,我們要從兩個維度來分析:
第一個維度是,我們的系統(tǒng) A 有多少個線程來處理請求,每個請求要耗費多少 ms 來完成,每個線程每秒可以執(zhí)行多少個請求。
第二個維度是,我們系統(tǒng) A 的 n 多線程拼命處理請求,這個時候會對機器的 CPU 負載造成多大壓力,大概所有線程每秒處理多少請求的時候,機器的 CPU 就扛不住了。
把這兩個問題解決清楚了,也就知道系統(tǒng)每秒可以抗多少請求了。
首先看第一個維度,系統(tǒng) A 一般來說對外接受用戶的請求,都是通過 Tomcat 這種 web 服務器,對外用 spring mvc 提供 controller 這種接口的,接收的都是 http 請求。
所以實際上 tomcat 一般來說,我們都會配置 200 左右的線程,就是說系統(tǒng) A 有 200 個線程會并發(fā)的處理用戶發(fā)來的請求,如下圖。
那么下一個問題來了:tomcat 線程處理一個請求要耗費多長時間?
這個就不好說了,因為一個線程處理一個請求的時候,往往會執(zhí)行你自己寫的一大堆業(yè)務代碼,從 controller 到 service 再到 dao,如果你用 mybatis 做數(shù)據(jù)持久層框架,那么應該會用 mybatis mapper 執(zhí)行一大堆的 SQL 語句。
這往往取決于你的系統(tǒng)代碼有多復雜,執(zhí)行的 SQL 語句有多復雜,要執(zhí)行多少個 SQL,數(shù)據(jù)庫里的表數(shù)據(jù)是萬級、十萬級、還是百萬級,甚至是千萬級、億級。
所以影響因素太多,我們這里取一個不多不少的均值,假設你一個請求需要調用 n 多次數(shù)據(jù)庫,執(zhí)行 n 個 SQL 語句,而且數(shù)據(jù)庫里的數(shù)據(jù)量還小,基本在十萬到百萬級,那么此時大概你一個請求處理要耗費 200ms,如下圖。
所以一個簡單的小學公式就可以計算出來了,你一個線程處理一個請求要耗費 200ms,那么每秒就可以處理 5 個請求,你有 200 個線程,每秒可以處理 200*5=1000 個請求,這個小學生級別的算數(shù)大家沒問題吧?
所以說,按這個維度來說,系統(tǒng) A 部署在 4 核 8G 的系統(tǒng)上,連接了 MySQL 數(shù)據(jù)庫,然后開 200 個 tomcat 線程處理請求,每秒處理 1000 個請求是比較合理的。
第二個維度呢?就是 CPU 負載這個角度來看,其實也是差不多的,這個沒法用算數(shù)來計算,只能告訴大家一個經驗值,那就是當你的系統(tǒng)部署在 4 核 8G 機器上,連接 MySQL 數(shù)據(jù)庫,然后每個請求都要執(zhí)行一堆 SQL 語句的時候,往往你的系統(tǒng)每秒處理到 1000 左右的請求量,你的機器 CPU 負載就會達到 80% 甚至 90% 的使用率,這個時候系統(tǒng)負載已經很高了,再讓機器處理更多請求,他已經完全就做不到了。
好,那么針對這個系統(tǒng) A 每秒可以處理 1000 個請求的經驗值,我們來考慮一個問題,萬一要是你公司搞個活動,突然之間每秒有 2000 個請求過來,或者是被黑客來了個攻擊,每秒的請求數(shù)量特別多,這個時候你怎么辦?
顯而易見你的系統(tǒng) A 會被打死,如下圖:
所以這個時候怎么辦呢?我們就得引入 SpringCloudAlibaba 里的第三個組件了,就是 Sentinel,這個 Sentinel 就是幫助你的系統(tǒng)實現(xiàn)流量防護的。
當你在系統(tǒng) A 里加入 Sentinel 以后,如果要是每秒請求超過了 1000,Sentinel 會直接幫你把多出來的那些請求都直接拒絕掉,這就叫做限流,限制你的系統(tǒng)可以處理的請求數(shù)量,這樣就可以保護你的系統(tǒng)不會被打死,如下圖。
那現(xiàn)在我們已經搞明白 SpringCloudAlibaba 里的三個組件的運行原理和使用場景了,Nacos 是服務注冊中心,Dubbo 是 RPC 調用框架,Sentinel 是流量防護組件,接著來看最后一個組件,那就是 Seata,分布式事務組件。
既然提到了分布式事務,那就肯定是跟事務是有關系的了,這個事務相信大家都知道,就是我們對 MySQL 可以開啟一個事務,事務里執(zhí)行 n 條 SQL,但凡有一個 SQL 失敗了,事務就會回滾,這 n 個 SQL 都不會生效的。
可是在系統(tǒng) A 調用系統(tǒng) B 這種分布式的場景下,事務會怎么樣呢?
大家看下圖,假設系統(tǒng) A 處理一個請求的時候,先對自己的數(shù)據(jù)庫執(zhí)行了一堆 SQL,提交了事務 A,然后通過 Dubbo 發(fā)起 RPC 調用系統(tǒng) B,系統(tǒng) B 對自己的數(shù)據(jù)庫執(zhí)行了一堆 SQL,提交了事務 B。
那么現(xiàn)在問題來了,假設我系統(tǒng) A 的事務 A 都提交了,結果到系統(tǒng) B 的時候,事務 B 執(zhí)行失敗,事務 B 回滾了,這可怎么整?
也就是說一個請求的處理不一致了,一個系統(tǒng)的事務成功都提交完了,沒法回滾了,另外一個系統(tǒng)的事務失敗了!
別著急,只要你引入 Seata 分布式事務框架,就可以輕松搞定這個問題,Seata 這個框架會自動記錄你的事務 A 執(zhí)行的 SQL 語句的逆向補償 SQL。
什么意思呢?假設你事務 A 執(zhí)行的是 insert,那么 Seata 就知道補償?shù)臅r候可以 delete 刪除。
假設你執(zhí)行的是 update,那么 Seata 就可以記錄你 update 之前的老數(shù)據(jù),補償?shù)臅r候可以把數(shù)據(jù)重新 update 回老版本數(shù)據(jù),而且這個逆向補償日志也是記錄在數(shù)據(jù)庫里的,如下圖。
接著 Seata 還會提供一個 Seata server 來監(jiān)控你的各個系統(tǒng)的事務執(zhí)行情況,系統(tǒng) A 的事務 A 執(zhí)行成功了得告訴 Seata server,系統(tǒng) B 的事務 B 執(zhí)行失敗了也得告訴 Seata server,如下圖。
當 Seata server 知道你的系統(tǒng) B 的事務 B 執(zhí)行失敗了,他會告訴系統(tǒng) A 里的 Seata 框架,小兄弟,人家系統(tǒng) B 都失敗了,你趕緊的吧,別墨跡,把你之前記錄的事務 A 逆向補償日志拿出來,把你之前提交的事務恢復到提交前的數(shù)據(jù)狀態(tài),搞一個逆向回滾,如下圖。
好了,到此為止,就給大家把 SpringCloudAlibaba 組件體系的幾個組件的使用場景和工作原理介紹清楚了,包括 Nacos 服務注冊中心、Dubbo RPC 調用框架、Sentinel 流量防護組件、Seata 分布式事務組件,大家看看上面的那個圖,是不是很有成就感?