Elasticsearch性能調優之搜索性能優化

magic,如果真的要優化搜索性能的話,就是以下幾種辦法

1/5,配合起來,就是搜索性能優化的殺手鐗
3/4,配合起來,解決各種複雜的搜索需求的性能

1、給filesysgtem cache更多的內存

es的搜索引擎嚴重依賴於底層的filesystem cache,你如果給filesystem cache更多的內存,儘量讓內存可以容納所有的indx segment file索引數據文件,那麼你搜索的時候就基本都是走內存的,性能會非常高。

比如說,你,es節點有3臺機器,每臺機器,看起來內存很多,64G,總內存,64 * 3

每臺機器給es jvm heap是32G,那麼剩下來留給filesystem cache的就是每臺機器才32g,總共集羣裏給filesystem cache的就是32 * 3 = 96gb內存

如果你此時,你整個,磁盤上索引數據文件,在3臺機器上,一共佔用了1T的磁盤容量,你的es數據量是1t

你覺得你的性能能好嗎?filesystem cache的內存才100g,十分之一的數據可以放內存,其他的都在磁盤,然後你執行搜索操作,大部分操作都是走磁盤,性能肯定差

歸根結底,你要讓es性能要好,最佳的情況下,就是你的機器的內存,至少可以容納你的總數據量的一半

比如說,你一共要在es中存儲1T的數據,那麼你的多臺機器留個filesystem cache的內存加起來綜合,至少要到512G,至少半數的情況下,搜索是走內存的,性能一般可以到幾秒鐘,2秒,3秒,5秒

如果最佳的情況下,我們自己的生產環境實踐經驗,最好是用es就存少量的數據,就是你要用來搜索的那些索引,內存留給filesystem cache的,就100G,那麼你就控制在100gb以內,相當於是,你的數據幾乎全部走內存來搜索,性能非常之高,一般可以在1秒以內

儘量在es裏,就存儲必須用來搜索的數據,比如說你現在有一份數據,有100個字段,其實用來搜索的只有10個字段,建議是將10個字段的數據,存入es,剩下90個字段的數據,可以放mysql,hadoop hbase,都可以

這樣的話,es數據量很少,10個字段的數據,都可以放內存,就用來搜索,搜索出來一些id,通過id去mysql,hbase裏面去查詢明細的數據

2、用更快的硬件資源

(1)給filesystem cache更多的內存資源
(2)用SSD固態硬盤
(3)使用本地存儲系統,不要用NFS等網絡存儲系統
(4)給更多的CPU資源

3、document模型設計

document模型設計是非常重要的,很多操作,不要在搜索的時候纔想去執行各種複雜的亂七八糟的操作。es能支持的操作就是那麼多,不要考慮用es做一些它不好操作的事情。如果真的有那種操作,儘量在document模型設計的時候,寫入的時候就完成。另外對於一些太複雜的操作,比如join,nested,parent-child搜索都要儘量避免,性能都很差的。

兩個思路,在搜索/查詢的時候,要執行一些業務強相關的特別複雜的操作:

(1)在寫入數據的時候,就設計好模型,加幾個字段,把處理好的數據寫入加的字段裏面
(2)自己用java程序封裝,es能做的,用es來做,搜索出來的數據,在java程序裏面去做,比如說我們,基於es,用java封裝一些特別複雜的操作

4、預先index data

爲了性能,提前優化data index時的數據模型,比如說document有一個price field,然後大多數查詢都對一個固定的範圍,對這個field使用range範圍查詢,那麼可以提前將這個price的範圍處理出來,寫入一個字段中。比如下面這樣:

 

PUT index/type/1
{
  "designation": "spoon",
  "price": 13
}

 

GET index/_search
{
  "aggs": {
    "price_ranges": {
      "range": {
        "field": "price",
        "ranges": [
          { "to": 10 },
          { "from": 10, "to": 100 },
          { "from": 100 }
        ]
      }
    }
  }
}

我們完全可以增加一個price_range字段:

 

PUT index
{
  "mappings": {
    "type": {
      "properties": {
        "price_range": {
          "type": "keyword"
        }
      }
    }
  }
}

然後寫入的時候,直接計算出來這個range:

 

PUT index/type/1
{
  "designation": "spoon",
  "price": 13,
  "price_range": "10-100"
}

然後搜索的時候,就可以直接用term查詢了,性能非常高:

 

GET index/_search
{
  "aggs": {
    "price_ranges": {
      "terms": {
        "field": "price_range"
      }
    }
  }
}

5、預熱filesystem cache

如果我們重啓了es,那麼filesystem cache是空殼的,就需要不斷的查詢才能重新讓filesystem cache熱起來,我們可以先說動對一些數據進行查詢。

比如說,你本來一個查詢,要用戶點擊以後才執行,才能從磁盤加載到filesystem cache裏,第一次執行要10s,以後每次就幾百毫秒

你完全可以,自己早上的時候,就程序執行那個查詢,預熱,數據就加載到filesystem cahce,程序執行的時候是10s,以後用戶真的來看的時候就才幾百毫秒

6、避免使用script腳本

說實話,一般是避免使用es script的,實際生產中更是少用,性能不高,儘量不要使用

7、使用固定範圍的日期查詢

儘量不要使用now這種內置函數來執行日期查詢,因爲默認now是到毫秒級的,是無法緩存結果,儘量使用一個階段範圍,比如now/m,就是到分鐘級

那麼如果一分鐘內,都執行這個查詢,是可以取用查詢緩存的

 

PUT index/type/1
{
  "my_date": "2016-05-11T16:30:55.328Z"
}

 

GET index/_search
{
  "query": {
    "constant_score": {
      "filter": {
        "range": {
          "my_date": {
            "gte": "now-1h",
            "lte": "now"
          }
        }
      }
    }
  }
}

完全可以替換爲:

 

GET index/_search
{
  "query": {
    "constant_score": {
      "filter": {
        "range": {
          "my_date": {
            "gte": "now-1h/m",
            "lte": "now/m"
          }
        }
      }
    }
  }
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章