12 | 架構設計流程:評估和選擇備選方案

上一期我講了設計備選方案,在完成備選方案設計后,如何挑選出最終的方案也是一個很大的挑戰(zhàn),主要原因有:

每個方案都是可行的,如果方案不可行就根本不應該作為備選方案。

沒有哪個方案是完美的。例如,A 方案有性能的缺點,B 方案有成本的缺點,C 方案有新技術不成熟的風險。

評價標準主觀性比較強,比如設計師說 A 方案比 B 方案復雜,但另外一個設計師可能會認為差不多,因為比較難將“復雜”一詞進行量化。因此,方案評審的時候我們經常會遇到幾個設計師針對某個方案或者某個技術點爭論得面紅耳赤。

正因為選擇備選方案存在這些困難,所以實踐中很多設計師或者架構師就采取了下面幾種指導思想:

最簡派

設計師挑選一個看起來最簡單的方案。例如,我們要做全文搜索功能,方案 1 基于 MySQL,方案 2 基于 Elasticsearch。MySQL 的查詢功能比較簡單,而 Elasticsearch 的倒排索引設計要復雜得多,寫入數(shù)據(jù)到 Elasticsearch,要設計 Elasticsearch 的索引,要設計 Elasticsearch 的分布式……全套下來復雜度很高,所以干脆就挑選 MySQL 來做吧。

最牛派

最牛派的做法和最簡派正好相反,設計師會傾向于挑選技術上看起來最牛的方案。例如,性能最高的、可用性最好的、功能最強大的,或者淘寶用的、微信開源的、Google 出品的等。

我們以緩存方案中的 Memcache 和 Redis 為例,假如我們要挑選一個搭配 MySQL 使用的緩存,Memcache 是純內存緩存,支持基于一致性 hash 的集群;而 Redis 同時支持持久化、支持數(shù)據(jù)字典、支持主備、支持集群,看起來比 Memcache 好很多啊,所以就選 Redis 好了。

最熟派

設計師基于自己的過往經驗,挑選自己最熟悉的方案。我以編程語言為例,假如設計師曾經是一個 C++ 經驗豐富的開發(fā)人員,現(xiàn)在要設計一個運維管理系統(tǒng),由于對 Python 或者 Ruby on Rails 不熟悉,因此繼續(xù)選擇 C++ 來做運維管理系統(tǒng)。

領導派

領導派就更加聰明了,列出備選方案,設計師自己拿捏不定,然后就讓領導來定奪,反正最后方案選的對那是領導厲害,方案選的不對怎么辦?那也是領導“背鍋”。

其實這些不同的做法本身并不存在絕對的正確或者絕對的錯誤,關鍵是不同的場景應該采取不同的方式。也就是說,有時候我們要挑選最簡單的方案,有時候要挑選最優(yōu)秀的方案,有時候要挑選最熟悉的方案,甚至有時候真的要領導拍板。因此關鍵問題是:這里的“有時候”到底應該怎么判斷?今天我就來講講架構設計流程的第 3 步:評估和選擇備選方案。

架構設計第 3 步:評估和選擇備選方案

前面提到了那么多指導思想,真正應該選擇哪種方法來評估和選擇備選方案呢?我的答案就是“360 度環(huán)評”!具體的操作方式為:列出我們需要關注的質量屬性點,然后分別從這些質量屬性的維度去評估每個方案,再綜合挑選適合當時情況的最優(yōu)方案。

常見的方案質量屬性點有:性能、可用性、硬件成本、項目投入、復雜度、安全性、可擴展性等。在評估這些質量屬性時,需要遵循架構設計原則 1“合適原則”和原則 2“簡單原則”,避免貪大求全,基本上某個質量屬性能夠滿足一定時期內業(yè)務發(fā)展就可以了。

假如我們做一個購物網站,現(xiàn)在的 TPS 是 1000,如果我們預期 1 年內能夠發(fā)展到 TPS 2000(業(yè)務一年翻倍已經是很好的情況了),在評估方案的性能時,只要能超過 2000 的都是合適的方案,而不是說淘寶的網站 TPS 是每秒 10 萬,我們的購物網站就要按照淘寶的標準也實現(xiàn) TPS 10 萬。

有的設計師會有這樣的擔心:如果我們運氣真的很好,業(yè)務直接一年翻了 10 倍,TPS 從 1000 上升到 10000,那豈不是按照 TPS 2000 做的方案不合適了,又要重新做方案?

