當前位置:網站首頁>當年,我的架構師之路差點完蛋,幸虧了它,萬字詳解微服務的哨兵機制

當年,我的架構師之路差點完蛋,幸虧了它,萬字詳解微服務的哨兵機制

2021-08-20 03:44:22 程序員小李子

三、

這種痛苦的糾結折磨了我大概一周,直到我看到了 CAP 定理。當 CAP 定理說分布式系統在分區容錯的時候,只能一致性和可用性二選一時,我高興的蹦了起來。

原來,可用性和一致性是不能兼得的。

為何我會那麼高興?因為逼我入死角的可不僅是技術上的問題了,我還承受著來自於業務方和領導的壓力。每天一上班,我就需要面對業務各方的抱怨,以及領導一輪又一輪的催促。

有了 CAP 定理的支持,我知道我最終是要面臨選擇的。既然在這個世界上做分布式架構的所有人都要面臨選擇,那我又怎麼可能獨善其身呢?

在對單機數據庫引發的各種問題做了一次徹底的各種歸因以後,我下了决心:

一定要搞定拆分數據庫並給出良好方案。

只是,2PC 這個攔路虎,它成為了我的大敵。通過 CAP 定理,我非常肯定,只要我選了 2PC 方案,可用性就一定會出現嚴重的問題,這個方案也肯定不可能拿出來丟人現眼的。

我唯一的方向就是去犧牲一些一致性,往可用性方向走。可是,怎麼走呢?

也許是老天眷顧,也許是大家都承受著和我一樣夜不能寐的壓力,很快,BASE 理論在國內傳開了。

BASE 理論讓我知道了,這個世上能排到前幾名的技術大公司也一樣會出問題,也一樣會對這些問題進行妥協。而且 BASE 理論的思想讓我的思路一下子就打開了,苦思而不得的問題開始有了頭緒。

我要開始著手制定技術方案了。

四、

BASE 思想中的 BA(Basically Available)基本可用,是鼓勵通過預先的架構設計或者前期規劃,盡量在分布式的系統中,把以前可能影響全平臺的嚴重問題,變成只會影響平臺中的一部分數據或者功能的非嚴重問題。

有了這個思想之後,我就對廣告平臺中的很多重要的數據錶進行了拆分,並將這些錶的數據分散到了不同的數據庫中。

比如,有個廣告流量詳情錶,每當用戶點擊廣告或者廣告展示出來的時候,為了保證不丟失,這些數據都是實時插入到這個錶裏的。

我對這張錶是怎麼切分的呢?

當有人點擊廣告了,他的點擊記錄會被傳到我的應用層,然後我會在應用層根據廣告 ID 做哈希,再根據哈希結果的不同,分別存到不同的數據庫中去。

image

假如這三個數據庫中的一個出現了問題,則只會有三分之一的數據受到影響。這就實現了 BASE 理論中的 BA——基本可用了。基本可用其實也真的就是錶達的這麼一回事:

通過一些架構設計,即使平臺中某部分組件出現了問題,也不會導致整個平臺不可用。

好了,既然采取了數據庫拆分的策略,又根據 BASE 理論中的 BA 思想拆分了一些重要的錶,那麼,到了現在,可能也無從後悔,只能繼續沿著 BASE 這條路,一條路走到黑了。

五、

接下來,需要著手解决性能問題了。2PC 方案……算了……它瘋狂的一致性性格會要了我的狗命的。

那麼極端點,我們不搞事務可不可以呢?

還用前面說的那套廣告平臺舉例。

當時,從業務上,要求廣告的訪問數據都要保證及時入庫不能丟,因為丟了就可能造成計費的損失,而這些損失全是錢。所以,每當用戶點擊廣告或者廣告展示出來的時候,為了保證不丟失,這些數據都是實時入庫的。

又根據業務需求,當廣告流量入庫時,還需要往廣告預算錶和媒體流水錶裏同時根據這筆流量進行記賬,以供後續財務計算。

image

如果完全不考慮事務,則拆分庫後,操作可能會是這個樣子。

image

這三個操作可能會並行發往不同的數據庫執行。由於三個操作之間沒有事務的約束,所以,一個操作出問題了,另外的操作並不會受到影響。

而這卻也引發了另外一個問題,數據狀態不一致。

如果在上面的業務中,插入廣告流量錶的操作失敗了,但其餘兩張錶插入成功了,業務就會面臨一個很尷尬的情况:他們算出的財務報錶沒有依據。財務流水中找不到產生了這筆流水的依據。

而這種不一致的狀態由於已經被持久化到了數據庫中,就會導致這種不一致的狀態永久存在了數據庫中。這業務能接受嗎?但凡有點職業精神的程序員能接受嗎?

要有折中的辦法!!!

六、

