撰稿 | 言征
出品 | 51CTO技術(shù)棧(微信號(hào):blog51cto)
公司業(yè)務(wù)高歌猛進(jìn)時(shí),云成本被掩埋在“數(shù)字繁榮”之中,但一旦紅利退卻,云超高的成本就會(huì)讓老板們覺得如鯁在喉。這并不是一朝一夕的問題。
這樣的大環(huán)境下,企業(yè)的側(cè)重點(diǎn)變成了,如何在不影響應(yīng)用性能、盡量保持基礎(chǔ)設(shè)施不變的情況下,削減云開支。
在今天的文章中,會(huì)為諸位帶來一個(gè)“對(duì)基礎(chǔ)設(shè)施做出簡(jiǎn)單改變,并將成本降低 30%的案例,并探究云成本到底哪里貴了。
一、一個(gè)操作,6萬美元沒了
云計(jì)算帶來的體驗(yàn)可以說是前所未有:幾秒鐘內(nèi)生成一個(gè)服務(wù)器,后端配上無服務(wù)器,前端配上存儲(chǔ)桶,就可以托管起整個(gè)網(wǎng)站,直到調(diào)用數(shù)量達(dá)到限制之前,該過程甚至都可以不花一分錢。
但是,流量開始增加后,痛苦就來了,就如同“走鋼絲”一般,必須變得小心翼翼起來,因?yàn)槊赓M(fèi)只是暫時(shí)的,一個(gè)操作不當(dāng),糟糕的事情就奔你而來。
網(wǎng)絡(luò)上有很多關(guān)于公司或某開發(fā)人員一夜之間云成本賬戶銀行卡被通知“刷爆”的恐怖故事,可謂觸目驚心:
上述造成的云賬單,有的是因?yàn)橐粋€(gè)調(diào)用了 lambda 函數(shù)而導(dǎo)致了 4.5k 美元的費(fèi)用,有的則是因?yàn)榘凑漳吃频恼f明文檔做了一個(gè)測(cè)試任務(wù),結(jié)果3個(gè)月后收到了6萬美元的郵件賬單。
圖片
這些并非個(gè)例,但因?yàn)楦甙旱厣显频某杀揪秃?jiǎn)單粗暴下云,卻又是另外一番動(dòng)人心魄的故事,這里不再贅述。
二、云,哪里跑“貴”了?
問題就在于,既想要云端的高效便捷、彈性足夠、便于維護(hù),又不想云賬單一日千里地不可控,有沒有一些可參考的方法和實(shí)踐?
我們不妨先看一下這張賬單:
圖片
21,433.21 歐元。這是筆者公司在 2022 年 10 月為臨時(shí)環(huán)境和生產(chǎn)環(huán)境支付的總費(fèi)用。細(xì)分來看,K8s集群、云存儲(chǔ)赫然在列——
- Kubernetes 集群13,743.83 歐元(折扣2,333.84歐元)
- 云存儲(chǔ)(存儲(chǔ)桶)6,124.75 歐元
- SQL 數(shù)據(jù)庫3,237.22 歐元
- 還有其他較小的成本,本文中忽略不計(jì)。
雖然成本并未失控,但 Kubernetes 集群和存儲(chǔ)讓我們付出了昂貴的代價(jià)。
三、K8s集群哪里貴了?
接下來,就是分開看這兩塊的成本產(chǎn)生過程。首先是 Kubernetes 集群本身在生產(chǎn)環(huán)境上的成本細(xì)分。通過下圖就能看出三大罪魁禍?zhǔn)祝?/p>
計(jì)算引擎中的N1預(yù)定義實(shí)例Core/RAM、Spot可搶占實(shí)例、區(qū)域間網(wǎng)絡(luò)出口產(chǎn)生的費(fèi)用最高。
圖片
谷歌云計(jì)費(fèi)頁面的屏幕截圖顯示了我們的臨時(shí)和生產(chǎn)環(huán)境的價(jià)格
Tips:對(duì)于那些不熟悉的人來說,這些標(biāo)簽可能需要解釋一下:
- N1 預(yù)定義實(shí)例 core/ram 是我們 Kubernetes 集群日常使用的節(jié)點(diǎn)。N1 是節(jié)點(diǎn)類型。
- Spot 可搶占實(shí)例 core/ram 是我們生成的用于運(yùn)行異步任務(wù)的節(jié)點(diǎn)??蓳屨家馕吨覀?yōu)檫@些節(jié)點(diǎn)支付更少的費(fèi)用,但我們無法保證可用性。
- 區(qū)域間網(wǎng)絡(luò)出口(Network Egress Inter Zone)是通過網(wǎng)絡(luò)在可用區(qū)域(AZ)之間移動(dòng)的數(shù)據(jù)。假設(shè)有一個(gè)托管在區(qū)域 AZ 中的節(jié)點(diǎn)中的 API,如果該 API 向 AZ B 中的節(jié)點(diǎn)中的另一個(gè) API 進(jìn)行查詢,將為從 AZ B 到 AZ A 的數(shù)據(jù)付費(fèi)。
問題一:沒有管理好Kubernetes的預(yù)期
我們接著逐個(gè)攻破。從成本明細(xì)中最高的開始:N1 預(yù)定義實(shí)例core/RAM。
問題的根源就在于我們有沒有告訴Kubernetes該如何擴(kuò)展新節(jié)點(diǎn)。
N1 預(yù)定義實(shí)例Core/RAM方面,當(dāng)前使用的是n1-standard-8節(jié)點(diǎn),它們根據(jù)使用情況自動(dòng)縮放。在進(jìn)行修正之前,了解 Kubernetes 如何擴(kuò)展新節(jié)點(diǎn)非常有必要。
當(dāng)定義 Pod 時(shí),需要告訴 Kubernetes 一個(gè)信息:Pod 需要多少 RAM 和 CPU 才能正常工作;這就是 Kubernetes 所說的 Request。
假設(shè)我的 API 的 pod A 需要 400mo RAM 和 0.2 vCPU 才能正常工作,而 Kubernetes 節(jié)點(diǎn)容量為 30 GB RAM 和 8 個(gè) vCPU??梢栽谠摴?jié)點(diǎn)中容納 40 個(gè) Pod,因?yàn)?8 個(gè) vCPU 除以 0.2 vCPU 等于 40 個(gè) Pod,而 30,000mo 除以 400mo 等于 75 個(gè) Pod。
所以,于K8s集群而言,明確預(yù)期的和未使用的資源,是一個(gè)技術(shù)活兒。
表示請(qǐng)求的 CPU 與節(jié)點(diǎn)實(shí)際容量的架構(gòu)
問題二:配置文件中的魔鬼細(xì)節(jié):CPU和內(nèi)存值
如果在 8 個(gè) vCPU 節(jié)點(diǎn)中有 40 個(gè) pod 請(qǐng)求 0.2 vCPU,Kubernetes 會(huì)認(rèn)為該節(jié)點(diǎn)已滿并啟動(dòng)一個(gè)新節(jié)點(diǎn),即使這些 pod 僅使用 4 個(gè) vCPU。
一個(gè)合理的配置,就能大大減少因節(jié)點(diǎn)數(shù)量產(chǎn)生的付費(fèi)。同時(shí),節(jié)點(diǎn)根據(jù)請(qǐng)求的資源進(jìn)行擴(kuò)展,如何才能避免過多的浪費(fèi)擴(kuò)展中的資源浪費(fèi)呢?
這就需要深入研究 Kubernetes yaml 配置文件,看看可以更改哪些內(nèi)容。
我們做的第一件事是將 pod 的 yaml 定義與 Grafana 中的實(shí)際資源使用情況進(jìn)行比較。我們可以使用 Grafana 輕松查看請(qǐng)求與實(shí)際使用情況的比較,如下所示。
圖片
Grafana 在運(yùn)行一個(gè) pod 時(shí)對(duì) 1 個(gè) API 的 RAM 請(qǐng)求/使用情況(在撰寫本文時(shí)拍攝的屏幕截圖,因此在配置更新之后)。
在此圖中,我們可以看到 RAM 的平均使用率為 0.1go,而請(qǐng)求的 RAM 為 0.4go 。
如果我們將其與此 API 的 YAML 配置進(jìn)行比較,我們可以發(fā)現(xiàn)類似的內(nèi)容。
來自部署.yaml 文件的 IAC 存儲(chǔ)庫中的更改的屏幕截圖
我們顯著減少了請(qǐng)求的內(nèi)存和 CPU 值,以更接近 API 使用的實(shí)際情況 —并且我們?nèi)匀槐3直J?;我們可以進(jìn)一步減少它。我們對(duì)所有服務(wù)都執(zhí)行了此流程。
問題3:默認(rèn)為單個(gè)服務(wù)運(yùn)行了太多的 Pod
例如,對(duì)于此部署,我們至少運(yùn)行三個(gè) Pod,這意味著即使 API 在夜間幾乎沒有收到任何調(diào)用,它仍然運(yùn)行3個(gè) Pod。
因此,我們檢查了每項(xiàng)服務(wù),并將 pod 副本的最小數(shù)量減少到一個(gè)(在安全的情況下)。
圖片
通過這幾項(xiàng)更改,搞定了 N1 預(yù)定義實(shí)例Core/RAM的成本問題,從4,235.43 歐元增加到 1,973.28 歐元。
問題4:區(qū)域間網(wǎng)絡(luò)出口的數(shù)據(jù)交互費(fèi)用
這方面是非常棘手的,可用區(qū)域之間的網(wǎng)絡(luò)的數(shù)據(jù)交互會(huì)產(chǎn)生很大的云費(fèi)用
我們有四十多個(gè)微服務(wù),但好處是它們做得很好,而且它們之間幾乎沒有直接通信,但我們?cè)谒羞@些服務(wù)前面有一個(gè)GraphQL 網(wǎng)關(guān)。這個(gè)網(wǎng)關(guān)接到很多調(diào)用。
筆者也采取了兩種方式解決了這個(gè)問題:
第一個(gè)是使用 Flow Logs追蹤哪些調(diào)用對(duì)于返回的數(shù)據(jù)最大。
第二種方法,也是我們最有信心的方法,是檢查哪個(gè) API 收到的調(diào)用最多,以及該 API 中的哪個(gè)端點(diǎn)非常適合緩存。我們已經(jīng)使用 Redis 作為發(fā)布/訂閱解決方案,因此我們也可以輕松地將它用作緩存。
我們決定先做緩存,因?yàn)槲覀儫o論如何都需要它,而且一切都已經(jīng)設(shè)置好了。但這仍然是一個(gè)錯(cuò)誤——因?yàn)槲覀冎皇菍栴}轉(zhuǎn)移到緩存系統(tǒng)中,而不知道數(shù)據(jù)是否太大是因?yàn)榇a問題還是因?yàn)檎{(diào)用次數(shù)過多。
使用Kiali,我們可以看到哪個(gè) API 收到的調(diào)用最多。
圖片
根據(jù)此信息和應(yīng)用程序的功能方面,我們決定應(yīng)緩存哪個(gè)端點(diǎn)。這樣,GraphQL 網(wǎng)關(guān)將實(shí)現(xiàn)緩存,并且不必對(duì)服務(wù)進(jìn)行 HTTP 調(diào)用來獲取數(shù)據(jù),從而降低了 Egress 成本。
僅通過實(shí)施第一個(gè)解決方案,我們就成功地將出口成本從 2.712,34 歐元降低到 1,095.19 歐元。
遺憾的是,我們尚未實(shí)現(xiàn)第二種解決方案來追蹤傳輸大量數(shù)據(jù)的剩余 HTTP 調(diào)用。
四、云存儲(chǔ)哪里貴了?
沒錯(cuò),云存儲(chǔ)的成本,大部分還是與容量本身有關(guān),而并非存儲(chǔ)桶中傳輸?shù)臄?shù)據(jù)產(chǎn)生的成本。解決的方法自然就很簡(jiǎn)單:刪。
筆者公司的應(yīng)用程序接收來自用戶的視頻,我們對(duì)其進(jìn)行標(biāo)準(zhǔn)化并存儲(chǔ)原始版本和標(biāo)準(zhǔn)化版本。然后,客戶會(huì)對(duì)這些視頻進(jìn)行編輯和驗(yàn)證(或拒絕)。
此前,我們從未刪除過任何內(nèi)容。我們多年來一直存儲(chǔ)用戶未使用的視頻,并擁有超過 100 TB 的數(shù)據(jù)。因此,根據(jù)我們的法律和產(chǎn)品團(tuán)隊(duì)的意見,我們?cè)O(shè)置了一個(gè) CRON 作業(yè),用于查詢數(shù)據(jù)庫的動(dòng)態(tài)參數(shù)(例如“視頻拒絕”)并存檔這些文件。
為了防止出現(xiàn)任何不可恢復(fù)的錯(cuò)誤,我們首先將文件的存儲(chǔ)類別在 GCP 中切換為“歸檔”(在 S3 中為 Glacier),并使用生命周期規(guī)則在六個(gè)月后將其完全刪除。
2022 年 10 月生產(chǎn)環(huán)境存儲(chǔ)成本
2023年9月生產(chǎn)環(huán)境存儲(chǔ)成本
這仍然是一個(gè)持續(xù)的過程,因?yàn)槲覀儽仨氈?jǐn)慎決定刪除哪些內(nèi)容,但我們成功地將生產(chǎn)中的存儲(chǔ)成本從 4,754.85 歐元降低到 3,029.93 歐元。
五、臨時(shí)環(huán)境的成本也很驚人
這里,還有一個(gè)細(xì)節(jié)不應(yīng)忽視,就是臨時(shí)環(huán)境所產(chǎn)生的費(fèi)用也很瘋狂。2022 年 10 月,我們?yōu)榕R時(shí)環(huán)境支付了 4,059.25 歐元,接近生產(chǎn)環(huán)境的1/4。
生產(chǎn)環(huán)境和臨時(shí)環(huán)境之間的成本明細(xì)對(duì)比
臨時(shí)環(huán)境下的成本明細(xì)
我們采取了四項(xiàng)簡(jiǎn)單的措施來降低成本:
我們?cè)诜寝k公時(shí)間關(guān)閉了環(huán)境。遺憾的是,由于我們是一支國(guó)際團(tuán)隊(duì),工作日晚上的時(shí)間不多。
我們縮小了 Kubernetes 集群規(guī)模,將所有部署的最小 pod 設(shè)置為 1,并防止自動(dòng)擴(kuò)展超過 1 個(gè) pod——除了一些關(guān)鍵服務(wù)。
我們向云存儲(chǔ)桶添加了生命周期規(guī)則,以刪除六個(gè)月或更早的所有內(nèi)容。我們清理了數(shù)據(jù)庫,并刪除了以前開發(fā)人員或 QA 中不再使用的所有數(shù)據(jù)。
圖片
通過這四個(gè)簡(jiǎn)單的步驟,我們將臨時(shí)環(huán)境的月開銷降低了 2500多歐元!
六、進(jìn)一步削減云成本的思路
其他削減云成本的辦法嗎?
當(dāng)然,我們已經(jīng)對(duì)計(jì)劃如何進(jìn)一步降低成本有了一些想法,更多的是延續(xù)上文的內(nèi)容。
(1)微調(diào) Kubernetes 請(qǐng)求,以更加精確地了解我們的微服務(wù)需要運(yùn)行的內(nèi)容;
(2)按照我們最初的計(jì)劃追蹤剩余的出口成本
(3)繼續(xù)在我們的歸檔 cron 中實(shí)施新規(guī)則,從存儲(chǔ)桶中刪除不必要的文件;
(4)將我們的視頻處理從 CPU 切換到 GPU(筆者實(shí)測(cè)速度更快且成本更低);
(5)清理生產(chǎn)中的 SQL 數(shù)據(jù)庫,存儲(chǔ)可存檔的 TB 級(jí)事件數(shù)據(jù)。
如果我們比較 2022 年 10 月和 2023 年 10 月,我們每個(gè)月節(jié)省了 6,369.75 歐元,幾乎節(jié)省了 30%,我相信我們可以節(jié)省更多。
七、寫在最后
追蹤云成本并優(yōu)化是一件非常非常有挑戰(zhàn)的、且富有成就感的事情。于與云程師、架構(gòu)師而言,即便支付云賬單的賬戶是公司,而不是自己。
但說起來容易,做起來難 。在個(gè)人項(xiàng)目上使用云的免費(fèi)層和在每天有數(shù)百萬次調(diào)用的生產(chǎn)環(huán)境中使用云是兩種完全不同的野獸。
本文帶大家從頭開始分析了云成本過高的幾個(gè)問題:生產(chǎn)環(huán)境下的K8s集群、云存儲(chǔ)的問題、以及臨時(shí)環(huán)境下的不必要的開支,并給出了解決思路和計(jì)劃。
記?。簭囊婚_始就考慮應(yīng)用程序的生命周期,并采取適當(dāng)?shù)谋Wo(hù)措施,以防止您的云成本過高,而不是一味按照文檔配置部署,否則,迎接你的只能是高昂的收費(fèi)通知。
參考鏈接:https://alexandreolive.medium.com/how-we-manage-to-reduce-our-cloud-costs-by-25-percents-3f8c26db704a