日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網為廣大站長提供免費收錄網站服務,提交前請做好本站友鏈:【 網站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(50元/站),

點擊這里在線咨詢客服
新站提交
  • 網站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747

你開發的系統到底可以支撐多少并發訪問?100萬?10萬?1萬?1千?500?為什么能支撐,又為什么不能支撐?這是個直擊心靈的問題,能否準確回答這個問題是程序員的一個分水嶺,也是一個能否持續做技術的門檻,能夠準確回答的人,可以不看這篇文章了,如果仔細思考過這個問題但是卻沒有思路去回答這個問題的人,建議讀下去。

微服務不等于高并發,集群也不等于高并發,k8s更不等于高并發,一提性能優化就想到壓測,連壓測結果是否合理可能都不知道,如何去優化呢?就是用explain去看看sql么?

所謂的高并發是針對某些大用戶量同時訪問系統的場景抽象而出的一個模糊的概念,高并發只是所有那些場景的統稱,所以不存在高并發的通用解決方案,只存在某些特定場景的解決方案。經過多年N多個高并發場景的不斷積累,目前針對特定的高并發場景均有相對成熟的解決方案,但僅僅是解決方案,對于具體業務還需要具體分析。

講個故事

針對一個簡單場景分析,開發了一個系統,若干個功能,會存在問題么?如果只是幾百個活躍用戶,談不上什么并發,那么很簡單,只需一個應用集群和一個數據庫主備即可,基本上80%的中小型公司開發的系統都是這樣部署的,一個Tomcat集群,一個主備MySQL數據庫,有錢的客戶來個主備的oracle就行了。此時無所謂什么性能優化,如下圖:

你開發的系統到底可以支撐多少并發訪問?

 

但是,此時,如果發現活躍用戶數到了幾千上萬,突然有一天客戶跟你說,系統崩了,無法訪問或者特別慢,此時到服務器上一看,進程還在啊,CPU也算正常啊,數據庫也還好啊,然后看日志,沒什么報錯啊,頂多是sql超時了,很可能會說,系統正常運行著,怎么訪問不了了呢,重啟下吧,重啟之后一切正常,客戶讓你寫故障報告,你憋了半天來了句可能是網絡問題,或者實話實說系統沒發現什么異常,不知道為何重啟就好了,這個事兒可能就過去了。之后很可能每隔一段時間來一次重啟,如果一直沒解決,也許客戶失去信心,也就不用這個系統了。這是一個比較常見的場景,我遇到過很多客戶的軟件開發商都是這樣處理問題的,這也是市面上大多數開發人員想要高并發經驗但是又沒有高并發經驗的原因。很多時候不是沒場景,而是即使遇到問題也沒思路解決。

故事的第一階段完了,現在需要針對第一階段來分析分析,如何解決這次的宕機問題。當系統的用戶數從幾百逐漸增加到幾萬的時候,如果預先沒有針對高并發場景進行特殊設計,那么當高并發或頻繁訪問某個功能的時候就會出現此類問題,要么是數據庫崩了一堆網絡請求異常,要么是系統特別慢一個接口執行個幾十秒,要么是系統內存溢出了。為何會出現這個問題?80%的原因都是數據庫查詢太慢了,這就是最常見的瓶頸點——數據庫慢查詢。

哪出的問題

數據庫慢查詢的原因實在太多,sql編寫不規范,沒有遵循ESR原則,業務復雜等等。拋去數據庫問題先不談,先說說瓶頸是如何出現的,為何某幾個查詢慢會導致服務器全面崩潰-雪崩呢,雪崩之后我們應該如何分析如何下手呢?看看下圖,一個請求從服務端接收開始,一直到數據庫,然后再返回給前端,大概經過這些步驟。這個時候我們就得逼著自己思考幾個問題了,假定100并發進來的時候,哪會存在瓶頸呢?網絡處理?程序執行?數據庫查詢?為什么存在或不存在瓶頸將是一個直擊靈魂的問題讓你久久不能寐。

你開發的系統到底可以支撐多少并發訪問?

 

網絡原因?

