Elasticsearch मध्ये दीर्घकालीन डेटा स्टोरेज

Elasticsearch मध्ये दीर्घकालीन डेटा स्टोरेज

माझे नाव इगोर सिडोरेंको आहे, मी प्रशासकांच्या टीममधील एक तांत्रिक नेता आहे जो डोमक्लिकच्या संपूर्ण पायाभूत सुविधांची देखभाल करतो.

मला Elasticsearch मध्ये वितरित डेटा स्टोरेज सेट करण्याचा माझा अनुभव शेअर करायचा आहे. शार्ड्सच्या वितरणासाठी नोड्सवरील कोणत्या सेटिंग्ज जबाबदार आहेत, ILM कसे कार्य करते आणि कसे कार्य करते ते आम्ही पाहू.

जे लोक लॉगसह काम करतात, एक मार्ग किंवा दुसर्या, नंतरच्या विश्लेषणासाठी दीर्घकालीन स्टोरेजच्या समस्येचा सामना करतात. Elasticsearch मध्ये, हे विशेषतः सत्य आहे, कारण सर्व काही क्युरेटर कार्यक्षमतेसह दुर्दैवी होते. आवृत्ती 6.6 ने ILM कार्यक्षमता सादर केली. यात 4 टप्प्यांचा समावेश आहे:

  • हॉट - निर्देशांक सक्रियपणे अद्यतनित केला जात आहे आणि चौकशी केली जात आहे.
  • उबदार - निर्देशांक यापुढे अद्यतनित केला जात नाही, परंतु तरीही त्याची चौकशी केली जात आहे.
  • थंड - निर्देशांक यापुढे अद्यतनित केला जात नाही आणि क्वचितच विचारला जातो. माहिती अद्याप शोधण्यायोग्य असणे आवश्यक आहे, परंतु क्वेरी हळू असू शकतात.
  • हटवा - अनुक्रमणिका यापुढे आवश्यक नाही आणि सुरक्षितपणे हटविली जाऊ शकते.

दिले

  • Elasticsearch डेटा हॉट: 24 प्रोसेसर, 128 GB मेमरी, 1,8 TB SSD RAID 10 (8 नोड्स).
  • Elasticsearch डेटा उबदार: 24 प्रोसेसर, 64 GB मेमरी, 8 TB NetApp SSD धोरण (4 नोड्स).
  • Elasticsearch डेटा कोल्ड: 8 प्रोसेसर, 32 GB मेमरी, 128 TB HDD RAID 10 (4 नोड्स).

गोल

या सेटिंग्ज वैयक्तिक आहेत, हे सर्व नोड्सवरील स्थान, अनुक्रमणिका, लॉग इत्यादींवर अवलंबून असते. आमच्याकडे दररोज 2-3 TB डेटा असतो.

  • 5 दिवस - गरम टप्पा (8 मुख्य / 1 प्रतिकृती).
  • 20 दिवस - उबदार टप्पा (shrink-index 4 मुख्य / 1 प्रतिकृती).
  • ९० दिवस - थंडीचा टप्पा (फ्रीज-इंडेक्स 4 मुख्य / 1 प्रतिकृती).
  • 120 दिवस - टप्पा हटवा.

Elasticsearch सेट करत आहे

नोड्समध्ये शार्ड वितरित करण्यासाठी, तुम्हाला फक्त एक पॅरामीटर आवश्यक आहे:

  • हॉट-नोड्स:
    ~]# cat /etc/elasticsearch/elasticsearch.yml | grep attr
    # Add custom attributes to the node:
    node.attr.box_type: hot
  • उबदार-नोड्स:
    ~]# cat /etc/elasticsearch/elasticsearch.yml | grep attr
    # Add custom attributes to the node:
    node.attr.box_type: warm
  • थंड-नोड्स:
    ~]# cat /etc/elasticsearch/elasticsearch.yml | grep attr
    # Add custom attributes to the node:
    node.attr.box_type: cold

