公有云(AWS)上的生產環境效能分析案例

weixin_33807284發表於2018-08-07

本文是我在 gitchat 上的文章雲端計算生產環境架構效能調優和遷移套路總結(以 AWS 為例)的前半部分,本文對原文有所修改和總結。交流實錄請點選這裡

案例背景

案例是一個泰國網站的生產環境(請腦補一句“薩瓦迪卡”,為了敘述方便,下文中均以"薩瓦迪卡"指代這個網站。)“薩瓦迪卡”是一個 採用 Wordpress + MySQL搭建的應用。這個遺留系統已經工作了五年。客戶已經把在其它 VPS 上平移到 AWS 上。平移(lift and shift)是說原樣複製,而遷移(migration)還要進行改造。而客戶唯一發揮 AWS 優勢的一點就是用了一個配置很高的 EC2 虛擬機器 —— m4.4xlarge。這樣一臺配置的虛擬機器有 16 個虛擬 CPU,64 GiB 的記憶體,以及 2000 Mbps 的網路頻寬,最高 3000 IOPS 的 200GiB 的塊儲存裝置(也就是硬碟)。

知識點: GiB 是用二進位制計算的,GB 是用十進位制計算的。1 GiB 是 2的30 次方,而1 GB 是10 的 9 次方,1 GiB 略大於 1GB。 而且,AWS 的 FreeTier 免費計劃是按 GB 計算的哦!

除了基本的網路和虛擬機器以外,“薩瓦迪卡” 的所有東西都放在一臺虛擬機器上。沒錯,是所有東西——Web 伺服器,反向代理,資料庫,上傳的檔案——都放在一臺虛擬機器上。唯一個一個負載均衡用來承載 HTTPS 證照,沒有使用叢集,沒有高可用,沒有資料庫/應用分離,沒有防火牆,沒有 WAF,沒有 APM,沒有 CDN 而且,沒有持續交付流水線,所有部署都要 ssh 到機器上進行操作。如圖所示:

274927-124d3e9ccead56c5.jpg
原始架構

“薩瓦迪卡”的生產環境可以被認為是一個裸奔的肉雞。我曾經一度它已經被輪番入侵很久了,只是還沒有被發現而已。而且,“薩瓦迪卡”生產環境的唯一一臺伺服器的記憶體率使用經常超過 95%,我很擔心它的狀況,任何一個小的 DoS,都不需要 DDoS,就可以讓它整站當機了。

我於是把我的擔憂彙報給了客戶,客戶也意識到了問題。在我發現問題之前的一個月就啟動了“薩瓦迪卡”的翻新(Revamp)專案,讓這個應用保持原樣(Keep it as is),直到 6 個月後新專案上線,替換掉當前應用。

然而,沒想到我一語成讖。一天,“薩瓦迪卡”被刪庫了!

刪庫?別慌!

作為一個運維工程師,最悲催的事情就是“人在家中坐,鍋從天上來”。這天是世界盃的某一場小組賽,而我剛吃完晚飯正在洗碗。突然被客戶的 P1 告警(P1 - Priority 1,最高階別告警)驚嚇到,得知“薩瓦迪卡”被刪庫了。

判斷的依據是:

  1. “薩瓦迪卡”主頁開啟是 Wordpress 的初始化安裝頁面。證明應用是正常的,資料不在了。
  2. 在伺服器上用 MySQL 客戶端登入資料庫,找不到“薩瓦迪卡”的資料庫。

還好客戶每天有全量資料備份,於是客戶快速從全量備份恢復了資料庫,只是缺少了從備份點到故障點的業務資料。全量資料庫的備份檔案有 10 GiB,這麼大的表如果採用 mysqldump 會因為鎖表而導致 10 分鐘左右的停機時間(別問我怎麼知道的)。

問題分析

