從性能角度看系統架構

系統架構

  漏斗原理:請求在網絡傳輸過程當中,越日後,請求慢慢的會減小,因此說到數據庫服務器的請求量會比在Web服務器的少css

 

1、基本架構

一個系統的網絡拓撲圖:咱們常說的服務器是軟硬件結合的一個概念,服務器服務器,只有硬件沒軟件其實不能稱之爲一個完整的服務器java

 

 

 

一個問題:什麼是 to B ,什麼是  to C?nginx

  有些人可能會說,B就是browser,C就是Client。可是實際上真的是如此麼???web

  其實C就是面向用戶,好比說淘寶、QQ、餓了麼、美團、大衆點評等對咱們我的來說,就是個 to C 的產品,客戶端;可是,面向商家的就是 to B(bussiness) 端 ,好比淘寶有商家平臺,B不是說一個瀏覽器,好比說QQ,是個客戶端。redis

  

 

  基本的系統架構就是上圖,可是當咱們的請求加多,日活增多,請求會發到哪裏???其實第一步是打在了網絡上!因此網絡加速發展了,可是最終的請求量所有打到了服務器上,早期就引入了一個名詞,叫——負載均衡,早期通常用apache作負載均衡,可是單機只能支持1W的併發,Nginx官方的介紹是支持20W的併發sql

2、負載均衡

  分爲兩種:硬負載,軟負載。那麼什麼叫硬負載,什麼叫軟負載呢?(左圖硬負載、右圖軟負載)mongodb

 

 

  硬負載(F5):就是企業單位,事業單位通常用到的,叫 F5 。直接在服務器和外部網絡間安裝負載均衡設備,這種設備咱們一般稱之爲負載均衡器。因爲專門的設備完成專門的任務,獨立於操做系統,總體性能獲得大量提升,加上多樣化的負載均衡策略,智能化的流量管理,可達到最佳的負載均衡需求。 通常而言,硬件負載均衡在功能、性能上優於軟件方式,不過成本昂貴,好比最多見的就是F5負載均衡器。數據庫

  優勢:可以直接經過智能交換機實現,處理能力更強,並且與系統無關,負載性能強更適用於一大堆設備、大訪問量、簡單應用apache

  缺點:成本高,除設備價格高昂,並且配置冗餘.很難想象後面服務器作一個集羣,但最關鍵的負載均衡設備倒是單點配置;沒法有效掌握服務器及應用狀態.瀏覽器

  硬件負載均衡,通常都無論實際系統與應用的狀態,而只是從網絡層來判斷,因此有時候系統處理能力已經不行了,但網絡可能還來 得及反應(這種狀況很是典型,好比應用服務器後面內存已經佔用不少,但尚未完全不行,若是網絡傳輸量不大就未必在網絡層能反映出來)

  軟負載Nginx、lvs、proxy):把請求分發到軟件上。

  優勢:基於系統與應用的負載均衡,可以更好地根據系統與應用的情況來分配負載。這對於複雜應用是很重要的,性價比高,實際上若是幾臺服務器,用F5之類的硬件產品顯得有些浪費,而用軟件就要合算得多,由於服務器同時還能夠跑應用作集羣等。

  缺點:負載能力受服務器自己性能的影響,性能越好,負載能力越大。

  綜述:對咱們管理系統應用環境來講,因爲負載均衡器自己不須要對數據進行處理,性能瓶頸更多的是在於後臺服務器,一般採用軟負載均衡器已很是夠用且其商業友好的軟件源碼受權使得咱們能夠很是靈活的設計,無逢的和咱們管理系統平臺相結合。

  Nginx的圖能夠這樣理解:這三個服務器,所放置的代碼都是一致的,鏈接的數據庫,也是一致的,不然個人數據就不知道跑到哪裏去了。。。Nginx至關因而處理請求的流向,至關於秩序的維護者

  

 

  這樣,能夠處理20W的用戶併發,可是若是個人請求再很大呢???那就作 Nginx 集羣,Nginx 下面再套 Nginx 去分發請求,可是咱們通常小公司用不到

 

3、數據庫

那麼,在 Web 服務器能處理這些請求的前提下,這些請求所有發送到一個數據庫服務器,數據庫訪問量大一個服務器能抗住麼???用戶量大加機器,數據庫要怎麼弄?

  結論:數據庫也作集羣組

  方式:

  一、數據庫備份

  早期都是用數據庫的備份,就是我有兩個數據庫服務器 A 和 B ,掛了 A 我還有 B 在撐着,定時把數據庫備份到其餘數據庫。這樣數據庫是有丟數據的現象的,通常晚上備份,可是丟數據總比沒有的強

  二、數據庫讀寫分離

  如今都是對數據庫進行讀寫分離。主庫負責寫(insert、delete、update),從庫負責讀。通常讀操做更多,因此讀操做的機器通常會更多。這樣數據庫的壓力會減輕

 

  

