Elasticsearch 在訂單場景的應(yīng)用

一、背景

公司業(yè)務(wù)訂單數(shù)據(jù)增量大概在 4 億每月允蜈,訂單在數(shù)據(jù)庫中存量保存 3 個月數(shù)據(jù),一共 12 億文檔 1 TB 數(shù)據(jù)鹅髓。平時讀 QPS 在 2500 左右,寫 QPS 在 1000 左右京景,訂單寫入為單條寫入方式,查詢?yōu)楦鶕?jù)訂單 ID 查詢骗奖。遷移 ES 之前确徙,數(shù)據(jù)存放在 MongoDB 中醒串,以主備方式部署,機器配置 16 核 128 g鄙皇,2 * 1.6 t 本地 SSD芜赌。在寫入 QPS 在 3、400 時伴逸,MongoDB 的負載還算正常缠沈,一旦寫入 QPS 增高時,MongoDB 負載飆升错蝴,一直處于較高狀態(tài)洲愤,比較危險。為了解決該問題顷锰,我們打算替換存儲系統(tǒng)柬赐,經(jīng)過多方考慮,我們選擇了 Elasticsearch官紫。

二肛宋、Elasticsearch 壓測

為了驗證 Elasticsearch 在訂單場景下的性能表現(xiàn),我們對 Elasticsearch 進行了壓測束世。測試數(shù)據(jù)為線上訂單數(shù)據(jù)酝陈,導(dǎo)入 6 億條數(shù)據(jù)(250g)。機器配置 16 核 128 g毁涉,2 * 16 t 本地 SSD后添,機器規(guī)模 3 節(jié)點 ,分配 31 g 堆內(nèi)存薪丁,其余內(nèi)存留給操作系統(tǒng)遇西。Elasticsearch 版本為 7.5.2,Index 設(shè)置如下:

settings" : {
      "index" : {
        "codec" : "best_compression",
        "refresh_interval" : "5s",
        "number_of_shards" : "24",
        "number_of_replicas" : "1",
        "translog" : {
          "sync_interval" : "5s",
          "durability" : "async"
        }
      }
    }

由于支持實時查詢訂單數(shù)據(jù)严嗜,因此我們使用 ES 的 GET Api粱檀,以訂單 ID 作為 docid。主要測試 GET 和 單條 INSERT 的性能漫玄。
GET-測試結(jié)果

并發(fā)數(shù) 總操作數(shù) QPS 平均延時(ms) 平均 CPU 使用率 1m_load
8 100000 6697 1.2 200% 0.75
16 200000 11264 1.4 330% 1.03
32 500000 17852 1.8 560% 1.92
64 1000000 21308 2.6 710% 4.51
128 2000000 21112 6.2 730% 5.26

從上面的結(jié)果可以看出茄蚯,ES 的 Get 性能表現(xiàn)很好,隨著并發(fā)數(shù)的增加睦优,qps 基本保持成倍增加渗常。當(dāng)并發(fā)數(shù)達到 64 時,測試機器的 cpu 負載基本跑滿汗盘,導(dǎo)致 ES 性能壓不上去皱碘,可以預(yù)計 ES 的 Get 性能還有很大的上升空間。

INSERT(以 orderid 作為 docid 寫入)-測試結(jié)果

并發(fā)數(shù) 總操作數(shù) QPS 平均延時(ms) 平均 CPU 使用率 1m_load
8 100000 4101 1.9 210% 0.91
16 200000 7369 2.1 636% 1.92
32 500000 10590 3.1 960% 3.66
64 1000000 12525 5.0 1100% 11.01
128 2000000 13826 9.2 1200% 16.09
256 2000000 13816 18 1300% 19.00

從上述結(jié)果可以看出隐孽,插入 QPS 達到 13826 左右癌椿,機器性能達到瓶頸健蕊。

總體來看,ES 的性能表現(xiàn)良好踢俄,足以滿足我們的業(yè)務(wù)需求缩功。

三、線上使用及踩坑

經(jīng)過壓測后都办,我們已經(jīng)確定 ES 的性能能夠很好的滿足業(yè)務(wù)需求嫡锌,于是果斷將數(shù)據(jù)從 MongoDB 遷移到 Elasticsearch,并將查詢切到 ES琳钉。本以為可以愉快地使用 Elasticsearch 來做訂單查詢了势木,但是一看監(jiān)控,發(fā)現(xiàn) ES 的負載很高槽卫,和 MongoDB 對比起來沒啥優(yōu)勢跟压,而且和測試結(jié)果出入很大。百思不得其解歼培,于是通過 GET _nodes/hot_threads 查看線程堆棧震蒋,如下:

