什么是高並發?
高並發(High Concurrency)是一種系統運行過程中遇到的一種“短時間內遇到大量操作請求”的情況,主要發生在web系統集中大量訪問收到大量請求(例如:12306的搶票情況;天貓雙十一活動)。該情況的發生會導致系統在這段時間內執行大量操作,例如對資源的請求,數據庫的操作等。
高並發的處理指標?
高並發相關常用的一些指標有:
1.響應時間(Response Time)
響應時間:系統對請求做出響應的時間。例如系統處理一個HTTP請求需要200ms,這個200ms就是系統的響應時間
2.吞吐量(Throughput)
吞吐量:單位時間內處理的請求數量。
3.每秒查詢率QPS(Query Per Second)
QPS:每秒響應請求數。在互聯網領域,這個指標和吞吐量區分的沒有這么明顯。
4.並發用戶數
並發用戶數:同時承載正常使用系統功能的用戶數量。例如一個即時通訊系統,同時在線量一定程度上代表了系統的並發用戶數。
高並發和多線程的關系和區別
“高並發和多線程”總是被一起提起,給人感覺兩者好像相等,實則 高並發 ≠ 多線程
多線程並發技術
多線程是java的特性,因為現在cpu都是多核多線程的,可以同時執行幾個任務,為了提高jvm的執行效率,java提供了這種多線程的機制,以增強數據處理效率。多線程對應的是cpu,高並發對應的是訪問請求,可以用單線程處理所有訪問請求,也可以用多線程同時處理訪問請求。
在過去單CPU時代,單任務在一個時間點只能執行單一程序。之后發展到多任務階段,計算機能在同一時間點並行執行多任務或多進程。雖然並不是真正意義上的“同一時間點”,而是多個任務或進程共享一個CPU,並交由操作系統來完成多任務間對CPU的運行切換,以使得每個任務都有機會獲得一定的時間片運行。
再后來發展到多線程技術,使得在一個程序內部能擁有多個線程並行執行。一個線程的執行可以被認為是一個CPU在執行該程序。當一個程序運行在多線程下,就好像有多個CPU在同時執行該程序。
總之,多線程是處理高並發的一種編程方法,java多線程並發編程一般會涉及到如下技術點:

1.並發編程三要素
- 原子性原子,即一個不可再被分割的顆粒。在Java中原子性指的是一個或多個操作要么全部執行成功要么全部執行失敗。
- 有序性程序執行的順序按照代碼的先后順序執行。(處理器可能會對指令進行重排序)
- 可見性當多個線程訪問同一個變量時,如果其中一個線程對其作了修改,其他線程能立即獲取到最新的值。
2. 線程的五大狀態
- 創建狀態當用 new 操作符創建一個線程的時候
- 就緒狀態調用 start 方法,處於就緒狀態的線程並不一定馬上就會執行 run 方法,還需要等待CPU的調度
- 運行狀態CPU 開始調度線程,並開始執行 run 方法
- 阻塞狀態線程的執行過程中由於一些原因進入阻塞狀態比如:調用 sleep 方法、嘗試去得到一個鎖等等
- 死亡狀態run 方法執行完 或者 執行過程中遇到了一個異常
3.悲觀鎖與樂觀鎖
- 悲觀鎖:每次操作都會加鎖,會造成線程阻塞。
- 樂觀鎖:每次操作不加鎖而是假設沒有沖突而去完成某項操作,如果因為沖突失敗就重試,直到成功為止,不會造成線程阻塞。
4.線程之間的協作:wait/notify/notifyAll等
5.synchronized 關鍵字
6.CAS
CAS全稱是Compare And Swap,即比較替換,是實現並發應用到的一種技術。操作包含三個操作數 —— 內存位置(V)、預期原值(A)和新值(B)。 如果內存位置的值與預期原值相匹配,那么處理器會自動將該位置值更新為新值 。否則,處理器不做任何操作。
7.線程池
如果我們使用線程的時候就去創建一個線程,雖然簡單,但是存在很大的問題。如果並發的線程數量很多,並且每個線程都是執行一個時間很短的任務就結束了,這樣頻繁創建線程就會大大降低系統的效率,因為頻繁創建線程和銷毀線程需要時間。線程池通過復用可以大大減少線程頻繁創建與銷毀帶來的性能上的損耗。
高並發
高並發不是JAVA的專有的東西,是語言無關的廣義的,為提供更好互聯網服務而提出的概念。
典型的場景,例如:12306搶火車票,天貓雙十一秒殺活動等。
該情況的發生會導致系統在這段時間內執行大量操作,例如對資源的請求,數據庫的操作等。如果高並發處理不好,不僅僅降低了用戶的體驗度(請求響應時間過長),同時可能導致系統宕機,嚴重的甚至導致OOM異常,系統停止工作等。
如果要想系統能夠適應高並發狀態,則需要從各個方面進行提高高並發能力。