問題:寫操做在 A 服務器,查詢的是 B 服務器。怎麼在 A、B 這幾個服務器怎麼數據同步???怎麼下降同步的延遲?
  方式: 數據庫主從同步
  用一個二進制文件傳輸,主庫有了數據以後,備份到二進制文件內,全部的從庫從二進制文件內讀;
  用戶操做主庫,往二進制文件內追加寫(往末尾寫,不復寫不改寫),全部的從庫對這個二進制文件是追加讀。用這種方式 ,進行同步,可是這樣必定是有延遲。
  全部有時候咱們刪了一個東西,加一條數據,或者修改什麼東西,可是數據沒有及時更新,界面上咱們刷一下也沒更新。可是過一下子,再刷新,就顯示正常了。這是數據讀寫分離,未及時同步形成的。
  主從讀寫分離 解決數據庫請求量大問題;但解決不了, 數據量大問題,好比說我數據庫搞100臺,也不能解決單表數據量大的問題


數據量大的問題是個啥子問題呢?好比說我一個單表A內,有100W條數據,去裏面找1條數據;一樣的一個表B,只有1W條數據,相比較起來在B表內找這條數據和在A表內查找,確定是在B表內檢索起來更快。那麼這個問題要怎麼解決呢?
  涉及到數據庫索引,打比方說,1W條數據,找一條數據,怎麼找?一條一條去找從頭找到尾,去核對……機器的處理速度很快,1W條數據可能比較快;可是若是100W條數據,從頭找到尾那就得卡死了。。。那麼什麼是索引呢?好比我說從中間開始找,從中間往前面你開始找,再從中間日後面找。索引就是劃定一個範圍去找,簡單理解。
  那咱們舉個例子,新浪,假設新浪微博,日活1000W,天天往數據庫內寫一條數據,那麼一天就是1000W條數據,那麼1個月呢?就是3個億,若是存在一個數據庫,一個表內,拿去查詢就得宕機了(查詢的時候在內存裏面查,內存滿了就宕機了,由於查詢不僅是一個用戶在查)。
  13年開始,解決數據量大的問題:數據庫拆庫分表。把1套數據庫,拆成圖內的4套庫,每一個庫的數據量是以前的1/4,也能夠拆成更多份;每一個表也能夠拆表,好比拆成1/4,那麼單表量就變成了1/16。拆庫分表在zhuangbility課程學習

 

4、微服務

  咱們用淘寶舉例子:簡單說一個業務:好比說帳戶系統,用戶系統。用戶系統不只僅是帳戶系統,是個大核心,對接多少東西?支付寶、天貓、阿里雲、阿里媽媽、餓了麼、web系統等……因此不只僅是一張表能把它存完,那些積分,收貨地址,收藏等。除了用戶系統,還有些商品模塊,商品的展現模塊有不少東西:庫存,分類,價格,銷量等等。檢索模塊,搜索不僅是搜索,裏面有不少內容在裏面,廣告、銷量排名等等。還有不少小業務:訂單,購物車,支付,消息等。這些小的業務就叫作微服務。

  若是這些服務在一個系統內實現,一個服務出了問題,那麼整個系統都得崩潰。天貓雙11上次的事件,改不了收件地址;退款退不了。這些個別功能使用很差使,並沒影響到其餘公司功能的使用,登陸==>搜索==>下單==>付款都沒問題。把大的業務,拆分紅一個一個的服務,減小系統的耦合度。下降由單個功能的故障引發整個系統不可用的可能性。

  用戶的集羣,商品功能的集羣,訂單的集羣,搜索的集羣,整個構成個大的淘寶/天貓
  用戶內集羣,商品內集羣,訂單內集羣,搜索的集羣……組成一個大的應用集羣
  
  那麼這些模塊對系統提供的都是接口,好比說搜索到商品,兩個服務之間確定有接口調用,那麼用什麼取保證接口調用訪問呢?爲了方便接口與接口間調用,接口間調用使用Zookeeper進行相互調用,這裏咱們加入一個Zookper的集羣。
  Zookeeper內有兩個模塊:生產者,消費者。生產者是什麼意思呢?
  就是說搜索服務內有那些接口,訂單服務呢有哪些接口,所有註冊到Zookeeper,別的系統纔有可能訪問到這個接口;消費者:誰能訪問哪個接口。這樣保證了整個系統接口的安全性以及可靠性。
  有哪些接口在生產者內,誰能訪問在消費者內。Zookeeper應該在Nginx和應用服務器之間。nginx-》zookeeper-》應用集羣。。。zookeeper能夠理解爲將請求分給哪一個接口
  