75.4% (377.2ms out of 500ms) cpu usage by thread 'elasticsearch[node-1][get][T#14]'
     3/10 snapshots sharing following 42 elements
       app//org.apache.lucene.codecs.lucene80.IndexedDISI.advance(IndexedDISI.java:384)
       app//org.apache.lucene.codecs.lucene80.IndexedDISI.nextDoc(IndexedDISI.java:459)
       app//org.apache.lucene.codecs.lucene80.Lucene80DocValuesProducer$SparseNumericDocValues.nextDoc(Lucene80DocValuesProducer.java:429)
       app//org.apache.lucene.index.ReadersAndUpdates$MergedDocValues.nextDoc(ReadersAndUpdates.java:469)
       app//org.apache.lucene.index.ReadersAndUpdates$2$1.nextDoc(ReadersAndUpdates.java:396)
       app//org.apache.lucene.index.SingletonSortedNumericDocValues.nextDoc(SingletonSortedNumericDocValues.java:53)
       app//org.apache.lucene.codecs.lucene80.Lucene80DocValuesConsumer.writeValues(Lucene80DocValuesConsumer.java:161)
       app//org.apache.lucene.codecs.lucene80.Lucene80DocValuesConsumer.addNumericField(Lucene80DocValuesConsumer.java:111)
       app//org.apache.lucene.codecs.perfield.PerFieldDocValuesFormat$FieldsWriter.addNumericField(PerFieldDocValuesFormat.java:109)
       app//org.apache.lucene.index.ReadersAndUpdates.handleDVUpdates(ReadersAndUpdates.java:373)
       app//org.apache.lucene.index.ReadersAndUpdates.writeFieldUpdates(ReadersAndUpdates.java:577)
       app//org.apache.lucene.index.ReaderPool.writeAllDocValuesUpdates(ReaderPool.java:230)
       app//org.apache.lucene.index.IndexWriter.writeReaderPool(IndexWriter.java:3311)
       app//org.apache.lucene.index.IndexWriter.getReader(IndexWriter.java:520)
       app//org.apache.lucene.index.StandardDirectoryReader.doOpenFromWriter(StandardDirectoryReader.java:297)
       app//org.apache.lucene.index.StandardDirectoryReader.doOpenIfChanged(StandardDirectoryReader.java:272)
       app//org.apache.lucene.index.StandardDirectoryReader.doOpenIfChanged(StandardDirectoryReader.java:262)
       app//org.apache.lucene.index.FilterDirectoryReader.doOpenIfChanged(FilterDirectoryReader.java:112)
       app//org.apache.lucene.index.DirectoryReader.openIfChanged(DirectoryReader.java:165)
       app//org.elasticsearch.index.engine.ElasticsearchReaderManager.refreshIfNeeded(ElasticsearchReaderManager.java:66)
       app//org.elasticsearch.index.engine.ElasticsearchReaderManager.refreshIfNeeded(ElasticsearchReaderManager.java:40)
       app//org.apache.lucene.search.ReferenceManager.doMaybeRefresh(ReferenceManager.java:176)
       app//org.apache.lucene.search.ReferenceManager.maybeRefreshBlocking(ReferenceManager.java:253)
       app//org.elasticsearch.index.engine.InternalEngine.refresh(InternalEngine.java:1603)
       app//org.elasticsearch.index.engine.InternalEngine.refreshIfNeeded(InternalEngine.java:2744)
       app//org.elasticsearch.index.engine.InternalEngine.get(InternalEngine.java:698)
       app//org.elasticsearch.index.shard.IndexShard.get(IndexShard.java:943)
       app//org.elasticsearch.index.get.ShardGetService.innerGet(ShardGetService.java:169)
       app//org.elasticsearch.index.get.ShardGetService.get(ShardGetService.java:93)
       app//org.elasticsearch.index.get.ShardGetService.get(ShardGetService.java:84)
       app//org.elasticsearch.action.get.TransportGetAction.shardOperation(TransportGetAction.java:106)
       app//org.elasticsearch.action.get.TransportGetAction.shardOperation(TransportGetAction.java:45)
       ... ...