首先看第一大類問題,網絡處理,這涉及到一個網絡編程的問題,即socket編程。我們開發的所有web服務或者說所有跟網絡有關的服務基本上都涉及到這個問題-網絡編程!

先看一個網絡請求是如何到了我們的web容器的,一個網絡請求從客戶端經過若干網線傳輸和交換機路由器的中間轉發,到了我們的網卡的時候,就是一堆的高低電頻信號,網卡在接收到這些信號后,會有個mac+PHY芯片進行處理,首先將物理信號轉變為數字信號,即01010101這樣一串數字,然后進行轉碼,轉變為幀,這就是程序處理網絡請求的第一個概念,從一個個幀再逐漸轉變成包,從IP包再轉變成TCP包,最后轉變成http包,這就是大學學網絡里面講過的四層協議或七層協議。這個過程,有網卡硬件的處理,有CPU和內存的交互,還有網卡驅動和操作系統的程序執行。如下圖:

你開發的系統到底可以支撐多少并發訪問?

 

根據上圖簡單分析下網絡請求處理過程:

  1. 網卡接收高低電頻信號經過MAC處理后,將數據包先暫存于片內FIFO接收隊列。
  2. 網卡控制器將FIFO隊列放入內存的一個環形緩沖區。
  3. 網卡控制器將環形緩沖區的數據放入內存,上半部處理完成。
  4. 觸發軟中斷,開始下半部處理。
  5. CPU軟中斷,調用網卡驅動程序繼續處理。
  6. 網卡驅動程序通過NAPI開始處理內存中的網絡包。
  7. 操作系統內核網絡處理模塊開始介入,執行大名鼎鼎的netif_receive_skb函數,執行完成后,網絡處理第一大部分完成,開始進入協議處理。
  8. linux內核的socket模塊開始介入,進行tcp或udp協議處理。

根據上圖分析,我們普通的服務器在處理網絡請求時,一般有三個瓶頸點,帶寬、網卡速率和協議處理。帶寬基本上是客戶花錢買的,一般幾十上百兆,1G也正常。網卡速率取決于硬件設備了,現在的千兆網卡和萬兆網卡比較主流;協議處理算是一個比較重要的瓶頸,目前面試寶典中的epoll技術就是協議處理所使用的最重要的一種技術,協議處理技術的變革直接導致了網絡并發請求和在線連接數從原來的幾百到了現在的幾十上百萬。

在這些軟硬件相互交互的過程中,大量前輩針對中斷、數據包處理,協議處理等做過大量優化,有軟硬中斷、上半部下半部分離處理、NAPI、DMA、Epoll等等,這些技術很好的解決了網絡請求處理過程中的各種瓶頸,發展到目前,出現了100Gb的網卡,阿里巴巴六年前就開始研究單機千萬連接,即解決C10M的問題,目前在網絡處理層面,基本上一臺物理機可以滿足我們正常的十萬連接并發處理了。關于網絡編程內容也不是一句兩句能說透的,此處暫且分析到只要使用了正常的一個服務器,并且使用epoll技術,適當的估算下并發量和帶寬,網絡處理這塊兒不太容易成為瓶頸。下面我們重點說說epoll和應用層的網絡請求處理。

首先我們可以做個基準測試,先隨意找一臺虛擬機服務器,然后部署個Nginx,直接用wrk來試試基準測試的結果,可以看到nginx在一臺很普通的服務器上可以支撐8萬并發。如果在這臺服務器多跑幾個nginx,基本上可以把網卡打滿,并發也可以上到十幾二十萬,這就跟本身服務器性能有關了,如果是個物理機,性能會更高。nginx只是測試了一個http請求的處理并發,nginx基準測試完成后,可以進一步進行tomcat的基準測試和springboot的基準測試,最后使用公司內部的框架做一個網絡處理的基準測試,得到一個相對合理的極限值。我們做的結果是nginx單機雙實例占用4核可以到15萬,tomcat可以到10萬,springboot和內部封裝后的框架可以到9萬。由此看來web容器和spring框架多多少少會損耗一些性能。此時的瓶頸為CPU,因為一直在處理網絡請求的收發,與預期相符,在網絡處理層面,CPU、網卡和帶寬絕對是瓶頸。下圖是nginx的壓測結果。