5、緩存

  咱們以前講爲何要參數化,是爲了不數據庫查詢緩存。關係型數據庫自己有緩存,指的是咱們查詢出一條數據,會生成一條查詢計劃,存在數據庫的緩存內,下次咱們查詢語句假設如出一轍,就會命中這個緩存,就能夠很快地返回出要的查詢數據。
  可是咱們這裏要將的數據庫緩存跟上面提到的不是一個東西。有不少東西在中間常常被訪問到。關係型數據庫是存放在磁盤的,不是在內存的,存放在內存重啓會失效。某些數據在訪問過程當中用戶常用到,就會被放到內存裏面,想要更快就能夠用鏈表形式存,那就更快。這裏咱們在數據庫服務器和應用服務器之間會設置一個緩存系統,是存在應用服務器集羣以及數據庫服務器集羣之間的,通常是 redis,redis是非關係型數據庫,用鏈表,key-value形式存在,查詢起來超級快。咱們這裏也考慮作個集羣。這樣的話,用戶的請求過來,直接在redis內查,查不到再去數據庫內查。
  那麼引入這種非關係型數據庫的前提是什麼?
  是redis內存在的數據,命中率要很是高。若是命中率不高,還要去關係型數據庫內查,還不如我直接去查關係型數據庫。高命中表明有不多次直接取查詢關係型數據庫,通常來說命中率要高達99%以上纔算合格。可是redis全部的數據是在內存裏面的,那麼每次啓動,數據會被清空,要關係型數據庫從裏面推數據。
  那麼假設我沒有命中,從關係型數據庫內返回的數據是直接給應服務器麼?並不會,它會先經過redis同步一份,再給應用服務器,這樣redis下次的命中率就高了。
  redis除了要有高命中率,也要考慮數據的失效,內存畢竟是有限的,因此先保存近redis的數據就先出內存。在這個前提下,redis會對數據進行按期檢查,假設一個數據在多長時間內沒有被訪問到,或者說訪問的次數沒達到某個標準,那麼這個數據也會被踢出redis,這叫清除非活躍數據。
  

 

 6、消息系統

  Kafka,消息中心。什麼叫消息中心呢?

  好比說在淘寶上支付商品完成,對系統來講要作哪幾件事?

  生成訂單,訂單號;通知商家,庫存-1;通知商家發貨等等,這些全部看不見的業務邏輯,得有一個統一的人去告訴別人,若是消息只發一條,那麼假設通知商家庫存減一,那麼可能就不能通知發貨。
  這個kafka就是生成消息的,是一個統一的通知渠道。其餘人來拿消息是有順序的。這樣就能保證消息的一致性、完整性、順序性。順序性也是很重要的,消息是堆積在kafuka內的,好比說我登陸獲取驗證碼A,手機沒獲取到,沒收到我再發一次驗證碼B,結果後面的驗證碼B先發到手機上。支付信息,我先支付,生成的訂單確實後一個支付者的訂單,這就亂套了,都是由kafuka管理的。有不少相似的管理系統,不必定是kafuka。
 

 7、圖片服務器&文件服務器

  圖片是存在哪?放在數據庫?若是在數據庫要從數據庫讀地址,再去DNS地址內找圖片再顯示?每一個公司都有圖片服務器,專門是負責處理圖片壓縮,拉伸放大,存儲等。

 

  文件服務器DFS(存入數據,報表之類的)好比說,淘寶的銷量表,不多是實時生成的,那樣查詢太慢了,是存儲在服務期內的。好比說小米的雙11銷量表,客戶從哪兒買的?分佈的城市,買的型號,價格等等;其餘廠商也是如此。若是要都是去數據庫查詢,那不就完蛋了。那麼確定是先生成,再展現,數據文件存儲在文件服務期內。文件服務器常見的是DFS
  

   

  MongoDB:存大數據,並且不是常見的數據,好比你朋友圈的數據。存在磁盤,存歷史數據用,一個頁面/一個接口可能會查多個或多種數據庫
  通常什麼樣的數據存儲在 mongodb? etl標籤、用戶開戶的註冊抓取的通信錄等隱私數據、地址等
 

