【轉帖】MySQL用得好好的,爲何要轉ES?

MySQL用得好好的,爲何要轉ES?

http://developer.51cto.com/art/201911/605288.htm

 

Elasticsearch做爲一款功能強大的分佈式搜索引擎,支持近實時的存儲、搜索數據,在京東到家訂單系統中發揮着巨大做用,目前訂單中心ES集羣存儲數據量達到10億個文檔,日均查詢量達到5億。算法

做者:佚名來源: 今日頭條|2019-11-01 15:50

京東到家訂單中心繫統業務中,不管是外部商家的訂單生產,或是內部上下游系統的依賴,訂單查詢的調用量都很是大,形成了訂單數據讀多寫少的狀況。數據庫

咱們把訂單數據存儲在MySQL中,但顯然只經過DB來支撐大量的查詢是不可取的。同時對於一些複雜的查詢,MySQL支持得不夠友好,因此訂單中心繫統使用了Elasticsearch來承載訂單查詢的主要壓力。緩存

MySQL用得好好的,爲何要轉ES?

 

Elasticsearch做爲一款功能強大的分佈式搜索引擎,支持近實時的存儲、搜索數據,在京東到家訂單系統中發揮着巨大做用,目前訂單中心ES集羣存儲數據量達到10億個文檔,日均查詢量達到5億。架構

隨着京東到家近幾年業務的快速發展,訂單中心ES架設方案也不斷演進,發展至今ES集羣架設是一套實時互備方案,很好地保障了ES集羣讀寫的穩定性,下面就給你們介紹一下這個歷程以及過程當中遇到的一些坑。負載均衡

ES 集羣架構演進之路

一、初始階段異步

訂單中心ES初始階段如一張白紙,架設方案基本沒有,不少配置都是保持集羣默認配置。整個集羣部署在集團的彈性雲上,ES集羣的節點以及機器部署都比較混亂。同時按照集羣維度來看,一個ES集羣會有單點問題,顯然對於訂單中心業務來講也是不被容許的。分佈式

二、集羣隔離階段性能

和不少業務同樣,ES集羣採用的混布的方式。但因爲訂單中心ES存儲的是線上訂單數據,偶爾會發生混布集羣搶佔系統大量資源,致使整個訂單中心ES服務異常。優化

顯然任何影響到訂單查詢穩定性的狀況都是沒法容忍的,因此針對於這個狀況,先是對訂單中心ES所在的彈性雲,遷出那些系統資源搶佔很高的集羣節點,ES集羣情況稍有好轉。但隨着集羣數據不斷增長,彈性雲配置已經不太能知足ES集羣,且爲了徹底的物理隔離,最終乾脆將訂單中心ES集羣部署到高配置的物理機上,ES集羣性能又獲得提高。搜索引擎

三、節點副本調優階段

ES的性能跟硬件資源有很大關係,當ES集羣單獨部署到物理機器上時,集羣內部的節點並非獨佔整臺物理機資源,在集羣運行的時候同一物理機上的節點仍會出現資源搶佔的問題。因此在這種狀況下,爲了讓ES單個節點可以使用最大程度的機器資源,採用每一個ES節點部署在單獨一臺物理機上方式。

但緊接着,問題又來了,若是單個節點出現瓶頸了呢?咱們應該怎麼再優化呢?

ES查詢的原理,當請求打到某號分片的時候,若是沒有指定分片類型(Preference參數)查詢,請求會負載到對應分片號的各個節點上。而集羣默認副本配置是一主一副,針對此狀況,咱們想到了擴容副本的方式,由默認的一主一副變爲一主二副,同時增長相應物理機。

MySQL用得好好的,爲何要轉ES?

訂單中心ES集羣架設示意圖

如圖,整個架設方式經過VIP來負載均衡外部請求:

整個集羣有一套主分片,二套副分片(一主二副),從網關節點轉發過來的請求,會在打到數據節點以前經過輪詢的方式進行均衡。集羣增長一套副本並擴容機器的方式,增長了集羣吞吐量,從而提高了整個集羣查詢性能。

下圖爲訂單中心ES集羣各階段性能示意圖,直觀地展現了各階段優化後ES集羣性能的顯著提高:

MySQL用得好好的,爲何要轉ES?

 

固然分片數量和分片副本數量並非越多越好,在此階段,咱們對選擇適當的分片數量作了進一步探索。分片數能夠理解爲MySQL中的分庫分表,而當前訂單中心ES查詢主要分爲兩類:單ID查詢以及分頁查詢。

分片數越大,集羣橫向擴容規模也更大,根據分片路由的單ID查詢吞吐量也能大大提高,但聚合的分頁查詢性能則將下降;分片數越小,集羣橫向擴容規模也更小,單ID的查詢性能也會降低,但分頁查詢的性能將會提高。

因此如何均衡分片數量和現有查詢業務,咱們作了不少次調整壓測,最終選擇了集羣性能較好的分片數。

四、主從集羣調整階段

到此,訂單中心的ES集羣已經初具規模,但因爲訂單中心業務時效性要求高,對ES查詢穩定性要求也高,若是集羣中有節點發生異常,查詢服務會受到影響,從而影響到整個訂單生產流程。很明顯這種異常狀況是致命的,因此爲了應對這種狀況,咱們初步設想是增長一個備用集羣,當主集羣發生異常時,能夠實時的將查詢流量降級到備用集羣。

那備用集羣應該怎麼來搭?主備之間數據如何同步?備用集羣應該存儲什麼樣的數據?

考慮到ES集羣暫時沒有很好的主備方案,同時爲了更好地控制ES數據寫入,咱們採用業務雙寫的方式來搭設主備集羣。每次業務操做須要寫入ES數據時,同步寫入主集羣數據,而後異步寫入備集羣數據。同時因爲大部分ES查詢的流量都來源於近幾天的訂單,且訂單中心數據庫數據已有一套歸檔機制,將指定天數以前已經關閉的訂單轉移到歷史訂單庫。

因此歸檔機制中增長刪除備集羣文檔的邏輯,讓新搭建的備集羣存儲的訂單數據與訂單中心線上數據庫中的數據量保持一致。同時使用ZK在查詢服務中作了流量控制開關,保證查詢流量可以實時降級到備集羣。在此,訂單中心主從集羣完成,ES查詢服務穩定性大大提高。

MySQL用得好好的,爲何要轉ES?

 

五、現今:實時互備雙集羣階段

期間因爲主集羣ES版本是較低的1.7,而現今ES穩定版本都已經迭代到6.x,新版本的ES不只性能方面優化很大,更提供了一些新的好用的功能,因此咱們對主集羣進行了一次版本升級,直接從原來的1.7升級到6.x版本。

集羣升級的過程繁瑣而漫長,不但須要保證線上業務無任何影響,平滑無感知升級,同時因爲ES集羣暫不支持從1.7到6.x跨越多個版本的數據遷移,因此須要經過重建索引的方式來升級主集羣,具體升級過程就不在此贅述了。

主集羣升級的時候必不可免地會發生不可用的狀況,但對於訂單中心ES查詢服務,這種狀況是不容許的。因此在升級的階段中,備集羣暫時頂上充當主集羣,來支撐全部的線上ES查詢,保證升級過程不影響正常線上服務。同時針對於線上業務,咱們對兩個集羣作了從新的規劃定義,承擔的線上查詢流量也作了從新的劃分。

備集羣存儲的是線上近幾天的熱點數據,數據規模遠小於主集羣,大約是主集羣文檔數的十分之一。集羣數據量小,在相同的集羣部署規模下,備集羣的性能要優於主集羣。

然而在線上真實場景中,線上大部分查詢流量也來源於熱點數據,因此用備集羣來承載這些熱點數據的查詢,而備集羣也慢慢演變成一個熱數據集羣。以前的主集羣存儲的是全量數據,用該集羣來支撐剩餘較小部分的查詢流量,這部分查詢主要是須要搜索全量訂單的特殊場景查詢以及訂單中心繫統內部查詢等,而主集羣也慢慢演變成一個冷數據集羣。

