開發與維運

索引生命週期管理-Elastic Stack 實戰手冊

作者:趙凱

Elasticsearch 在 6.7 版本正式加入索引生命週期管理,旨在管理 Elasticsearch 中的索引。

通常我們使用 elasticsearch 的時候,index 命名都是 xxx-YYYY.MM.dd 類似這樣的格式,每天創建一個index,這需要我們自己創建 index,或者通過自動創建。

  1. 每天創建一個 index,但是每天的數據量又非常少,這對集群來說是不利的。
  2. 如果是自動創建的話,集群 index 和 shard 數過多,那麼在每天的 00:00 時,大量的 index 同時創建,這時我們就會發現集群的寫入速度會變慢,可能會發生 index 寫入拒絕的情況。
  3. 集群需要對冷熱數據進行分離,性能好的機器放最近頻繁查詢的數據,隨著時間推移,數據查詢不在頻繁,需要將數據遷移到性能較差的機器上。

以上這些我們可以使用 Elasticsearch 提供的索引生命週期管理功能能很好的解決,接下來我們瞭解一下 索引生命週期管理。

索引生命週期的四個階段

  • Hot:

index 正在查詢和更新,一般性能好的機器會設置為 Hot 節點來進行數據的讀寫。

  • Warm:

index不再更新,但是仍然需要查詢,節點性能一般可以設置為 Warm 節點。

  • Cold:

index不再被更新,且很少被查詢,數據仍然可以搜索,但是能接受較慢的查詢,節點性能較差,但有大量的磁盤空間。

  • Delete:

數據不需要了,可以刪除。

節點的類型可以通過一下兩種方式設置,推薦第二種,第一種後續可能會棄用。

第一種:

# elasticsearch.yml
# node.attr.xxx: xxx
node.attr.data: warm

第二種(推薦):

# elasticsearch.yml 
# data_content, data_hot, data_warm, data_cold
# 配置該節點既屬於內容層又屬於熱層
node.roles: ["data_hot", "data_content"]

這四個階段按照 Hot,Warm,Cold,Delete 順序執行,上一個階段沒有執行完成是不會執行下一個階段的,對於不存在的階段,會跳過該階段進入到下一個階段。

生命週期默認每 10 分鐘檢測一次,可以通過集群的配置動態修改,如下

PUT _cluster/settings
{
  "transient": {
    "indices.lifecycle.poll_interval": "10m" 
  }
}

生命週期管理 API

每個階段支持的行為會在下一章節進行介紹,此章節僅僅為了介紹 API。

  1. 創建生命週期管理策略

min_age 參數指定從 index 創建後多長時間進入到該階段。

以下示例是指從當 index 創建時間超過 10 天后,進入到 warm 階段,將 segment 數量 merge 為 1,warm 階段完成後,進入 delete 階段,index 創建時間超過 30 天后,將 index 刪除。

PUT _ilm/policy/my_policy
{
  "policy": {
    "phases": {
      "warm": {
        "min_age": "10d",
        "actions": {
          "forcemerge": {
            "max_num_segments": 1
          }
        }
      },
      "delete": {
        "min_age": "30d",
        "actions": {
          "delete": {}
        }
      }
    }
  }
}
  1. 查看生命週期管理策略
# 查看所有的生命週期管理策略
GET _ilm/policy

# 查看特定的生命週期管理策略
# GET _ilm/policy/<policy_id>
  1. 刪除生命週期管理策略
DELETE _ilm/policy/<policy_id>
  1. 觸發生命週期策略中特定步驟的執行

current_step

    - phase 當前階段的名稱

    - action 當前行為的名稱

    - name  當前步驟的名稱

next_step

    - phase 想要執行階段的名稱

    - action 想要執行行為的名稱

    - name  想要執行步驟的名稱
POST _ilm/move/my-index-000001
{
  "current_step": { 
    "phase": "new",
    "action": "complete",
    "name": "complete"
  },
  "next_step": { 
    "phase": "warm",
    "action": "forcemerge",
    "name": "forcemerge"
  }
}
  1. 移除生命週期管理策略