你開發的系統到底可以支撐多少并發訪問?

 

如果這篇文章說不清epoll的本質,那就過來掐死我吧!

這篇文章把epoll的原理講得比較透,nginx、tomcat、redis、kafka等等所有高性能的中間件的底層都是使用epoll。

此處的基準測試是個很重要的環節,我們網上能夠看到的很多文章所謂的高并發高性能,都是一些理論值,或者說是推測出來的一個量級,實際值跟網絡情況服務器情況的不同會有較大的差別,做好基準測試是我們做性能優化非常重要的一環,而基準測試的核心就是在一個簡單的配置環境下發現核心性能點的瓶頸,例如如果一臺服務器裝了個nginx,發現壓測結果是并發1萬,那就是由于某些原因完全沒測出來瓶頸,需要從CPU、網絡等角度來排查哪一環出現了問題。很多時候我們可以使用壓測工具得到一個數值,這不是關鍵點,關鍵點在于這個值對不對,到底瓶頸在哪,是CPU還是網絡,是內存還是硬盤。

應用問題?

確認了網絡編程在epoll配置下普通服務器都可以達到10萬并發級別,現在來看看十萬并發的請求到了應用代碼執行層面會不會出現問題。如果拋去數據庫的查詢速度,單純在代碼執行和內存訪問,基本都是在納秒級別,下圖可以看到各硬件訪問的速度,單純執行1000行代碼還是處于微妙級別,訪問1000次內存,也只是100微秒即0.1毫秒,所以如果沒有高并發下的鎖競爭,僅是代碼執行也很少會出現高CPU的情況,除非是遞歸調用等特殊場景。

你開發的系統到底可以支撐多少并發訪問?

 

數據庫問題?

分析了網絡層瓶頸在單機十萬,應用層基本不會存在瓶頸,那么下一層就是數據庫查詢了,也就是說,當十萬并發請求進來的時候,基本上在網絡處理和程序執行上不會存在多少損耗,會直接將流量打到數據庫上,那么此時就需要了解數據庫的瓶頸點和極限值了。數據庫的知識點就比較多了,因為經過這么多年的發展,數據庫做了N多優化,而且存儲也是一個系統的重中之重,基本上所有的優化都是從數據庫開始的。可以先從數據庫的簡單原理了解下數據庫的性能到底怎么樣。

你開發的系統到底可以支撐多少并發訪問?

 

上圖以mysql為例列出了請求從網絡到執行再到持久化四個大過程的基本實現原理。第一步是connection pool來處理連接,認證等工作;第二步是解析sql、優化sql和查詢mysql庫級別緩存;第三步進入存儲引擎處理,mysql目前默認的存儲引擎是innodb;第四步就是磁盤訪問了。根據上述的網絡處理分析,第一步基本不會存在瓶頸。第二步都是代碼執行的內存訪問,也不太會成為瓶頸。第三步是引擎執行,innodb支持三種行鎖,但是查詢時mvcc不加鎖,并且當數據庫記錄數量不是特別大(百萬或千萬級)時,數據的定為都是基于內存中的page進行的,一般情況下也不會存在瓶頸,只有第四步的磁盤訪問會成為瓶頸。

為了保證數據穩定持久化,一定是要將數據存儲在磁盤上的,因為計算機一共就有兩類存儲,磁盤和內存,內存是基于電容的,原理就是通電后通過01信號來表示數據,而磁盤是通過磁極變化來記錄表示01數據,通電改變磁場寫入數據,斷電后不會發生改變。所以要想讓數據持久保留,必須用磁盤。當然磁盤有很多種,普通的機械硬盤,SSD硬盤,磁帶等等。因為內存是靠電來表示數據,所以足夠快,但是磁盤中,當磁頭掃過盤面,通過感應電流就可以識別出不同狀態,即讀取數據;增強磁頭的磁性,可以改變盤面記錄單元的狀態,實現寫入數據。此時帶著磁頭的機械臂擺動就會成為訪問瓶頸,由此可見,數據庫的第一大瓶頸就是磁盤的寫入和讀取。

