高并發(fā)設(shè)計(jì),都有哪些技術(shù)方案?
大家好,我是 Tom哥。
作為互聯(lián)網(wǎng)從業(yè)者,高并發(fā)一直是我們繞不開的一個話題。
那么高并發(fā)系統(tǒng)都有哪些經(jīng)驗(yàn),掌握核心技巧,你可以快速成為一個架構(gòu)師,主導(dǎo)一些高訪問量系統(tǒng)的架構(gòu)設(shè)計(jì)。
然后,升職加薪自然也就是水到渠成的事。
一、負(fù)載均衡
靠優(yōu)化單臺機(jī)器的內(nèi)存、CPU、磁盤、網(wǎng)絡(luò)帶寬,使其發(fā)揮極致性能,已經(jīng)不太現(xiàn)實(shí)。
正所謂 "雙拳難敵四手,惡虎還怕群狼",現(xiàn)在早已經(jīng)是分布式時代,靠的是shu量取勝,也稱之為水平伸縮方案。
這么多的系統(tǒng),如何流量調(diào)度,這里的第一道入口就是負(fù)載均衡。
負(fù)載均衡,它的職責(zé)是將網(wǎng)絡(luò)請求 “均攤”到不同的機(jī)器上。避免集群中部分服務(wù)器壓力過大,而另一些服務(wù)器比較空閑的情況。
通過負(fù)載均衡,可以讓每臺服務(wù)器獲取到適合自己處理能力的負(fù)載。在為高負(fù)載服務(wù)器分流的同時,還可以避免資源浪費(fèi),一舉兩得。
常見的負(fù)載算法:
- 隨機(jī)算法。
- 輪詢算法。
- 輪詢權(quán)重算法。
- 一致性哈希算法。
- 最小連接。
- 自適應(yīng)算法。
常用負(fù)載均衡工具:
- LVS。
- Nginx。
- HAProxy。
對于一些大型系統(tǒng),一般會采用 DNS+四層負(fù)載+七層負(fù)載的方式進(jìn)行多層次負(fù)載均衡。
二、分布式微服務(wù)
過去是一個大而全的系統(tǒng),面對復(fù)雜的業(yè)務(wù)規(guī)則,我們采用分而治之的思想,通過SOA架構(gòu),將一個大的系統(tǒng)拆分成若干個微服務(wù),粒度越來越小,稱之為微服務(wù)架構(gòu)。
每個微服務(wù)獨(dú)立部署,服務(wù)和服務(wù)間采用輕量級的通信機(jī)制,如:標(biāo)準(zhǔn)的HTTP協(xié)議、或者私有的RPC協(xié)議。
微服務(wù)特點(diǎn):
- 按照業(yè)務(wù)劃分服務(wù),單個服務(wù)代碼量小,業(yè)務(wù)單一,容易維護(hù)。
- 每個微服務(wù)都有自己獨(dú)立的基礎(chǔ)組件,例如數(shù)據(jù)庫。
- 微服務(wù)之間的通信是通過HTTP協(xié)議或者私有協(xié)議,且具有容錯能力。
- 微服務(wù)有一套服務(wù)治理的解決方案,服務(wù)之間不耦合,可以隨時加入和剔除。
- 單個微服務(wù)能夠集群化部署,有負(fù)載均衡的能力。
- 整個微服務(wù)系統(tǒng)應(yīng)該有完整的安全機(jī)制,包括用戶驗(yàn)證,權(quán)限驗(yàn)證,資源保護(hù)。
- 整個微服務(wù)系統(tǒng)有鏈路追蹤的能力。
- 有一套完整的實(shí)時日志系統(tǒng)。
市面常用微服務(wù)框架有:Spring Cloud 、Dubbo 、kubernetes、gRPC、Thrift 等。
這么多的微系統(tǒng)之間如何感知?這里面會引入注冊中心。
常用的注冊中心有:Zookeeper、etcd、Eureka、Nacos、Consul。
萬事有利就有弊,分布式微服務(wù)由于拆分的過細(xì),引入一些復(fù)雜化問題需要關(guān)注:
- 分布式事務(wù)。
- 限流機(jī)制。
- 熔斷機(jī)制。
- 網(wǎng)關(guān)。
- 服務(wù)鏈路追蹤。
三、緩存機(jī)制
性能不夠,緩存來湊。要想快速提升性能,緩存肯定少不了。
緩存能夠帶來性能的大幅提升,以 Memcache 為例,單臺 Memcache 服務(wù)器簡單的 key-value 查詢能夠達(dá)到 TPS 50000 以上;Redis性能數(shù)據(jù)是10W+ QPS。
為什么緩存的速度那么快?
從上圖中發(fā)現(xiàn),同機(jī)房兩臺服務(wù)器跑個來回,再從內(nèi)存中順序讀取1M數(shù)據(jù),共耗時0.75ms。如果從硬盤讀取,做一次磁盤尋址需要10ms,再從磁盤里順序讀取1M數(shù)據(jù)需要30ms??梢姡褂脙?nèi)存緩存性能上提高多個數(shù)量級,同時也能支持更高的并發(fā)量。
常見的緩存分為本地緩存和分布式緩存,區(qū)別在與是否要走網(wǎng)絡(luò)通訊。
本地緩存是部署在應(yīng)用服務(wù)器中,而我們應(yīng)用服務(wù)器通常會部署多臺,當(dāng)數(shù)據(jù)更新時,我們不能確定哪臺服務(wù)器本地中了緩存,更新或者刪除所有服務(wù)器的緩存不是一個好的選擇,所以我們通常會等待緩存過期。因此,這種緩存的有效期很短,通常為分鐘或者秒級別,以避免返回前端臟數(shù)據(jù)。
相反,分布式緩存采用集群化管理,支持水平擴(kuò)容,并提供客戶端路由數(shù)據(jù),數(shù)據(jù)一致性維護(hù)更好。雖然有不到 1ms 的網(wǎng)絡(luò)開銷,但比起其優(yōu)勢,這點(diǎn)損耗微不足道。
緩存更新常用策略?
- Cache aside,通常會先更新數(shù)據(jù)庫,然后再刪除緩存,為了兜底還會設(shè)置緩存時間。
- Read/Write through, 一般是由一個 Cache Provider 對外提供讀寫操作,應(yīng)用程序不用感知操作的是緩存還是數(shù)據(jù)庫。
- Write behind,延遲寫入,Cache Provider 每隔一段時間會批量寫入數(shù)據(jù)庫,大大提升寫的效率。像操作系統(tǒng)的page cache也是類似機(jī)制。
四、分布式關(guān)系型數(shù)據(jù)庫
MySQL數(shù)據(jù)庫采用B+數(shù)索引,三層結(jié)構(gòu),為了保證IO性能,一般建議單表存儲 千萬 條數(shù)據(jù)。
如果遇到單機(jī)數(shù)據(jù)庫性能瓶頸,我們可以考慮分表。
分表又可以細(xì)分為 垂直分表 和 水平分表 兩種形式。
1、垂直分表
數(shù)據(jù)表垂直拆分就是縱向地把一張表中的列拆分到多個表,表由“寬”變“窄”,簡單來講,就是將大表拆成多張小表,一般會遵循以下幾個原則:
- 冷熱分離,把常用的列放在一個表,不常用的放在一個表。
- 字段更新、查詢頻次拆分。
- 大字段列獨(dú)立存放。
- 關(guān)系緊密的列放在一起。
2、水平分表
表結(jié)構(gòu)維持不變,對數(shù)據(jù)行進(jìn)行切分,將表中的某些行切分到一張表中,而另外的某些行又切分到其他的表中,也就是說拆分后數(shù)據(jù)集的并集等于拆分前的數(shù)據(jù)集。
分庫分表技術(shù)點(diǎn):
- SQl組合。因?yàn)槭沁壿嫳砻?,需要按分表鍵計(jì)算對應(yīng)的物理表編號,根據(jù)邏輯重新組裝動態(tài)的SQL。
- 數(shù)據(jù)庫路由。如果采用分庫,需要根據(jù)邏輯的分表編號計(jì)算數(shù)據(jù)庫的編號。
- 結(jié)果合并。如果查詢沒有傳入指定的分表鍵,會全庫執(zhí)行,此時需要將結(jié)果合并再輸出。
目前市面有很多的開源框架,大致分為兩種模式:
Proxy模式。SQL 組合、數(shù)據(jù)庫路由、執(zhí)行結(jié)果合并等功能全部存放在一個代理服務(wù)中,業(yè)務(wù)方可以當(dāng)做。
- 優(yōu)點(diǎn):支持多種語言。升級方便。對業(yè)務(wù)代碼無侵入。
- 缺點(diǎn):額外引入一個中間件,容易形成流量瓶頸,安全風(fēng)險(xiǎn)較高,有運(yùn)維成本。
Client 模式。常見是 sharding-jdbc,業(yè)務(wù)端系統(tǒng)只需要引入一個jar包即可,按照規(guī)范配置路由規(guī)則。jar 中處理 SQL 組合、數(shù)據(jù)庫路由、執(zhí)行結(jié)果合并等相關(guān)功能。
- 優(yōu)點(diǎn):簡單、輕便。不存在流量瓶頸,減少運(yùn)維成本
- 缺點(diǎn):單語言,升級不方便。
實(shí)現(xiàn)思路:
1、如何選擇分表鍵。
數(shù)據(jù)盡量均勻分布在不同表或庫、跨庫查詢操作盡可能少、這個字段的值不會變。比如電商訂單采用user_id。
2、分片策略。
根據(jù)范圍分片、根據(jù) hash 值分片、根據(jù) hash 值及范圍混合分片
3、如何編寫業(yè)務(wù)代碼。結(jié)合具體的業(yè)務(wù)實(shí)現(xiàn)。
4、歷史數(shù)據(jù)遷移。
- 增量數(shù)據(jù)監(jiān)聽 binlog,然后通過 canal 通知遷移程序開始增量數(shù)據(jù)遷移。
- 開啟任務(wù),全量數(shù)據(jù)遷移。
- 開啟雙寫,并關(guān)閉增量遷移任務(wù)。
- 讀業(yè)務(wù)切換到新庫。
- 線上運(yùn)行一段時間,確認(rèn)沒有問題后,下線老庫的寫操作。
有一種說法:數(shù)據(jù)量大,就分表;并發(fā)高,就分庫。
在實(shí)際的業(yè)務(wù)開發(fā)中,要做好數(shù)據(jù)量的增長預(yù)測,做好技術(shù)方案選型。另外,在引入分表方案后,要考慮數(shù)據(jù)傾斜問題,這個跟分表鍵有很大關(guān)系,避免數(shù)據(jù)分布不均衡影響系統(tǒng)性能。
五、分布式消息隊(duì)列
并不是所有的調(diào)用都要走同步形式,對于時間要求不高、或者非核心邏輯,我們可以采用異步處理機(jī)制。
也就衍生出消息隊(duì)列。
消息隊(duì)列主要有三種角色:生產(chǎn)者、消息隊(duì)列、消費(fèi)者。
生產(chǎn)端核心的邏輯處理完后,會封裝一個MQ消息,發(fā)送到消息隊(duì)列。下游系統(tǒng),如果關(guān)心這個事件,只需要訂閱這個 topic ,便可以收到消息,進(jìn)行后續(xù)的業(yè)務(wù)邏輯處理。
兩者之間通過消息中間件完成了解耦,系統(tǒng)的擴(kuò)展性非常高。
常用的消息框架有哪些?
ActiveMQ,RabbitMQ,ZeroMQ,Kafka,MetaQ,RocketMQ、Pulsar 等。
消息隊(duì)列的應(yīng)用場景?
- 異步處理。將一個請求鏈路中的非核心流程,拆分出來,異步處理,減少主流程鏈路的處理邏輯,縮短RT,提升吞吐量。如:注冊新用戶發(fā)短信通知。
- 削峰填谷。避免流量暴漲,打垮下游系統(tǒng),前面會加個消息隊(duì)列,平滑流量沖擊。比如:秒殺活動。生活中像電源適配器也是這個原理。
- 應(yīng)用解耦。兩個應(yīng)用,通過消息系統(tǒng)間接建立關(guān)系,避免一個系統(tǒng)宕機(jī)后對另一個系統(tǒng)的影響,提升系統(tǒng)的可用性。如:下單異步扣減庫存。
- 消息通訊。內(nèi)置了高效的通信機(jī)制,可用于消息通訊。如:點(diǎn)對點(diǎn)消息隊(duì)列、聊天室。
六、CDN
CDN 全稱 (Content Delivery Network),內(nèi)容分發(fā)網(wǎng)絡(luò)。
目的是在現(xiàn)有的網(wǎng)絡(luò)中增加一層網(wǎng)絡(luò)架構(gòu),將網(wǎng)站的內(nèi)容發(fā)布到最接近用戶的網(wǎng)絡(luò)“邊緣”,使用戶可以就近取得所需的內(nèi)容,提高用戶訪問網(wǎng)站的響應(yīng)速度。
CDN = 鏡像(Mirror)+緩存(Cache)+整體負(fù)載均衡(GSLB)。
CDN都以緩存網(wǎng)站中的靜態(tài)數(shù)據(jù)為主,如:CSS、JS、圖片和靜態(tài)頁面等數(shù)據(jù)。用戶從主站服務(wù)器中請求到動態(tài)內(nèi)容后,再從CDN下載靜態(tài)數(shù)據(jù),從而加速網(wǎng)頁數(shù)據(jù)內(nèi)容的下載速度。
主要特點(diǎn):
- 本地Cache加速。
- 鏡像服務(wù)。
- 遠(yuǎn)程加速。
- 帶寬優(yōu)化。
- 集群抗攻擊。
應(yīng)用場景
- 網(wǎng)站站點(diǎn)/應(yīng)用加速。
- 視音頻點(diǎn)播/大文件下載分發(fā)加速。
- 視頻直播加速。
- 移動應(yīng)用加速。
七、其他
作為補(bǔ)充,像分布式文件系統(tǒng)、大數(shù)據(jù)、NoSQL、NewSQL,慢慢也開始成為高并發(fā)系統(tǒng)的周圍框架生態(tài)補(bǔ)充。