天天看點

99.999%,提升ElasticSearch穩定性的秘密

作者:empeliu,騰訊 TEG 背景開發工程師

ElasticSearch 是一個分布式的開源搜尋和分析引擎,因其功能強大、簡單易用而被應用到很多業務場景。在生産環境使用 ES 時,如果未進行優化則服務的穩定性可能得不到保障,目前我們使用 ES 作為賬單平台的基礎元件為微信支付提供服務時就遇到這種問題。本文即從目前的業務場景出發,分析 ES 穩定性未到達要求的原因并提供相應的解決思路。

一、背景

微信支付的賬單系統是友善使用者擷取交易記錄,針對不同的使用者群,賬單也分為三類:

  • 個人賬單:針對普通使用者群,這類使用者特點是基數大,單個使用者資料量小,使用賬單系統主要是擷取清單以及基礎統計;
  • 商戶賬單:針對商戶使用者群,這類使用者特點是基數小,單個使用者資料量非常大,使用賬單系統主要是擷取清單,并且在擷取清單時需要支援豐富查詢條件;
  • 業務賬單:針對使用者群介于普通使用者和商戶之間,比如微商或面對面小商戶,使用賬單系統主要是擷取清單以及豐富統計功能;

目前賬單平台為微信支付的這三類賬單提供寫入、存儲和查詢服務,基本架構如下:

99.999%,提升ElasticSearch穩定性的秘密

賬單平台主要包括兩部分:

  • 邏輯側:業務側直接對接子產品,主要是降低業務接入成本,提高接入效率;
  • 存儲側:包含 ES 以及接入層 ESProxy,接入層對上屏蔽索引劃分機制,友善上層使用;

目前微信支付對整體品質要求非常高,展現在可用性方面是需要達到 99.99%,同樣賬單平台也需要達到甚至超過該要求。但是在 ES 及系統環境未做優化的情況下,讀寫成功率是沒有達到要求,在個人賬單 ES 索引場景下,寫成功率為 99.85%,讀成功率為 99.95%,是以這裡亟需優化。

二、記憶體回收慢優化

問題分析

針對讀寫成功率低問題,我們首先檢視存儲側接入層 ESProxy 逾時失敗的情況,對應如下圖:

99.999%,提升ElasticSearch穩定性的秘密

可以看出接入層通路 ES 節點出現了大量逾時,在排除接入層自身的問題後,基本上把問題源鎖定到 ES 節點。

通過進一步确認 ES 節點負載情況(如下圖),機器會出現 CPU 抖動,而抖動時上層會出現逾時,這就表明讀寫成功率低是 CPU 抖動導緻的,于是我們重心就是解決 CPU 抖動問題。

99.999%,提升ElasticSearch穩定性的秘密

那麼是什麼原因導緻 ES 節點的 CPU 抖動呢?首先我們先确定 CPU 抖動時系統具體在做什麼,根據已有經驗,很有可能是 ES 熱點線程或 GC 導緻的,但是在分析 CPU 抖動時 user 和 system 程序占比情況,其中 user 程序 CPU 占比基本沒有變化,而 system 程序 CPU 卻增長很多,由于 ES 熱點線程或 GC 是 user 程序,是以排除了這裡的影響。通過系統相關統計以及 perf 得到下面現象:

  • 抖動時系統在大量掃描可回收記憶體
99.999%,提升ElasticSearch穩定性的秘密
  • 系統在不斷進行記憶體回收
99.999%,提升ElasticSearch穩定性的秘密
  • 系統配置設定記憶體時出現了失敗
99.999%,提升ElasticSearch穩定性的秘密

通過這三個現象,我們也得出了一個結論,CPU 抖動是因為記憶體不足導緻。

優化方案

明确了抖動問題原因後,那麼我們接下來的優化方向就是保證有足夠的空閑記憶體,避免記憶體不斷回收而出現 CPU 抖動。針對記憶體不足問題,我們首先确認系統目前的記憶體分布情況,具體資料如下:

99.999%,提升ElasticSearch穩定性的秘密

進一步分析如下:

  • ES 節點記憶體主要是被 JVM 以及 PageCache 記憶體占用
  • Jvm 記憶體是被 java 獨占,該部分記憶體是不會被回收
  • PageCache 記憶體由作業系統維護,該部分記憶體是可以被回收的

正常情況下,如果系統記憶體不足,則核心通過回收 PageCache 的記憶體即可提供足夠的空閑記憶體,即不會記憶體不足的情況;反過來說,目前出現記憶體不足,則說明 PageCache 未被正常回收,于是針對記憶體優化則聚焦到 PageCache 回收問題上。

針對 PageCache 回收問題,首先我們先明确什麼因素導緻 PageCache 不能及時回收,其中 MMap 就可能導緻 PageCache 不能正常回收,原因是 MMap 後應用程式會引用到這部分記憶體,則核心在回收記憶體時會忽略這部分記憶體。而 ES 節點讀取檔案的方式預設就是 MMap,整體的記憶體關聯關系如下圖:

99.999%,提升ElasticSearch穩定性的秘密

既然 MMap 方式會導緻 PageCache 不能及時回收,那麼自然考慮是采用其他方式替換 MMap 去通路檔案,在 Java 中即可采用 NIO 方式讀取檔案,對應記憶體關聯關系如下:

99.999%,提升ElasticSearch穩定性的秘密

采用 NIO 方式通路檔案,PageCache 記憶體隻被作業系統維護,則核心可以及時回收 PageCache 以保證足夠的記憶體使用,這樣就解決了記憶體不足問題,進而解決 CPU 抖動問題,進而提高讀寫成功率;

但是采用 NIO 通路檔案也存在問題,即資料會多一次記憶體複制,會導緻延遲方面比 MMap 方式的高,經過測試發現延遲會高 30%左右,這樣的結果也不是我們想要的,于是我們考慮将兩者結合起來,目的是加快記憶體回收的同時降低延遲,采取的政策是根據通路頻率來确定檔案的讀寫方式(即高頻采用 MMap 方式,這樣可以保證延遲低,低頻采用 Nio 方式,這樣可以加快核心回收 PageCache),具體不同檔案類型讀取方式如下表:

99.999%,提升ElasticSearch穩定性的秘密

優化效果

采用 MMap+Nio 的方式後,通過測試驗證:

  • 延遲方面和 MMap 基本一緻
  • 記憶體回收方面也比 MMap 好

采用 MMap+Nio 組合方式上線後,對應現網寫成功率由 99.85%提升到 99.99%。

三、高階記憶體優化

問題分析

在系統運作一段時間後,現網的成功率逐漸降低,由 99.99%降低到 99.97%,對應接入層的逾時失敗也相應增多,有了之前的經驗,我們相應檢視了 ES 節點的負載情況,發現仍然有 CPU 抖動的現象(如下圖)。考慮到之前已經優化了記憶體回收慢的問題,此時應是新的問題導緻的 CPU 抖動,于是接下來優化點依舊是解決抖動。

99.999%,提升ElasticSearch穩定性的秘密

和之前分析 CPU 抖動問題一樣,我們先确認 CPU 抖動系統在做什麼。通過 perf 分析,如下圖所示:

99.999%,提升ElasticSearch穩定性的秘密

采樣的結果可以明确 CPU 抖動時,系統在進行記憶體碎片整合(即有 compact_zone()等函數調用),這就意味着此時系統高階記憶體是不足,為了進一步驗證目前的高階記憶體不足,通過  cat/proc/buddyinfo  檢視目前系統空閑記憶體的分布情況,如下圖所示:

99.999%,提升ElasticSearch穩定性的秘密

分析上面資料可以得出,目前空閑記憶體有 4G 左右,86%的記憶體是 0 階記憶體,大于等于 2 階的高階記憶體占比隻有 4%左右,這裡驗證目前空閑記憶體是基本都是碎片化的,碎片化記憶體示意圖如下所示:

99.999%,提升ElasticSearch穩定性的秘密

優化方案

明确了目前的問題後,那麼接下來重點就是考慮将碎片化的記憶體變成連續記憶體。前文我們明确了目前 ES 節點的記憶體主要有兩部分組成,分别是 JVM 記憶體和 PageCache 記憶體,并且在我們現網環境中,這兩部分記憶體基本上是獨立的(目前現網機器記憶體有兩個 NODE,每個 NODE 占了一半的實體記憶體,其中 JVM 和 PageCache 分布在不同的 NODE 上),這就意味着我們可以隻優化 PageCache 間的記憶體碎片,這樣就可以滿足我們需求;對應優化流程如下:

99.999%,提升ElasticSearch穩定性的秘密

具體分為兩個步驟:

1、釋放記憶體:釋放 PageCache 記憶體,保證新的空閑記憶體盡可能連續,具體的處理措施是 echo1 > /proc/sys/vm/drop_cache

2、保留一定空閑記憶體:目的是避免記憶體的不斷申請和回收,導緻記憶體碎片化再次變的嚴重,具體處理措施是限制 PageCache 的大小(這裡依賴 tlinux 的實作),具體的指令是 echo36 > /proc/sys/vm/pagecache_limit_ratio

優化效果

經過上述的優化之後,系統的空閑記憶體分布如下:

99.999%,提升ElasticSearch穩定性的秘密

此時的空閑也是在 4G 左右,但是大于等于 2 階的高階記憶體占比達到 95%左右,即高階記憶體目前是非常充足的,并且機器的 CPU 幾乎沒有抖動(如下圖所示)。

99.999%,提升ElasticSearch穩定性的秘密

在現網進行相應調整之後,讀寫成功率提升效果如下:

  • 寫成功率由 99.85%提升到 99.999%
  • 讀成功率由 99.95%提升到 99.999%

四、結論

針對賬單平台的 ES 系統的讀寫成功率未滿足要求,進行了如下優化措施:1、記憶體回收慢優化:優化 ES 檔案讀取方式,加快記憶體回收,降低 CPU 在記憶體回收方面消耗;2、高階記憶體不足優化:整理碎片化記憶體,保證有充足高階記憶體,降低 CPU 在記憶體碎片整理消耗;

經過上述優化措施後,ES 系統的讀寫成功率達到 99.999%,超出目前的可用性要求,保障 ES 在生産環境穩定性。

參考:

1、Node Hot threadsAPI

2、Physical PageAllocation

3、Describing PhysicalMemory

99.999%,提升ElasticSearch穩定性的秘密