面試被問到在百萬級請求的情況下,伺服器如何保證可用性,我一順嘴就說了訪問量大了會崩潰,面試官就說為什麼會崩潰呢,處理慢點不就行了。我一時語塞,訪問量大了為啥會伺服器會崩潰呢?還是壓根就是反應慢而已?還是因為死鎖或者太熱了硬體受不了?
作為一個穩定的系統是不會崩潰的,這輩子都不會,要不怎麼能叫穩定呢。
那為什麼實踐中我們確實會遇到訪問量過大而伺服器趴窩呢?因為實際情況比較複雜。
第一個是內存的問題。
服務每個請求都是要吃內存的,請求越多內存用量越大,但內存畢竟是有限的,可能是物理內存確實用光了,也可能是OS或者中間層的限制。但不管怎樣,一旦發生後果嚴重。
daemon大概率會被os殺死,或者內部出現了問題導致完全失去響應。伺服器就趴窩了。
第二個是設計上的局限。
有些東西設計上就不是為大負載高並發來做的。比如早年的mysql/myisam。速度快不快?飛快。但一定資料庫大到一定程度,性能就會直線下降。雖然在這個階段還只是反應慢,伺服器沒有趴窩,但這種慢並非是線性增長的,而是近似於指數那這樣增長方式。比如100個請求的時候每個請求1秒,200個請求的時候每個1.5秒,300個請求的時候每個5秒,到了1000個的時候就每個一個小時了。
就像高速公路,車少的時候大家都能跑到法定速度。車一旦增多就會堵車。更嚴重的是即使堵車之後即使進入的車流沒有繼續增加,因為出高速的車流越來越慢,堵車也會越來越嚴重,最後堵到所有人都堵死。
到這個程度就可以認為是事實上的趴窩了,因為幾乎所有人的請求都會因為超時而掛掉。
第三個是設計上的缺陷
其實說第二個問題的時候已經提到這個問題了,雖然擁堵本身是等一等就能消解,但一旦系統負荷增大到遠超預期,那就不一定會發生什麼事。比如大量的擁堵導致緩衝區爆了,導致了一連串連鎖反應,比如前面提過的內存也爆了,進而引發一些不可逆的後果,最後導致伺服器宕機。
現實生活中,情況可能會更複雜,宕機可能是多重作用的結果。
比如一個系統有4個節點做負載分散,哪怕4個死了3個也不會完全宕機。
結果一波高峰導致其中兩個節點暫時負荷變高,反映變慢。然後導致接下來短時間所有的流量都被導入剩下的兩個節點,把剩下兩個節點搞到完全不動了。
這個時候雖然前兩個反應過來了,但面對海量的求情也很快就趴窩了。畢竟是是需要四個人才能搞定的活,現在兩個兄弟趴了,剩下兩個孤軍奮戰趴也是遲早的事。
這樣伺服器就全趴了。
面試被問到在百萬級請求的情況下,伺服器如何保證可用性
這很難說,隨便講講我能給你講一整天。
如果要一句話回答這個問題的話:那就是具體看是什麼樣的系統。
完全靜態的還是請求特別複雜特別重的那種。前者倒是簡單,後者你要每秒出1百萬張火車票12306也一樣做不到。
你的應用有加防禦嗎,,瀏覽量大不大,並發數多嗎,還有你的伺服器配置咯這些都是問題,我也是做伺服器有問題也可以交流交流,我是做香港伺服器的。
訪問量大了,理論上不會崩潰,只是理論上。
訪問量大了,你的內存滿了、TCP連接到頂了(比如time_wait太多,無法接受新連接)、CPU已經忙不過來了——這一切的理論後果是處理速度慢了,或者直接拒絕新的服務請求。
但如果你的伺服器代碼有缺陷,比如內存無法分配,拋出異常,而你沒有處理這異常(大家都知道,一些情況下處理各種錯誤的代碼甚至可能會佔你代碼量的一半,非常繁瑣),會造成進程的退出——崩潰;或者無法建立新的TCP連接,你又沒有處理這種異常——崩潰;磁碟滿了——崩潰……程序一大這種細小的問題會多如牛毛。甚至你依賴的基礎軟體,如JVM,內存不足也可能導致崩潰。雖然有交換分區的存在,但也只是延遲了內存分配失敗的時間,但此時性能已經急劇下降,與崩潰無異——完全沒響應了。
所以,始於Erlang的「就讓它崩潰」思路,在這是有用的。它不會因為一些事情導致你的整個程序退出,而是某個「進程」(erlang的「進程」你可以粗略理解為一個線程)退出,並讓父「進程」捕獲到這個錯誤。等這些破事過去,你的伺服器就又像以前一樣歡快了。
那麼,如何防止這些崩潰?一方面你的程序要健壯,不會因為這些錯誤而導致整個程序的退出,將錯誤限制在工作線程或子進程里。另一方面,你的系統要做限流。
宕機是個計算機術語。多指些網站、遊戲、網路應用等伺服器種區別於正常運行的狀態,也叫「Down機」、「當機」或「死機」。宕機狀態不僅僅是指伺服器「掛掉了」、「死機了」狀態,也包括伺服器假死、停用、關閉等些原因而導致出現的不能夠正常運行的狀態。