這種情況確實有可能存在,但概率很小,如果每次做方案都考慮這種小概率事件,我們的方案會出現(xiàn)過度設計,導致投入浪費??紤]這個問題的時候,需要遵循架構設計原則 3“演化原則”,避免過度設計、一步到位的想法。按照原則 3 的思想,即使真的出現(xiàn)這種情況,那就算是重新做方案,代價也是可以接受的,因為業(yè)務如此迅猛發(fā)展,錢和人都不是問題。例如,淘寶和微信的發(fā)展歷程中,有過多次這樣大規(guī)模重構系統(tǒng)的經歷。

通常情況下,如果某個質量屬性評估和業(yè)務發(fā)展有關系(例如,性能、硬件成本等),需要評估未來業(yè)務發(fā)展的規(guī)模時,一種簡單的方式是將當前的業(yè)務規(guī)模乘以 2 ~4 即可,如果現(xiàn)在的基數(shù)較低,可以乘以 4;如果現(xiàn)在基數(shù)較高,可以乘以 2。例如,現(xiàn)在的 TPS 是 1000,則按照 TPS 4000 來設計方案;如果現(xiàn)在 TPS 是 10000,則按照 TPS 20000 來設計方案。

當然,最理想的情況是設計一個方案,能夠簡單地擴容就能夠跟上業(yè)務的發(fā)展。例如,我們設計一個方案,TPS 2000 的時候只要 2 臺機器,TPS 20000 的時候只需要簡單地將機器擴展到 20 臺即可。但現(xiàn)實往往沒那么理想,因為量變會引起質變,具體哪些地方質變,是很難提前很長時間能預判到的。舉一個最簡單的例子:一個開發(fā)團隊 5 個人開發(fā)了一套系統(tǒng),能夠從 TPS 2000 平滑擴容到 TPS 20000,但是當業(yè)務規(guī)模真的達到 TPS 20000 的時候,團隊規(guī)模已經擴大到了 20 個人,此時系統(tǒng)發(fā)生了兩個質變:

首先是團隊規(guī)模擴大,20 個人的團隊在同一個系統(tǒng)上開發(fā),開發(fā)效率變將很低,系統(tǒng)迭代速度很慢,經常出現(xiàn)某個功能開發(fā)完了要等另外的功能開發(fā)完成才能一起測試上線,此時如果要解決問題,就需要將系統(tǒng)拆分為更多子系統(tǒng)。

其次是原來單機房的集群設計不滿足業(yè)務需求了,需要升級為異地多活的架構。

如果團隊一開始就預測到這兩個問題,系統(tǒng)架構提前就拆分為多個子系統(tǒng)并且支持異地多活呢?這種“事后諸葛亮”也是不行的,因為最開始的時候團隊只有 5 個人,5 個人在有限的時間內要完成后來 20 個人才能完成的高性能、異地多活、可擴展的架構,項目時間會遙遙無期,業(yè)務很難等待那么長的時間。

完成方案的 360 度環(huán)評后,我們可以基于評估結果整理出 360 度環(huán)評表,一目了然地看到各個方案的優(yōu)劣點。但是 360 度環(huán)評表也只能幫助我們分析各個備選方案,還是沒有告訴我們具體選哪個方案,原因就在于沒有哪個方案是完美的,極少出現(xiàn)某個方案在所有對比維度上都是最優(yōu)的。例如:引入開源方案工作量小,但是可運維性和可擴展性差;自研工作量大,但是可運維和可維護性好;使用 C 語言開發(fā)性能高,但是目前團隊 C 語言技術積累少;使用 Java 技術積累多,但是性能沒有 C 語言開發(fā)高,成本會高一些……諸如此類。

面臨這種選擇上的困難,有幾種看似正確但實際錯誤的做法。

數(shù)量對比法:簡單地看哪個方案的優(yōu)點多就選哪個。例如,總共 5 個質量屬性的對比,其中 A 方案占優(yōu)的有 3 個,B 方案占優(yōu)的有 2 個,所以就挑選 A 方案。

這種方案主要的問題在于把所有質量屬性的重要性等同,而沒有考慮質量屬性的優(yōu)先級。例如,對于 BAT 這類公司來說,方案的成本都不是問題,可用性和可擴展性比成本要更重要得多;但對于創(chuàng)業(yè)公司來說,成本可能就會變得很重要。

其次,有時候會出現(xiàn)兩個方案的優(yōu)點數(shù)量是一樣的情況。例如,我們對比 6 個質量屬性,很可能出現(xiàn)兩個方案各有 3 個優(yōu)點,這種情況下也沒法選;如果為了數(shù)量上的不對稱,強行再增加一個質量屬性進行對比,這個最后增加的不重要的屬性反而成了影響方案選擇的關鍵因素,這又犯了沒有區(qū)分質量屬性的優(yōu)先級的問題。