# POST <target>/_ilm/remove
POST my-index-000001/_ilm/remove
  1. 生命週期重試
# POST <index>/_ilm/retry
POST my-index-000001/_ilm/retry
  1. 查看當前索引生命週期管理狀態
GET /_ilm/status
  1. 查看一個或多個索引的當前生命週期狀態
# GET <target>/_ilm/explain
GET my-index-000001/_ilm/explain
  1. 啟動索引生命週期管理插件
POST _ilm/start
  1. 停止索引生命週期管理插件
POST /_ilm/stop

四個階段支持的行為

索引生命週期每個階段支持的行為如下:

  • Hot

    • Set Priority
    • Unfollow
    • Force Merge
    • Rollover
  • Warm

    • Set Priority
    • Unfollow
    • Read only
    • Allocate
    • Shrink
    • Force Merge
    • Migrate
  • Cold

    • Set Priority
    • Unfollow
    • Allocate
    • Migrate
    • Freeze
    • Searchable Snapshot
  • Delete

    • Wait For Snapshot
    • Delete

行為

Set Priority

設置索引的優先級,一旦進入到某階段,就設置索引的優先級,節點重新啟動後,優先級較高的索引將會優先恢復。

參數:

  • priority: 正整數。

例如:設置 warm 階段 index 的優先級為 50

PUT _ilm/policy/my_policy
{
  "policy": {
    "phases": {
      "warm": {
        "actions": {
          "set_priority" : {
            "priority": 50
          }
        }
      }
    }
  }
}

Rollover

當 index 滿足三個條件中的任何一個時,會將別名指向新生成的索引。

參數:

  • max_age

達到索引創建的最大時間

  • max_docs

達到指定的文檔數後

  • max_size

index 達到指定的大小時,主分片的大小,不包含副本。

以上三個參數至少應該存在一個

例如:當前 index 主分片大小達到 100GB 或文檔數超過 100000000 或者 index 創建超過 7天 生產新的 index

PUT _ilm/policy/my_policy
{
  "policy": {
    "phases": {
      "hot": {
        "actions": {
          "rollover" : {
            "max_size": "100GB",
            
"max_docs": 100000000,
            "max_age": "7d"
          }
        }
      }
    }
  }
}

Unfollow

將 follow 索引轉換為正常索引。

例如:

PUT _ilm/policy/my_policy
{
  "policy": {
    "phases": {
      "hot": {
        "actions": {
          "unfollow" : {}
        }
      }
    }
  }
}

Allocate

指定 index 的副本數,遷移 index 到某些節點,冷熱節點數據遷移依賴此步驟。

參數:

  • number_of_replicas

指定 index 的副本數

  • include

將 index 遷移到具有指定屬性之一的節點

  • exclude

將 index 遷移到不包含指定屬性的節點

  • require

將 index 遷移到具有所有指定屬性的節點

Note: include 滿足其中一個就可以, require 必須全部滿足。

例如:到達 warm 階段將 index 的備份數設置為 2,並且將 index 遷移至屬性 box_type 包含 hot, warm 且不包含 cold 的節點。

PUT _ilm/policy/my_policy
{
  "policy": {
    "phases": {
      "warm": {
        "actions": {
          "allocate" : {
            "number_of_replicas" : 2,
            "include" : {
                "box_type": "hot"
            },
            "exclude" : {
                "box_type": "cold"
            },
            "require" : {
                "box_type": "hot,warm"
            }
          }
        }
      }
    }
  }
}

Force Merge

指定 index 合併後 segment 數量,在 hot 階段使用時,必須包含 rollover ,merge 時會將 index 設置為只讀。

參數:

  • max_num_segments

segment 最大數量

  • index_codec

壓縮文件存儲, default: LZ4

例如:warm 階段將 index 的 segments 合併為 1。

PUT _ilm/policy/my_policy
{
  "policy": {
    "phases": {
      "warm": {
        "actions": {
          "forcemerge" : {
            "max_num_segments": 1
          }
        }
      }
    }
  }
}

Read only

將 index 設置為只讀。

例如:

PUT _ilm/policy/my_policy
{
  "policy": {
    "phases": {
      "warm": {
        "actions": {
          "readonly" : { }
        }
      }
    }
  }
}

Shrink

index 設置為只讀,然後將 index 縮小為具有更少的的 shard, 縮小後的 index 名稱為 shrink-

參數:

  • number_of_shards

合併後的主分片數

例如:warm 階段將 index 的 shard 數合併為 1 個。

PUT _ilm/policy/my_policy
{
  "policy": {
    "phases": {
      "warm": {
        "actions": {
          "shrink" : {
            "number_of_shards": 1
          }
        }
      }
    }
  }
}

Freeze

最大程度減少 index 的內存佔用。

例如:cold 階段將 index freeze,釋放內存。

PUT _ilm/policy/my_policy
{
  "policy": {
    "phases": {
      "cold": {
        "actions": {
          "freeze" : { }
        }
      }
    }
  }
}

Migrate

通過更新 index.routing.allocation.include._tier_preference 設置,將 index 移動到對應的數據層,如果指定了 allocate,會在遷移前先將副本數減少。如果在熱階段和冷階段沒有指定 allocate 分配選項,ILM 會自動注入遷移操作,如果要禁用可以將 enabled 設置為 false。

參數:

  • enabled

default: true, 控制 ILM 在此階段是否自動遷移索引

例如:warm 階段禁用遷移操作, 主動將 index 備份數設置為 1,並且將 index 遷移至屬性 rack_id 為 one 或者 two 的節點。

PUT _ilm/policy/my_policy
{
  "policy": {
    "phases": {
      "warm": {
        "actions": {
          "migrate" : {
           "enabled": false
          },
          "allocate": {
            "number_of_replicas": 1,
            "include" : {
              "rack_id": "one,two"
            }
          }
        }
      }
    }
  }
}

Searchable Snapshot

生成可搜索快照,在 7.10 版本還處於 beta,在新版可能會有所更改。

在 delete action 步驟中默認會刪除快照,如果需要保留,在 delete action 中將 delete_searchable_snapshot 設置 false

參數:

  • snapshot_repository

Required,指定存儲快照的位置

  • force_merge_index

Boolean,default: true, 如果索引在先前的操作中已經使用了 force merge, 則可搜索快照操作不會執行強制合併。

例如:在 cold 階段生成快照。

PUT _ilm/policy/my_policy
{
  "policy": {
    "phases": {
      "cold": {
        "actions": {
          "searchable_snapshot" : {
            "snapshot_repository" : "backing_repo"
          }
        }
      }
    }
  }
}

Wait For Snapshot

等待制定的 SLM 策略執行,然後在刪除索引,為了確保刪除的索引快照是可用的。

參數:

  • policy

required, SML 策略的名字

例如:delete 階段等待 SLM 策略執行,然後刪除索引。

PUT _ilm/policy/my_policy
{
  "policy": {
    "phases": {
      "delete": {
        "actions": {
          "wait_for_snapshot" : {
            "policy": "slm-policy-name"
          }
        }
      }
    }
  }
}

Delete

刪除 index

參數:

  • delete_searchable_snapshot

boolean, default: true, 是否刪除 cold 階段創建的 searchable snapshot。

例如:index 創建 90 天后,刪除 index

PUT _ilm/policy/my_policy
{
  "policy": {
    "phases": {
      "delete": {
        "min_age" : "90d",
        "actions": {
          "delete" : { }
        }
      }
    }
  }
}

通過 alias 使用 ILM

  1. 創建生命週期策略

warm 階段將 index 分配給節點屬性 data 為 warm 的節點, cold 階段將 index 分配給節點屬性 data 為 cold 的節點。

節點屬性可以通過 elasticsearch.yml 進行配置或環境變量設置。

# 啟動命令
bin/elasticsearch -Enode.attr.data=warm

# elasticsearch.yml
# node.attr.xxx: xxx
# 建議使用 node.roles 進行配置, 可以參考 通過 data tiers 使用 ILM 這一章節
# node.attr 後續版本可能不在使用

node.attr.data: warm

創建生命週期策略,