8、CDN節點加速

  國內最出名的cdn兩家是哪兩家?藍汛 網宿

  也是一種緩存,緩存的是啥?通常來說是緩存圖片,怎麼緩存?

  把那些圖片存在就近的那個地域的服務器上,不一樣的用戶區請求服務器,就從就近的服務器取,而不是從最大的那個後臺的服務器取;好比說廣州的請求,就在南方這邊的服務器上取,而不是從北京的終端後臺。cdn存的是靜態的資源,某些一段時間不變的東西,js,css那些;能夠看下f12,域名不是本身的基本是從cdn節點取

  

  

  好比說百度的首頁:有些js,圖片,這個域名都不是baidu,因此是存在cdn節點上的

  

 

  請求經過DNS域名解析,解析成一個ip:port這個ip:port是Nginx的域名和端口,不是的話那就直接訪問到後面的應用服務器了。Nginx是負載均衡,請求來了,分發給後面的服務器,Nginx幹了活可是不處理請求的業務邏輯,只是分配任務。請求分發到註冊中心(配後臺有哪些接口的,這些接口誰能調用它?),而後看接口是誰配的,給接口的提供者,而後再處理業務邏輯註冊,而後去數據庫裏面查有沒有這個用戶,給出相應提示。這裏咱們沒用到redis,由於不是重複的,註冊一次就好了。那麼什麼會用到redis?天貓首頁的商品,那些首頁的商品金額等。也就是用戶會頻繁點擊,用戶訪問量大的東西。哪裏用到kafuka呢?日過作了某件事,對其餘的服務有通知,有影響,那麼就須要kafuka,好比典型的下單付款等。這意思是,不是每一個業務邏輯都得走完服務器全部東西。

   整個架構:

   以上算是一個比較成熟的系統,應用服務期內並無徹底寫完,不一樣的服務內部也有不一樣的內部架構,要深刻理解而且記住,對於不理解的內容,中間件等的原理還得本身深刻去理解。

系統分析

1、響應時間

  響應時間是哪些的和?N1+N2+N3+N4+A1+A2  

  若是說響應時間過長,有多是 N一、N二、N三、N4 的也多是 A一、A2 的問題,也有多是Client的 A3 太慢,試想若是 A3 發1W個請求,有可能會阻塞,可是咱們作性能測試會默認忽略掉這塊東西

  服務端的接口處理的時間實際上是分爲兩部分的,一是接口自己響應的時間,二是去數據庫查數據的時間之和:=A1+A2+N2+N3

  

  繼續拆分時間:
  請求發到webserver以前,要有空閒線程才能進行處理,因此真正進行執行以前,會有等待空閒線程的等待時間,有了空閒進程以後,才能進去讀代碼

  讀代碼以後,讀到請求數據庫的語句時,這個線程就會掛起,須要找到空閒的程序與數據庫的鏈接池,才能把請求發到數據庫內,容器裏面通常配20-30個,120個最大

  數據庫自己也有鏈接池,通常1800(黃線)

 

   

  假設空閒線程,拿到請求,就必定會立刻處理麼?不必定,要看服務器的CPU,內存,磁盤(硬件),假設線程空閒,可是CPU滿了,是不會當即去讀代碼的,得有空閒的片。CPU在內存裏面幹活,若是內存滿了,CPU也沒辦法幹活;磁盤滿了,也幹不了活DB Server也是以來與硬件資源,資源充足才能繼續,不足也沒辦法處理
 
 
  過程詳解:上圖,將響應時間拆解,請求到了web容器,經過tomcat,這個代碼來了不必定立刻執行,要有空閒線程,而後開始讀代碼,讀到sql語句,而後就去進行鏈接數據庫,數據庫的鏈接池(藍色)有可能會排隊。過去了以後,線程會被掛起。可是過去了以後還要進入數據庫自己的鏈接池,要有空閒的數據庫鏈接池(黃線),可是數據庫鏈接池通常很大,因此用虛線,時間能夠忽略。取完了sql的值,再返回到tomcat內,那個掛起的線程再進行執行。這裏也要進行鏈接池鏈接,可也能會排隊。web服務器處理完後再返回給用戶Client端。
  以上的全部的環境都沒考慮硬件環境,cpu,內存,磁盤也會制約軟件的運行。
 
 
  還有個JVM-java虛擬機,在tomcat裏面
  tomcat是java跨平臺的,new是要佔內存的,java裏面的new都是將類去實例化,也就是對象,這些對象所有佔了內存,佔滿了再new是new不動的,後面的代碼就讀不動了。內存就會崩潰。
  GC回收就是將沒用的對象,回收掉,也就是把內存回收
 
  結合到上邊,內存沒了,就得垃圾回收,也就是GC
  

 