上面是GET 線程的堆棧信息,這里我們看到 GET Api 觸發(fā)了 refresh 操作躲庄,而 refresh 又是一個比較耗的動作查剖,看到這里我們可以確定導(dǎo)致負載高的原因大概率是 refresh 導(dǎo)致。那為什么會觸發(fā) refresh 呢噪窘?帶著疑問笋庄,理了下 Elasticsearch-7.5.2 的源碼,總結(jié)了下 GET Api 的大體流程如下:


GET 流程

從上圖可以看到倔监,ES 為了 GET 能夠?qū)崟r獲取最新數(shù)據(jù)直砂,會判斷文檔是否有 refresh(只有 refresh 后才能被檢索),如果文檔已經(jīng) refresh 便直接從 index 獲取浩习,否則執(zhí)行 refresh 強制刷新静暂,然后再從 index 查詢。結(jié)合 GET 流程谱秽,再分析我們的業(yè)務(wù)場景洽蛀,我們的訂單一般都是寫入后會立刻查詢,因此大部分情況下文檔還未 refresh 便進行檢索疟赊,導(dǎo)致出現(xiàn)大量的 refresh 操作郊供,消耗性能。

問題定位到了近哟,但是該如何解決呢驮审?首先想到的是官方最新版本是否有優(yōu)化,于是查看 7.x 的 release note,很幸運头岔,發(fā)現(xiàn)確實有優(yōu)化:


release note

我們可以看到從 7.6 開始塔拳,ES 的 GET 流程改為首先從 translog 中讀取數(shù)據(jù)鼠证,如果沒有則讀取 index峡竣,這樣避免了 refresh 的開銷,性能明顯提升量九。

于是果斷決定升級版本到 7.6.2适掰,測試效果,如下:


image.png

可以看到荠列,升級后类浪,系統(tǒng)負載明顯下降,效果非常明顯肌似。目前線上訂單已成功遷移至 ES费就,并穩(wěn)定運行提供服務(wù)。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末川队,一起剝皮案震驚了整個濱河市力细,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌固额,老刑警劉巖眠蚂,帶你破解...
    沈念sama閱讀 218,682評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異斗躏,居然都是意外死亡逝慧,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,277評論 3 395
  • 文/潘曉璐 我一進店門啄糙,熙熙樓的掌柜王于貴愁眉苦臉地迎上來笛臣,“玉大人,你說我怎么就攤上這事隧饼∩虮ぃ” “怎么了?”我有些...
    開封第一講書人閱讀 165,083評論 0 355
  • 文/不壞的土叔 我叫張陵桑李,是天一觀的道長踱蛀。 經(jīng)常有香客問我,道長贵白,這世上最難降的妖魔是什么率拒? 我笑而不...
    開封第一講書人閱讀 58,763評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮禁荒,結(jié)果婚禮上猬膨,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好勃痴,可當(dāng)我...
    茶點故事閱讀 67,785評論 6 392
  • 文/花漫 我一把揭開白布谒所。 她就那樣靜靜地躺著,像睡著了一般沛申。 火紅的嫁衣襯著肌膚如雪劣领。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,624評論 1 305
  • 那天铁材,我揣著相機與錄音尖淘,去河邊找鬼。 笑死著觉,一個胖子當(dāng)著我的面吹牛村生,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播饼丘,決...
    沈念sama閱讀 40,358評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼趁桃,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了肄鸽?” 一聲冷哼從身側(cè)響起卫病,我...
    開封第一講書人閱讀 39,261評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎贴捡,沒想到半個月后忽肛,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,722評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡烂斋,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年屹逛,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片汛骂。...
    茶點故事閱讀 40,030評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡罕模,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出帘瞭,到底是詐尸還是另有隱情淑掌,我是刑警寧澤,帶...
    沈念sama閱讀 35,737評論 5 346
  • 正文 年R本政府宣布蝶念,位于F島的核電站抛腕,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏媒殉。R本人自食惡果不足惜担敌,卻給世界環(huán)境...
    茶點故事閱讀 41,360評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望廷蓉。 院中可真熱鬧全封,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,941評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至土匀,卻和暖如春子房,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背恒削。 一陣腳步聲響...
    開封第一講書人閱讀 33,057評論 1 270
  • 我被黑心中介騙來泰國打工池颈, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留尾序,地道東北人钓丰。 一個月前我還...
    沈念sama閱讀 48,237評論 3 371
  • 正文 我出身青樓,卻偏偏與公主長得像每币,于是被迫代替她去往敵國和親携丁。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,976評論 2 355