高併發服務器邏輯處理瓶頸,如何解決?
下面就用我有限的知識和經驗,講一講高併發下的系統處理方案。
1、大部分的系統應用,在建設初期都是單機應用,也就是一個應用服務器加一個數據庫。
2、當訪問量增多、併發量增加的時候,很多時候應用服務器會先扛不住,通常我們解決這個問題的方法是:把應用服務器做集群部署,在前面搭建負載均衡,例如硬件負載F5、軟件負載Nginx。
3、應用服務器的壓力暫時解決,但是數據庫畢竟還是單臺,這時候我們可以在整體的架構中增加緩存,已減少數據庫的壓力,最常見的是引入Redis,做集群化的部署。
4、業務繼續發展,併發量持續增多,單庫已經到了極限;這時候可以考慮分庫,常見的做法是對分庫字段進行hash()%N,按照結果將數據路由到某一個分庫(分表)上。
5、系統繼續發展,雖然應用是集群化部署,但是畢竟是單個應用,並且隨著項目功能的增加,應用包也會越來越大,代碼改動起來非常痛苦;這時候需要把應用拆分成多個應用,庫也各自獨立出來(說的很簡單,過程非常之痛苦,所以很多公司在初期,就是按照這個架構搭建):
應用拆分成多個應用;
應用之間的服務發現和調用,都需要服務註冊中心和網關的幫助;
6、雖然應用和庫都拆開了,但是應用和應用質檢的耦合度依然非常高,所以通常會引入消息隊列,例如各種MQ、Kafka,把一些實時性要求不是那麼高的服務解耦,比如交易完成時候給客戶發一條短信,那麼可以把待發送的短信放到消息隊列中,短信平臺從消息隊列中獲得消息發送短信。
7、這時候應用的體量已經比較大了,部署、運維、查錯的難度加大,這時候需要引入很多組件,來幫助整個系統的穩定運行:
認證中心:安全性的問題要注意,一個接口不是隨隨便便都能訪問的;
限流:當併發量突增的時候,系統肯定會扛不住,這時候限制一部分流量的進入;
監控中心:包括日誌監控、服務鏈路監控、流量監控等等;
告警平臺:系統發生異常時,需要及時通知運維人員;
圖畫的有些倉促,難免有不嚴謹的地方,大家可以留言指正(如果留言中有態度不好的,我就自動忽略了)。
我將持續分享Java開發、架構設計、程序員職業發展等方面的見解,希望能得到你的關注。
高併發服務器邏輯處理瓶頸,如何解決?首先我們先了解什麼是併發!
併發,在操作系統中,是指一個時間段中有幾個程序都處於已啟動運行到運行完畢之間,且這幾個程序都是在同一個處理機上運行,但任一個時刻點上只有一個程序在處理機上運行。———來源《百度百科》
顧名思義,高併發就是在指定時間內,系統同時能夠處理大量的請求(連接數)。
那麼如何衡量高併發呢?
高併發衡量指標
響應時間:系統對請求做出響應的時間,即一個http請求返回所用的時間;
吞吐量:單位時間內處理的請求數量;
QPS(TPS):每秒可以處理的請求數或事務數;
併發用戶數:同時承載正常使用系統功能的用戶數量,即多少人同時使用,系統還能正常運行的用戶數量;
根據上面衡量指標可以看到,提高併發能力必須解決如下幾個問題:
如何提高併發連接數?
那麼多的連接數怎麼進行業務處理?
應用服務器的處理水平又該怎麼提高?
如何使用微服務架構提升高併發邏輯?
彆著急,這麼多問題我們一個一個來分析解決!
1)、如何提高併發連接數?
如下圖所示,常規的單一網絡連接模型只能1個連接對應1個線程,壓力都集中在內存,導致內存開銷非常大,肯定支撐的連接數有限!(直接掛掉)
單一網絡連接模型
有道是業務寫的再好不如一臺高性能服務器,這個鍋不一定要開發人員背的哦!!!服務器的連接入口就那麼大(比如tomcat只有幾千的連接數),那麼處理的能力也只侷限於幾千。
怎麼解決呢?選用合適的網絡IO模型或者selector,通過使用一個線程輪詢或者事件觸發的方式,能支持幾萬甚至更多的連接數,再配合上nginx做負載就更完美了。
2)那麼多的連接數怎麼進行業務處理?
大家都知道nginx只是具有反向代理和負載均衡的功能,並不能處理具體的業務邏輯,不能擔當應用服務器來使用。例如webSphere 、tomcat和jetty等,但是我們可以利用nginx將接受到的大量連接通過均衡的方式(輪詢,權重,hash)分配到不同的應用服務器中進行業務處理!
nginx負載
3)應用服務器的處理水平又該怎麼提高?
要提高應用服務器的處理水平就要了解自己的應用服務器的瓶頸在哪裡,一般有兩個:
數據庫壓力:數據庫是支撐產品業務的核心模塊,系統的高併發的主要壓力也是來源於數據庫。處理方式有如下這些:
數據庫本身:建立有效索引、讀寫分離、雙主互備、分庫分表(sharding-jdbc等實現)等策略,提高數據庫處理能力,減少壓力!
結合內存數據庫:例如redid、memcached等,根據業務需要緩存一些數據字典、枚舉變量和頻繁使用數據等減少數據庫訪問次數,提升數據庫處理能力。
web集群架構圖
如上圖web集群架構圖所示:
用nginx負載多臺應用服務器;
使用redid/memcached做業務緩存;
再加上數據庫集群;
組成了經典的web高併發集群架構。
代碼中的業務邏輯:
大家可以 參考阿里巴巴java開發手冊 中的開發規範來做就好了,總代來說少創建線程、少創建對象、少加鎖、防止死鎖、少創建線程、注意內存回收等策略,來提升代碼性能。
開發中可以採用前後端分離的架構模式,動靜分離、鬆耦合等提升前後端處理能力。
4)如何使用微服務架構提升高併發邏輯?
先看一下非常火的這張微服務架構圖:
微服務架構圖
主要包含11大核心組件,分別是:
核心支撐組件
服務網關Zuul
服務註冊發現Eureka+Ribbon
服務配置中心Apollo
認證授權中心Spring Security OAuth
服務框架Spring MVC/Boot
監控反饋組件
數據總線Kafka
日誌監控ELK
調用鏈監控CAT
Metrics監控KairosDB
健康檢查和告警ZMon
限流熔斷和流聚合Hystrix/Turbine
總結
出來上述幾點解決高併發服務器邏輯處理瓶頸外,還要考慮網絡因素,例如採用CDN加速,將不同地點的請求分發到不同的服務集群上,避免網絡對速度的影響!
總之,根據自身實際業務在合理範圍內儘可能的拆分,拆分以後同類服務可以通過水平擴展達到整體的高性能高併發,同時將越脆弱的資源放置在鏈路的越末端,訪問的時候儘量將訪問鏈接縮短,降低每次訪問的資源消耗。服務之間直接restful模型使用http調用,或者redis,kafka類的消息中間件通信。單個服務直接使用nginx做負載集群,同時前後端分離,數據庫分庫分表等一整套分佈式服務系統!
hash()%N是什麼?