लॉगस्टॅश सेट करत आहे

हे सर्व कसे कार्य करते आणि आम्ही हे वैशिष्ट्य कसे लागू केले? Elasticsearch मध्ये लॉग मिळवून सुरुवात करूया. दोन मार्ग आहेत:

  1. लॉगस्टॅश काफ्काकडून लॉग आणते. स्वच्छ उचलू शकता किंवा आपल्या बाजूला रूपांतरित करू शकता.
  2. काहीतरी स्वतः Elasticsearch वर लिहिते, उदाहरणार्थ, एपीएम सर्व्हर.

लॉगस्टॅशद्वारे निर्देशांक व्यवस्थापित करण्याचे उदाहरण विचारात घ्या. तो एक निर्देशांक तयार करतो आणि त्यावर लागू होतो अनुक्रमणिका टेम्पलेट आणि संबंधित आयएलएम.

k8s-ingress.conf

input {
    kafka {
        bootstrap_servers => "node01, node02, node03"
        topics => ["ingress-k8s"]
        decorate_events => false
        codec => "json"
    }
}

filter {
    ruby {
        path => "/etc/logstash/conf.d/k8s-normalize.rb"
    }
    if [log] =~ "[warn]" or [log] =~ "[error]" or [log] =~ "[notice]" or [log] =~ "[alert]" {
        grok {
            match => { "log" => "%{DATA:[nginx][error][time]} [%{DATA:[nginx][error][level]}] %{NUMBER:[nginx][error][pid]}#%{NUMBER:[nginx][error][tid]}: *%{NUMBER:[nginx][error][connection_id]} %{DATA:[nginx][error][message]}, client: %{IPORHOST:[nginx][error][remote_ip]}, server: %{DATA:[nginx][error][server]}, request: "%{WORD:[nginx][error][method]} %{DATA:[nginx][error][url]} HTTP/%{NUMBER:[nginx][error][http_version]}", (?:upstream: "%{DATA:[nginx][error][upstream][proto]}://%{DATA:[nginx][error][upstream][host]}:%{DATA:[nginx][error][upstream][port]}/%{DATA:[nginx][error][upstream][url]}", )?host: "%{DATA:[nginx][error][host]}"(?:, referrer: "%{DATA:[nginx][error][referrer]}")?" }
            remove_field => "log"
        }
    }
    else {
        grok {
            match => { "log" => "%{IPORHOST:[nginx][access][host]} - [%{IPORHOST:[nginx][access][remote_ip]}] - %{DATA:[nginx][access][remote_user]} [%{HTTPDATE:[nginx][access][time]}] "%{WORD:[nginx][access][method]} %{DATA:[nginx][access][url]} HTTP/%{NUMBER:[nginx][access][http_version]}" %{NUMBER:[nginx][access][response_code]} %{NUMBER:[nginx][access][bytes_sent]} "%{DATA:[nginx][access][referrer]}" "%{DATA:[nginx][access][agent]}" %{NUMBER:[nginx][access][request_lenght]} %{NUMBER:[nginx][access][request_time]} [%{DATA:[nginx][access][upstream][name]}] (?:-|%{IPORHOST:[nginx][access][upstream][addr]}:%{NUMBER:[nginx][access][upstream][port]}) (?:-|%{NUMBER:[nginx][access][upstream][response_lenght]}) %{DATA:[nginx][access][upstream][response_time]} %{DATA:[nginx][access][upstream][status]} %{DATA:[nginx][access][request_id]}" }
            remove_field => "log"
        }
    }
}
output {
    elasticsearch {
        id => "k8s-ingress"
        hosts => ["node01", "node02", "node03", "node04", "node05", "node06", "node07", "node08"]
        manage_template => true # включаем управление шаблонами
        template_name => "k8s-ingress" # имя применяемого шаблона
        ilm_enabled => true # включаем управление ILM
        ilm_rollover_alias => "k8s-ingress" # alias для записи в индексы, должен быть уникальным
        ilm_pattern => "{now/d}-000001" # шаблон для создания индексов, может быть как "{now/d}-000001" так и "000001"
        ilm_policy => "k8s-ingress" # политика прикрепляемая к индексу
        index => "k8s-ingress-%{+YYYY.MM.dd}" # название создаваемого индекса, может содержать %{+YYYY.MM.dd}, зависит от ilm_pattern
    }
}

किबाना सेटअप

एक बेस पॅटर्न आहे जो सर्व नवीन निर्देशांकांना लागू होतो. हे हॉट इंडेक्सचे वितरण, शार्ड्सची संख्या, प्रतिकृती इत्यादी सेट करते. टेम्पलेटचे वजन पर्यायाद्वारे निर्धारित केले जाते order. जास्त वजन असलेले टेम्पलेट विद्यमान टेम्पलेट पॅरामीटर्स ओव्हरराइड करतात किंवा नवीन जोडतात.

Elasticsearch मध्ये दीर्घकालीन डेटा स्टोरेज
Elasticsearch मध्ये दीर्घकालीन डेटा स्टोरेज

_टेम्पलेट/डीफॉल्ट मिळवा

{
  "default" : {
    "order" : -1, # вес шаблона
    "version" : 1,
    "index_patterns" : [
      "*" # применяем ко всем индексам
    ],
    "settings" : {
      "index" : {
        "codec" : "best_compression", # уровень сжатия
        "routing" : {
          "allocation" : {
            "require" : {
              "box_type" : "hot" # распределяем только по горячим нодам
            },
            "total_shards_per_node" : "8" # максимальное количество шардов на ноду от одного индекса
          }
        },
        "refresh_interval" : "5s", # интервал обновления индекса
        "number_of_shards" : "8", # количество шардов
        "auto_expand_replicas" : "0-1", # количество реплик на ноду от одного индекса
        "number_of_replicas" : "1" # количество реплик
      }
    },
    "mappings" : {
      "_meta" : { },
      "_source" : { },
      "properties" : { }
    },
    "aliases" : { }
  }
}

नंतर निर्देशांकांवर मॅपिंग लागू करा k8s-ingress-* जास्त वजन असलेले टेम्पलेट वापरणे.

Elasticsearch मध्ये दीर्घकालीन डेटा स्टोरेज
Elasticsearch मध्ये दीर्घकालीन डेटा स्टोरेज

_template/k8s-ingress मिळवा

{
  "k8s-ingress" : {
    "order" : 100,
    "index_patterns" : [
      "k8s-ingress-*"
    ],
    "settings" : {
      "index" : {
        "lifecycle" : {
          "name" : "k8s-ingress",
          "rollover_alias" : "k8s-ingress"
        },
        "codec" : "best_compression",
        "routing" : {
          "allocation" : {
            "require" : {
              "box_type" : "hot"
            }
          }
        },
        "number_of_shards" : "8",
        "number_of_replicas" : "1"
      }
    },
    "mappings" : {
      "numeric_detection" : false,
      "_meta" : { },
      "_source" : { },
      "dynamic_templates" : [
        {
          "all_fields" : {
            "mapping" : {
              "index" : false,
              "type" : "text"
            },
            "match" : "*"
          }
        }
      ],
      "date_detection" : false,
      "properties" : {
        "kubernetes" : {
          "type" : "object",
          "properties" : {
            "container_name" : {
              "type" : "keyword"
            },
            "container_hash" : {
              "index" : false,
              "type" : "keyword"
            },
            "host" : {
              "type" : "keyword"
            },
            "annotations" : {
              "type" : "object",
              "properties" : {
                "value" : {
                  "index" : false,
                  "type" : "text"
                },
                "key" : {
                  "index" : false,
                  "type" : "keyword"
                }
              }
            },
            "docker_id" : {
              "index" : false,
              "type" : "keyword"
            },
            "pod_id" : {
              "type" : "keyword"
            },
            "labels" : {
              "type" : "object",
              "properties" : {
                "value" : {
                  "type" : "keyword"
                },
                "key" : {
                  "type" : "keyword"
                }
              }
            },
            "namespace_name" : {
              "type" : "keyword"
            },
            "pod_name" : {
              "type" : "keyword"
            }
          }
        },
        "@timestamp" : {
          "type" : "date"
        },
        "nginx" : {
          "type" : "object",
          "properties" : {
            "access" : {
              "type" : "object",
              "properties" : {
                "agent" : {
                  "type" : "text"
                },
                "response_code" : {
                  "type" : "integer"
                },
                "upstream" : {
                  "type" : "object",
                  "properties" : {
                    "port" : {
                      "type" : "keyword"
                    },
                    "name" : {
                      "type" : "keyword"
                    },
                    "response_lenght" : {
                      "type" : "integer"
                    },
                    "response_time" : {
                      "index" : false,
                      "type" : "text"
                    },
                    "addr" : {
                      "type" : "keyword"
                    },
                    "status" : {
                      "index" : false,
                      "type" : "text"
                    }
                  }
                },
                "method" : {
                  "type" : "keyword"
                },
                "http_version" : {
                  "type" : "keyword"
                },
                "bytes_sent" : {
                  "type" : "integer"
                },
                "request_lenght" : {
                  "type" : "integer"
                },
                "url" : {
                  "type" : "text",
                  "fields" : {
                    "keyword" : {
                      "type" : "keyword"
                    }
                  }
                },
                "remote_user" : {
                  "type" : "text"
                },
                "referrer" : {
                  "type" : "text"
                },
                "remote_ip" : {
                  "type" : "ip"
                },
                "request_time" : {
                  "format" : "yyyy/MM/dd HH:mm:ss||yyyy/MM/dd||epoch_millis||dd/MMM/YYYY:H:m:s Z",
                  "type" : "date"
                },
                "host" : {
                  "type" : "keyword"
                },
                "time" : {
                  "format" : "yyyy/MM/dd HH:mm:ss||yyyy/MM/dd||epoch_millis||dd/MMM/YYYY:H:m:s Z",
                  "type" : "date"
                }
              }
            },
            "error" : {
              "type" : "object",
              "properties" : {
                "server" : {
                  "type" : "keyword"
                },
                "upstream" : {
                  "type" : "object",
                  "properties" : {
                    "port" : {
                      "type" : "keyword"
                    },
                    "proto" : {
                      "type" : "keyword"
                    },
                    "host" : {
                      "type" : "keyword"
                    },
                    "url" : {
                      "type" : "text",
                      "fields" : {
                        "keyword" : {
                          "type" : "keyword"
                        }
                      }
                    }
                  }
                },
                "method" : {
                  "type" : "keyword"
                },
                "level" : {
                  "type" : "keyword"
                },
                "http_version" : {
                  "type" : "keyword"
                },
                "pid" : {
                  "index" : false,
                  "type" : "integer"
                },
                "message" : {
                  "type" : "text"
                },
                "tid" : {
                  "index" : false,
                  "type" : "keyword"
                },
                "url" : {
                  "type" : "text",
                  "fields" : {
                    "keyword" : {
                      "type" : "keyword"
                    }
                  }
                },
                "referrer" : {
                  "type" : "text"
                },
                "remote_ip" : {
                  "type" : "ip"
                },
                "connection_id" : {
                  "index" : false,
                  "type" : "keyword"
                },
                "host" : {
                  "type" : "keyword"
                },
                "time" : {
                  "format" : "yyyy/MM/dd HH:mm:ss||yyyy/MM/dd||epoch_millis||dd/MMM/YYYY:H:m:s Z",
                  "type" : "date"
                }
              }
            }
          }
        },
        "log" : {
          "type" : "text"
        },
        "@version" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "ignore_above" : 256,
              "type" : "keyword"
            }
          }
        },
        "eventtime" : {
          "type" : "float"
        }
      }
    },
    "aliases" : { }
  }
}

