以前的兩篇系統架構的博客中都提到了高併發、高可用技術,可是卻都沒有詳細聊過,今天就好好聊一下常見的高併發技術。java
高併發技術的核心是分流;分別針對請求的各個環節,根據具體場景和業務特色採用不一樣的分流方案,逐層逐級的分擔系統壓力,從而達到高併發能力。ajax
常見的高併發技術有:動靜分離、緩存、異步併發、水平擴展等。分流簡單來講就是:一臺服務器承擔不了的流量,就讓多臺服務器共同分擔;DB承擔不了流量就讓緩存來幫忙分擔;等等。接下來討論的全部內容都是圍繞着分流來實現的。redis
現實中沒有一招鮮吃遍天的美事兒,每個公司、每一種業務、每個場景、每個功能都有其不同凡響的特色,現實中通常都會根據業務特徵、根據請求的各個環節特色,作針對性優化。數據庫
一次請求主要分爲四個階段:客戶端發起請求;經過網絡將請求信息發送到服務端;服務端處理請求;服務端將結果返回給客戶端。爲了追求併發的極致,咱們能夠針對每個階段分別使用不一樣的策略,來提高系統的併發性能。模型以下:緩存
這是一個漏斗型的模型,經過逐層過濾,將流量分散,讓儘量少的請求到達底層。服務器
此模型的核心就是,根據各環節的特色,選擇相應的優化策略,從而實現高併發的目的。微信
客戶端優化技術主要指的是客戶端經過緩存數據,減小訪問服務端的次數,以實現下降服務端壓力,達到支持更多併發量的需求。網絡
常見的處理方式是:緩存不常常變更的內容,每隔必定時間更新一次,或者除非修改了不然較長時間不更新;如:更新微信公衆帳號的頭像時,手機端不會當即看到這個更新。另外,根據業務場景能夠限制沒必要要的請求;如:點擊一個按鈕,發送一次請求到服務端時,禁用按鈕,避免因用戶屢次點擊,而發送沒必要要的請求。數據結構
網絡優化的核心目標是:將資源緩存到距離用戶最近的網絡節點上,這樣除了能夠省下大量網絡帶寬外,還能夠達到最快的請求速度;通常針對靜態資源。架構
經過靜態化技術(將不常常變更的內容生成靜態文件)或動靜分離技術(例如H5+ajax),將靜態的內容存儲在CDN上,當用戶查看一個頁面時,只讓少數的動態請求落到服務器端,其餘內容從CDN上直接獲取,這樣就能夠極大的減小服務器端的流量。
負載均衡的核心是讓每臺服務器以一個合適的負載來分擔全部的請求。
常見的負載均衡方案有:隨機、輪詢、hash、一致性hash。固然在這些基礎上有不少擴展,例如在負載均衡的機器中設置不一樣的權重;根據key的範圍不一樣調用不一樣的服務器等等。
a) 爲何高效
緩存的結構通常都是key-value結構,經過key直接尋址,時間複雜度爲O(1),這比DB的遍歷比較來快了很是多;另外,很多的緩存中間件經過在內存中存儲數據,不用從磁盤中獲取數據,性能也就會很是高。
說明一下:大部分緩存中間件都會對value作一些擴充,讓value也成爲一個複雜的數據結構,例如Redis的Set、SortSet,若是須要在value中尋找某一個值,時間複雜度會退化成爲O(N);這些數據結構提供了強大的功能,使用的時候注意合理使用,以免由於緩存亂用致使性能下降的問題。
b) 分佈式緩存
如redis、tair、memcached等。
優勢是:集羣部署,不用考慮容量問題,數據支持持久化,支持高可用。
缺點是:由於服務器和緩存數據交換時存在一次網絡交互,若是數據結構選擇不合理或者併發量很是大或者每次交互的數據量較大時,可能會引發io阻塞等問題,需謹慎。
c) 堆緩存
經過java的堆來緩存數據。
優勢是:速度很是快。
缺點是:存儲數據量受限,斷點數據丟失,分佈式場景中若是出現不一致時,處理麻煩。
d) 磁盤文件緩存
將數據存儲到服務器所在的磁盤上。
優勢是:存儲內容較堆內存多(少於分佈式緩存),是持久化的。
缺點是:服務器遷移時也要遷移磁盤中的文件,分佈式場景中若是出現不一致時,處理麻煩。
e) 注意事項
緩存數據和數據庫數據不一致的問題。
緩存擊穿問題。
緩存數據丟失問題(緩存通常都須要持久化的,爲了保證性能緩存通常都不是同步持久化,因此是可能存在數據丟失問題的)。
高性能的IO通訊模型能夠給系統帶來巨大的性能提高。目前就較爲成熟、高效的IO通行模型是NIO(也叫IO多路複用、異步阻塞IO)。
在java服務器前加一層Nginx服務器,它既能夠提供良好的負載均衡能力,也可以支持很是高的併發。固然Nginx的高性能還與他的master-worker設計有關,幾乎作到了無線程切換。
使用Dubbo進行RPC調用時,默認使用的Netty也是基於NIO的。