加權法:每個質量屬性給一個權重。例如,性能的權重高中低分別得 10 分、5 分、3 分,成本權重高中低分別是 5 分、3 分、1 分,然后將每個方案的權重得分加起來,最后看哪個方案的權重得分最高就選哪個。

這種方案主要的問題是無法客觀地給出每個質量屬性的權重得分。例如,性能權重得分為何是 10 分、5 分、3 分,而不是 5 分、3 分、1 分,或者是 100 分、80 分、60 分?這個分數(shù)是很難確定的,沒有明確的標準,甚至會出現(xiàn)為了選某個方案,設計師故意將某些權重分值調高而降低另外一些權重分值,最后方案的選擇就變成了一個數(shù)字游戲了。

正確的做法是按優(yōu)先級選擇,即架構師綜合當前的業(yè)務發(fā)展情況、團隊人員規(guī)模和技能、業(yè)務發(fā)展預測等因素,將質量屬性按照優(yōu)先級排序,首先挑選滿足第一優(yōu)先級的,如果方案都滿足,那就再看第二優(yōu)先級……以此類推。那會不會出現(xiàn)兩個或者多個方案,每個質量屬性的優(yōu)缺點都一樣的情況呢?理論上是可能的,但實際上是不可能的。前面我提到,在做備選方案設計時,不同的備選方案之間的差異要比較明顯,差異明顯的備選方案不可能所有的優(yōu)缺點都是一樣的。

評估和選擇備選方案實戰(zhàn)

再回到我們設計的場景“前浪微博”。針對上期提出的 3 個備選方案,架構師組織了備選方案評審會議,參加的人有研發(fā)、測試、運維、還有幾個核心業(yè)務的主管。

1. 備選方案 1:采用開源 Kafka 方案

業(yè)務主管傾向于采用 Kafka 方案,因為 Kafka 已經比較成熟,各個業(yè)務團隊或多或少都了解過 Kafka。

中間件團隊部分研發(fā)人員也支持使用 Kafka,因為使用 Kafka 能節(jié)省大量的開發(fā)投入;但部分人員認為 Kafka 可能并不適合我們的業(yè)務場景,因為 Kafka 的設計目的是為了支撐大容量的日志消息傳輸,而我們的消息隊列是為了業(yè)務數(shù)據(jù)的可靠傳輸。

運維代表提出了強烈的反對意見:首先,Kafka 是 Scala 語言編寫的,運維團隊沒有維護 Scala 語言開發(fā)的系統(tǒng)的經驗,出問題后很難快速處理;其次,目前運維團隊已經有一套成熟的運維體系,包括部署、監(jiān)控、應急等,使用 Kafka 無法融入這套體系,需要單獨投入運維人力。

測試代表也傾向于引入 Kafka,因為 Kafka 比較成熟,無須太多測試投入。

2. 備選方案 2:集群 + MySQL 存儲

中間件團隊的研發(fā)人員認為這個方案比較簡單,但部分研發(fā)人員對于這個方案的性能持懷疑態(tài)度,畢竟使用 MySQL 來存儲消息數(shù)據(jù),性能肯定不如使用文件系統(tǒng);并且有的研發(fā)人員擔心做這樣的方案是否會影響中間件團隊的技術聲譽,畢竟用 MySQL 來做消息隊列,看起來比較“土”、比較另類。

運維代表贊同這個方案,因為這個方案可以融入到現(xiàn)有的運維體系中,而且使用 MySQL 存儲數(shù)據(jù),可靠性有保證,運維團隊也有豐富的 MySQL 運維經驗;但運維團隊認為這個方案的成本比較高,一個數(shù)據(jù)分組就需要 4 臺機器(2 臺服務器 + 2 臺數(shù)據(jù)庫)。

測試代表認為這個方案測試人力投入較大,包括功能測試、性能測試、可靠性測試等都需要大量地投入人力。

業(yè)務主管對這個方案既不肯定也不否定,因為反正都不是業(yè)務團隊來投入人力來開發(fā),系統(tǒng)維護也是中間件團隊負責,對業(yè)務團隊來說,只要保證消息隊列系統(tǒng)穩(wěn)定和可靠即可。

3. 備選方案 3:集群 + 自研存儲系統(tǒng)