現在再回過頭來看看 2PC 的問題。假設 2PC 的實現是一步步執行的(當然,不管是一步一步還是异步並發,他們總是要確保大家要麼一起成功要麼一起失敗的。

所以,即使並發操作,也不會節省多少性能,因為短板在執行最慢的那條語句上。如果執行我們上面的事務需要幾步呢?

假如現在要執行事務 A:

  1. 協調器發出事務 A 中的第一條語句 Insert into 流量錶
  2. 協調器等待結果
  3. 協調器發出事務 A 中的第二條語句 Insert into 預算錶
  4. 協調器等待結果
  5. 協調器發出事務 A 中的第三條語句 Insert into 流水錶
  6. 協調器等待結果

如果中間有失敗的,協調器還需要做額外的操作:

  1. 協調器告訴事務 A 中第一條語句做回滾操作
  2. 協調器等待結果
  3. 協調器告訴事務 A 中第二條語句做回滾操作
  4. 協調器等待結果
  5. 協調器告訴事務 A 中第三條語句做回滾操作
  6. 協調器等待結果

“天哪,這麼多步操作啊!!!”

這簡直是讓人窒息的操作步驟了。如果有一種方法既能節省步驟又能節省事務執行時間該有多好啊。

嗯……我只能說當時的自己實在是長得醜卻想的美。

世上尚不存在這種方法的。但是,世上還存在另外的解决此類事情的方式:

异步處理,時間分攤

我們分析下關於插入廣告流量這塊兒的業務。你會發現一個神奇的現象,即廣告流量錶中的數據才是核心,而預算錶和流水錶統統都是廣告流量錶中數據的一種緩存而已。

如果,嗯,我是說如果有這麼一種辦法,即我們先把廣告流量數據插入數據庫,成功以後,再把以廣告流量數據作為根基的附屬操作(這裏是插入預算錶和流水錶)放到一個地方持久化。然後,我們再從那個存放附屬操作的地方把操作信息取出來,專門對這些操作信息進行處理。

而這種處理方式可能會非常靈活,要麼可以對這些操作信息進行批量處理,要麼可以對他們异步的在後臺處理。處理這些操作信息成功以後,再把以前持久化好的操作信息給删除。

整個方法實施下來,相當於把應該在 A 時刻在前臺阻塞著花 3 秒處理業務的操作,變成了在 A 時刻前臺花 1 秒,然後在 B 時刻後臺花 2 秒處理業務的操作,這不也可以變相的達到我們想節省步驟和事務執行時間的目標了嗎?

這真的是一個好的思路啊,還記得當時的自己想到這個思路的時候,忍不住在內心大喊了起來:“那個存附屬操作信息的地方就是 MQ 啊。用 MQ,MQ 就能做這件事情。”

那麼就一起來看下 MQ 是如何幫我解决這個大難題的吧,針對上面的廣告流量詳情的業務,我們用了 MQ 之後會有如下的步驟:

  1. 執行 Insert into 流量錶語句
  2. 等待結果
  3. 發消息到 MQ 裏,內容為 Insert into 預算錶
  4. 等待 MQ 持久化成功
  5. 發消息到 MQ 裏,內容為 Insert into 流水錶
  6. 等待 MQ 持久化成功

如果發給 MQ 消息失敗:

  1. 可以降級寫到本地日志中

OK,那麼這改進後的方法是怎麼提昇性能的呢?

  • 首先,我們發給 MQ 的消息可以批量發送;
  • 其次,發給 MQ 並持久化消息要比數據庫執行一次事務快了一個數量級;
  • 最後,失敗後,回滾操作成本降低了不止一個數量級。

這個方法本質上,在應用層其實就執行了一條語句而已,剩下的完全可以根據業務需求的不同,選擇處理 MQ 中的消息的方式。比如,處理消息既可以异步慢慢處理,也可以推遲一段時間後處理,更可以淩晨定時處理。

可以看到,使用 MQ 方案後,對廣告流量這個業務需求而言,其實,出現了一個中間狀態:廣告流量錶有數據,但是以這條數據為基准的預算錶和流水錶暫時還沒有數據。

中間這個狀態此時是不滿足業務需求的。而這種狀態,在 BASE 理論中就被稱為:

軟狀態(Soft state)

至於廣告流量錶當時沒有及時插入到預算錶和流水錶中的數據呢,它們最終也將會隨著後續對 MQ 消息的處理而被補充完整的。

而對於這種當時不符合業務需求的軟狀態,通過一些後續內部的自動化操作把數據狀態補充完整從而最終滿足業務需求的情况,在 BASE 理論中就被稱為了:

最終一致性(Eventually consistent)

由此,我通過不斷利用 BASE 理論中的軟狀態和最終一致性的思路,最終補上了平臺數據庫切分需要的最後一塊拼圖——平臺性能大提昇

最近我根據上述的技術體系圖搜集了幾十套騰訊、頭條、阿裏、美團等公司21年的面試題,把技術點整理成了視頻(實際上比預期多花了不少精力),包含知識脈絡 + 諸多細節,由於篇幅有限,這裏以圖片的形式給大家展示一部分

 戳這裏免費領取下面所有資料

版權聲明
本文為[程序員小李子]所創,轉載請帶上原文鏈接,感謝
https://cht.chowdera.com/2021/08/20210820034421804i.html

隨機推薦