सर्व टेम्पलेट्स लागू केल्यानंतर, आम्ही ILM धोरण लागू करतो आणि निर्देशांकांच्या आयुष्याचे परीक्षण करू लागतो.

Elasticsearch मध्ये दीर्घकालीन डेटा स्टोरेज

Elasticsearch मध्ये दीर्घकालीन डेटा स्टोरेज

Elasticsearch मध्ये दीर्घकालीन डेटा स्टोरेज

_ilm/policy/k8s-ingress मिळवा

{
  "k8s-ingress" : {
    "version" : 14,
    "modified_date" : "2020-06-11T10:27:01.448Z",
    "policy" : {
      "phases" : {
        "warm" : { # теплая фаза
          "min_age" : "5d", # срок жизни индекса после ротации до наступления теплой фазы
          "actions" : {
            "allocate" : {
              "include" : { },
              "exclude" : { },
              "require" : {
                "box_type" : "warm" # куда перемещаем индекс
              }
            },
            "shrink" : {
              "number_of_shards" : 4 # обрезание индексов, т.к. у нас 4 ноды
            }
          }
        },
        "cold" : { # холодная фаза
          "min_age" : "25d", # срок жизни индекса после ротации до наступления холодной фазы
          "actions" : {
            "allocate" : {
              "include" : { },
              "exclude" : { },
              "require" : {
                "box_type" : "cold" # куда перемещаем индекс
              }
            },
            "freeze" : { } # замораживаем для оптимизации
          }
        },
        "hot" : { # горячая фаза
          "min_age" : "0ms",
          "actions" : {
            "rollover" : {
              "max_size" : "50gb", # максимальный размер индекса до ротации (будет х2, т.к. есть 1 реплика)
              "max_age" : "1d" # максимальный срок жизни индекса до ротации
            },
            "set_priority" : {
              "priority" : 100
            }
          }
        },
        "delete" : { # фаза удаления
          "min_age" : "120d", # максимальный срок жизни после ротации перед удалением
          "actions" : {
            "delete" : { }
          }
        }
      }
    }
  }
}