中間件團隊部分研發(fā)人員認為這是一個很好的方案,既能夠展現(xiàn)中間件團隊的技術實力,性能上相比 MySQL 也要高;但另外的研發(fā)人員認為這個方案復雜度太高,按照目前的團隊人力和技術實力,要做到穩(wěn)定可靠的存儲系統(tǒng),需要耗時較長的迭代,這個過程中消息隊列系統(tǒng)可能因為存儲出現(xiàn)嚴重問題,例如文件損壞導致丟失大量數(shù)據(jù)。

運維代表不太贊成這個方案,因為運維之前遇到過幾次類似的存儲系統(tǒng)故障導致數(shù)據(jù)丟失的問題,損失慘重。例如,MongoDB 丟數(shù)據(jù)、Tokyo Tyrant 丟數(shù)據(jù)無法恢復等。運維團隊并不相信目前的中間件團隊的技術實力足以支撐自己研發(fā)一個存儲系統(tǒng)(這讓中間件團隊的人員感覺有點不爽)。

測試代表贊同運維代表的意見,并且自研存儲系統(tǒng)的測試難度也很高,投入也很大。

業(yè)務主管對自研存儲系統(tǒng)也持保留意見,因為從歷史經驗來看,新系統(tǒng)上線肯定有 bug,而存儲系統(tǒng)出 bug 是最嚴重的,一旦出 bug 導致大量消息丟失,對系統(tǒng)的影響會嚴重。

針對 3 個備選方案的討論初步完成后,架構師列出了 3 個方案的 360 度環(huán)評表:

列出這個表格后,無法一眼看出具體哪個方案更合適,于是大家都把目光投向架構師,決策的壓力現(xiàn)在集中在架構師身上了。

架構師經過思考后,給出了最終選擇備選方案 2,原因有:

排除備選方案 1 的主要原因是可運維性,因為再成熟的系統(tǒng),上線后都可能出問題,如果出問題無法快速解決,則無法滿足業(yè)務的需求;并且 Kafka 的主要設計目標是高性能日志傳輸,而我們的消息隊列設計的主要目標是業(yè)務消息的可靠傳輸。

排除備選方案 3 的主要原因是復雜度,目前團隊技術實力和人員規(guī)模(總共 6 人,還有其他中間件系統(tǒng)需要開發(fā)和維護)無法支撐自研存儲系統(tǒng)(參考架構設計原則 2:簡單原則)。

備選方案 2 的優(yōu)點就是復雜度不高,也可以很好地融入現(xiàn)有運維體系,可靠性也有保障。

針對備選方案 2 的缺點,架構師解釋是:

備選方案 2 的第一個缺點是性能,業(yè)務目前需要的性能并不是非常高,方案 2 能夠滿足,即使后面性能需求增加,方案 2 的數(shù)據(jù)分組方案也能夠平行擴展進行支撐(參考架構設計原則 3:演化原則)。

備選方案 2 的第二個缺點是成本,一個分組就需要 4 臺機器,支撐目前的業(yè)務需求可能需要 12 臺服務器,但實際上備機(包括服務器和數(shù)據(jù)庫)主要用作備份,可以和其他系統(tǒng)并行部署在同一臺機器上。

備選方案 2 的第三個缺點是技術上看起來并不很優(yōu)越,但我們的設計目的不是為了證明自己(參考架構設計原則 1:合適原則),而是更快更好地滿足業(yè)務需求。

最后,大家針對一些細節(jié)再次討論后,確定了選擇備選方案 2。

通過“前浪微博”這個案例我們可以看出,備選方案的選擇和很多因素相關,并不單單考慮性能高低、技術是否優(yōu)越這些純技術因素。業(yè)務的需求特點、運維團隊的經驗、已有的技術體系、團隊人員的技術水平都會影響備選方案的選擇。因此,同樣是上述 3 個備選方案,有的團隊會選擇引入 Kafka(例如,很多創(chuàng)業(yè)公司的初創(chuàng)團隊,人手不夠,需要快速上線支撐業(yè)務),有的會選擇自研存儲系統(tǒng)(例如,阿里開發(fā)了 RocketMQ,人多力量大,業(yè)務復雜是主要原因)。

小結

今天我為你講了架構設計流程的第三個步驟:評估和選擇備選方案,并且基于模擬的“前浪微博”消息隊列系統(tǒng),給出了具體的評估和選擇示例,希望對你有所幫助。

這就是今天的全部內容,留一道思考題給你吧,RocketMQ 和 Kafka 有什么區(qū)別,阿里為何選擇了自己開發(fā) RocketMQ?

歡迎你把答案寫到留言區(qū),和我一起討論。相信經過深度思考的回答,也會讓你對知識的理解更加深刻。(編輯亂入:精彩的留言有機會獲得豐厚福利哦?。?/p>

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容