如何避免AWS的高額賬單?
作者 | 劉龍飛
前言
Serverless架構(gòu)在今天已經(jīng)不再是新鮮的事物。該架構(gòu)具有多個(gè)特點(diǎn):較低的運(yùn)營(yíng)和開(kāi)發(fā)成本、能快速上線、自動(dòng)擴(kuò)展、安全性高和適合微服務(wù)等。各大云服務(wù)商也提供了各自的Severless解決方案。然而,盡管Serverless架構(gòu)在某些方面表現(xiàn)出色,但在當(dāng)前轟轟烈烈的“微服務(wù)”進(jìn)程中,它仍然不是一種主要的選擇。
除了由于本身特性導(dǎo)致的使用場(chǎng)景受限外,我想乏善可陳的關(guān)于Serverless最佳實(shí)踐的總結(jié)也是一個(gè)重要的因素。我有幸參與了一項(xiàng)基于AWS搭建的Serverless (FaaS) 系統(tǒng)的開(kāi)發(fā)工作,該系統(tǒng)提供了一組核心服務(wù)。
通過(guò)幾次系統(tǒng)故障調(diào)研和性能優(yōu)化的實(shí)際體驗(yàn),我發(fā)現(xiàn)系統(tǒng)監(jiān)控在Serverless架構(gòu)中至關(guān)重要。所以本文將從Serverless系統(tǒng)監(jiān)控的角度來(lái)展開(kāi)一些討論。
哪些指標(biāo)需要被監(jiān)控?
先分享一個(gè)真實(shí)發(fā)生的故事:
我們?cè)趯?duì)上文提到的FaaS 系統(tǒng)做一次部署時(shí),由于API測(cè)試不通過(guò)導(dǎo)致流水線構(gòu)建失敗。調(diào)查發(fā)現(xiàn)是因?yàn)闇y(cè)試運(yùn)行時(shí)間過(guò)久導(dǎo)致請(qǐng)求使用的令牌過(guò)期。這一發(fā)現(xiàn)直接指向了系統(tǒng)的性能問(wèn)題。我們回溯大量流水線構(gòu)建記錄后發(fā)現(xiàn),API測(cè)試所耗時(shí)長(zhǎng)在近一個(gè)月以來(lái)逐日遞增。
在調(diào)查了CloudWatch中各項(xiàng)觀測(cè)指標(biāo)后發(fā)現(xiàn):從一個(gè)月前開(kāi)始,Lambda的調(diào)用次數(shù)始終保持在最大并發(fā)量,并且Lambda一直處于高執(zhí)行時(shí)延狀態(tài)。最終找到根因在于一個(gè)會(huì)觸發(fā)Lambda執(zhí)行的消息事件由于某個(gè)bug被大量復(fù)制,并且該事件在被Lambda處理后原樣發(fā)回SQS,導(dǎo)致發(fā)生死循環(huán)。
盡管這個(gè)問(wèn)題發(fā)生在非生產(chǎn)環(huán)境,但帶來(lái)的影響依然是非常大的:首先,測(cè)試環(huán)境性能明顯降低。另一方面,AWS是按使用收費(fèi)。該問(wèn)題導(dǎo)致一個(gè)月以來(lái),Lambda,SQS,RDS,DynamoDB和CloudWatch等AWS服務(wù)被持續(xù)不斷地使用,因而產(chǎn)生了高額的賬單。
上述故事中反映出來(lái)的問(wèn)題可能有很多方面,但缺乏監(jiān)控與告警無(wú)疑是導(dǎo)致該問(wèn)題持續(xù)近一個(gè)月而沒(méi)有被發(fā)現(xiàn)和解決的罪魁禍?zhǔn)住D敲?,在Severless系統(tǒng)中,一般有哪些需要監(jiān)控的指標(biāo)呢?其實(shí)AWS 的CloudWatch已經(jīng)給出了部分答案。不同于需要監(jiān)控CPU/內(nèi)存使用率等指標(biāo)的長(zhǎng)生命周期服務(wù),Severless服務(wù)的一大特點(diǎn)就是不需要開(kāi)發(fā)和運(yùn)維人員過(guò)多關(guān)注底層資源的分配和管理。那么與之相對(duì)應(yīng)地,針對(duì)Severless (FaaS) 而言,有以下一些值得關(guān)注的指標(biāo)需要監(jiān)控并配置告警。
1. 執(zhí)行時(shí)延 (Duration)
一般Severless系統(tǒng)的函數(shù)都有最大執(zhí)行時(shí)間的限制。而且從系統(tǒng)的設(shè)計(jì)原則上講,一次函數(shù)調(diào)用也不應(yīng)執(zhí)行過(guò)長(zhǎng)的時(shí)間。當(dāng)監(jiān)控到較多的長(zhǎng)時(shí)延函數(shù)調(diào)用時(shí),表明系統(tǒng)出現(xiàn)了異常情況,且極有可能導(dǎo)致性能問(wèn)題。同時(shí),長(zhǎng)時(shí)延也意味著成本的增加。函數(shù)執(zhí)行時(shí)延的異常增高通常有如下原因:
- 如果該函數(shù)依賴于第三方服務(wù)或同一云平臺(tái)的其他服務(wù),則有可能是網(wǎng)絡(luò)通信,數(shù)據(jù)庫(kù)訪問(wèn)等I/O操作延遲增大;
- 若該函數(shù)會(huì)批處理事件,則有可能是事件的生產(chǎn)者出現(xiàn)了異常,導(dǎo)致函數(shù)每次調(diào)用都需要處理大量任務(wù)。
所以函數(shù)執(zhí)行時(shí)延的異常增高,通常就是系統(tǒng)某一部分出現(xiàn)問(wèn)題的信號(hào)。
2. 調(diào)用次數(shù) (Invocations)
調(diào)用次數(shù)表示某一時(shí)間范圍內(nèi)函數(shù)的調(diào)用次數(shù),它能夠反映當(dāng)前函數(shù)的活躍程度以及整體上的執(zhí)行情況。調(diào)用次數(shù)的突然變化也會(huì)反映系統(tǒng)中的異常情況。另外,監(jiān)控各個(gè)函數(shù)的調(diào)用情況也有助于我們合理配置該函數(shù)的最大并發(fā)量。
Severless系統(tǒng)的自動(dòng)擴(kuò)容就依賴于函數(shù)的調(diào)用情況。當(dāng)多個(gè)請(qǐng)求進(jìn)入系統(tǒng),而當(dāng)前函數(shù)實(shí)例正在處理請(qǐng)求,系統(tǒng)會(huì)自動(dòng)創(chuàng)建新的實(shí)例來(lái)處理其他請(qǐng)求。這個(gè)過(guò)程會(huì)一直持續(xù)到有足夠的函數(shù)實(shí)例來(lái)處理所有請(qǐng)求,除非達(dá)到最大并發(fā)量。一旦達(dá)到最大并發(fā)量后仍有待處理請(qǐng)求,則認(rèn)為發(fā)生了瓶頸(Throttles)。出現(xiàn)瓶頸則是一個(gè)非常明顯的需要告警的情況,因此為瓶頸這一指標(biāo)配置告警通常是非常有效的做法。
3. 錯(cuò)誤率 (Error rate)
無(wú)論是函數(shù)調(diào)用錯(cuò)誤或者是函數(shù)執(zhí)行異常都說(shuō)明系統(tǒng)出現(xiàn)了非預(yù)期的行為,都需要盡快處理使系統(tǒng)恢復(fù)正常。但需要說(shuō)明的是,如果系統(tǒng)出現(xiàn)的是性能問(wèn)題,則不一定會(huì)導(dǎo)致錯(cuò)誤率提高。所以不能僅依靠這單一指標(biāo)來(lái)衡量系統(tǒng)的健康狀態(tài)。
以上是我認(rèn)為的針對(duì)FaaS系統(tǒng)最基本的和最重要的三個(gè)指標(biāo)。合理配置這幾個(gè)指標(biāo)的監(jiān)控與告警,可以提前發(fā)現(xiàn)大多數(shù)非業(yè)務(wù)問(wèn)題的系統(tǒng)異常,進(jìn)而及時(shí)調(diào)查和解決問(wèn)題避免更大的損失。
當(dāng)然,除了函數(shù),Severless系統(tǒng)還會(huì)依賴于大量云平臺(tái)提供的其他服務(wù)。以AWS為例,一個(gè)典型的Severless架構(gòu)通常會(huì)使用到API Gateway, SQS, SNS, DynamoDB和RDS等服務(wù)。而每個(gè)服務(wù)都有對(duì)應(yīng)的需要關(guān)心并監(jiān)控的指標(biāo),從學(xué)習(xí)了解的角度,有個(gè)技巧是直接去看CloudWatch提供了哪些已經(jīng)被自動(dòng)監(jiān)控的指標(biāo),進(jìn)而深入了解每個(gè)指標(biāo)所代表的含義和所反映的深層次問(wèn)題。了解得越清楚,在配置監(jiān)控和告警時(shí)會(huì)更得心應(yīng)手,收到告警后也有助于快速定位問(wèn)題。
除了針對(duì)各個(gè)基礎(chǔ)服務(wù)的各類指標(biāo)進(jìn)行監(jiān)控外,監(jiān)控云平臺(tái)各個(gè)賬號(hào)的賬單也是避免損失的一大法寶。Severless系統(tǒng)中很多問(wèn)題都會(huì)導(dǎo)致賬單的異常增加,而通常我們的精力都會(huì)放在系統(tǒng)問(wèn)題的調(diào)查和修復(fù)上,后知后覺(jué)地才發(fā)現(xiàn)這一實(shí)打?qū)嵉慕?jīng)濟(jì)損失。大多云平臺(tái)都提供了成本管理功能。如AWS可以監(jiān)控賬單信息,并配置通知告警。甚至還可以配置預(yù)算操作,當(dāng)賬單達(dá)到某些條件時(shí)自動(dòng)執(zhí)行一些預(yù)先定義好的行為,以達(dá)到止損的目的。
最后需要強(qiáng)調(diào)的是,除了監(jiān)控各項(xiàng)服務(wù)的基礎(chǔ)指標(biāo)外,監(jiān)控業(yè)務(wù)指標(biāo)以及由業(yè)務(wù)指標(biāo)導(dǎo)向的技術(shù)指標(biāo)也是監(jiān)控中非常重要的一環(huán),畢竟任何軟件系統(tǒng)提供具體業(yè)務(wù)都是第一位的。在這一方面,Severless架構(gòu)和其他類型架構(gòu)沒(méi)有太多本質(zhì)上的差別,所以不在此過(guò)多討論,但這也是設(shè)計(jì)系統(tǒng)監(jiān)控架構(gòu)時(shí)必不可少的。
分布式監(jiān)控
盡管云服務(wù)商已經(jīng)提供了很多基礎(chǔ)指標(biāo)的監(jiān)控,但由于函數(shù)的事件驅(qū)動(dòng)以及短生命周期特性,使我們很難從這些基礎(chǔ)指標(biāo)中讀到一個(gè)完整的“故事”。若是我們想基于這些基礎(chǔ)監(jiān)控去分析系統(tǒng)性能瓶頸,或者嘗試調(diào)研特定業(yè)務(wù)問(wèn)題,則會(huì)面臨重重困難。當(dāng)然,很容易想到的方式是分析日志來(lái)進(jìn)行分析和調(diào)研,但以我們實(shí)際經(jīng)驗(yàn)來(lái)看,嘗試從大量日志中發(fā)現(xiàn)性能瓶頸絕不是一個(gè)簡(jiǎn)單的事情。
我們?cè)鴮?duì)上述FaaS系統(tǒng)嘗試進(jìn)行整體性能調(diào)優(yōu),以及針對(duì)特定業(yè)務(wù)場(chǎng)景的性能優(yōu)化。需要做的事情大致分為以下步驟:識(shí)別性能瓶頸,對(duì)發(fā)現(xiàn)的瓶頸排列優(yōu)先級(jí),依次嘗試優(yōu)化,本地驗(yàn)證局部?jī)?yōu)化效果,測(cè)試環(huán)境驗(yàn)證特定業(yè)務(wù)場(chǎng)景下的優(yōu)化效果,生產(chǎn)環(huán)境驗(yàn)證整體性能提升和特定業(yè)務(wù)場(chǎng)景優(yōu)化效果。在整個(gè)調(diào)查、修復(fù)和驗(yàn)證過(guò)程中,遇到了很多痛點(diǎn),其中最為明顯的就是尋找瓶頸和驗(yàn)證優(yōu)化后效果兩個(gè)方面:
問(wèn)題1:找到性能瓶頸
由于每個(gè)請(qǐng)求都會(huì)有若干個(gè)函數(shù)依次進(jìn)行處理,其中整個(gè)過(guò)程還會(huì)包括消息隊(duì)列中事件的寫入和讀出,數(shù)據(jù)庫(kù)的連接和數(shù)據(jù)讀寫,第三方服務(wù)的訪問(wèn)等過(guò)程。而我們所能采用的手段只能是首先分析日志進(jìn)行初步定位,然后再本地調(diào)試進(jìn)行更為精確地定位。因?yàn)楝F(xiàn)有日志缺少一些必要信息,所以需要增加日志。但這樣做,一方面帶來(lái)了額外的工作量,另一方面也會(huì)帶來(lái)大量的“噪音”,增加了分析日志的復(fù)雜程度。更重要的是,記錄大量日志有可能影響函數(shù)本身執(zhí)行的性能,也會(huì)增加監(jiān)控系統(tǒng)的成本。另外,本地調(diào)試也不是一件容易的事情。由于函數(shù)依賴于很多第三方服務(wù)或者云平臺(tái)其他服務(wù),本地需要隔離掉或提供虛擬的依賴。即使使用單元測(cè)試來(lái)觀察特定事件處理過(guò)程的執(zhí)行性能,因?yàn)橐P(guān)注特定業(yè)務(wù)場(chǎng)景,也需要花費(fèi)大量時(shí)間準(zhǔn)備測(cè)試數(shù)據(jù)。
問(wèn)題2:驗(yàn)證優(yōu)化后效果
由于依賴過(guò)多,每次修復(fù)后都需要部署到個(gè)人測(cè)試環(huán)境中,而部署過(guò)程會(huì)花費(fèi)較多的時(shí)間。另外,想要端到端地去驗(yàn)證整體和局部性能的提升效果,也只能通過(guò)寫復(fù)雜的查詢命令來(lái)從日志中進(jìn)行統(tǒng)計(jì)。在部署到生產(chǎn)環(huán)境后,想要統(tǒng)計(jì)特定業(yè)務(wù)場(chǎng)景下的性能提升也是很大的一個(gè)挑戰(zhàn)。由于日志主要關(guān)注局部過(guò)程,很難通過(guò)日志提取出特定業(yè)務(wù)場(chǎng)景并得到統(tǒng)計(jì)意義上的結(jié)果,所以遲遲無(wú)法衡量?jī)?yōu)化后的真實(shí)效果。
雖然以上問(wèn)題最終都通過(guò)各種手段得到了一定程度上的解決,但過(guò)程顯然不是輕松愉快的。以上問(wèn)題的癥結(jié)在于單單依靠日志無(wú)法完整地貫通端到端過(guò)程,各處日志信息格式不統(tǒng)一,不能方便地聚合各個(gè)服務(wù)中的監(jiān)控信息。
分布式監(jiān)控系統(tǒng)就是可以有效解決這一類問(wèn)題的技術(shù)手段。它通過(guò)采用統(tǒng)一數(shù)據(jù)模型和API,從各個(gè)系統(tǒng)子服務(wù)/函數(shù)中收集數(shù)據(jù),統(tǒng)一聚合和分析處理,以良好的可視化方式進(jìn)行結(jié)果的呈現(xiàn)。構(gòu)建良好的分布式監(jiān)控系統(tǒng)可以從端到端的視角提供請(qǐng)求跟蹤,過(guò)程分析,甚至實(shí)時(shí)調(diào)試等功能。所以在業(yè)務(wù)場(chǎng)景較為復(fù)雜的情況下,為Serverless系統(tǒng)應(yīng)用分布式監(jiān)控工具應(yīng)該成為一種必然的選擇。
以AWS為例,它提供了原生的監(jiān)控工具X-Ray。X-Ray具備端到端跟蹤功能,可以監(jiān)控到Lambda,RDS,DynamoDB,SQS和SNS等服務(wù)中的元數(shù)據(jù),并提供應(yīng)用程序的端到端和跨服務(wù)視圖。Service map 則提供了應(yīng)用程序中的服務(wù)間匯總數(shù)據(jù)的連接視圖,其中包括平均延遲和故障率等。其他如延遲檢測(cè),數(shù)據(jù)注釋和篩選等也是非常實(shí)用的功能。當(dāng)然,還有很多其他類似的工具也能達(dá)到相同的目的,我們?cè)谑褂弥懈鶕?jù)具體需求進(jìn)行選擇就好。
寫在最后
本文只是拋磚引玉,沒(méi)有過(guò)于深入的討論,目的是想總結(jié)與記錄在Serverless系統(tǒng)中試水的所見(jiàn)與所得?;蛟S我們遇到的很多問(wèn)題,有可能是因?yàn)镾everless架構(gòu)目前并不適用于我們所面臨的復(fù)雜業(yè)務(wù)。但我想說(shuō),實(shí)踐是最好的老師,體驗(yàn)和經(jīng)歷這些痛點(diǎn)才會(huì)讓人更有動(dòng)力去思考和解決這些問(wèn)題。監(jiān)控系統(tǒng)單拎出來(lái)也是一個(gè)龐大的話題,希望能通過(guò)本文讓我們更多地回過(guò)頭去思考監(jiān)控的目的,總結(jié)那些切實(shí)幫助和啟發(fā)到了我們的實(shí)踐。