如何從零設(shè)計一款高并發(fā)架構(gòu)
點擊上方藍色字體,選擇“標(biāo)星公眾號”
優(yōu)質(zhì)文章,第一時間送達

-? ? ?前言? ? -

-? ? ?服務(wù)器架構(gòu)? ? -
服務(wù)器 均衡負載(如:nginx,阿里云SLB) 資源監(jiān)控 分布式 數(shù)據(jù)庫 主從分離,集群 DBA 表優(yōu)化,索引優(yōu)化,等 分布式 nosql 主從分離,集群 主從分離,集群 主從分離,集群 redis mongodb memcache cdn html css js image

-? ? ?并發(fā)測試? ? -
阿里云性能測試
Apache JMeter Visual Studio性能負載測試 Microsoft Web Application Stress Tool

-? ? ?實戰(zhàn)方案? ? -
通用方案
日用戶流量大,但是比較分散,偶爾會有用戶高聚的情況;

用戶簽到獲取積分 計算出用戶分布的key,redis hash中查找用戶今日簽到信息 如果查詢到簽到信息,返回簽到信息 如果沒有查詢到,DB查詢今日是否簽到過,如果有簽到過,就把簽到信息同步redis緩存。 如果DB中也沒有查詢到今日的簽到記錄,就進行簽到邏輯,操作DB添加今日簽到記錄,添加簽到積分(這整個DB操作是一個事務(wù)) 緩存簽到信息到redis,返回簽到信息 注意這里會有并發(fā)情況下的邏輯問題,如:一天簽到多次,發(fā)放多次積分給用戶。 用戶訂單 這里我們只緩存用戶第一頁的訂單信息,一頁40條數(shù)據(jù),用戶一般也只會看第一頁的訂單數(shù)據(jù) 用戶訪問訂單列表,如果是第一頁讀緩存,如果不是讀DB 計算出用戶分布的key,redis hash中查找用戶訂單信息 如果查詢到用戶訂單信息,返回訂單信息 如果不存在就進行DB查詢第一頁的訂單數(shù)據(jù),然后緩存redis,返回訂單信息 用戶中心 計算出用戶分布的key,redis hash中查找用戶訂單信息 如果查詢到用戶信息,返回用戶信息 如果不存在進行用戶DB查詢,然后緩存redis,返回用戶信息 其他業(yè)務(wù) 上面例子多是針對用戶存儲緩存,如果是公用的緩存數(shù)據(jù)需要注意一些問題,如下 注意公用的緩存數(shù)據(jù)需要考慮并發(fā)下的可能會導(dǎo)致大量命中DB查詢,可以使用管理后臺更新緩存,或者DB查詢的鎖住操作。 博文《大話Redis進階》對更新緩存問題和推薦方案的分享。

-? ? ?消息隊列? ? -
秒殺、秒搶等活動業(yè)務(wù),用戶在瞬間涌入產(chǎn)生高并發(fā)請求

一般習(xí)慣使用 redis的 list 當(dāng)用戶參與活動,將用戶參與信息push到隊列中 然后寫個多線程程序去pop數(shù)據(jù),進行發(fā)放紅包的業(yè)務(wù) 這樣可以支持高并發(fā)下的用戶可以正常的參與活動,并且避免數(shù)據(jù)庫服務(wù)器宕機的危險

-? ? ?一級緩存? ? -


-? ? ?靜態(tài)化數(shù)據(jù)? ? -
其他方案
對于更新頻繁度不高的數(shù)據(jù),APP,PC瀏覽器,可以緩存數(shù)據(jù)到本地,然后每次請求接口的時候上傳當(dāng)前緩存數(shù)據(jù)的版本號,服務(wù)端接收到版本號判斷版本號與最新數(shù)據(jù)版本號是否一致,如果不一樣就進行最新數(shù)據(jù)的查詢并返回最新數(shù)據(jù)和最新版本號,如果一樣就返回狀態(tài)碼告知數(shù)據(jù)已經(jīng)是最新。減少服務(wù)器壓力:資源、帶寬等。