1.分布式緩存:redis、memcached等,結合CDN來解決圖片文件等訪問。
2.消息隊列中間件:activeMQ等,解決大量消息的異步處理能力。
3.應用拆分:一個工程被拆分為多個工程部署,利用dubbo解決多工程之間的通信。
4.數據庫垂直拆分和水平拆分(分庫分表)等。
5.數據庫讀寫分離,解決大數據的查詢問題。
6.還可以利用nosql ,例如mongoDB配合mysql組合使用。
7.還需要建立大數據訪問情況下的服務降級以及限流機制等。
高並發、多線程
1.高並發
高並發是請求,指的是多個客戶端同一時刻向服務端發送請求, 它是一種現象。
比如,在雙11凌晨12:00分同時有10萬個下單請求。
高並發標准:
1)高並發用戶數
2)TPS(Transactions Per Second)每秒事務數
3)QPS(Query Per Second)每秒查詢率等。
2.多線程
多線程是處理,指的是同一時刻多個執行者處理同一類的任務, 它有具體的實現。
比如,電商網站在雙11凌晨12:00分同時有100個線程處理2000個下單請求。
3.並發
多個線程操作相同的資源,保證線程安全,合理使用資源。
多線程技術

1:並發基礎
2:並發鎖
3:並發工具類
4:集合&並發容器
ArrayList、Vector、LinkedList等區別詳解
5:並發隊列
6:並發其它
高並發架構技術

