实践中的弹性基础架构
幾周前,我獲得了一個(gè)難得的機(jī)會,可以在基礎(chǔ)設(shè)施領(lǐng)域弄臟雙手。 在JVM內(nèi)部的深入了解下,我每天的工作經(jīng)歷發(fā)生了有趣的變化,我想與您分享動機(jī)和成果。 希望它可以啟發(fā)類似的問題類別。
背景
我將從解釋需要解決方案的上下文開始。 如果您知道Plumbr性能監(jiān)控的全部內(nèi)容,則可以跳過此部分。 對于其他所有人,我們Plumbr都在構(gòu)建性能監(jiān)控解決方案。 我們的方法是獨(dú)特的,因?yàn)槲覀冎荚谑顾行阅軉栴}都具有源代碼的根本原因。
此類問題的最復(fù)雜類別之一是其根源隱藏在Java內(nèi)存分配和管理中。 此類別中的問題包括:
- 內(nèi)存不足;
- 面臨太頻繁/太長時(shí)間的GC暫停;
- 嘗試減少應(yīng)用程序的內(nèi)存占用。
我們對此類問題的解決方案是建立在對對象圖進(jìn)行快照并從那里公開最耗費(fèi)內(nèi)存的數(shù)據(jù)結(jié)構(gòu)的基礎(chǔ)上的。 結(jié)果,您將獲得運(yùn)行時(shí)透明性,以了解JVM堆中實(shí)際發(fā)生的情況:
以上是我們在監(jiān)視我們自己的服務(wù)時(shí)發(fā)現(xiàn)的示例。 如我們所見,在重大GC暫停后的某個(gè)時(shí)刻,我們占據(jù)了70%以上的舊一代。 老一代的高占用率通常會導(dǎo)致長時(shí)間的GC暫停,因此Plumbr捕獲了快照以顯示其中的實(shí)際內(nèi)容。
在這種特殊情況下,我們發(fā)現(xiàn)包含ProbeDataProcessingTasks的處理隊(duì)列的大小已增長到近1 GB。 了解應(yīng)歸咎于哪些數(shù)據(jù)結(jié)構(gòu)使解決該問題變得微不足道。 結(jié)果,GC暫停的頻率和持續(xù)時(shí)間保持不變。
但是,拍攝這些快照有些昂貴。 捕獲快照所需的時(shí)間取決于堆中對象的數(shù)量以及它們之間的引用。 我們的代理商會仔細(xì)安排快照的時(shí)間,以避免自己成為性能瓶頸。
綜上所述:在我們的基礎(chǔ)架構(gòu)中,此特殊功能導(dǎo)致不可預(yù)測的內(nèi)存快照流入。 更糟糕的是,快照的大小也是不可預(yù)測的。 有時(shí)我們每小時(shí)可能只收到一個(gè)微小的快照,然后突然間,我們在很短的時(shí)間內(nèi)被許多10 + G快照轟炸:
我們最初的解決方案存在問題
我們構(gòu)建的第一個(gè)解決方案是專用的微服務(wù),用于處理快照的傳入流。 我們立即開始面臨問題。 首先,我們還無法估算這些快照的大小。 最初配置的4G內(nèi)存還遠(yuǎn)遠(yuǎn)不足以處理流向我們的較大快照。 要分析快照,我們需要將對象圖加載到內(nèi)存中,因此快照越大,分析所需的RAM越多。
因此,我們需要從亞馬遜購買更大的計(jì)算機(jī)。 突然之間,微服務(wù)不再是微服務(wù)了。 正如我們很快發(fā)現(xiàn)的那樣,在您的每月賬單中實(shí)際上可以看到保持m4.10xlarge實(shí)例嗡嗡作響的24×7。 除了非常昂貴外,機(jī)器有99%的時(shí)間幾乎處于空閑狀態(tài)–發(fā)生的巨大堆快照很少見,因此經(jīng)常會超額配置10倍以上的機(jī)器來處理偶發(fā)的峰值。
此外,分析持續(xù)時(shí)間很快就成為瓶頸。 快照需要花費(fèi)10秒鐘到數(shù)十分鐘的時(shí)間來分析每個(gè)快照,因此當(dāng)在短時(shí)間內(nèi)到達(dá)多個(gè)大型快照時(shí),隊(duì)列等待時(shí)間成為一個(gè)問題:
解決方案要求
了解了問題之后,下一步就是將問題簡化為解決方案的要求:
- 分析任務(wù)不應(yīng)在隊(duì)列中等待數(shù)小時(shí)。 我們應(yīng)該能夠并行處理它們。 每當(dāng)一個(gè)巨大的快照到達(dá)并且需要很長時(shí)間進(jìn)行分析時(shí),其他快照就不應(yīng)等待它完成。
- 對于每個(gè)快照,我們可以估計(jì)執(zhí)行分析將需要多少堆。 我們希望使用盡可能多的資源,而不會過度配置基礎(chǔ)架構(gòu)。
對于以前建立過彈性環(huán)境的人來說,解決方案的要求可能會很明顯。 對于那些還沒有的人,我將在下一部分中介紹解決方案體系結(jié)構(gòu)和實(shí)現(xiàn)的關(guān)鍵案例。
建立解決方案
這些要求有效地指示我們,我們應(yīng)該維護(hù)一個(gè)靈活的基礎(chǔ)架構(gòu),而不是一個(gè)單獨(dú)的專用實(shí)例。 實(shí)例應(yīng)按需生成,實(shí)例類型應(yīng)與接收到的快照的大小相對應(yīng)。
因此,我們繼續(xù)將快照分析代碼包裝到docker容器中,并利用AWS ECS將此類容器用作集群中的任務(wù)。 這樣做之后,我們偶然發(fā)現(xiàn)了第一個(gè)問題:向外擴(kuò)展并不像預(yù)期的那么瑣碎。
僅僅為每個(gè)分析生成一個(gè)適當(dāng)大小的新實(shí)例并在之后立即終止的天真的方法被證明是一個(gè)壞主意。 啟動實(shí)例最多可能需要五分鐘,具體取決于實(shí)例類型。 此外,AWS每小時(shí)執(zhí)行一次計(jì)費(fèi),因此,使一個(gè)實(shí)例運(yùn)行60分鐘的成本要比運(yùn)行十個(gè)實(shí)例每6分鐘的成本便宜十倍。
在這種情況下,典型的方法是使用AWS 自動擴(kuò)展組。 顯然,這不適合我們,因?yàn)锳WS無法根據(jù)ECS任務(wù)所需的內(nèi)存量自動生成實(shí)例。 您無法將任務(wù)提交給ECS集群,除非該集群已經(jīng)有足夠的資源來容納它。
我們的解決方案是根據(jù)分析任務(wù)所需的內(nèi)存量將其劃分為多個(gè)存儲桶,并為每個(gè)存儲桶分配一個(gè)單獨(dú)的群集。 收到新快照后,我們檢查目標(biāo)集群是否有足夠的可用資源來運(yùn)行任務(wù)。 如果沒有,我們將在其自動擴(kuò)展組中增加所需的實(shí)例數(shù)。 然后,AWS自動啟動一個(gè)具有適當(dāng)大小的新實(shí)例。 因此,從本質(zhì)上講,我們最終得到了六個(gè)存儲桶,每個(gè)存儲桶包含適當(dāng)大小的實(shí)例,可以根據(jù)需求進(jìn)行擴(kuò)展:
第二個(gè)問題是通過擴(kuò)展來解決自身問題。用于擴(kuò)展的標(biāo)準(zhǔn)CloudWatch警報(bào)基于集群使用不足的情況。 如果集群閑置了足夠長的時(shí)間,我們會減少所需實(shí)例的數(shù)量。 “空閑”是根據(jù)群集中消耗的內(nèi)存計(jì)算的,如果在45分鐘內(nèi)內(nèi)存使用率一直低于指定的閾值,則立即擴(kuò)展并終止額外的實(shí)例。
這里也有一個(gè)警告:在自動伸縮組中進(jìn)行伸縮時(shí),AWS選擇一種特殊的方式來終止實(shí)例。 例如,如果一個(gè)群集有兩個(gè)實(shí)例,其中一個(gè)實(shí)例處于空閑狀態(tài),而另一個(gè)實(shí)例正在運(yùn)行分析,則完全有可能該活動實(shí)例將被殺死而不是空轉(zhuǎn)一個(gè)實(shí)例。
擴(kuò)展問題的解決方案是,在分析期間,我們?yōu)閳?zhí)行此擴(kuò)展的特定實(shí)例設(shè)置了擴(kuò)展保護(hù) 。 當(dāng)我們開始分析時(shí),我們設(shè)置標(biāo)志,并在完成時(shí)將其刪除。 自動縮放不會終止受保護(hù)而無法放大的實(shí)例。 最后一點(diǎn)就足夠了,從那以后我們就開始平穩(wěn)運(yùn)行。
找到了兩個(gè)問題的解決方案,我們得到了預(yù)期的結(jié)果。 更改后,隊(duì)列中等待的時(shí)間現(xiàn)在如下所示:
帶走
這是少數(shù)情況下的一種,您可以提高應(yīng)用程序的性能,并減少容量需求以降低成本。 在大多數(shù)情況下,您必須為提高性能付出很大的代價(jià),因此人們可以欣賞這些時(shí)刻。 現(xiàn)在,按需計(jì)算比以往任何時(shí)候都容易,因此也許您可以以類似的方式優(yōu)化應(yīng)用程序。
而且,如果除了彈性基礎(chǔ)架構(gòu)的有趣案例之外,該帖子還引發(fā)了人們對如何獲得應(yīng)用程序內(nèi)存使用透明性的興趣,那就繼續(xù)免費(fèi)試用Plumbr試用一下。
翻譯自: https://www.javacodegeeks.com/2016/05/elastic-infrastructure-practice.html
總結(jié)
以上是生活随笔為你收集整理的实践中的弹性基础架构的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Lightroom:与 3D LUT C
- 下一篇: ActiveMQ 5.x中的消息持久性