天天看點

ElasticSearch Tune for search speed Translation

1.給檔案系統緩存提供更多的記憶體

es嚴重依賴檔案系統緩存來提高搜尋速度。通常,為了使es将搜尋保持在實體記憶體的熱區域中,需要確定至少一般的可用記憶體提供給檔案系統緩存

2.使用更快的硬體

如果索引速度受到I/O制約,你需要提供為檔案系統緩存提供更多的記憶體或者更新更快的硬體裝置。一般固态比機械硬碟性能更好。始終使用本地檔案系統,遠端檔案系統像NFS以及SMB都應該避免。對例如亞馬遜的EBS(elastic block storage)也要留意,es在虛拟存儲上表現更好,由于更快以及易于安裝使得它變得越來越受歡迎。但是不幸的是相比于本地存儲虛拟存儲還是有一些差距。如果你要使用EBS請注意要使用提供的IOPS否則會被限流。

如果索引速度受到CPU制約,你需要購買更快的CPU

3.文檔模組化

文檔需要模組化這樣能夠使得索引操作變得更快。

尤其是joins操作應該盡量避免,而嵌套(nested)會降低幾倍查詢速度,而父子關系(parent-child relations)查詢更會使得查詢以數百倍的速度下降。是以如果可以使用不規範的文檔而不是使用joins也能達到同樣的效果,盡量使用這些來提高速度

4.盡量使用更少的字段

query_string和multi_match的字段越多,查詢越慢。提高多字段查詢速度中普遍使用的一項技術就是将多個字段值拷貝到一個字段,查詢的時候隻需要查詢這個字段即可。這可以使用映射中的copy_to 指令來做到并且該指令不會改變文檔源,下面是一個例子

PUT movies
{
  "mappings": {
    "_doc": {
      "properties": {
        "name_and_plot": {
          "type": "text"
        },
        "name": {
          "type": "text",
          "copy_to": "name_and_plot"
        },
        "plot": {
          "type": "text",
          "copy_to": "name_and_plot"
        }
      }
    }
  }
}           
5.預索引資料

你應該使用查詢模式優化資料索引方式。例如,如果所有文檔都有price字段,并且大多數查詢都會使用固定的price 範圍查詢,那麼我們可以事先将該範圍映射到索引中來加快聚合此字段,看下面例子:

使用前:

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

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

使用後:

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

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

GET index/_search
{
  "aggs": {
    "price_ranges": {
      "terms": {
        "field": "price_range"
      }
    }
  }
}           
6.考慮将辨別符映射為關鍵字

事實上一些數值型字段并不一定會被映射為數值型,es在term的數值型範圍查詢中使用關鍵字會更好。典型的,字段存儲的例如ISBN或者來自另一個資料庫的數值型辨別符号會很少被用在範圍查詢或聚合中,這是因為将它們映射為關鍵字而不是integer或long更好。

7.避免腳本

通常情況下,腳本盡量避免使用,不得已時最好也要使用painless和expressions引擎

8.搜尋邊界資料

使用now作為日期範圍查詢一般不會被緩存這是因為now一直在變化。然而就使用者體驗而言使用邊界資料會更好,而且還有利于查詢緩存。

PUT index/_doc/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"
          }
        }
      }
    }
  }
}
           

在這個案例中我們四舍五入到分鐘,如果目前時間是16:31:29,這個查詢會查詢15:31:00到16:31:59之間的所有資料。此時如果很多使用者進行包含該範圍的查詢,查詢緩存會幫助加快速度。四舍五入的間隔越大,查詢緩存越能起到作用。但是太大範圍的四舍五入會影響使用者體驗。

我們也可以使用更大和更小的範圍來四舍五入進而提高查詢緩存效率

GET index/_search
{
  "query": {
    "constant_score": {
      "filter": {
        "bool": {
          "should": [
            {
              "range": {
                "my_date": {
                  "gte": "now-1h",
                  "lte": "now-1h/m"
                }
              }
            },
            {
              "range": {
                "my_date": {
                  "gt": "now-1h/m",
                  "lt": "now/m"
                }
              }
            },
            {
              "range": {
                "my_date": {
                  "gte": "now/m",
                  "lte": "now"
                }
              }
            }
          ]
        }
      }
    }
  }
}           

但是需要注意的是,有些情況下這種方式會适得其反,因為bool查詢(在不同的時間分段中搜尋)帶來的開銷可能會超過查詢緩存帶來的效率。

9.合并隻讀索引

将隻讀索引合并到單個分片中會更好,這種情況在時間索引中尤為明顯,因為隻有目前時間的索引才會需要寫入,過時的索引隻需要隻讀狀态。

注意:對于需要寫入的索引不要将其合并,另外合并可以作為一個背景程序運作

10.備份全球序數

全球序數是一個作為關鍵字段被用于terms聚合的資料結構。由于es并不知道哪些字段會被用于terms聚合以及哪些字段不會被用于terms聚合,是以它們一般是被懶加載到記憶體中。那麼你可以使用es在重新整理時間通過配置映射來指定某個屬性是否被es以全球序數的饑渴狀态來加載

PUT index
{
  "mappings": {
    "_doc": {
      "properties": {
        "foo": {
          "type": "keyword",
          "eager_global_ordinals": true
        }
      }
    }
  }
}           
11.備份檔案系統緩存

如果機器重新開機,檔案系統緩存會被清空。這會導緻作業系統加載索引到熱區域之前話費一定的時間。你可以通過index.store.preload配置指定哪些被馬上緩存到記憶體中

注意:如果檔案系統緩存不足以裝下所有的索引資料,立馬加載大量資料到檔案系統緩存中會導緻查詢變慢。

12.使用索引排序加快連接配接速度

索引排序會犧牲較少的索引速度來加快連接配接速度

13.使用preference來優化緩存使用率

有很多可以提高查詢性能的緩存,例如檔案系統緩存,請求緩存或者查詢緩存。目前這些緩存都是節點級别的,這意味着連續發送兩個相同的請求,在1個或多個副本的情況下,使用round-robin分布式負載均衡政策以及預設的算法,這兩個請求會被路由到不同的分片,這會導緻節點級别的緩存無法起到作用。

因為對于使用者來說一個接一個發送相同請求是很普遍的,是以為了分析索引的較窄子集,使用辨別目前使用者或會話的偏好值可以幫助優化高速緩存的使用

14.複制可以幫助提高高吞吐但是有條件的

一個節點上分片越少也就意味着為該分片配置設定的記憶體越多進而提高吞吐的能力,但是這是以犧牲高可用為前提的,因為缺少了副本分片作為災備。在這兩者之間最好保持平衡,副本分片的最優數量一般是

max(max_failures, ceil(num_nodes / num_primaries) - 1) max_failures:每次最多有這麼多節點去處理失敗。具體見官網

15.打開自适應副本選擇

當存在多個副本分片時,es會使用一組稱為自适應副本選擇的标準,根據包含每個分片副本的節點的響應時間,服務時間和隊列大小來選擇最佳資料副本。這可以提高查詢吞吐量并減少搜尋量大的程式的延遲