-? ? ?分層、分割、分布式? ? -
分層 將系統(tǒng)在橫向維度上切分成幾個部分,每個部門負責(zé)一部分相對簡單并比較單一的職責(zé),然后通過上層對下層的依賴和調(diào)度組成一個完整的系統(tǒng) 比如把電商系統(tǒng)分成:應(yīng)用層,服務(wù)層,數(shù)據(jù)層。(具體分多少個層次根據(jù)自己的業(yè)務(wù)場景) 應(yīng)用層:網(wǎng)站首頁,用戶中心,商品中心,購物車,紅包業(yè)務(wù),活動中心等,負責(zé)具體業(yè)務(wù)和視圖展示 服務(wù)層:訂單服務(wù),用戶管理服務(wù),紅包服務(wù),商品服務(wù)等,為應(yīng)用層提供服務(wù)支持 數(shù)據(jù)層:關(guān)系數(shù)據(jù)庫,nosql數(shù)據(jù)庫 等,提供數(shù)據(jù)存儲查詢服務(wù) 分層架構(gòu)是邏輯上的,在物理部署上可以部署在同一臺物理機器上,但是隨著網(wǎng)站業(yè)務(wù)的發(fā)展,必然需要對已經(jīng)分層的模塊分離部署,分別部署在不同的服務(wù)器上,使網(wǎng)站可以支撐更多用戶訪問 分割 在縱向方面對業(yè)務(wù)進行切分,將一塊相對復(fù)雜的業(yè)務(wù)分割成不同的模塊單元 包裝成高內(nèi)聚低耦合的模塊不僅有助于軟件的開發(fā)維護,也便于不同模塊的分布式部署,提高網(wǎng)站的并發(fā)處理能力和功能擴展 比如用戶中心可以分割成:賬戶信息模塊,訂單模塊,充值模塊,提現(xiàn)模塊,優(yōu)惠券模塊等 分布式 分布式應(yīng)用和服務(wù),將分層或者分割后的業(yè)務(wù)分布式部署,獨立的應(yīng)用服務(wù)器,數(shù)據(jù)庫,緩存服務(wù)器 當(dāng)業(yè)務(wù)達到一定用戶量的時候,再進行服務(wù)器均衡負載,數(shù)據(jù)庫,緩存主從集群 分布式靜態(tài)資源,比如:靜態(tài)資源上傳cdn 分布式計算,比如:使用hadoop進行大數(shù)據(jù)的分布式計算 分布式數(shù)據(jù)和存儲,比如:各分布節(jié)點根據(jù)哈希算法或其他算法分散存儲數(shù)據(jù)


-? ? ?集群? ? -
應(yīng)用服務(wù)器集群 nginx 反向代理 slb … … (關(guān)系/nosql)數(shù)據(jù)庫集群 主從分離,從庫集群


-? ? ?異步? ? -
如: 自動彈窗簽到,雙11跨0點的時候并發(fā)請求簽到接口 雙11搶紅包活動 雙11訂單入庫 等 設(shè)計考慮: 逆向思維,壓力在數(shù)據(jù)庫,那業(yè)務(wù)接口就不進行數(shù)據(jù)庫操作不就沒壓力了 數(shù)據(jù)持久化是否允許延遲? 如何讓業(yè)務(wù)接口不直接操作DB,又可以讓數(shù)據(jù)持久化? 方案設(shè)計: 像這種涉及數(shù)據(jù)庫操作的高并發(fā)的業(yè)務(wù),就要考慮使用異步了 客戶端發(fā)起接口請求,服務(wù)端快速響應(yīng),客戶端展示結(jié)果給用戶,數(shù)據(jù)庫操作通過異步同步 如何實現(xiàn)異步同步? 使用消息隊列,將入庫的內(nèi)容enqueue到消息隊列中,業(yè)務(wù)接口快速響應(yīng)給用戶結(jié)果(可以溫馨提示高峰期延遲到賬) 然后再寫個獨立程序從消息隊列dequeue數(shù)據(jù)出來進行入庫操作,入庫成功后刷新用戶相關(guān)緩存,如果入庫失敗記錄日志,方便反饋查詢和重新持久化 這樣一來數(shù)據(jù)庫操作就只有一個程序(多線程)來完成,不會給數(shù)據(jù)帶來壓力 補充: 消息隊列除了可以用在高并發(fā)業(yè)務(wù),其他只要有相同需求的業(yè)務(wù)也是可以使用,如:短信發(fā)送中間件等 高并發(fā)下異步持久化數(shù)據(jù)可能會影響用戶的體驗,可以通過可配置的方式,或者自動化監(jiān)控資源消耗來切換時時或者使用異步,這樣在正常流量的情況下可以使用時時操作數(shù)據(jù)庫來提高用戶體驗 異步同時也可以指編程上的異步函數(shù),異步線程,在有的時候可以使用異步操作,把不需要等待結(jié)果的操作放到異步中,然后繼續(xù)后面的操作,節(jié)省了等待的這部分操作的時間

