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