Elasticsearch 效率優化 (1)
現在使用 Kubernetes 容器架構,搭配了 elk 做為我們的 logging solution。 但是目前使用預設的配置,在搜尋 log 時效率很慢。 這邊紀錄排查 index 的狀況,並且嘗試做改善。
思路
- 先確認目前 index 狀況,評估可以優化的部分。
 - 新建兩個 index,分別為原本的設定 test-old;調整過後的設定 test-new。
 - 從舊有的 index 中抓出 n 筆資料,分邊寫入新建的兩的 index。
 - 比較兩個 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 的部分如下:
- 移除不必要的屬性。
 - 不需要動態配置 index 結構,使用 
dynamic: false。 - 配置正確的欄位資料型態。
 - Index 改為一個環境一個,並配置 ilm 的 rollover 配置。
 - 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 效率
| record | old time | old size | new time | new size | 
|---|---|---|---|---|
| 1 | 1049 ms | 23.8 kB | 669 ms | 22.7 kB | 
| 2 | 1321 ms | 24.0 kB | 907 ms | 22.6 kB | 
| 3 | 1414 ms | 24.0 kB | 728 ms | 22.6 kB | 
| 4 | 1818 ms | 23.9 kB | 932 ms | 22.8 kB | 
| 5 | 1302 ms | 23.8 kB | 641 ms | 22.8 kB | 
| 6 | 1620 ms | 23.8 kB | 685 ms | 22.8 kB | 
| 7 | 1505 ms | 23.8 kB | 686 ms | 22.7 kB | 
| 7 | 1505 ms | 23.8 kB | 908 ms | 22.6 kB | 
| 8 | 1334 ms | 23.9 kB | 794 ms | 22.9 kB | 
| 9 | 1535 ms | 23.9 kB | 831 ms | 22.7 kB | 
| 10 | 1479 ms | 23.8 kB | 889 ms | 22.7 kB | 
這邊比較結果,效率提升約 183%。
- 舊的 index 花費時間平均為 sum(old time) / 10 = 1588.2
 - 新的 index 花費時間平均為 sum(new time) / 10 = 867
 
補充
clone index
確認目前 index 的 setting 狀況,確認有沒有 index.blocks.write 為 true 的設定。
1GET /kubernetes-prod-2021.06.02/_settings
若沒有就配置 index.blocks.write 為 true,如果要移除則設定為 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.02 為 old
1POST /kubernetes-prod-2021.06.02/_clone/old