1、Redis為代表的分布式緩存技術
2、RocketMQ為代表的分布式消息隊列技術
4、Dubbo為代表的服務架構技術
5、數據庫層分庫分表等技術
6、億級負載均衡技術
7、熔斷限流等技術
8、高並發秒殺等技術
大型Web網站的特點如下:
大型Web網站的技術挑戰主要來自於大量的用戶,高並發的訪問和海量的數據存儲,任何簡單的業務一旦需要處理TB級別的數據和面對數以億計的用戶,問題就會變得很棘手。那么如何打造一個高可用、高性能、易擴展、可伸縮且安全的網站?首先要從架構方面入手,以高性能架構為基礎,輔以優化后的前端應用(如減少Http請求,終端緩存等等)和后台程序(如Jvm優化,操作系統優化等等)即可以構建一個高性能的Web網站。
首先我們來了解下構建一個高性能Web網站時,性能的瓶勁在哪里?如下圖所示:
從上圖可以分析出性能瓶勁主要表現在兩個方面:
1、 硬件資源層面,如不同運營上的網絡,服務器的帶寬限制,服務器的CPU、內存及磁盤IO等;
2、 軟件層面,Web應用程序的性能,數據庫服務器的性能;
硬件資源的提升對性能的提升時逐級遞減的直至趨於0,所以性能的提高不能通過無休止的增加硬件資源,所以我們就要考慮如何從軟件架構的層面來提供性能,下圖為高性能架構的主要思路:
架構思路的說明如下:
1、 負載均衡,包括早期的使用DNS負載均衡,四層交換的負載均衡及七層交換的負載均衡;一般業界多采用硬件四層交換負載均衡和軟件四層交換負載均衡,硬件四層交換負載均衡優勢時穩定性高,功能強大,但價格較高,一般的公司難以承受,典型產品是F5、A10;軟件四層交換負載均衡的優勢是免費開源,通過熱備等方式也可以構建一個穩定性高的負載均衡,所以我們的首選軟件四層交換負載均衡(即LVS)
2、 高可用性方面要考慮避免單點故障,需要引入熱備(包括主從和主主兩種方式),集群以及災備;
3、 Web應用開發架構方面要選擇合適的應用開發框架同時考慮將動態頁面進行靜態化並進行靜態資源(圖片,CSS,JS及頁面)的緩存(此點建議使用Nginx或者Varnish進行緩存);數據存儲方面考慮使用分布式存儲系統(需要根據所存儲文件的大小選擇合適的存儲系統,比如一般的圖片文件和視頻文件選擇的存儲系統就會有所不同,前者一般可以選擇FastDFS,后者選擇HDFS)以及引入數據緩存(如Redis集群)和NoSql數據庫(也叫內存數據庫,比如:MongoDB)
4、 數據庫方面需要考慮進行讀寫分離,分庫、分表、分區等;
5、 網絡方面引入CDN來解決不同網絡服務商的接入速度問題並考慮在不同運營商機房部署服務器,通過鏡像技術來實現不同網絡服務商的接入速度問題。
Web應用架構的演化歷程:
Web應用架構的特點如下圖
微服務架構有其明顯的優勢,已經是目前及未來Web應用架構的首選,其缺點是:微服務過多,服務治理成本高,不利於系統維護;分布式系統開發的技術成本高(容錯、分布式事務等),對團隊挑戰大;所以如果是一般初學者建議還是選擇先從MVC架構開始。
綜合以上的簡單分析,我們可以大致得出高性能的架構如下圖:
1、 使用LVS作為軟件四層交換負載均衡並使用Heartbeat實現雙機熱備;
2、 使用反向代理軟件來實現數據緩存(靜態資源緩存),此處我們可以選擇使用Nginx或者Varnish
3、 Web應用框架可以更加系統規模進行選擇,小編建議初學者選擇先從MVC架構開始;
4、 數據持久化層使用MyBatis以提高性能,數據緩存使用Redis集群;
5、 分布式存儲選擇HDFS並引入NoSql數據庫,數據庫方面實現讀寫分離和熱備,必要的時候還需要分庫分表等;
--------------------------------------------------------------------------------------------------------------------
高並發設計的技術方案
1.負載均衡
2.分布式微服務
3.緩存機制
4.分布式關系型數據庫
4.1 垂直分表
4.2 水平分表
4.3 開源框架分類
4.4 實現方案
5.分布式消息隊列
5.1 常見的消息隊列
5.2 消息隊列的場景
6.CDN 內容分發網絡
7.其他
8.總結
————————————————
1.負載均衡
靠優化單台機器的內存、CPU、磁盤、網絡帶寬,使其發揮極致性能,已經不太現實。
負載均衡,它的職責是將網絡請求 “均攤”到不同的機器上。避免集群中部分服務器壓力過大,而另一些服務器比較空閑的情況
通過負載均衡,可以讓每台服務器獲取到適合自己處理能力的負載。在為高負載服務器分流的同時,還可以避免資源浪費,一舉兩得。
常見的負載算法:
- 隨機算法
- 輪詢算法
- 輪詢權重算法
- 一致性哈希算法
- 最小連接
- 自適應算法
常用負載均衡工具:
- LVS
- Nginx
- HAProxy
對於一些大型系統,一般會采用 DNS+四層負載+七層負載的方式進行多層次負載均衡。
————————————————
2.分布式微服務
每個微服務獨立部署,服務和服務間采用輕量級的通信機制,如:標准的HTTP協議、或者私有的RPC協議。
微服務特點:
按照業務划分服務,單個服務代碼量小,業務單一,容易維護
每個微服務都有獨立的基礎組件, 例如數據庫
微服務之間的通信為Http 協議或者其他協議, 具有容錯性
微服務有一定的治理方案, 服務之間不耦合, 可以隨時加入和刪除
單個微服務可以集群部署, 有負載均衡的能力
整個微服務有安全機制, 包括用戶驗證, 權限驗證, 資源保護
整個微服務有鏈路跟蹤的能力
有完整的實時日志系統
市面常用微服務框架有:Spring Cloud 、Dubbo 、kubernetes、gRPC、Thrift 等
常用的注冊中心有:Zookeeper、etcd、Eureka、Nacos、Consul
需要注意一些很復雜的問題
- 分布式事務
- 限流機制
- 熔斷機制
- 網關
- 服務鏈路跟蹤
————————————————
3.緩存機制
性能不夠,緩存來湊。要想快速提升性能,緩存肯定少不了
緩存能夠帶來性能的大幅提升,以 Memcache 為例,單台 Memcache 服務器簡單的 key-value 查詢能夠達到 TPS 50000 以上;Redis性能數據是10W+ QPS
常見的緩存分為本地緩存和分布式緩存,區別在與是否要走網絡通訊。
本地緩存是部署在應用服務器中,而我們應用服務器通常會部署多台,當數據更新時,我們不能確定哪台服務器本地中了緩存,更新或者刪除所有服務器的緩存不是一個好的選擇,所以我們通常會等待緩存過期。因此,這種緩存的有效期很短,通常為分鍾或者秒級別,以避免返回前端臟數據。
分布式緩存采用集群化管理,支持水平擴容,並提供客戶端路由數據,數據一致性維護更好。雖然有不到 1ms 的網絡開銷,但比起其優勢,這點損耗微不足道。
緩存更新常用策略:
Cache aside,通常會先更新數據庫,然后再刪除緩存,為了兜底還會設置緩存時間。
Read/Write through, 一般是由一個 Cache Provider 對外提供讀寫操作,應用程序不用感知操作的是緩存還是數據庫。
Write behind,延遲寫入,Cache Provider 每隔一段時間會批量寫入數據庫,大大提升寫的效率。像操作系統的page cache也是類似機制。
————————————————
4.分布式關系型數據庫
MySQL數據庫采用B+數索引,三層結構,為了保證IO性能,一般建議單表存儲 千萬 條數據.
分表又可以細分為 垂直分表 和 水平分表 兩種形式。
4.1 垂直分表
數據表垂直拆分就是縱向地把一張表中的列拆分到多個表,表由“寬”變“窄”,簡單來講,就是將大表拆成多張小表,一般會遵循以下幾個原則:
冷熱分離,把常用的列放在一個表,不常用的放在一個表。
字段更新、查詢頻次拆分
大字段列獨立存放
關系緊密的列放在一起
4.2 水平分表
表結構維持不變,對數據行進行切分,將表中的某些行切分到一張表中,而另外的某些行又切分到其他的表中,也就是說拆分后數據集的並集等於拆分前的數據集。
SQl組合。因為是邏輯表名,需要按分表鍵計算對應的物理表編號,根據邏輯重新組裝動態的SQL
數據庫路由。如果采用分庫,需要根據邏輯的分表編號計算數據庫的編號
結果合並。如果查詢沒有傳入指定的分表鍵,會全庫執行,此時需要將結果合並再輸出。
4.3 開源框架分類
Proxy模式。SQL 組合、數據庫路由、執行結果合並等功能全部存放在一個代理服務中,業務方可以當做。
支持多語言, 但是引入一個中間件, 會形成流量瓶頸, 安全風險高, 運維成本高
Client 模式。常見是 sharding-jdbc,業務端系統只需要引入一個jar包即可,按照規范配置路由規則。jar 中處理 SQL 組合、數據庫路由、執行結果合並等相關功能。
簡單, 輕便, 減少了流量瓶頸與運維成本, 但是單語言, 升級不方便
4.4 實現方案
如何選擇分表鍵。
數據盡量均勻分布在不同表或庫、跨庫查詢操作盡可能少、這個字段的值不會變。比如電商訂單采用user_id。
基因分庫分表
數據存儲中,相互關系的表,盡量分庫時落到同一個庫中,避免遍歷多個庫查詢,而且還能避免分布式事務。
一般分庫或者分表我們采用取余操作,余數相同的id落到相同的庫中,或分表規則一致。
分片策略。
根據范圍分片、根據 hash 值分片、根據 hash 值及范圍混合分片
歷史數據遷移
增量數據監聽 binlog,然后通過 canal 通知遷移程序開始增量數據遷移
開啟任務,全量數據遷移
開啟雙寫,並關閉增量遷移任務
讀業務切換到新庫
線上運行一段時間,確認沒有問題后,下線老庫的寫操作
數據量大,就分表;並發高,就分庫
在實際的業務開發中,要做好數據量的增長預測,做好技術方案選型。另外,在引入分表方案后,要考慮數據傾斜問題,這個跟分表鍵有很大關系,避免數據分布不均衡影響系統性能
————————————————
5.分布式消息隊列
並不是所有的調用都要走同步形式,對於時間要求不高、或者非核心邏輯,我們可以采用異步處理機制。
消息隊列主要有三種角色:生產者、消息隊列、消費者。兩者之間通過消息中間件完成了解耦,系統的擴展性非常高。
5.1 常見的消息隊列
ActiveMQ,RabbitMQ,ZeroMQ,Kafka,MetaQ,RocketMQ、Pulsar 等
5.2 消息隊列的場景
異步處理。將一個請求鏈路中的非核心流程,拆分出來,異步處理,減少主流程鏈路的處理邏輯,縮短RT,提升吞吐量。如:注冊新用戶發短信通知。
削峰填谷。避免流量暴漲,打垮下游系統,前面會加個消息隊列,平滑流量沖擊。比如:秒殺活動。生活中像電源適配器也是這個原理。
應用解耦。兩個應用,通過消息系統間接建立關系,避免一個系統宕機后對另一個系統的影響,提升系統的可用性。如:下單異步扣減庫存
消息通訊。內置了高效的通信機制,可用於消息通訊。如:點對點消息隊列、聊天室。
————————————————
6.CDN 內容分發網絡
目的是在現有的網絡中增加一層網絡架構,將網站的內容發布到最接近用戶的網絡“邊緣”,使用戶可以就近取得所需的內容,提高用戶訪問網站的響應速度。
CDN = 鏡像(Mirror)+緩存(Cache)+整體負載均衡(GSLB)
CDN都以緩存網站中的靜態數據為主,如:CSS、JS、圖片和靜態頁面等數據。用戶從主站服務器中請求到動態內容后,再從CDN下載靜態數據,從而加速網頁數據內容的下載速度。
CDN 特點:
本地Cache加速
鏡像服務
遠程加速
帶寬優化
集群抗攻擊
CDN 應用場景
網站站點/應用加速
視音頻點播/大文件下載分發加速
視頻直播加速
移動應用加速
————————————————
7.其他
分布式文件系統、大數據、NoSQL、NewSQL,慢慢也開始成為高並發系統的周圍框架生態補充。
8.總結
本文列舉了高並發設計的技術方案:
1 負載均衡 2.分布式微服務 3. 緩存 4.分布式數據庫 6.消息隊列 7.CDN
其實還有分布式鎖等, 分布式鎖可以通過redis, zk, mysql, etcd去實現
————————————————
【高並發解決方案】
一、對於被頻繁調用,更新頻率較低的頁面,可以采用HTML靜態化技術
二、圖片服務器分離
三、數據庫集群和庫表散列
mysql主從。m-m-s-s-s...(2個主,多個從。多個從使用負載均衡。主寫入數據,從讀取數據)
四、緩存。眾多的緩存框架
五、負載均衡。nginx,lvs,F5
六、搜索用單獨的服務器,搜索框架
七、使用MQ服務器
-----------------------------------
集群主要分成三大類:
高可用集群(High Availability Cluster/HA),
負載均衡集群(Load Balance Cluster),
高性能計算集群(High Performance Computing Cluster/HPC)
秒殺架構設計理念
限流: 鑒於只有少部分用戶能夠秒殺成功,所以要限制大部分流量,只允許少部分流量進入服務后端。
削峰:對於秒殺系統瞬時會有大量用戶涌入,所以在搶購一開始會有很高的瞬間峰值。高峰值流量是壓垮系統很重要的原因,所以如何把瞬間的高流量變成一段時間平穩的流量也是設計秒殺系統很重要的思路。實現削峰的常用的方法有利用緩存和消息中間件等技術。
異步處理:秒殺系統是一個高並發系統,采用異步處理模式可以極大地提高系統並發量,其實異步處理就是削峰的一種實現方式。
內存緩存:秒殺系統最大的瓶頸一般都是數據庫讀寫,由於數據庫讀寫屬於磁盤IO,性能很低,如果能夠把部分數據或業務邏輯轉移到內存緩存,效率會有極大地提升。
可拓展:當然如果我們想支持更多用戶,更大的並發,最好就將系統設計成彈性可拓展的,如果流量來了,拓展機器就好了。像淘寶、京東等雙十一活動時會增加大量機器應對交易高峰。