響應時間太慢,可能的緣由在哪???  

一、自身的Client端產生請求阻塞(CPU排隊/帶寬滿了)

二、網絡傳輸時間過長/網絡帶寬是否有瓶頸(帶寬能上傳多少,要除以8,好比說100Mbps,一秒只能上傳100/8Mb)

三、web應用服務器裏面的問題分如下幾點:

  • 服務器的CPU/內存/磁盤是否是符合條件;  CPU滿了,內存滿了,磁盤滿了不夠資源後面的就不用看了,應爲軟件運行的基本環境都不具有,而後往下走
  • web容器tomcat沒有空閒線程/進程; 有空閒線程才能處理,若是都繁忙,容器內沒有線程處理,都滿了,在容器池那裏就得排隊,沒問題再往下走
  • 代碼的業務邏輯實現好壞; 進入到web服務期內,纔開始讀代碼,讀到代碼的業務邏輯實現太爛了也可能會影響運行的時間
  • 若是請求須要請求數據庫,須要看應用程序跟數據庫服務器沒有空閒的鏈接池,是否要進行排隊; 有數據庫交互要看web和db之間有沒有空閒的鏈接池通道,沒有也得排隊
  • 應用服務器與數據庫服務器鏈接,網絡是否通暢;  若是這倆不在一個服務器上,也是用網絡鏈接

四、DB服務器

  • 數據庫自己的鏈接池夠不夠
  • 這裏面的CPU、內存、磁盤分析
  • 數據庫的執行效率過低

五、web服務器容器內沒有進行垃圾回收(GC),沒有足夠的內存去執行代碼

六、返回的網絡以及帶寬

怎麼分析問題所在?

  1. 拿到系統結構圖,分析出架構的數據流向
  2. 根據系統架構畫出業務請求的數據流圖
  3. 根據數據流畫出流程節點中可能存在的問題節點以及出現問題的可能性:易出現問題的9點
  4. 經過依次監控數據,排查以上問題是否存在
  5. 若是排查了節點,改了還有問題,重複第4步
  6. 能夠經過經驗作一些小的手段幫助本身快速排查問題

  這裏單單拎出第6點分析

  有可能存在問題的點(紫色):負載機性能瓶頸,網絡帶寬,硬件資源,線程池/進程池,數據庫鏈接池,代碼邏輯,SQL執行效率,數據庫自己鏈接池, JVM---9點

  排查,從咱們能拿到數據的地方去先排查,由簡至難。

  關於代碼,讓開發加日誌。業務裏面能夠加日誌,幫助定位業務問題。性能裏面加日誌,幫咱們定位性能消耗在哪一個時間。那怎麼加呢?在web服務器上打印出時間戳  

  性能測試加日誌:定位哪一段時間比較長(時間日誌)
  比方說登陸的代碼:
  t1,t2爲時間戳,用時爲(t2-t1),整個接口的時間
  

  t4-t3是sql的執行時間

  

  

  

例如:
一、測出的登陸接口響應時間=10s,接口時間爲8s,sql時間爲7s
  那麼,核心的問題在於==>sql慢了(sql查詢時間+網絡+數據庫鏈接池)==》定位到了問題
二、接口=8s,sql=1s
  核心問題在於代碼業務邏輯問題/GC/鏈接池
三、接口=1s,sql=0.7s
  那麼是哪裏的問題?反正跟代碼沒問題,那麼是代碼以前的問題:負載機/網絡/容器鏈接池
 
log4j,記錄全部的數據庫操做日誌

 

有個更復雜的問題:
A調用B,B調用C怎麼測?
隔離法。
先測C;再測B,把C接口mock掉;那怎麼把C mock 掉?其實至關於B調用C的返回結果,把C接口的返回結果固定就能夠,這個能夠依賴於 MockServer工具,某個ip:port返回固定值/變化值;
A測試就把B Mock 掉,再測A的性能

 

結論:

負載均衡解決的是用戶請求流量大的問題;
數據庫讀寫分離解決的是數據庫請求量大的問題;
拆庫分表解決數據庫數據量大的問題;
相關文章
相關標籤/搜索