Elasticsearch 效率優化 (1)

現在使用 Kubernetes 容器架構,搭配了 elk 做為我們的 logging solution。但是目前使用預設的配置,在搜尋 log 時效率很慢。 這邊紀錄排查 index 的狀況,並且嘗試做改善。

思路

  1. 先確認目前 index 狀況,考量可以優化的部分。
  2. 新建兩個 index,分別為原本的設定 test-old;調整過後的設定 test-new。
  3. 從舊有的 index 中抓出 n 筆資料,分邊寫入新建的兩的 index。
  4. 比較兩個 index 效率。

先確認目前 index 狀況,考量可以優化的部分

Index 的設定:可以看到第 9、13、27 行被折疊了大量的行數,也就是說我們使用了很多不必要的欄位。

1GET /kubernetes-prod
 1  0 {
 2  1   "kubernetes-prod" : {
 3  2     "aliases" : { },
 4  3     "mappings" : {
 5  4       "_meta" : {
 6  5         "beat" : "filebeat",
 7  6         "version" : "7.9.1"
 8  7       },
 9  8       "dynamic_templates" : [
10  9 +-----132 lines: {································
11 10       ],
12 11       "date_detection" : false,
13 12       "properties" : {
14 13 +-----20620 lines: "@timestamp" : {···············
15 14       }
16 15     },
17 16     "settings" : {
18 17       "index" : {
19 18         "mapping" : {
20 19           "total_fields" : {
21 20             "limit" : "10000"
22 21           }
23 22         },
24 23         "refresh_interval" : "5s",
25 24         "provided_name" : "kubernetes-prod",
26 25         "query" : {
27 26           "default_field" : [
28 27 +-------875 lines: "message",······················
29 28           ]
30 29         },
31 30         "creation_date" : "1623044585326",
32 31         "priority" : "100",
33 32         "number_of_replicas" : "0",
34 33         "uuid" : "uuid",
35 34         "version" : {
36 35           "created" : "7100099"
37 36         },
38 37         "lifecycle" : {
39 38           "name" : "kubernetes-prod",
40 39           "rollover_alias" : "kubernetes-prod"
41 40         },
42 41         "routing" : {
43 42           "allocation" : {
44 43             "include" : {
45 44               "_tier_preference" : "data_content"
46 45             }
47 46           }
48 47         },
49 48         "number_of_shards" : "1",
50 49         "max_docvalue_fields_search" : "200"
51 50       }
52 51     }
53 52   }
54 53 }

Index lifecycle policies 的配置:原本 index 設計為 一天一個 index,ilm 的部分規則就是 60 天後刪除。這部分 index 太零散。

1GET _ilm/policy/kubernetes-prod
 1{
 2  "kubernetes-prod" : {
 3    "version" : 1,
 4    "modified_date" : "2021-02-01T12:37:13.306Z",
 5    "policy" : {
 6      "phases" : {
 7        "hot" : {
 8          "min_age" : "0ms",
 9          "actions" : {
10            "set_priority" : {
11              "priority" : 100
12            }
13          }
14        },
15        "delete" : {
16          "min_age" : "60d",
17          "actions" : {
18            "delete" : {
19              "delete_searchable_snapshot" : true
20            }
21          }
22        }
23      }
24    }
25  }
26}

這邊預計優化 index 的部分如下:

  1. 移除不必要的屬性。
  2. 不需要動態配置 index 結構,使用 dynamic: false
  3. 配置正確的欄位資料型態。
  4. Index 改為一個環境一個,並配置 ilm 的 rollover 配置。
  5. Kibana 的 index patterns 使用 filter 處理。

新建兩個 index,分別為 test-old、test-new

test-old 的 json 檔案又臭又長,這邊就不記錄了。

1PUT /test-old
2{json}

test-new 的 json 範例檔案放在 Github 上。

1# 建立 index template
2PUT /_index_template/test-new
3{json}
4
5# 建立 index
6PUT /test-new

查看結果,可以看到 index 已經被建立,並且沒有任何 documents。

1GET _cat/indices?v&index=test*
2
3health status index    uuid                   pri rep docs.count docs.deleted store.size pri.store.size
4green  open   test-new oaQjuBzFTiKLhnzPpm6bXQ   1   0          0            0       208b           208b
5green  open   test-old iMNI2tWAQASzUCjYHrWB6Q   1   0          0            0       208b           208b

從舊有的 index 中抓出 n 筆資料,分邊寫入新建的兩的 index

使用 bulk 批次插入資料,注意 json 不可以斷行(資料量過多會出錯)。

1POST /test-new/_bulk
2{ "index":{} }
3{ "message" : "foo" }
4{ "index":{} }
5{ "message" : "bar" }

由於資料過多,使用 Dev Tools 出錯,改使用 curl 匯入,分別匯入 test-old、test-new。

1curl -XPOST --user elastic:password http://elasticsearch.example.com:9200/test-old/_bulk -H "Content-Type: application/json" --data-binary @/Users/chiehtinglee/tmp.json
2
3
4curl -XPOST --user elastic:password http://elasticsearch.example.com:9200/test-old/_bulk -H "Content-Type: application/json" --data-binary @/Users/chiehtinglee/tmp.json

查看是否有執行成功,這邊可以看到 docs.count 各為 1000 筆資料。

1GET _cat/indices?v&index=test*
2
3health status index    uuid                   pri rep docs.count docs.deleted store.size pri.store.size
4green  open   test-new _DvAB-_rQvKJ1lG1eWsj6Q   1   0       1000            0    210.3kb        210.3kb
5green  open   test-old iMNI2tWAQASzUCjYHrWB6Q   1   0       1000            0    210.3kb        210.3kb

比較兩個 index 效率

recordold timeold sizenew timenew size
11049 ms23.8 kB669 ms22.7 kB
21321 ms24.0 kB907 ms22.6 kB
31414 ms24.0 kB728 ms22.6 kB
41818 ms23.9 kB932 ms22.8 kB
51302 ms23.8 kB641 ms22.8 kB
61620 ms23.8 kB685 ms22.8 kB
71505 ms23.8 kB686 ms22.7 kB
71505 ms23.8 kB908 ms22.6 kB
81334 ms23.9 kB794 ms22.9 kB
91535 ms23.9 kB831 ms22.7 kB
101479 ms23.8 kB889 ms22.7 kB

這邊比較結果,效率提升約 183%。

  • 舊的 index 花費時間平均為 sum(old time) / 10 = 1588.2
  • 新的 index 花費時間平均為 sum(new time) / 10 = 867

補充

clone index

確認目前 index 的 setting 狀況,確認有沒有 index.blocks.writetrue 的設定。

1GET /kubernetes-prod-2021.06.02/_settings

若沒有就配置 index.blocks.writetrue,如果要移除則設定為 null

1PUT /kubernetes-prod-2021.06.02/_settings
2{
3  "settings": {
4    "index.blocks.write": true # null
5  }
6}

執行 clone index kubernetes-prod-2021.06.02old

1POST /kubernetes-prod-2021.06.02/_clone/old
comments powered by Disqus