-? ? ?緩存? ? -
設(shè)計考慮: 還是逆向思維,壓力在數(shù)據(jù)庫,那么我們就不進行數(shù)據(jù)庫查詢 數(shù)據(jù)不經(jīng)常變化,我們?yōu)樯兑恢辈樵僁B? 數(shù)據(jù)不變化客戶端為啥要向服務(wù)器請求返回一樣的數(shù)據(jù)? 方案設(shè)計: 數(shù)據(jù)不經(jīng)常變化,我們可以把數(shù)據(jù)進行緩存,緩存的方式有很多種,一般的:應(yīng)用服務(wù)器直接Cache內(nèi)存,主流的:存儲在memcache、redis內(nèi)存數(shù)據(jù)庫 Cache是直接存儲在應(yīng)用服務(wù)器中,讀取速度快,內(nèi)存數(shù)據(jù)庫服務(wù)器允許連接數(shù)可以支撐到很大,而且數(shù)據(jù)存儲在內(nèi)存,讀取速度快,再加上主從集群,可以支撐很大的并發(fā)查詢 根據(jù)業(yè)務(wù)情景,使用配合客戶端本地存,如果我們數(shù)據(jù)內(nèi)容不經(jīng)常變化,為啥要一直請求服務(wù)器獲取相同數(shù)據(jù),可以通過匹配數(shù)據(jù)版本號,如果版本號不一樣接口重新查詢緩存返回數(shù)據(jù)和版本號,如果一樣則不查詢數(shù)據(jù)直接響應(yīng) 這樣不僅可以提高接口響應(yīng)速度,也可以節(jié)約服務(wù)器帶寬,雖然有些服務(wù)器帶寬是按流量計費,但是也不是絕對無限的,在高并發(fā)的時候服務(wù)器帶寬也可能導(dǎo)致請求響應(yīng)慢的問題 補充: 緩存同時也指靜態(tài)資源客戶端緩存 cdn緩存,靜態(tài)資源通過上傳cdn,cdn節(jié)點緩存我們的靜態(tài)資源,減少服務(wù)器壓力


-? ? ?面向服務(wù)? ? -
SOA面向服務(wù)架構(gòu)設(shè)計 微服務(wù)更細粒度服務(wù)化,一系列的獨立的服務(wù)共同組成系統(tǒng)
服務(wù)例子: 用戶行為跟蹤記錄統(tǒng)計 說明: 通過上報應(yīng)用模塊,操作事件,事件對象,等數(shù)據(jù),記錄用戶的操作行為 比如:記錄用戶在某個商品模塊,點擊了某一件商品,或者瀏覽了某一件商品 背景: 由于服務(wù)需要記錄用戶的各種操作行為,并且可以重復(fù)上報,準(zhǔn)備接入服務(wù)的業(yè)務(wù)又是核心業(yè)務(wù)的用戶行為跟蹤,所以請求量很大,高峰期會產(chǎn)生大量并發(fā)請求。 架構(gòu): nodejs WEB應(yīng)用服務(wù)器均衡負載 redis主從集群 mysql主 nodejs+express+ejs+redis+mysql 服務(wù)端采用nodejs,nodejs是單進程(PM2根據(jù)cpu核數(shù)開啟多個工作進程),采用事件驅(qū)動機制,適合I/O密集型業(yè)務(wù),處理高并發(fā)能力強 業(yè)務(wù)設(shè)計: 并發(fā)量大,所以不能直接入庫,采用:異步同步數(shù)據(jù),消息隊列 請求接口上報數(shù)據(jù),接口將上報數(shù)據(jù)push到redis的list隊列中 nodejs寫入庫腳本,循環(huán)pop redis list數(shù)據(jù),將數(shù)據(jù)存儲入庫,并進行相關(guān)統(tǒng)計Update,無數(shù)據(jù)時sleep幾秒 因為數(shù)據(jù)量會比較大,上報的數(shù)據(jù)表按天命名存儲 接口: 上報數(shù)據(jù)接口 統(tǒng)計查詢接口 上線跟進: 服務(wù)業(yè)務(wù)基本正常 每天的上報表有上千萬的數(shù)據(jù)

-? ? ?冗余,自動化? ? -
冗余 數(shù)據(jù)庫備份 備用服務(wù)器 自動化 自動化監(jiān)控 自動化報警 自動化降級

-? ? ?總結(jié)? ? -
來源:網(wǎng)絡(luò)
評論
圖片
表情