समस्या

सेटअप आणि डीबगिंग स्टेजवर समस्या होत्या.

गरम टप्पा

निर्देशांकांच्या योग्य रोटेशनसाठी, शेवटी उपस्थिती महत्त्वपूर्ण आहे index_name-date-000026 स्वरूप क्रमांक 000001. कोडमध्ये अशा रेषा आहेत ज्या शेवटी संख्यांच्या उपस्थितीसाठी नियमित अभिव्यक्ती वापरून निर्देशांक तपासतात. अन्यथा, एक त्रुटी असेल, निर्देशांकावर कोणतीही धोरणे लागू केली जाणार नाहीत आणि ती नेहमीच गरम अवस्थेत असेल.

उबदार टप्पा

संकोच (कटऑफ) - शार्ड्सची संख्या कमी करा, कारण आमच्याकडे उबदार आणि थंड टप्प्यात 4 नोड्स आहेत. दस्तऐवजीकरणात खालील ओळी आहेत:

  • अनुक्रमणिका केवळ वाचनीय असणे आवश्यक आहे.
  • निर्देशांकातील प्रत्येक शार्डची प्रत त्याच नोडवर असणे आवश्यक आहे.
  • क्लस्टर आरोग्य स्थिती हिरवी असणे आवश्यक आहे.