在 index 創建 1 天后進入 hot 階段,設置優先級為 100, 當 index 主分片大小超過 50gb 或者 index 文檔數超過 500000000 或者 index 創建超過 2 天生成新的 index

warm 階段將 index 遷移至屬性 data 為 warm 的節點

cold 階段將 index 副本數設置為 1 並將 index 遷移至屬性 data 為 cold 的節點

當 hot ,warm,cold 階段的動作都完成並且 index 創建達到 7 天,刪除 index。

PUT _ilm/policy/logx_policy
{
  "policy": {
    "phases": {
      "hot": {
        "min_age": "1d",
        "actions": {
          "set_priority": {
            "priority": 100
          },
          "rollover": {
            "max_age": "2d",
            "max_docs": 500000000,
            "max_size": "50gb"
          }
        }
      },
      "warm": {
        "min_age": "1d",
        "actions": {
          "set_priority": {
            "priority": 50
          },
          "allocate": {
            "include": {
              "data" : "warm"
            }
          }
        }
      },
      "cold": {
        "min_age": "1d",
        "actions": {
          "set_priority": {
            "priority": 0
          },
          "allocate": {
            "number_of_replicas": 1,
            "include" : {
              "data": "cold"
            }
          }
        }
      }, 
      "delete": {
        "min_age": "7d",
        "actions": {
          "delete": {}
        }
      }
    }
  }
}
  1. 創建索引模板,將生命週期應用到 index

設置 shard 數為 2, 備份數 為 1, 生命週期策略為 logx_policy,滾動別名為 logx

PUT _index_template/logx-template
{
  "index_patterns" : ["logx-*"],
  "priority" : 1,
  "template": {
    "settings" : {
      "index" : {
        "number_of_shards" : "2",
        "number_of_replicas" : "1",
        "lifecycle.name": "logx_policy",
        "lifecycle.rollover_alias": "logx"
      }
    }
  }
}
  1. 創建第一個 index,以下兩種形式任選一種即可, index 格式必須滿足該正則 ^.-\d+$* , example:logs-000001
PUT logx-000001
{
  "aliases": {
    "logx": {
      "is_write_index": true
    }
  }
}
# OR 帶創建日期的 index
# PUT /<logx-{now/d}-1> with URI encoding:
PUT /%3Clogx-%7Bnow%2Fd%7D-1%3E 
{
  "aliases": {
    "logx": {
      "is_write_index": true
    }
  }
} 

後續的數據讀寫均使用固定別名 logx

通過 Data stream 使用 ILM

  1. 創建生命週期策略

創建生命週期策略,在 index 創建 1 天后進入 hot 階段,設置優先級為 100, 當 index 主分片大小超過 50gb 或者 index 文檔數超過 500000000 或者 index 創建超過 2 天生成新的 index,warm 階段將 index 遷移至屬性 data 為 warm 的節點,cold 階段將 index 副本數設置為 1 並將 index 遷移至屬性 data 為 cold 的節點,當 hot ,warm,cold 階段的動作都完成並且 index 創建達到 7 天,刪除 index。

PUT _ilm/policy/logx_policy
{
  "policy": {
    "phases": {
      "hot": {
        "min_age": "1d",
        "actions": {
          "set_priority": {
            "priority": 100
          },
          "rollover": {
            "max_age": "2d",
            "max_docs": 500000000,
            "max_size": "50gb"
          }
        }
      },
      "warm": {
        "min_age": "1d",
        "actions": {
          "set_priority": {
            "priority": 50
          },
          "allocate": {
            "include": {
              "data" : "warm"
            }
          }
        }
      },
      "cold": {
        "min_age": "1d",
        "actions": {
          "set_priority": {
            "priority": 0
          },
          "allocate": {
            "number_of_replicas": 1,
            "include" : {
              "data": "cold"
            }
          }
        }
      }, 
      "delete": {
        "min_age": "7d",
        "actions": {
          "delete": {}
        }
      }
    }
  }
}
  1. 創建索引模板,將生命週期應用到 index