根據上面列出的硬件訪問速度,磁盤訪問在10ms左右,因為機械臂的移動速度在7ms左右。如果每次數據庫查詢都需要10ms,那么此時我們就可以算算,數據庫CPU此時除了網絡處理和數據查找(定位磁盤位置)以外,剩余的執行時間都是等待磁盤IO,可以適當增加線程數并行執行網絡處理和數據查找,并行等待磁盤IO,即提高數據庫連接數,傳導到應用層面即為增加請求的連接數。此時通過增加應用連接數來提高并發能力,可以快速將數據庫的瓶頸突破到磁盤瓶頸,按照正常物理機的固態硬盤的速度,每秒可以處理116k次16KB數據的隨機讀,即11萬并發,當然此時數據庫基本處于滿負荷狀態,崩潰邊緣,正常支撐6萬以下并發處于合理范圍,如果將數據庫部署到虛擬機上或者低配機上,那么并發量會直線下滑,我們內部的一個虛擬機作為數據庫服務器的基準測試結果慘不忍睹,16k隨機讀的IOPS僅為600,即當有600查詢請求進來時,磁盤IO為100%了。以上數據均屬于內部基準測試得出的結果,實際生產環境或其他環境需要根據基準測試和全流程壓測的實際值為準。

由此可見,即使我們使用高性能數據庫服務器,安全運行的并發能力也只是6萬的QPS,TPS可能還要低很多。如果一個高并發的業務接口需要訪問5次數據庫,那么最高能支撐1.2萬的接口并發。如果前端業務功能每次點擊需要走三四個接口,如果這三四個接口有查詢有更新插入,也許連并發2000都撐不到。而這都是基于單次查詢只有一次磁盤IO的情況,如果單次查詢數據量大于1頁,或者查詢內容需要跨頁訪問,那就會產生多次IO,那性能就更低了,也許連四五百都撐不住,甚至于一個沒有太高并發的業務,但是查詢語句非常復雜,可能直接導致并發能力在幾十甚至個位數。而數據庫又因為ACID的原因,基本只能實現多讀無法實現多寫,分布式事務到現在也是難以突破的一個技術鴻溝,要實現需要付出巨大成本。

怎么優化

分析到此,就找到了幾千用戶訪問時無論怎么加應用服務器,最后還會雪崩的原因了,根兒就不在應用層面,加再多的服務器都沒有用。那么數據庫的問題僅僅靠優化sql解決么?sql從慢到快,只是一個表象,系統宕機的根本原因在于數據庫服務器達到了瓶頸,資源不足導致的,我們應該先分析什么問題導致了資源瓶頸,然后對癥下藥的分析。也許只需在某幾個點加個緩存,也許見個合理的索引,也許是變動下只查id不查內容避免回表,都可以一針見血的解決掉性能問題。現在特別流行使用的nosql可以支持分布式存儲,性能也可以隨著節點數增多而線性遞增,是不是換成分布式存儲就可以支撐高并發了呢?也不是,僅僅支撐幾萬并發,使用數據庫+緩存還是可以的,傳統數據庫的ACID、使用簡單、技術成熟穩定是我們必須要考慮的,也是我們首次開發一個項目的首選存儲。這也是為何很多大的金融機構還在使用IOE(IBM+ORACLE+EMC)的原因。

現在我們經過上述一系列分析,知道了系統真正的瓶頸點了,網絡上只有流量會成為瓶頸,應用上只有鎖、線程切換、遞歸調用和大數據量處理會成為運算和內存瓶頸,數據庫因為ACID是單點,所以此處的性能是最難擴展的。面對大流量,核心目標就是盡量讓高并發接口可以支持橫向擴展。最開始的性能優化基本都是圍繞著數據庫的瓶頸而進行的,一般有如下幾個階段:

第一階段:緩存熱數據