इंडेक्स छाटण्यासाठी, Elasticsearch सर्व प्राथमिक शार्ड्स एका नोडवर हलवते, आवश्यक पॅरामीटर्ससह कापलेल्या इंडेक्सची डुप्लिकेट करते आणि नंतर जुने हटवते. पॅरामीटर total_shards_per_node एका नोडवर बसण्यासाठी मुख्य शार्ड्सच्या संख्येइतके किंवा त्यापेक्षा जास्त असणे आवश्यक आहे. अन्यथा, सूचना मिळतील आणि शार्ड्स योग्य नोड्सवर हलणार नाहीत.

Elasticsearch मध्ये दीर्घकालीन डेटा स्टोरेज
Elasticsearch मध्ये दीर्घकालीन डेटा स्टोरेज

मिळवा /shrink-k8s-ingress-2020.06.06-000025/_settings

{
  "shrink-k8s-ingress-2020.06.06-000025" : {
    "settings" : {
      "index" : {
        "refresh_interval" : "5s",
        "auto_expand_replicas" : "0-1",
        "blocks" : {
          "write" : "true"
        },
        "provided_name" : "shrink-k8s-ingress-2020.06.06-000025",
        "creation_date" : "1592225525569",
        "priority" : "100",
        "number_of_replicas" : "1",
        "uuid" : "psF4MiFGQRmi8EstYUQS4w",
        "version" : {
          "created" : "7060299",
          "upgraded" : "7060299"
        },
        "lifecycle" : {
          "name" : "k8s-ingress",
          "rollover_alias" : "k8s-ingress",
          "indexing_complete" : "true"
        },
        "codec" : "best_compression",
        "routing" : {
          "allocation" : {
            "initial_recovery" : {
              "_id" : "_Le0Ww96RZ-o76bEPAWWag"
            },
            "require" : {
              "_id" : null,
              "box_type" : "cold"
            },
            "total_shards_per_node" : "8"
          }
        },
        "number_of_shards" : "4",
        "routing_partition_size" : "1",
        "resize" : {
          "source" : {
            "name" : "k8s-ingress-2020.06.06-000025",
            "uuid" : "gNhYixO6Skqi54lBjg5bpQ"
          }
        }
      }
    }
  }
}