與通過 alias 的形式區別: 模板不需要指定 index.rollover_alias,也不需要手動創建第一個index,直接將數據寫入符合模板的 index 即可,至於這個 index 在 Elasticsearch 中對應幾個index,我們無需關注。

PUT _index_template/logx-template
{
  "index_patterns" : ["logx-*"],
  "priority" : 1,
  "data_stream": { },
  "template": {
    "settings" : {
      "index" : {
        "number_of_shards" : "2",
        "number_of_replicas" : "1",
        "lifecycle.name": "logx_policy"
      }
    }
  }
}
  1. 創建 data stream
POST /logx-business/_doc/
{
    "@timestamp":"2021-04-13T11:04:05.000Z",
    "message":"Loginattemptfailed"
}
# OR 
PUT /_data_stream/logx-business

後續的數據讀寫均使用固定 index: logx-business

通過 Data tiers 使用 ILM

data tiers ( 數據層 )是具有相同數據角色的節點的集合

  • Content tier ( 內容層 )節點處理諸如產品目錄之類的內容的索引和查詢負載。
  • Hot tier ( 熱層 ) 節點處理諸如日誌或指標之類的時間序列數據的索引負載,並保存你最近,最常訪問的數據。
  • Warm tier ( 溫層 )節點保存的時間序列數據訪問頻率較低,並且很少需要更新。
  • Cold tier ( 冷層 )節點保存時間序列數據,這些數據偶爾會被訪問,並且通常不會更新。

推薦冷熱分離採用 data tiers 這種方式,節點可以通過如下配置方式配置:

# elasticsearch.yml 
# data_content, data_hot, data_warm, data_cold
# 配置該節點既屬於內容層又屬於熱層
node.roles: ["data_hot", "data_content"]
  1. 創建生命週期策略

warm 階段將 index 遷移至 warm 節點,cold 階段禁用 migrate,將 index 分配給 rack_id 為 one 或 two 的節點。

創建生命週期策略,在 index 創建 1 天后進入 hot 階段,設置優先級為 100, 當 index 主分片大小超過 50gb 或者 index 文檔數超過 500000000 或者 index 創建超過 2 天生成新的 index,warm 階段將 index 遷移至 warm 節點,cold 階段將 index 副本數設置為 1,禁用 migrate, 並將 index 遷移至屬性 data 為 cold 的節點,當 hot ,warm,cold 階段的動作都完成並且 index 創建達到 7 天,刪除 index。

PUT _ilm/policy/logx_policy
{
  "policy": {
    "phases": {
      "hot": {
        "min_age": "1d",
        "actions": {
          "set_priority": {
            "priority": 100
          },
          "rollover": {
            "max_age": "2d",
            "max_docs": 500000000,
            "max_size": "50gb"
          }
        }
      },
      "warm": {
        "min_age": "1d",
        "actions": {
          "set_priority": {
            "priority": 50
          },
          "migrate" : {
          }
        }
      },
      "cold": {
        "min_age": "1d",
        "actions": {
          "set_priority": {
            "priority": 0
          },
          "allocate": {
            "number_of_replicas": 1,
            "include" : {
              "data": "cold"
            }
          }, 
          "migrate" : {
            "enabled": false
          }
        }
      }, 
      "delete": {
        "min_age": "7d",
        "actions": {
          "delete": {}
        }
      }
    }
  }
}
  1. 創建索引模板,將生命週期應用到 index

設置 shard 數為 2, 備份數 為 1, 生命週期策略為 logx_policy

PUT _index_template/logx-template
{
  "index_patterns" : ["logx-*"],
  "priority" : 1,
  "data_stream": { },
  "template": {
    "settings" : {
      "index" : {
        "number_of_shards" : "2",
        "number_of_replicas" : "1",
        "lifecycle.name": "logx_policy"
      }
    }
  }
}
  1. 創建 data stream
POST /logx-business/_doc/
{
    "@timestamp":"2021-04-13T11:04:05.000Z",
    "message":"Loginattemptfailed"
}
# OR 
PUT /_data_stream/logx-business

後續的數據讀寫均使用固定 index: logx-business

Leave a Reply

Your email address will not be published. Required fields are marked *