有些熱點數據如果需要多次查詢,而且查多改少,那么一般是可以放到redis緩存中的,利用內存訪問來替代磁盤訪問,可以明顯提升效率。同時,針對數據庫的回表問題,也可以在mysql中只查id,根據id在redis中查詢數據內容。這種緩存只適用于大多數人查詢的內容都相同的情況,緩存只需要存一份,更新緩存相對容易。

第二階段:擴散寫

有些查詢根據每個人會得到不同結果,那么每個人來訪問系統都需要查詢一次數據庫,并發量上來后很可能會把數據庫壓到瓶頸,所以需要預先算出每個人的查詢結果并緩存,這就是倒排索引,也就是擴散寫的思路。此時為了降低數據庫壓力提高查詢效率,需要為每個人冗余一份數據,更新會比較復雜,因為需要重新計算每個人的數據。但是查詢會非常快,而且未來也可以針對查詢做各種擴展。

第三階段:異步處理

有些業務場景是需要高并發插入更新的,此時數據庫也容易成為瓶頸。為了保證系統可以正常使用,只能延遲返回插入更新的結果,放入隊列,慢慢消費,也算是削峰的一種。

第四階段:讀寫分離

上面三個階段都處于單機狀態,但是熱點數據的緩存有很多場景還是先查庫后緩存,也容易把數據庫壓崩,所以此時需要橫向擴展,通過讀寫分離,擴展讀的mysql服務器,但此時就會存在讀寫服務器的數據同步延時問題需要考慮和解決。

第五階段:分庫分表

第四階段的讀寫分離,但是一寫多讀,當寫的單機成為瓶頸時,就只能橫向或者眾向分表了,我們一般說得分庫分表都是眾向分表,即選擇一個合理的分表策略,一般是根據高并發的查詢條件設置,因為要防止跨表查詢,同時還得考慮分布式事務的問題。一個事務里涉及到的表盡量在一個庫中。

第六階段:NoSQL

有些復雜查詢和聚合查詢,真的不適合使用mysql這種關系型數據庫來支撐,就需要使用es這類倒排索引的存儲引擎或者一些列式存儲的mapreduce的來解決,此時就需要考慮使用NoSQL來冗余數據存儲,以解決這類特殊場景的業務查詢。

總結

在性能優化過程中,加機器是最容易實現的。所以針對應用層的CPU算力問題是最容易解決的,網絡層的帶寬只要預先算好,客戶也能欣然接受。而針對存儲層的各種優化都是極為復雜的,單機的維護比多機簡單的多,單寫比多寫簡單的多,一個存儲的維護也要比多個存儲的維護簡單的多,每一個階段的優化都意味著更高的維護成本,所以優化是根據業務需求被動提出的而不是過度設計出來的。說白了我們都想舒舒服服地坐在這喝茶看著系統穩定運行,不要自己給自己加碼提高維護成本。

提到并發大家就會想到秒殺,就會想到紅包、春節活動、雙十一、12306等等。他們確實是極為典型的高并發大流量,他們的接口qps甚至可以達到幾十萬上百萬,他們的存儲可能需要支撐幾千萬上億的qps。他們在解決這個問題上使用了各種各樣高大上的技術,限流熔斷,分布式存儲,隊列,緩存,調用鏈跟蹤,全鏈路監控等等等等。

對于軟件開發人員來說,性能優化的根本就是在協調CPU、內存、磁盤和網絡等硬件設備的性能瓶頸,把單機性能優化到極致,然后優化為可以支持多機擴展。不能隨心所欲地使用一些流行技術堆積出一個系統,解鈴還須系鈴人,找到性能瓶頸的本質才是最關鍵的。

分享到:
標簽:并發 訪問
用戶無頭像

網友整理

注冊時間:

網站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網站吧!
最新入駐小程序

數獨大挑戰2018-06-03

數獨一種數學游戲,玩家需要根據9

答題星2018-06-03

您可以通過答題星輕松地創建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學四六

運動步數有氧達人2018-06-03

記錄運動步數,積累氧氣值。還可偷

每日養生app2018-06-03

每日養生,天天健康

體育訓練成績評定2018-06-03

通用課目體育訓練成績評定