在前面的專欄里信夫,有同學(xué)留言說(shuō)想看看具體的架構(gòu)設(shè)計(jì)文檔窃蹋。由于信息安全的原因,再加上稍微復(fù)雜的系統(tǒng)静稻,設(shè)計(jì)文檔都是幾十頁(yè)警没,因此專欄無(wú)法直接給出詳細(xì)的文檔案例。但我認(rèn)為提供一個(gè)架構(gòu)設(shè)計(jì)文檔模板還是很有必要的振湾,可以方便你在實(shí)際進(jìn)行架構(gòu)設(shè)計(jì)的時(shí)候更好地編寫相關(guān)文檔杀迹。我還以前面講過(guò)的“前浪微博”消息隊(duì)列為例,給出架構(gòu)設(shè)計(jì)中最重要的兩個(gè)文檔的模板和關(guān)鍵說(shuō)明押搪。這個(gè)案例文檔僅給出一些關(guān)鍵內(nèi)容供你參考树酪,部分細(xì)節(jié)無(wú)法全面覆蓋或者完全保證正確浅碾。
備選方案模板
1. 需求介紹
[需求介紹主要描述需求的背景、目標(biāo)续语、范圍等]
隨著前浪微博業(yè)務(wù)的不斷發(fā)展垂谢,業(yè)務(wù)上拆分的子系統(tǒng)越來(lái)越多,目前系統(tǒng)間的調(diào)用都是同步調(diào)用疮茄,由此帶來(lái)幾個(gè)明顯的系統(tǒng)問(wèn)題:
性能問(wèn)題:當(dāng)用戶發(fā)布了一條微博后埂陆,微博發(fā)布子系統(tǒng)需要同步調(diào)用“統(tǒng)計(jì)子系統(tǒng)”“審核子系統(tǒng)”“獎(jiǎng)勵(lì)子系統(tǒng)”等共 8 個(gè)子系統(tǒng),性能很低娃豹。
耦合問(wèn)題:當(dāng)新增一個(gè)子系統(tǒng)時(shí)焚虱,例如如果要增加“廣告子系統(tǒng)”,那么廣告子系統(tǒng)需要開發(fā)新的接口給微博發(fā)布子系統(tǒng)調(diào)用懂版。
效率問(wèn)題:每個(gè)子系統(tǒng)提供的接口參數(shù)和實(shí)現(xiàn)都有一些細(xì)微的差別鹃栽,導(dǎo)致每次都需要重新設(shè)計(jì)接口和聯(lián)調(diào)接口,開發(fā)團(tuán)隊(duì)和測(cè)試團(tuán)隊(duì)花費(fèi)了許多重復(fù)工作量躯畴。
基于以上背景民鼓,我們需要引入消息隊(duì)列進(jìn)行系統(tǒng)解耦,將目前的同步調(diào)用改為異步通知蓬抄。
2. 需求分析
[需求分析主要全方位地描述需求相關(guān)的信息]
5W
[5W 指 Who丰嘉、When、What嚷缭、Why饮亏、Where。
Who:需求利益干系人阅爽,包括開發(fā)者路幸、使用者、購(gòu)買者付翁、決策者等简肴。
When:需求使用時(shí)間,包括季節(jié)百侧、時(shí)間砰识、里程碑等。
What:需求的產(chǎn)出是什么佣渴,包括系統(tǒng)辫狼、數(shù)據(jù)、文件观话、開發(fā)庫(kù)予借、平臺(tái)等越平。
Where:需求的應(yīng)用場(chǎng)景频蛔,包括國(guó)家灵迫、地點(diǎn)、環(huán)境等晦溪,例如測(cè)試平臺(tái)只會(huì)在測(cè)試環(huán)境使用瀑粥。
Why:需求需要解決的問(wèn)題,通常和需求背景相關(guān)]
消息隊(duì)列的 5W 分析如下:
Who:消息隊(duì)列系統(tǒng)主要是業(yè)務(wù)子系統(tǒng)來(lái)使用三圆,子系統(tǒng)發(fā)送消息或者接收消息狞换。
When:當(dāng)子系統(tǒng)需要發(fā)送異步通知的時(shí)候,需要使用消息隊(duì)列系統(tǒng)舟肉。
What:需要開發(fā)消息隊(duì)列系統(tǒng)修噪。
Where:開發(fā)環(huán)境、測(cè)試環(huán)境路媚、生產(chǎn)環(huán)境都需要部署黄琼。
Why:消息隊(duì)列系統(tǒng)將子系統(tǒng)解耦,將同步調(diào)用改為異步通知整慎。
1H
[這里的 How 不是設(shè)計(jì)方案也不是架構(gòu)方案脏款,而是關(guān)鍵業(yè)務(wù)流程。消息隊(duì)列系統(tǒng)這部分內(nèi)容很簡(jiǎn)單裤园,但有的業(yè)務(wù)系統(tǒng) 1H 就是具體的用例了撤师,有興趣的同學(xué)可以嘗試寫寫 ATM 機(jī)取款的業(yè)務(wù)流程。如果是復(fù)雜的業(yè)務(wù)系統(tǒng)拧揽,這部分也可以獨(dú)立成“用例文檔”]
消息隊(duì)列有兩大核心功能:
業(yè)務(wù)子系統(tǒng)發(fā)送消息給消息隊(duì)列剃盾。
業(yè)務(wù)子系統(tǒng)從消息隊(duì)列獲取消息。
8C
[8C 指的是 8 個(gè)約束和限制淤袜,即 Constraints万俗,包括性能 Performance、成本 Cost饮怯、時(shí)間 Time闰歪、可靠性 Reliability、安全性 Security蓖墅、合規(guī)性 Compliance库倘、技術(shù)性 Technology、兼容性 Compatibility]
注:需求中涉及的性能论矾、成本教翩、可靠性等僅僅是利益關(guān)聯(lián)方提出的訴求,不一定準(zhǔn)確贪壳;如果經(jīng)過(guò)分析有的約束沒有必要饱亿,或成本太高、難度太大,這些約束是可以調(diào)整的彪笼。
性能:需要達(dá)到 Kafka 的性能水平钻注。
成本:參考 XX 公司的設(shè)計(jì)方案,不超過(guò) 10 臺(tái)服務(wù)器配猫。
時(shí)間:期望 3 個(gè)月內(nèi)上線第一個(gè)版本幅恋,在兩個(gè)業(yè)務(wù)嘗試使用。
可靠性:按照業(yè)務(wù)的要求泵肄,消息隊(duì)列系統(tǒng)的可靠性需要達(dá)到 99.99%捆交。
安全性:消息隊(duì)列系統(tǒng)僅在生產(chǎn)環(huán)境內(nèi)網(wǎng)使用,無(wú)需考慮網(wǎng)絡(luò)安全腐巢;如消息中有敏感信息品追,消息發(fā)送方需要自行進(jìn)行加密,消息隊(duì)列系統(tǒng)本身不考慮通用的加密冯丙。
合規(guī)性:消息隊(duì)列系統(tǒng)需要按照公司目前的 DevOps 規(guī)范進(jìn)行開發(fā)诵盼。
技術(shù)性:目前團(tuán)隊(duì)主要研發(fā)人員是 Java,最好用 Java 開發(fā)银还。
兼容性:之前沒有類似系統(tǒng)风宁,無(wú)需考慮兼容性。
3. 復(fù)雜度分析
[分析需求的復(fù)雜度蛹疯,復(fù)雜度常見的有高可用戒财、高性能、可擴(kuò)展等捺弦,具體分析方法請(qǐng)參考專欄前面的內(nèi)容]
注:文檔的內(nèi)容省略了分析過(guò)程饮寞,實(shí)際操作的時(shí)候每個(gè)約束和限制都要有詳細(xì)的邏輯推導(dǎo),避免完全拍腦袋式?jīng)Q策列吼,具體請(qǐng)參考專欄第 10 期的分析荡澎。
高可用
對(duì)于微博子系統(tǒng)來(lái)說(shuō)奋早,如果消息丟了,導(dǎo)致沒有審核,然后觸犯了國(guó)家法律法規(guī)斯辰,則是非常嚴(yán)重的事情板鬓;對(duì)于等級(jí)子系統(tǒng)來(lái)說(shuō)告私,如果用戶達(dá)到相應(yīng)等級(jí)后寂殉,系統(tǒng)沒有給他獎(jiǎng)品和專屬服務(wù),則 VIP 用戶會(huì)很不滿意您炉,導(dǎo)致用戶流失從而損失收入柒爵,雖然也比較關(guān)鍵,但沒有審核子系統(tǒng)丟消息那么嚴(yán)重赚爵。
綜合來(lái)看棉胀,消息隊(duì)列需要高可用性法瑟,包括消息寫入、消息存儲(chǔ)唁奢、消息讀取都需要保證高可用性霎挟。
高性能
前浪微博系統(tǒng)用戶每天發(fā)送 1000 萬(wàn)條微博,那么微博子系統(tǒng)一天會(huì)產(chǎn)生 1000 萬(wàn)條消息驮瞧,平均一條消息有 10 個(gè)子系統(tǒng)讀取氓扛,那么其他子系統(tǒng)讀取的消息大約是 1 億次枯芬。將數(shù)據(jù)按照秒來(lái)計(jì)算论笔,一天內(nèi)平均每秒寫入消息數(shù)為 115 條,每秒讀取的消息數(shù)是 1150 條千所;再考慮系統(tǒng)的讀寫并不是完全平均的狂魔,設(shè)計(jì)的目標(biāo)應(yīng)該以峰值來(lái)計(jì)算。峰值一般取平均值的 3 倍淫痰,那么消息隊(duì)列系統(tǒng)的 TPS 是 345最楷,QPS 是 3450,考慮一定的性能余量待错。由于現(xiàn)在的基數(shù)較低籽孙,為了預(yù)留一定的系統(tǒng)容量應(yīng)對(duì)后續(xù)業(yè)務(wù)的發(fā)展,我們將設(shè)計(jì)目標(biāo)設(shè)定為峰值的 4 倍火俄,因此最終的性能要求是:TPS 為 1380犯建,QPS 為 13800。TPS 為 1380 并不高瓜客,但 QPS 為 13800 已經(jīng)比較高了适瓦,因此高性能讀取是復(fù)雜度之一。
可擴(kuò)展
消息隊(duì)列的功能很明確谱仪,基本無(wú)須擴(kuò)展玻熙,因此可擴(kuò)展性不是這個(gè)消息隊(duì)列的關(guān)鍵復(fù)雜度。
4. 備選方案
[備選方案設(shè)計(jì)疯攒,至少 3 個(gè)備選方案嗦随,每個(gè)備選方案需要描述關(guān)鍵的實(shí)現(xiàn),無(wú)須描述具體的實(shí)現(xiàn)細(xì)節(jié)敬尺。此處省略具體方案描述称杨,詳細(xì)請(qǐng)參考專欄第 11 期]
備選方案 1:直接引入開源 Kafka
[此處省略方案描述]
備選方案 2:集群 + MySQL 存儲(chǔ)
[此處省略方案描述]
備選方案 3:集群 + 自研存儲(chǔ)
[此處省略方案描述]
5. 備選方案評(píng)估
[備選方案 360 度環(huán)評(píng),詳細(xì)請(qǐng)參考專欄第 12 期筷转。注意備選方案評(píng)估的內(nèi)容會(huì)根據(jù)評(píng)估會(huì)議的結(jié)果進(jìn)行修改姑原,也就是說(shuō)架構(gòu)師首先給出自己的備選方案評(píng)估,然后舉行備選方案評(píng)估會(huì)議呜舒,再根據(jù)會(huì)議結(jié)論修改備選方案文檔]
架構(gòu)設(shè)計(jì)模板
[備選方案評(píng)估后會(huì)選擇一個(gè)方案落地實(shí)施锭汛,架構(gòu)設(shè)計(jì)文檔就是用來(lái)詳細(xì)描述細(xì)化方案的]
1. 總體方案
[總體方案需要從整體上描述方案的結(jié)構(gòu),其核心內(nèi)容就是架構(gòu)圖,以及針對(duì)架構(gòu)圖的描述唤殴,包括模塊或者子系統(tǒng)的職責(zé)描述般婆、核心流程]
2. 架構(gòu)總覽
[架構(gòu)總覽給出架構(gòu)圖以及架構(gòu)的描述]
架構(gòu)關(guān)鍵設(shè)計(jì)點(diǎn):
采用數(shù)據(jù)分散集群的架構(gòu),集群中的服務(wù)器進(jìn)行分組朵逝,每個(gè)分組存儲(chǔ)一部分消息數(shù)據(jù)蔚袍。
每個(gè)分組包含一臺(tái)主 MySQL 和一臺(tái)備 MySQL,分組內(nèi)主備數(shù)據(jù)復(fù)制配名,分組間數(shù)據(jù)不同步啤咽。
正常情況下,分組內(nèi)的主服務(wù)器對(duì)外提供消息寫入和消息讀取服務(wù)渠脉,備服務(wù)器不對(duì)外提供服務(wù)宇整;主服務(wù)器宕機(jī)的情況下,備服務(wù)器對(duì)外提供消息讀取的服務(wù)芋膘。
客戶端采取輪詢的策略寫入和讀取消息鳞青。
3. 核心流程
消息發(fā)送流程
[此處省略流程描述]
消息讀取流程
[此處省略流程描述]
4. 詳細(xì)設(shè)計(jì)
[詳細(xì)設(shè)計(jì)需要描述具體的實(shí)現(xiàn)細(xì)節(jié)]
高可用設(shè)計(jì)
消息發(fā)送可靠性
業(yè)務(wù)服務(wù)器中嵌入消息隊(duì)列系統(tǒng)提供的 SDK,SDK 支持輪詢發(fā)送消息为朋,當(dāng)某個(gè)分組的主服務(wù)器無(wú)法發(fā)送消息時(shí)臂拓,SDK 挑選下一個(gè)分組主服務(wù)器重發(fā)消息,依次嘗試所有主服務(wù)器直到發(fā)送成功习寸;如果全部主服務(wù)器都無(wú)法發(fā)送胶惰,SDK 可以緩存消息,也可以直接丟棄消息融涣,具體策略可以在啟動(dòng) SDK 的時(shí)候通過(guò)配置指定童番。
如果 SDK 緩存了一些消息未發(fā)送,此時(shí)恰好業(yè)務(wù)服務(wù)器又重啟威鹿,則所有緩存的消息將永久丟失剃斧,這種情況 SDK 不做處理,業(yè)務(wù)方需要針對(duì)某些非常關(guān)鍵的消息自己實(shí)現(xiàn)永久存儲(chǔ)的功能忽你。
消息存儲(chǔ)可靠性
消息存儲(chǔ)在 MySQL 中幼东,每個(gè)分組有一主一備兩臺(tái) MySQL 服務(wù)器,MySQL 服務(wù)器之間復(fù)制消息以保證消息存儲(chǔ)高可用科雳。如果主備間出現(xiàn)復(fù)制延遲根蟹,恰好此時(shí) MySQL 主服務(wù)器宕機(jī)導(dǎo)致數(shù)據(jù)無(wú)法恢復(fù),則部分消息會(huì)永久丟失糟秘,這種情況不做針對(duì)性設(shè)計(jì)简逮,DBA 需要對(duì)主備間的復(fù)制延遲進(jìn)行監(jiān)控,當(dāng)復(fù)制延遲超過(guò) 30 秒的時(shí)候需要及時(shí)告警并進(jìn)行處理尿赚。
消息讀取可靠性
每個(gè)分組有一主一備兩臺(tái)服務(wù)器散庶,主服務(wù)器支持發(fā)送和讀取消息蕉堰,備服務(wù)器只支持讀取消息,當(dāng)主服務(wù)器正常的時(shí)候備服務(wù)器不對(duì)外提供服務(wù)悲龟,只有備服務(wù)器判斷主服務(wù)器故障的時(shí)候才對(duì)外提供消息讀取服務(wù)屋讶。
主備服務(wù)器的角色和分組信息通過(guò)配置指定,通過(guò) ZooKeeper 進(jìn)行狀態(tài)判斷和決策须教。主備服務(wù)器啟動(dòng)的時(shí)候分別連接到 ZooKeeper皿渗,在 /MQ/Server/[group] 目錄下建立 EPHEMERAL 節(jié)點(diǎn),假設(shè)分組名稱為 group1轻腺,則主服務(wù)器節(jié)點(diǎn)為 /MQ/Server/group1/master乐疆,備服務(wù)器的節(jié)點(diǎn)為 /MQ/Server/group1/slave。節(jié)點(diǎn)的超時(shí)時(shí)間可以配置约计,默認(rèn)為 10 秒诀拭。
高性能設(shè)計(jì)
[此處省略具體設(shè)計(jì)]
可擴(kuò)展設(shè)計(jì)
[此處省略具體設(shè)計(jì)迁筛。如果方案不涉及煤蚌,可以簡(jiǎn)單寫上“無(wú)”,表示設(shè)計(jì)者有考慮但不需要設(shè)計(jì)细卧;否則如果完全不寫的話尉桩,方案評(píng)審的時(shí)候可能會(huì)被認(rèn)為是遺漏了設(shè)計(jì)點(diǎn)]
無(wú)
安全設(shè)計(jì)
消息隊(duì)列系統(tǒng)需要提供權(quán)限控制功能,權(quán)限控制包括兩部分:身份識(shí)別和隊(duì)列權(quán)限控制贪庙。
身份識(shí)別
消息隊(duì)列系統(tǒng)給業(yè)務(wù)子系統(tǒng)分配身份標(biāo)識(shí)和接入 key蜘犁,SDK 首先需要建立連接并進(jìn)行身份校驗(yàn),消息隊(duì)列服務(wù)器會(huì)中斷校驗(yàn)不通過(guò)的連接止邮。因此这橙,任何業(yè)務(wù)子系統(tǒng)如果想接入消息隊(duì)列系統(tǒng),都必須首先申請(qǐng)身份標(biāo)識(shí)和接入 key导披,通過(guò)這種方式來(lái)防止惡意系統(tǒng)任意接入屈扎。
隊(duì)列權(quán)限
某些隊(duì)列信息可能比較敏感,只允許部分子系統(tǒng)發(fā)送或者讀取撩匕,消息隊(duì)列系統(tǒng)將隊(duì)列權(quán)限保存在配置文件中鹰晨,當(dāng)收到發(fā)送或者讀取消息的請(qǐng)求時(shí),首先需要根據(jù)業(yè)務(wù)子系統(tǒng)的身份標(biāo)識(shí)以及配置的權(quán)限信息來(lái)判斷業(yè)務(wù)子系統(tǒng)是否有權(quán)限止毕,如果沒有權(quán)限則拒絕服務(wù)模蜡。
其他設(shè)計(jì)
[其他設(shè)計(jì)包括上述以外的其他設(shè)計(jì)考慮點(diǎn),例如指定開發(fā)語(yǔ)言扁凛、符合公司的某些標(biāo)準(zhǔn)等忍疾,如果篇幅較長(zhǎng),也可以獨(dú)立進(jìn)行描述]
消息隊(duì)列系統(tǒng)需要接入公司已有的運(yùn)維平臺(tái)谨朝,通過(guò)運(yùn)維平臺(tái)發(fā)布和部署卤妒。
消息隊(duì)列系統(tǒng)需要輸出日志給公司已有的監(jiān)控平臺(tái)丸边,通過(guò)監(jiān)控平臺(tái)監(jiān)控消息隊(duì)列系統(tǒng)的健康狀態(tài),包括發(fā)送消息的數(shù)量荚孵、發(fā)送消息的大小妹窖、積壓消息的數(shù)量等,詳細(xì)監(jiān)控指標(biāo)在后續(xù)設(shè)計(jì)方案中列出收叶。
部署方案
[部署方案主要包括硬件要求骄呼、服務(wù)器部署方式、組網(wǎng)方式等]
消息隊(duì)列系統(tǒng)的服務(wù)器和數(shù)據(jù)庫(kù)服務(wù)器采取混布的方式部署判没,即:一臺(tái)服務(wù)器上蜓萄,部署同一分組的主服務(wù)器和主 MySQL,或者備服務(wù)器和備 MySQL澄峰。因?yàn)橄㈥?duì)列服務(wù)器主要是 CPU 密集型嫉沽,而 MySQL 是磁盤密集型的,所以兩者混布互相影響的幾率不大俏竞。
硬件的基本要求:32 核 48G 內(nèi)存 512G SSD 硬盤绸硕,考慮到消息隊(duì)列系統(tǒng)動(dòng)態(tài)擴(kuò)容的需求不高,且對(duì)性能要求較高魂毁,因此需要使用物理服務(wù)器玻佩,不采用虛擬機(jī)。
5. 架構(gòu)演進(jìn)規(guī)劃
[通常情況下席楚,規(guī)劃和設(shè)計(jì)的需求比較完善咬崔,但如果一次性全部做完,項(xiàng)目周期可能會(huì)很長(zhǎng)烦秩,因此可以采取分階段實(shí)施垮斯,即:第一期做什么、第二期做什么只祠,以此類推]
整個(gè)消息隊(duì)列系統(tǒng)分三期實(shí)現(xiàn):
第一期:實(shí)現(xiàn)消息發(fā)送兜蠕、權(quán)限控制功能,預(yù)計(jì)時(shí)間 3 個(gè)月铆农。
第二期:實(shí)現(xiàn)消息讀取功能牺氨,預(yù)計(jì)時(shí)間 1 個(gè)月。
第三期:實(shí)現(xiàn)主備基于 ZooKeeper 切換的功能墩剖,預(yù)計(jì)時(shí)間 2 周猴凹。