前言
Kenna 是一家網絡設備安全管理公司。這家公司通過收集客戶公司的網絡設備的漏洞數據,進行特征分析和風險識別,幫助其客戶識別優先級最高的安全風險,并通知客戶快速解決。網絡設備及安全漏洞的原始數據存儲在MySQL里面,用于分析的數據被抽取并存儲在了ES中,如下圖:
問題
在2015年,Kenna的ES中集群存儲了5億個documents,其中有每天參與計算處理的document個數為1百萬。在那時,這樣的處理能力已經是該ES集群所能處理的上限了,已經無法勝任更大的數據規模的處理需求了。經過Kenna的工程師的性能優化,ES集群存儲40億個docment的情況下,每天可以處理超過2億的docment。下面看看他們是怎么從Index、Search兩方面做性能優化的。
Index(寫)調優
前面已經提到,需要從MySQL的原始表里面抽取并存儲到Index,而MySQL的原始數據也是經常在變化的,所以快速寫入ES、以保持ES和MySQL的數據及時同步也是很重要的。Kenna的工程師主要是下面幾個方面優化來提高寫入的速度:
1.調整索引的刷新間隔
該參數缺省是1s,強制ES每秒創建一個新segment,從而保證新寫入的數據近實時的可見、可被搜索到。在Kenna,該參數被調整為30s,降低了刷新的次數,把刷新操作消耗的系統資源釋放出來給index操作使用。
PUT /my_index/_settings
{
?"index" : {
??? ??"refresh_interval": "30s"
????}
}
這種方案以犧牲可見性的方式,提高了index操作的性能。
2.批處理
批處理把多個index操作請求合并到一個batch中去處理,和mysql的jdbc的bacth有類似之處。如圖:
Kenna的場景中,每批1000個documents是一個性能比較好的size。每批中多少document條數合適,受很多因素影響而不同,如單個document的大小等。ES官網建議通過在單個node、單個shard做性能基準測試來確定這個參數的最優值。
批處理方案幫助Kenna撐過了一年的數據增長。到了后期,ES又出現了index操作的性能問題。在index操作的高峰時段,node的CPU超負荷運轉、并出現了一堆429(TOO_MANY_RWQUEST)的錯誤。
3.Document的路由處理
當對一批中的documents進行index操作時,該批index操作所需的線程的個數由要寫入的目的shard的個數決定。看下圖:
上圖中,有2批documents寫入ES, 每批都需要寫入4個shard,所以總共需要8個線程。如果能減少shard的個數,那么耗費的線程個數也會減少。例如下圖,兩批中每批目的shard個數都只有2個,總共線程消耗個數4個,減少一半。
值得注意的是線程數雖然降低了,但是單批的處理耗時可能增加了。和提高刷新間隔方法類似,這有可能會延長數據不見的時間。
Search(讀)調優
在存儲的Document條數超過10億條后,我們看看Kenna工程師如何進行搜索調優的。
1.數據分組
很多人拿ES用來存儲日志,日志的索引管理方式一般基于日期的,基于天、周、月、年建索引。如下圖,基于天建索引:
當搜索單天的數據,只需要查詢一個索引的shards就可以。當需要查詢多天的數據時,需要查詢多個索引的shards。這種方案其實和數據庫的分表、分庫、分區查詢方案相比,思路類似,小數據范圍查詢而不是大海撈針。
Kenna一開始的方案是建一個index,當數據量增大的時候,就擴容增加index的shard的個數。當shards增大時,要搜索的shards個數也隨之顯著上升。
基于數據分組的思路,Kenna基于client進行數據分組,每一個client只需依賴自己的index的數據shards進行搜索,而不是所有的數據shards,大大提高了搜索的性能,如下圖:
2.使用Filter替代Query
在搜索時候使用Query,需要為Document的相關度打分。使用Filter,沒有打分環節處理,做的事情更少,而且filter理論上更快一些。
如果搜索不需要打分,可以直接使用filter查詢。如果部分搜索需要打分,建議使用'bool'查詢。這種方式可以把打分的查詢和不打分的查詢混在一起使用,如:
GET /_search
{
??"query": {
? ?? "bool" : {
? ? ?? "must" : {
? ? ?? ?"term" : { "user" : "kimchy" }
? ? ?? },
? ? ?? "filter": {
? ? ?? ?"term" : { "tag" : "tech" }
? ?? ? }
? ? ? }
? ? }
}
3.ID字段定義為Keywords
一般情況,如果ID字段不會被用作Range 類型搜索字段,都可以定義成keywords類型。這是因為keywords會被優化,以便進行terms查詢。Integers等數字類的mapping類型,會被優化來進行range類型搜索。
Kenna在將integers改成Keywords類型之后,搜索性能提升了30%。
4.別讓用戶的無約束的輸入拖累了ES集群的性能
Kenan的工程師通過監控發現所有node的CPU 使用及其負載突然異常飆高。通過對Slow Logs分析發現,用戶查詢輸入的條件中夾帶了很多'OR'語句以及通配符“*”開頭的字符串,如下圖
為了不讓用戶無約束的查詢語句拖累ES集群的查詢性能,可以限制用戶用來查詢的keywords。對于可以用來查詢的keyworkds,也可以寫成文檔來幫助用戶更正確的使用。