थंड टप्पा

गोठवू (फ्रीज) - आम्ही ऐतिहासिक डेटावरील क्वेरी ऑप्टिमाइझ करण्यासाठी निर्देशांक गोठवतो.

गोठवलेल्या निर्देशांकांवर केलेले शोध प्रत्येक नोडवर गोठवलेल्या शार्ड्सना मारणाऱ्या समवर्ती शोधांची संख्या नियंत्रित करण्यासाठी लहान, समर्पित, शोध_थ्रॉटल्ड थ्रेडपूल वापरतात. हे फ्रोझन शार्ड्सशी संबंधित क्षणिक डेटा स्ट्रक्चर्ससाठी आवश्यक अतिरिक्त मेमरीचे प्रमाण मर्यादित करते, ज्यामुळे नोड्सचे जास्त मेमरी वापरापासून संरक्षण होते.
गोठवलेल्या निर्देशांक केवळ वाचनीय आहेत: तुम्ही त्यामध्ये अनुक्रमित करू शकत नाही.
गोठवलेल्या निर्देशांकांवरील शोध हळूहळू कार्यान्वित होणे अपेक्षित आहे. गोठलेले निर्देशांक उच्च शोध भारासाठी अभिप्रेत नाहीत. हे शक्य आहे की गोठवलेल्या निर्देशांकाचा शोध पूर्ण होण्यासाठी काही सेकंद किंवा मिनिटे लागू शकतात, जरी निर्देशांक गोठलेले नसतानाही तेच शोध मिलिसेकंदात पूर्ण झाले.

परिणाम

ILM सोबत काम करण्यासाठी नोड्स कसे तयार करायचे, हॉट नोड्समध्ये शार्ड्सचे वितरण करण्यासाठी टेम्पलेट कसे सेट करायचे आणि आयुष्याच्या सर्व टप्प्यांसह इंडेक्ससाठी ILM कसे सेट करायचे हे आम्ही शिकलो.

उपयुक्त दुवे

स्त्रोत: www.habr.com