同時備集羣增長一鍵降級到主集羣的功能,兩個集羣地位同等重要,但均可以各自降級到另外一個集羣。雙寫策略也優化爲:假設有AB集羣,正常同步方式寫主(A集羣)異步方式寫備(B集羣)。A集羣發生異常時,同步寫B集羣(主),異步寫A集羣(備)。

MySQL用得好好的,爲何要轉ES?

 

ES 訂單數據的同步方案

MySQL數據同步到ES中,大體總結能夠分爲兩種方案:

  • 方案1:監聽MySQL的Binlog,分析Binlog將數據同步到ES集羣中。
  • 方案2:直接經過ES API將數據寫入到ES集羣中。

考慮到訂單系統ES服務的業務特殊性,對於訂單數據的實時性較高,顯然監聽Binlog的方式至關於異步同步,有可能會產生較大的延時性。且方案1實質上跟方案2相似,但又引入了新的系統,維護成本也增高。因此訂單中心ES採用了直接經過ES API寫入訂單數據的方式,該方式簡潔靈活,可以很好的知足訂單中心數據同步到ES的需求。

因爲ES訂單數據的同步採用的是在業務中寫入的方式,當新建或更新文檔發生異常時,若是重試勢必會影響業務正常操做的響應時間。

因此每次業務操做只更新一次ES,若是發生錯誤或者異常,在數據庫中插入一條補救任務,有Worker任務會實時地掃這些數據,以數據庫訂單數據爲基準來再次更新ES數據。經過此種補償機制,來保證ES數據與數據庫訂單數據的最終一致性。

遇到的一些坑

一、實時性要求高的查詢走DB

對於ES寫入機制的有了解的同窗可能會知道,新增的文檔會被收集到Indexing Buffer,而後寫入到文件系統緩存中,到了文件系統緩存中就能夠像其餘的文件同樣被索引到。

然而默認狀況文檔從Indexing Buffer到文件系統緩存(即Refresh操做)是每秒分片自動刷新,因此這就是咱們說ES是近實時搜索而非實時的緣由:文檔的變化並非當即對搜索可見,但會在一秒以內變爲可見。

當前訂單系統ES採用的是默認Refresh配置,故對於那些訂單數據實時性比較高的業務,直接走數據庫查詢,保證數據的準確性。

MySQL用得好好的,爲何要轉ES?

 

二、避免深分頁查詢

ES集羣的分頁查詢支持from和size參數,查詢的時候,每一個分片必須構造一個長度爲from+size的優先隊列,而後回傳到網關節點,網關節點再對這些優先隊列進行排序找到正確的size個文檔。

假設在一個有6個主分片的索引中,from爲10000,size爲10,每一個分片必須產生10010個結果,在網關節點中匯聚合併60060個結果,最終找到符合要求的10個文檔。

因而可知,當from足夠大的時候,就算不發生OOM,也會影響到CPU和帶寬等,從而影響到整個集羣的性能。因此應該避免深分頁查詢,儘可能不去使用。

三、FieldData與Doc Values

FieldData

線上查詢出現偶爾超時的狀況,經過調試查詢語句,定位到是跟排序有關係。排序在es1.x版本使用的是FieldData結構,FieldData佔用的是JVM Heap內存,JVM內存是有限,對於FieldData Cache會設定一個閾值。

若是空間不足時,使用最久未使用(LRU)算法移除FieldData,同時加載新的FieldData Cache,加載的過程須要消耗系統資源,且耗時很大。因此致使這個查詢的響應時間暴漲,甚至影響整個集羣的性能。針對這種問題,解決方式是採用Doc Values。

Doc Values

Doc Values是一種列式的數據存儲結構,跟FieldData很相似,但其存儲位置是在Lucene文件中,即不會佔用JVM Heap。隨着ES版本的迭代,Doc Values比FieldData更加穩定,Doc Values在2.x起爲默認設置。

總結

架構的快速迭代源於業務的快速發展,正是因爲近幾年到家業務的高速發展,訂單中心的架構也不斷優化升級。而架構方案沒有最好的,只有最合適的,相信再過幾年,訂單中心的架構又將是另外一個面貌,但吞吐量更大,性能更好,穩定性更強,將是訂單中心繫統永遠的追求。

相關文章
相關標籤/搜索