實戰 3天讓Web應用承載拓展1000倍

2021-09-06 05:01:53 字數 3697 閱讀 1970

環境:由ngnix,ruby on rails和mysql構成。注:這個web應用只是乙個旅行指南。

當使用者進入我們的**時,會通過tripit導航或者選定目標,再依據詳細資訊進行下面的操作。他們可以根據自己的喜好選擇不同類別(比如餐廳的菜式風格、評級指標等吸引點進行篩選)。或者也可以通過瀏覽器檢視生活指南做一些預訂。

儘管我們的**還處於beta版中,但是每天仍有幾百萬的訪問量。周一下午2點我們接到一則通知,**將在周四早上9:30(東部時間)乙個非常受歡迎的電視節目上出現,根據以往的經驗,我們料想這一天將會有20,000至150,000的需求訪量,峰值可達到10,000,而伺服器將承受100x至1,000x的需求請求數。

我們估計將會有10,000人同時訪問,也就意味著要建立每分鐘約40,000頁的請求數。

我們所具備的:

周一,我們在幾台電腦上安裝了jmeter(jmeter是apache組織的開放源**專案,它是功能和效能測試的工具

經過幾次試驗,我們發現當執行緒超過125個時,就無法在單一的jmeter例項上執行了。因此,如果我們要模擬真正的高負荷,這需要將jmeter同時執行在幾台電腦上。同時,我們還要確定本地網路不在飽和狀態,登陸vpn進入另乙個網路,由乙個客戶端切換到另乙個遠端客戶端。

我們很快了解到:

經過這些改變後,讓應用服務端規模擴大至16臺,但這受到資料庫的約束。資料庫很快達到100%負荷,儘管我們擴大了aws(amazon web services)資料庫的規模(超大的cpu和記憶體)但是仍然受約束。於是我們採用jmeter執行測試,設定平均響應時間為30秒,我們清楚的知道,如果這個問題無法解決,那我們便失敗了。這一天是星期二。

我說過「我們會失敗」,此前,我們採取了很多解決措施,團隊中的大部分成員認為這樣做未免太冒險了,會釀成大錯。因為根據以往100%正確經驗:在高負荷載入情況下會導致頁面無法顯示,這是100%有風險的。經過幾個小時深思熟慮之後,我們深信,必須要解決可擴充套件性問題。

我們簡要的**了幾個不同的且動作較大的方法,但這些風險很大:

因此,我們決定採取行動:

我們將一些易於識別的db需求執行在每個頁面上,這樣能夠滿足每次載入相同的資料。我們在儲存器中重新編寫**進行快取,所以,當伺服器重新啟動載入時,不會重複。

週三早上,我們開始靈活運用jmeter做壓力測試。為了防止由於來自於客戶端成千上萬的併發執行緒訪問使伺服器不堪重負,並保證監控到的(併發)請求次數在可控範圍之內。我們讓執行緒緩慢增加,保持著伺服器的穩定性,統計每一秒總吞吐數,同時核查cpu的平均負載。接著,我們繼續增加執行緒,核查(的步驟)。通過截圖,我們記錄了相關資料並讓每個人都能看到。我們的目標是不僅要承受住高峰期的rpm,同時不額外增加響應時間。

隨著時間的推移,我們通過改變**來快取資料庫的一些需求。同時,在周四之前,我們不斷更新最新需求來滿足我們的需要。這就是我們的部署過程。

我們所具備的環境:本地機器,開發,示例,分期,生產(local machines, dev, demo, staging, production)。通常情況下,在進入開發之前,會有乙個指令碼測試執行(大約40分鐘)。

指令碼部署大概需要15—30分鐘(80%的人把時間花在git clone上)我們需要重複這一過程,與生產逐漸靠近。

而生產最主要的乙個環境正在上演。如果我們將**優化,我們需要測試效能,這將花費幾個小時部署過程才能有所變化。

相反,我們可以臨時進入伺服器,手動套用變更(利用ssh進入伺服器,vi編輯檔案,重新啟動mongrel),但是我們要在4臺伺服器上重複這一過程,取消auto-scale伺服器,重建auto-scale ami,然後在連線auto-scale伺服器。即使你採取捷徑過程,仍需要20—30分鐘。

我們重複了好幾次,很小心的儲存資料,這時我們發現,我們正進入乙個錯誤的方向。因為每秒(900rpm)能維持15個請求,而數量也隨之一天天的變少。聰明的資料庫管理員看到這裡也許會偷笑,知道是什麼原因造成的。但是我們沒有專門的dba團隊,我的資料庫方面技能也有點生疏。

於是我們安裝了new relic,自從幾年前我利用new relic來開發facebook應用程式後,便愛上了它。這是乙個針對rails和web應用環境的效能監控解決方案。我只把它當做一款開發工具,因為它可以讓你看到應用程式所花費的時間。它同樣適用於生產監控,比如我們需要為職業規化付款,它還可以確定頁面請求執行慢的原因並且便於資料庫查詢並且對已執行的資料可提供很多細節。

因此,我們迫切希望得到更多的資料以便公升級至new relic pro計畫中。我們有一些豐富的資料(資料庫請求緩慢原因和應用所要花費的時間)。

乙個資料庫查詢時間花費了整個資料庫的95%。當我看到這一點時,我知道我們的表現變得很糟糕,這時我意識到在查詢上還有個未索引的領域。也許是因為jmeter測試在資料庫列表中建立了新條目,或許是因為已經執行了幾個小時的緣故,在資料庫中有成千上萬行,因此我們需要對整個條目進行掃瞄。

於是我檢查了資料庫中schema.rb檔案,發現有人錯誤的建立了乙個multi-column索引(我想說避免建立multi-column索引,除非你知道需要乙個特別的索引)。在多列索引中,如果你在查詢中指定a,b,c,你可以用它來查詢a,或者a和b,或者a和b和c。前提是必須依賴列,比如你無法脫離a列。

這在我們的案例中是真實存在的,所以,我立即為索引建立乙個遷移。當然我們是在伺服器上遷移,這樣可以使伺服器有5分鐘時間去建立牽引,然後重新執行測試。每秒擴充套件到120個請求數(7.200 rpm),此時資料庫載入時間只有16%。

週三下午大約3點鐘,這時資料庫伺服器可以承受的負荷為每分鐘約36,000頁的請求數。我們再次突破伺服器cpu載入的時間。

就在這一天,我們已經刷爆了ec2例項,我們還有一支團隊一直在忙於擴充套件性測試,突破了極限。我們去除了amis一些不必要的執行,並要求其他人停止測試,我們反覆的請求並新增aws(amazon web services)限制,然後進入客戶代表的賬號,並讓他們提出公升級需求。

週三晚上很晚我們才離開,此時我們信心倍加,相信能處理好周四早上的超負荷。

周四,我們所有人都在使用google分析new relic,它涵蓋了所有螢幕的後端介面,因為它將在pst(太平洋標準時間pacific standard time)上午5:30開始舉行,我們遍布在酒店的每個角落,用篝火進行實時聊天。

第一次載入的時間在5:38分,此時此刻發生了極大的變化:在短短的一分鐘時間裡從原有0訪量變成上千人訪問。頁面響應時間穩定在500ms,在伺服器客戶端頁面,沒出現過任何延誤。

當然,我們也出現bug,這就要求在載入的時候必須要對此進行修補,然後重新啟動,(可以同時進行),還要確保頁面通暢。載入高峰值我們已測試過,當然,執行的非常好,這也遠遠超過了我們周一下午前所做的改變。因此,這兩天的辛苦,沒白費,我們獲得了回報。

經驗與教訓:

如果我們早些使用使用new relic pro計畫,那麼我們將節省很多時間,但是無論用哪種方法,我相信是new relic拯救了我們的漏洞,如果我們在週三下午還沒有得到所需要的資料,那麼周四早上的一切都是扯談。

載入測試需要定期進行,而不是在大事件發生時才想起測試。在任何時候也許某人使資料庫發生改變,比如忘記了索引或是注入了一些其他的異常效能而又未被發現,直到系統載入時才知道。

需要乙個相對安全的、自動化的方式便於提供執行加快部署分段和生產次數。必需制定捷徑的常規過程。而不是依賴於某人用vi編輯檔案,不會造成任何錯誤。

如果不使用雲服務,我們根本不會如此之快擴充套件應用程式例項和資料庫伺服器。

團隊的作用很重要,通常情況下,如果不是有危機發生我們是分散的,各司其職,也不會想到做些遙不可及的事情。 

實戰 3天讓Web應用承載拓展1000倍

環境 由ngnix,ruby on rails和mysql構成。注 這個web應用只是乙個旅行指南。當使用者進入我們的 時,會通過tripit導航或者選定目標,再依據詳細資訊進行下面的操作。他們可以根據自己的喜好選擇不同類別 比如餐廳的菜式風格 評級指標等吸引點進行篩選 或者也可以通過瀏覽器檢視生活...

web應用開發實戰作業day02

1.屬性和標籤什麼關係?html屬性一般都出現在html標籤中,html屬性是html標籤的一部分。標籤可以有屬性,它包含了額外的資訊,屬性的值一般要在引號中 有時也可以不加引號 標籤可以擁有乙個或多個屬性,也可以沒有屬性 屬性一般由屬性名和值成對出現。屬性選擇器可以挑選帶有特殊屬性的標籤語法 屬性...

redis實戰讀後感(二) 構建web應用

雜湊 cookie令牌和已登入使用者,最近登入使用者有序集合,使用者瀏覽過商品的有序集合 1.使用者登入 檢查登入使用者 更新令牌 更新雜湊表,更新最近登入使用者有序集合,更新使用者瀏覽過商品的有序集合,zremrangebyrank刪除多餘商品 定期清理會話 如果最近登入使用者有序集合超過限制,則...