這里我借鑒了網上其他大佬的觀點:
一:
高並發帶來的挑戰
原因:秒殺搶購會經常會帶來每秒幾萬的高並發場景,為了更快的返回結果給用戶。
吞吐量指標QPS(每秒處理請求數),假設一個業務請求響應耗時為100ms,我們有10台Web服務器,每台給它最大連接數500。
理想化計算方式:
10 * 500/0.1 = 50000
難道我們真的有處理5萬並發?
不然。高並發場景下,Web服務器打開了越多的連接進程,CPU切換上下文的也越多。會增加CPU的壓力,導致CPU業務請求響應耗時 會超出預期很多。可能你的系統只能承受2萬的並發了。
這個時候我們需要怎么做?
答:1、請求的接口需要設計合理,怎么做?
動靜分離,靜態HTML可以通過Ng部署。
核心瓶頸在后台接口上,高並發情況下存儲壓力大,MySQL不合適,用Redis內存讀寫快。
2、重啟與過載保護
如果你2萬的並發硬抗3萬流量,導致服務器沒有連接進程可用,系統就要陷入異常狀態了,響應時間極慢。當系統響應時間很久 ,有些用戶越喜歡頻繁點擊。惡性循環導致“雪崩”,導致整個系統垮掉,就算重啟服務也無濟於事。
怎么做?
過載保護,如果檢測到系統滿載狀態,拒絕請求自我保護。
(1)前端過濾簡單方式
(2)過載保護設置在CGI入口層,將客戶端的請求直接返回
二:
高並發下的數據安全
多線程寫入同一個文件的時候,會出現“線程安全問題”。高並發的數據安全就是這個道理。比如有可能會出現超發。
方案:
悲觀鎖思路:修改數據時,鎖定狀態,排斥外部請求的修改。
缺點:
高並發下某些線程可能永遠都搶不到這個“鎖”,請求就會死在那里。堆積到一定程度,連接數被耗盡,系統異常。
FIFO隊列思路:請求都排好隊,不會導致某些請求永遠拿不到鎖。
缺點:
高並發可能導致隊列內存“撐爆”,如果設置一個極大的內存隊列,系統處理請求的速度根本跟不上不斷快速涌入的請求。越積 越多,還是會導致響應變慢,系統陷入異常。
樂觀鎖思路:
跟悲觀鎖相比,樂觀鎖都有資格去執行請求,但會獲得一個版本號,符合版本號的才算更新成功。
缺點:
加大計算機CPU計算的開銷,但是這是一個比較好的解決方案。
緩存服務器思路:
Redis分布式要保證數據都能能夠平均的緩存到每一台機器,首先想到的做法是對數據進行分片,因為Redis是key-value存儲的, 首先想到的是Hash分片,可能的做法是對key進行哈希運算,得到一 個 long值對分布式的數量取模會得到一個一個對應數據庫的一 個映射,沒有讀取就可以定位到這台數據庫
三:
高並發下的水分與查殺。
原因:秒殺或是搶購等海量請求有時候並不是真正的用戶在發送請求,有些為了“搶”到商品會使用一些“刷票”等類似的工具。這種做 法是幫助他們發送更多的請求到服務器。更高級的還制作一些自動請求 腳本。這些做法都是使自己的請求數占比多,成功率高。
這些很顯然都是屬於作弊行為,不過,我們也有一些解決方案。
答:分為以下幾種情況
1、同一個賬號,一次性發送多個請求。
高並發有可能會導致跳過某些邏輯判斷。
方案:程序入口處,一個用戶只允許一次請求,其他過濾。可以通過Redis內存緩存服務,寫入一個標志位(只允許一個請求成功 ,結合watch樂觀鎖的特性)
2、多個賬號,一次性發送多個請求
很多早期注冊功能沒有限制,導致一些特殊的工作室通過編寫自動注冊腳本注冊一大批“僵屍賬號”。專門做各種刷的行為,以 及一些轉發抽獎活動,大大提升自己中獎的概率。
方案:檢測指定機器IP請求頻率,如果一個IP的請求頻率異常的高。給它彈出一個驗證碼或者禁止它的請求。
3、多個賬號,不同IP發送不同請求
有一些機構自己獨占一批IP,然后做成一個隨機代理IP的服務,有償提供給這些“工作室”使用。還有一些直接黑掉用戶電腦, 轉發IP包,使普通用戶的電腦變成IP代理出口。
方案:難以分辨了,容易“誤傷”。可以通過高門檻的業務,或者通過“數據挖掘”來提前清理。
個人整理並發解決方案。
a.應用層面:讀寫分離、緩存、隊列、集群、令牌、系統拆分、隔離、系統升級(可水平擴容方向)。
b.時間換空間:降低單次請求時間,這樣在單位時間內系統並發就會提升。
c.空間換時間:拉長整體處理業務時間,換取后台系統容量空間。