1.高併發,高可用系統的一些思考 高併發依賴於場景和邏輯 不一定每個場景都會產生高併發,不要為了高併發而盲目的設計,過度設計帶來 的問題遠比意料之外的高併發要多很多,依賴於具體場景和行為進行分析,一個 購物類網站,搶購場景,會觸發很多的讀取商品詳情,計算庫存等操作,而且不 需要每個請求都到達支付頁面 ...
1.高併發,高可用系統的一些思考
高併發依賴於場景和邏輯
不一定每個場景都會產生高併發,不要為了高併發而盲目的設計,過度設計帶來 的問題遠比意料之外的高併發要多很多,依賴於具體場景和行為進行分析,一個 購物類網站,搶購場景,會觸發很多的讀取商品詳情,計算庫存等操作,而且不 需要每個請求都到達支付頁面,也不會在網站主頁帶來很多的請求,所以需要針 對搶購場景進行優化,而不是巨大的支付流程進行優化,當然商品數量多和用戶 多的情況,才需要也優化一下支付流程。
拋開場景,不談流量的盲目高併發設計,一般是過度設計,未來維護臃腫而復 雜的代碼會懲罰你當初的過度設計。
突如其來的高併發
基本是被人刷了,或者比預估的情況要多了幾倍,才有這種情況,前者可能性很 大,最近這兩年的金融網站,區塊鏈,xx 幣網站,基本會被羊毛黨盯上,沒做 好訪問防作弊,或者被對手 ddos 攻擊,都會造成高併發中網站癱瘓,清洗流 量一般就可以的,不要讓辣雞流量貫穿整個業務。高併發會帶來網站請求慢,但 網站請求慢不一定是高併發了,對症下藥。
如果是網紅帶貨什麼的,給網站帶來高併發了,這種情況下可以在提前流量上做 些手腳,例如:1. 用消息隊列排隊流量,例如猴王網站的搶購 2. 採用一些高 端點的驗證碼,讓一些秒殺搶購的機器號被過濾出去,儘量不影響真實用戶的 搶購結果 3. 分層過濾,例如靜態資源放在 CDN 上,NGINX 層面使用自身的 緩存,根據路由緩存基礎數據,其他動態數據再讀寫資料庫,而不是每個請求 都經過整體的業務,這樣帶來的壓力太大了,而且也不值得。
併發中的整體項目穩定性
可以將高併發的業務部分分離到單獨的伺服器。這種情況下能夠避免這部分業務 帶來機器性能的消耗,從而影響整個項目的穩定性,這樣的結果不太好的。也可 以預先將熱數據放到緩存中,提高讀寫效率,也能讓 MySQL 比較穩定,一般 情況下能有高併發的網站,數據量也不少,舉例某個電商網站,可能有 100w 商 品數據,但大家搶購的是今天熱推的 10 個商品,將這十個數據提取放到緩存 中,而不是每次去資料庫中查詢,當然 MySQL 設置合理的話,自身的 buffer pool 也能搞定這些熱數據緩存。這樣相當於將這 10 條數據隔離出來,而不是影響到整體數據。關於熱點數據的發現,還有一些高端的是從 NGINX 訪問日 志層面實時分析,據說淘寶這種是這樣的,實時發現訪問很多的路由,分析路由 獲取到對應的商品數據,放到緩存中,減輕伺服器壓力。
穩定性不光存在於業務機器層面,也可能是網路寬頻不夠,或者程式在磁碟寫日 志的時候遇到瓶頸,或者記憶體不夠,導致可用緩存空間很小。這些在測試和計算 層面需要註意的問題,也會影響整體穩定性和性能的,應該提前解決。例如秒殺 系統需要關註 CPU,併發讀需要關註緩存,靜態資源多的也需要考慮寬頻。
預先測試
簡單可以是壓測關鍵業務部分,簡單的查詢一般不會帶來問題,這個頁面的靜態 資源太多,同時都在統一個功能變數名稱下的話,相當於在現有併發的數量上加了更多, 這非常不利,對於瀏覽器的載入也是不利的,簡單業務也會體驗很差。壓力測試 應當遵循慢慢提升流量的方式,併發量和響應時間並不是等比例上漲的,慢慢 提升併發量的測試,會展示代碼的瓶頸部分在哪,然後在去解決和提升。測試也 可以
在基礎的併發測試之外,還有在正是伺服器上的全鏈路壓力測試,為了防止和真 實數據衝突,可以將請求中加上額外的標記,或者針對特定的用戶帳號測試,在 數據中體現這部分額外標記,測試完畢之後將數據刪除。
同時,不要高併發的主要業務一直占用機器的 100% 的運算能力,這樣整體邏 輯和請求支持已經到了極限,基本再高一點就會造成問題,應該儘量讓業務只占 用機器 60-70% 的運算能力,留出一部分的餘地,防止意外。
安全及備用方案
1. 從 NGINX 層面限制單個 IP 單位時間內請求頻率和次數,屏蔽掉機器刷 的可能性,從而不影響正常訪問。 2. 切記高併發 + 高可用不可以用單 點系統,例如不能因為熱數據少而就用一臺 Redis 伺服器,或者更狠的 直接本機緩存,一旦系統崩潰,相當於觸發連鎖反應,連保存現場和恢復 都很難。 3. 提前設計兜底方案 ① 降級,例如商品詳情頁面不展示推薦 商品,或者減少推薦商品展示數量等, ② 限流,不讓更多流量涌入,能 減少很多壓力 ③ 過載臨界點拒絕服務,這個是最壞的情況,直接阻斷壓 垮系統的最後一個流量。
2.面試官為什麼會問你,如何設計一個高併發系統?
面試官心理分析
說實話,如果面試官問你這個題目,那麼你必須要使出全身吃奶勁了。為啥?因 為你沒看到現在很多公司招聘的 JD 里都是說啥,有高併發就經驗者優先。
如果你確實有真才實學,在互聯網公司里乾過高併發系統,那你確實拿 offer 基 本如探囊取物,沒啥問題。面試官也絕對不會這樣來問你,否則他就是蠢。
假設你在某知名電商公司乾過高併發系統,用戶上億,一天流量幾十億,高峰期 併發量上萬,甚至是十萬。那麼人家一定會仔細盤問你的系統架構,你們系統啥 架構?怎麼部署的?部署了多少台機器?緩存咋用的?MQ 咋用的?資料庫咋 用的?就是深挖你到底是如何扛住高併發的。
因為真正乾過高併發的人一定知道,脫離了業務的系統架構都是在紙上談兵,真 正在複雜業務場景而且還高併發的時候,那系統架構一定不是那麼簡單的,用個 redis,用 mq 就能搞定?當然不是,真實的系統架構搭配上業務之後,會比這 種簡單的所謂“高併發架構”要複雜很多倍。
如果有面試官問你個問題說,如何設計一個高併發系統?那麼不好意思,一定是 因為你實際上沒乾過高併發系統。面試官看你簡歷就沒啥出彩的,感覺就不咋地, 所以就會問問你,如何設計一個高併發系統?其實說白了本質就是看看你有沒有 自己研究過,有沒有一定的知識積累。
最好的當然是招聘個真正乾過高併發的哥兒們咯,但是這種哥兒們人數稀缺,不 好招。所以可能次一點的就是招一個自己研究過的哥兒們,總比招一個啥也不會 的哥兒們好吧!
所以這個時候你必須得做一把個人秀了,秀出你所有關於高併發的知識!
面試題剖析
其實所謂的高併發,如果你要理解這個問題呢,其實就得從高併發的根源出發, 為啥會有高併發?為啥高併發就很牛逼?
我說的淺顯一點,很簡單,就是因為剛開始系統都是連接資料庫的,但是要知道 資料庫支撐到每秒併發兩三千的時候,基本就快完了。所以才有說,很多公司, 剛開始乾的時候,技術比較 low,結果業務發展太快,有的時候系統扛不住壓力 就掛了。
當然會掛了,憑什麼不掛?你資料庫如果瞬間承載每秒 5000/8000,甚至上萬 的併發,一定會宕機,因為比如 mysql 就壓根兒扛不住這麼高的併發量。
所以為啥高併發牛逼?就是因為現在用互聯網的人越來越多,很多 app、網站、 系統承載的都是高併發請求,可能高峰期每秒併發量幾千,很正常的。如果是什 麽雙十一之類的,每秒併發幾萬幾十萬都有可能。
那麼如此之高的併發量,加上原本就如此之複雜的業務,咋玩兒?真正厲害的, 一定是在複雜業務系統里玩兒過高併發架構的人,但是你沒有,那麼我給你說一 下你該怎麼回答這個問題:
可以分為以下 6 點:
系統拆分 緩存
MQ
分庫分表
讀寫分離
ElasticSearch
系統拆分
將一個系統拆分為多個子系統,用 dubbo 來搞。然後每個系統連一個資料庫, 這樣本來就一個庫,現在多個資料庫,不也可以扛高併發麽。
緩存
緩存,必須得用緩存。大部分的高併發場景,都是讀多寫少,那你完全可以在數 據庫和緩存里都寫一份,然後讀的時候大量走緩存不就得了。畢竟人家 redis 輕 輕鬆松單機幾萬的併發。所以你可以考慮考慮你的項目里,那些承載主要請求的 讀場景,怎麼用緩存來抗高併發。
MQ
MQ,必須得用 MQ。可能你還是會出現高併發寫的場景,比如說一個業務操作 里要頻繁搞資料庫幾十次,增刪改增刪改,瘋了。那高併發絕對搞掛你的系統, 你要是用 redis 來承載寫那肯定不行,人家是緩存,數據隨時就被 LRU 了,數 據格式還無比簡單,沒有事務支持。所以該用 mysql 還得用 mysql 啊。那你 咋辦?用 MQ 吧,大量的寫請求灌入 MQ 里,排隊慢慢玩兒,後邊系統消費 後慢慢寫,控制在 mysql 承載範圍之內。所以你得考慮考慮你的項目里,那些 承載複雜寫業務邏輯的場景里,如何用 MQ 來非同步寫,提升併發性。MQ 單機 抗幾萬併發也是 ok 的,這個之前還特意說過。
分庫分表
分庫分表,可能到了最後資料庫層面還是免不了抗高併發的要求,好吧,那麼就 將一個資料庫拆分為多個庫,多個庫來扛更高的併發;然後將一個表拆分為多個 表,每個表的數據量保持少一點,提高 sql 跑的性能。
讀寫分離
讀寫分離,這個就是說大部分時候資料庫可能也是讀多寫少,沒必要所有請求都 集中在一個庫上吧,可以搞個主從架構,主庫寫入,從庫讀取,搞一個讀寫分離。 讀流量太多的時候,還可以加更多的從庫。
ElasticSearch
Elasticsearch,簡稱 es。es 是分散式的,可以隨便擴容,分散式天然就可以支 撐高併發,因為動不動就可以擴容加機器來扛更高的併發。那麼一些比較簡單的 查詢、統計類的操作,可以考慮用 es 來承載,還有一些全文搜索類的操作,也 可以考慮用 es 來承載。
上面的 幾點點,基本就是高併發系統肯定要乾的一些事兒,大家可以仔細結合之 前講過的知識考慮一下,到時候你可以系統的把這塊闡述一下,然後每個部分要 註意哪些問題,之前都講過了,你都可以闡述闡述,表明你對這塊是有點積累的。
說句實話,畢竟你真正厲害的一點,不是在於弄明白一些技術,或者大概知道一 個高併發系統應該長什麼樣?其實實際上在真正的複雜的業務系統里,做高併發 要遠遠比上面提到的點要複雜幾十倍到上百倍。你需要考慮:哪些需要分庫分表, 哪些不需要分庫分表,單庫單表跟分庫分表如何 join,哪些數據要放到緩存里 去,放哪些數據才可以扛住高併發的請求,你需要完成對一個複雜業務系統的分 析之後,然後逐步逐步的加入高併發的系統架構的改造,這個過程是無比複雜的, 一旦做過一次,並且做好了,你在這個市場上就會非常的吃香。
其實大部分公司,真正看重的,不是說你掌握高併發相關的一些基本的架構知識, 架構中的一些技術,RocketMQ、Kafka、Redis、Elasticsearch,高併發這一塊, 你瞭解了,也只能是次一等的人才。對一個有幾十萬行代碼的複雜的分散式系統, 一步一步架構、設計以及實踐過高併發架構的人,這個經驗是難能可貴的。