1.背景
??????12月9日,PIS針對地震多報問題,做了一次緊急需求迭代隘竭,然而在上線驗證過程中,測試同學使用多臺手機接收app push定踱,卻并沒有按照預期全部接收到地震預警。排查日志恃鞋,發(fā)現(xiàn)如下報錯:
??????該報警是在分頁查詢ES中查詢滿足push條件的用戶時崖媚,由ES報錯觸發(fā)的。從報警信息中不難看出恤浪,ES中有對分頁大小限制的“閾值”至扰,恰好某次分頁查詢超出了這個“閾值”,導致報錯资锰。
2.原因
帶著這個疑問,查閱相關(guān)資料:
elasticsearch深度分頁問題: https://www.cnblogs.com/hello-shf/p/11543453.html
es 默認采用的分頁方式是 from+ size 的形式阶祭,在深度分頁的情況下绷杜,這種使用方式效率是非常低的:
ElasticSearch在分布式系統(tǒng)中的深度分頁
???????理解為什么深度分頁是有問題的,我們可以假設(shè)在一個有 4 個主分片的索引中搜索濒募。 當我們請求結(jié)果的第一頁(結(jié)果從 1 到 10 )鞭盟,每一個分片產(chǎn)生前 10 的結(jié)果,并且返回給 協(xié)調(diào)節(jié)點 瑰剃,協(xié)調(diào)節(jié)點對 40 個結(jié)果排序得到全部結(jié)果的前 10 個齿诉。
??????現(xiàn)在假設(shè)我們請求第 990 頁--結(jié)果從 990 到 1000 。所有都以相同的方式工作除了每個分片不得不產(chǎn)生前1000個結(jié)果以外晌姚。 然后協(xié)調(diào)節(jié)點對全部 4000 個結(jié)果排序最后丟棄掉這些結(jié)果中的 3990 個結(jié)果粤剧。
??????可以看到,在分布式系統(tǒng)中挥唠,對結(jié)果排序的成本隨分頁的深度成指數(shù)上升抵恋。這就是 web 搜索引擎對任何查詢都不要返回超過 10000 個結(jié)果的原因。
[圖片上傳中...(image-3fed2-1585304297229-0)]
??????很顯然宝磨,這次ES報錯弧关,也是由于當前的分頁窗口查詢到第5000條及以后的數(shù)據(jù)時盅安,數(shù)據(jù)大小超出了5000這個系統(tǒng)參數(shù)配置,導致報錯并觸發(fā)app push失敗世囊。
??????事實也的確是這樣的别瞭,本次觸發(fā)報錯的模擬地震數(shù)據(jù)如下:
震中位置 經(jīng)度:114.72 維度:41.15
預警等級:4.8
震源深度:8
影響用戶:51770(條件:烈度大于1)
??????由于影響用戶已經(jīng)超出了50000,并且max_result_window這個參數(shù)配置為50000株憾,當分頁查詢50000條之后的數(shù)據(jù)時蝙寨,ES拋出異常。最直接的影響就是号胚,按照目前的配置籽慢,最多能為50000用戶發(fā)送push...
{
"index": {
"max_result_window": 50000 }
}
3.解決辦法
??????很顯然,單純的調(diào)大 max_result_window這個參數(shù)并不滿足系統(tǒng)的可擴展猫胁,可維護性箱亿,因為誰也不能保證一次真實的地震影響的用戶數(shù)量是否在這個范圍之內(nèi)。
??????ES提供了Search After這種查詢方式弃秆,有效的解決了上面的問題:
Search After
??????實時獲取下一頁文檔信息
- 不支持指定頁數(shù)
- 只能往下翻
??????假設(shè)Size 10,當查詢990-1000届惋,它通過唯一排序值定位,將每次要處理的文檔數(shù)都控制在10菠赚。
??????search_after 是一種假分頁方式脑豹,根據(jù)上一頁的最后一條數(shù)據(jù)來確定下一頁的位置,同時在分頁請求的過程中衡查,如果有索引數(shù)據(jù)的增刪改查瘩欺,這些變更也會實時的反映到游標上。為了找到每一頁最后一條數(shù)據(jù)拌牲,每個文檔必須有一個全局唯一值俱饿,官方推薦使用 _uid 作為全局唯一值,但是只要能表示其唯一性就可以塌忽。
4.其他
??????還有一種scrll方式拍埠,但是使用的是數(shù)據(jù)快照,不能滿足實時查詢的需求土居,這里不做討論枣购。
分頁方式對比
分頁方式 | 性能 | 優(yōu)點 | 缺點 | 場景 | |
---|---|---|---|---|---|
from + size | 低 | 靈活性好,實現(xiàn)簡單 | 深度分頁問題 | 數(shù)據(jù)量比較小擦耀,能容忍深度分頁問題 | |
scroll | 中 | 解決了深度分頁問題 | 無法反應(yīng)數(shù)據(jù)的實時性(快照版本)維護成本高棉圈,需要維護一個 scroll_id, | 海量數(shù)據(jù)的導出,需要查詢海量結(jié)果集的數(shù)據(jù) | |
search_after | 高 | 性能最好不存在深度分頁問題能夠反映數(shù)據(jù)的實時變更 | 實現(xiàn)復雜眷蜓,需要有一個全局唯一的字段連續(xù)分頁的實現(xiàn)會比較復雜迄损,因為每一次查詢都需要上次查詢的結(jié)果 | 海量數(shù)據(jù)的分頁 |