在恢復應用的同時,我們也開始進行了分析的工作。首先,我們懷疑是被攻擊了。於是通過 AWS 的 CloudTrail(一種審計工具,用來記錄登入 AWS 使用者的操作)和 主機上的命令歷史(history 命令)和登入日誌進行分析,結果一無所獲。其次,我開始檢查 MySQL 的日誌(/var/lib/mysql/*.err),在日誌上發現如下片段:

InnoDB: Log scan progressed past the checkpoint lsn 126908965949
180622 17:21:09  InnoDB: Database was not shut down normally!
InnoDB: Starting crash recovery.

<此處省略很多行>

180622 17:21:32 InnoDB: Initializing buffer pool, size = 3.0G
InnoDB: mmap(3296722944 bytes) failed; errno 12
180622 17:21:32 InnoDB: Completed initialization of buffer pool
180622 17:21:32 InnoDB: Fatal error: cannot allocate memory for the buffer pool
180622 17:21:32 [ERROR] Plugin 'InnoDB' init function returned error.
180622 17:21:32 [ERROR] Plugin 'InnoDB' registration as a STORAGE ENGINE failed.

通過分析,我們發現 mysql 發現自己有問題的時候嘗試恢復資料庫,但因為虛擬機器可用記憶體不足而載入儲存引擎失敗,導致找不到資料庫。因此,解決方案有以下三種:

  1. 採用工具進行對 mysql 伺服器引數進行調優。
  2. 擴大記憶體,換個配置更高的虛擬機器。
  3. 將應用和資料庫部署在不同的虛擬機器例項或者 RDS (關聯式資料庫服務)上。

而三種有各自的問題:

對於方案1,資料庫調優需要頻繁重啟。對於生產環境來說,必須在低流量的時段(一般是夜間)進行。而且所花時間未知且效果很難保證。由於資源有上限,且程式相互影響,很難發現問題。所以風險較高,價值有限。

對於方案2,需要對虛擬機器進行不停機映象複製,因此會導致部分資料丟失,而且資料同步恢復困難大。而且,不知道需要多少資源的虛擬才足夠。問題同方案1,只不過由於資源更多,下次出現同樣問題的時間更晚罷了。這個方案的風險雖然比第一種小,但用空間換時間的價值仍然有限,不曉得能撐到什麼時候。而且,可能會帶來一定的資源浪費。

方案3是風險最小,價值最大的方案。它將資料作為核心資源並託管至高可用服務上,有效了隔離了風險,保護了資料的可用性。但唯一的缺點就是對於需要的資源和效能是未知的。因此,在實施這個方案之前,我們需要進行效能測量。

你可能會想,只需要增加一些基礎設施監控和 APM (Application Performance Monitoring,應用效能監控)就可以得到相應的資料了。然而,在生產環境的效能度量沒那麼簡單。

首先,我們要保證生產環境的業務連續性。APM 也是一種應用程式,也會佔用資源,你如何確定安裝和執行 APM 的過程不會造成生產環境停機?其次,如果一定會造成停機,那麼會停機多久?當這些問題都是未知的情況下,魯莽的行為只能增加更多的不確定性風險。

因此,在遷移之前,我們要模擬生產環境進行度量並進行分析。

設計效能度量

效能度量是一個從“未知”到“已知”的過程。

首先,你需要明確所要度量的問題。你可以和你的小組一起商定需要解決的問題。在上面這個案例裡,我們所需要回答的問題包括:

  1. 正常執行應用程式需要多少記憶體?
  2. 正常執行資料庫需要多少記憶體?
  3. 進行哪些操作會導致停機時間?停機時間會持續多久?
  4. 資源使用對效能的影響有多少?
  5. 效能拐點在哪裡?

當然,對於 CPU,網路和儲存,你也可以設計以上的問題。

然後,找到資料基線(Benchmark)

由於資源的使用是和使用者訪問數量息息相關的,你還需要知道資源使用的均值峰值邊際值

均值是資源使用基線,也就是最小值。

峰值是資源使用的警告線,如果過去發生過這麼高。

邊際值是指每單位的使用者請求所消耗的資源。

一般來說,這些資料都可以從雲端計算提供商的非侵入式監控服務獲得,它的資料收集不會影響資源的效能。例如 AWS 的 CloudWatch 。我們可以根據過去 6 個月或者 3個月的時間來估計均值和峰值。但由於未來是不確定的,因此過去 6 個月或者 3 個�月的資料是建立在“未來訪問量不會突變”的假設基礎上的。例如,如果有類似於“6·18” 或者 “雙十一” 的流量高峰,則日常的資料參考意義不大。

如果缺乏這樣的手段,就要通過複製生產環境來度量了。

複製生產環境

複製生產環境的一點原則就是“儘量減少不同”,儘可能的按照生產環境的配置來構建你的沙盒環境以得到更接近真實的資料。很多雲提供商都提供映象(Image)或者快照(Snapshot)的功能用來複制當前有狀態的資源。有時候二者是同一個意思。如果有區別,二者的區別在於以下幾點:

  1. 映象是全量,快照是增量。
  2. 映象的構建需要停機,而快照不需要。
  3. 映象生成時間長,快照生成時間短。
  4. 映象不能指定時間點部分還原,快照可以根據時間點部分還原。

無論是哪一種,我們都要選擇一個對生產環境影響最小的方案。在 AWS 中,我們可以根據當前的虛擬機器例項構建虛擬機器映象 AMI (Amazon Machine Images)。它提供兩種方式:一種是不重啟(no reboot),這種方式的缺點是會造成構建映象時間點以後的資料丟失。另外一種是在構建之前重啟例項,這樣不會導致資料丟失。

對於上述的案例來說,生產資料的完整性並不會影響我們的度量,因此,無需重啟例項。但如果你要度量重啟例項會帶來多少資料丟失,則需要重啟例項。

此外,為了保證你不會誤操作,我建議你在非生產環境的雲端計算賬號下重建應用。如果你一定要在同一個賬戶中進行復制,請確保你做好了生產環境資源隔離。

設計測試場景

當你在測試環境下複製了生產環境,你就有了一個安全的沙箱來進行測試了。當我們開始進行效能測試的時候,我們要通過“整體”的測試來計算對“區域性”的影響。並找到。以“薩瓦迪卡”為例,我們通過 AWS 上的資料得到了“薩瓦迪卡”生產環境的平均響應時間:0.2 ~ 0.4 秒,RPM(Requests Per Minute 每分鐘請求)大概在 4500 左右。

因此我們設計瞭如下測試場景:

  1. 空閒使用率:0 請求的時候,資源使用率。
  2. 1 個,10 個,20 個 併發請求的時候,資源使用率和響應時間,用於計算邊際資源使用率。
  3. RPM 和生產環境 RPM 均值相等的情況下,資源使用率和響應時間。
  4. 2 倍 ,4 倍, 10 倍 生產環境 RPM 均值的情況下,資源使用率和響應時間。
  5. 模擬生產環境的 RPM 增長速度(逐步增加請求到相應值,例如 5 分鐘增長到 2000 RPM)進行測試。
  6. 模擬生產環境極限 RPM 增長速度(一次增加請求到對應值,例如 5 秒鐘增長到 2000 RPM)進行測試。

根據以上的測試場景,我們可以構建資源使用率和響應時間之間的關係。

如果你有 CDN 或者 URL 訪問分析資料,可以它來構建你的測試案例。如果什麼沒有,例如“薩瓦迪卡”這種情況,你就可以使用主頁的 URL 來進行測試。常用的工具有 Selenium, Jmeter 和 Gatling。你可以用 Selenium 錄製一個使用者訪問的指令碼,來模擬使用者訪問。你也可以通過 Jmeter 或 Gatling 來增加併發進行負載測試,後者能提供更加有用的資訊。

如果你無法模擬足夠多的真實使用者資料,把以上的工具生成的指令碼或配置放到 flood.io 上執行,得到更好的參考報告,如下圖所示:

274927-f686e39700710f39.png
flood.io

如果你需要度量某些操作的停機時間,你可以在進行負載測試的時候進行操作。也可以使用我寫的小工具 wade (Web Application Downtime Estimation)來測試。關於 wade 的故事可以參考 一怒之下,我寫了一個開源流量測試工具

通過模擬“薩瓦迪卡”的訪問資料,我得到了以下資料:

  1. 當 Web 伺服器(Apache)重啟完,僅有健康檢查訪問的情況下,系統佔用 367 MiB 記憶體。
  2. 資料庫佔用 10 GiB 左右記憶體,也就是說,給 Web 應用剩下的記憶體有 53 GiB 左右。
  3. 分別度量了 1個使用者,10 個使用者,20 個使用者併發訪問下的記憶體使用情況。平均每處理一個請求,最多需要消耗 133 MiB 記憶體。
  4. 也就是說,剩下的記憶體最大能服務 400 個左右的使用者的併發訪問。如果超過 400 個使用者,系統會因為資源不足而當機。
  5. 升級虛擬機器 Linux 中的軟體包和安全補丁會帶來 5 秒鐘左右的停機。
  6. APM (NewRelic)的安裝會佔用 63 MiB 左右記憶體且無停機時間。

編寫效能度量報告

當我們完成了效能度量的時候,就要編寫一份效能度量報告。效能度量報告包含以下 6 個部分:

  1. 背景:主要回答為什麼(Why)要做這一次效能度量。
  2. 關鍵問題:通過效能度量期望知道哪些問題(What)。
  3. 測試設計:主要介紹度量方法(How),以及度量方法中的注意事項。
  4. 測試條件:由於是模擬測試,要強調與真實值的匹配情況,哪些部分重要,哪些部分不重要。
  5. 測試資料結果:採用工具得出的真實資料,要有源可查,最好是截圖。
  6. 結論:根據資料的計算解答第 2 步 提出的關鍵問題。
  7. 建議:根據度量資料得出的下一步優化建議。

至此,我們完成了對生產環境效能的分析。接下來,就要為效能設計架構遷移方案了。請關注下篇《AWS 上的生產環境架構優化案例

相關文章