1.概述
最近看了一篇關於熱key導致redis服務集群掛掉的文章, 非常的精彩導致我在想當流量非常大時為什么redis服務會掛掉,於是我就找了大量的資料研究服務為什么會掛掉及其原理,服務器為什么會宕機等等就有了如下內容。
其實服務崩潰總結起來無非就兩種,一種是資源枯竭導致的服務崩潰,另一種就是超時引起的服務崩潰。
2.資源枯竭導致
先說第一種資源枯竭導致的服務崩潰,顧名思義就是因為服務器的資源或者分配的資源不能滿足服務運行的需要從而引發服務崩潰。比較常見有內存溢出,磁盤滿載,帶寬不足等三種。
寫java的程序員遇到最多的估計就是內存溢出了,比如操作系統給jvm分配了2G的物理內存供程序運行使用,可能有個程序頭鐵在一段代碼中創建了循環引用的對象或者大量未能及時回收的對象,在請求量大時gc不能及時回收垃圾對象導致堆內存一直在增大超過了操作系統所分配的2G內存,此時就會觸發操作系統的kill -9信號把程序殺死這樣用戶再請求服務時就無響應了。
電商大促期間前有很多准備工作,其中有一項就是去運營商那里購買寬帶,這是因為在大促期間有大量用戶訪問,如果機器帶寬不足會導致服務崩潰,進而導致非常大損失。我們以一台機器80M的寬帶為例,經過計算能承受的最大下載速度就是10M/s, 拿單個用戶的一個請求數據大小為10k為例,在1s內有1024個用戶請求時需要80M的寬帶機器剛好能滿足要求,如果是1s內有2000用戶請求時需要160M的流量那么處理完這2000個用戶的請求需要2s,如果持續30s都有2000個用戶來請求服務,那么就需要4800M的流量處理完需要600多s那么就會大量請求出現等待進而引發超時導致服務崩潰。
3.超時導致
第二種超時引起的服務崩潰,就是大量用戶請求服務時因為大面積連接超時導致服務崩潰,和寬帶不足的例子很像,我們以單台機器服務啟動單進程為例,在一個進程中我們通常會通過線程池去處理請求,我們假設線程池中一共有1000個請求來處理請求且每個請求的響應時間為100ms,當1s鍾有10000個請求發來時我們可以很快的處理並返回,當1s內有20000個請求發來時服務器要處理就需要2s鍾的時間了,那么在一段持續時間20000請求來時就會積壓大量的請求不能被處理導致超時,然后后面過來的請求肯定超時,這樣服務就崩潰了。
4.總結
在真實的生產環境,崩潰的原因可能會非常復雜且是多種因素互相作用的結果,但了解了服務奔潰的本質后就能很快找到對應的解決方案,如萬能的增加機器,優化代碼邏輯,加入緩存等等。完畢!