Laangfristeg Datelagerung an Elasticsearch

Laangfristeg Datelagerung an Elasticsearch

Mäin Numm ass Igor Sidorenko, ech sinn en technesche Lead an engem Team vun Administrateuren, déi d'ganz Domklik Infrastruktur an der Aarbecht behalen.

Ech wéilt meng Erfahrung deelen beim Opbau vun verdeelt Datelagerung an Elasticsearch. Mir wäerte kucken wéi eng Astellungen op Noden fir d'Verdeelung vu Schnëtt verantwortlech sinn, wéi ILM strukturéiert ass a funktionnéiert.

Déi, déi mat Logbicher schaffen, sinn op eng oder aner Manéier mam Problem vu laangfristeg Lagerung fir spéider Analyse konfrontéiert. Dëst ass besonnesch wouer an Elasticsearch well d'Kuratorfunktionalitéit schlëmm war. An der Versioun 6.6 erschéngt ILM Funktionalitéit. Et besteet aus 4 Phasen:

  • Hot - Den Index gëtt aktiv aktualiséiert a gefrot.
  • Warm - den Index gëtt net méi aktualiséiert, awer nach ëmmer gefrot.
  • Kale - Den Index gëtt net méi aktualiséiert a gëtt selten gefrot. D'Informatioun sollt nach ëmmer sichtbar sinn, awer Ufroe kënne méi lues sinn.
  • Läschen - Den Index ass net méi gebraucht a ka sécher geläscht ginn.

Gitt

  • Elasticsearch Data Hot: 24 Prozessoren, 128 GB Erënnerung, 1,8 TB SSD RAID 10 (8 Wirbelen).
  • Elasticsearch Data Warm: 24 Prozessoren, 64 GB Erënnerung, 8 TB NetApp SSD Politik (4 Noden).
  • Elasticsearch Data Cold: 8 Prozessoren, 32 GB Erënnerung, 128 TB HDD RAID 10 (4 Wirbelen).

Goal geschoss huet

Dës Astellunge sinn individuell, et hänkt alles vum Raum op den Wirbelen of, d'Zuel vun den Indexen, Logbicher, asw. Fir eis sinn dat 2-3 TB vun Daten pro Dag.

  • 5 Deeg - Hot Phase (8 Haaptsäit / 1 replica).
  • 20 Deeg - Waarm Phase (schrumpfen-index 4 Haapt / 1 Replica).
  • 90 Deeg - Kale Phase (afréieren-index 4 Haapt / 1 Replica).
  • 120 Deeg - Phase läschen.

Elasticsearch konfiguréieren

Fir Shards tëscht Noden ze verdeelen, braucht Dir nëmmen ee Parameter:

  • Hot-Knäppchen:
    ~]# cat /etc/elasticsearch/elasticsearch.yml | grep attr
    # Add custom attributes to the node:
    node.attr.box_type: hot
  • waarm-Knäppchen:
    ~]# cat /etc/elasticsearch/elasticsearch.yml | grep attr
    # Add custom attributes to the node:
    node.attr.box_type: warm
  • Kale-Knäppchen:
    ~]# cat /etc/elasticsearch/elasticsearch.yml | grep attr
    # Add custom attributes to the node:
    node.attr.box_type: cold

Logstash opbauen

Wéi funktionéiert dat alles a wéi hu mir dës Funktioun ëmgesat? Loosst eis ufänken mat de Logbicher an Elasticsearch ze kréien. Et ginn zwou Méiglechkeeten:

  1. Logstash retrieves Logbicher aus Kafka. Kann propper ophuelen oder op senger Säit konvertéieren.
  2. Eppes schreift sech op Elasticsearch, zum Beispill, en APM Server.

Loosst eis e Beispill kucken fir Indexen duerch Logstash ze managen. Et erstellt en Index a gëllt Index Schabloun an entspriechend WËSSENSCHAFT.

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
    }
}

Kibana opsetzen

Et gëtt eng Basis Schabloun déi fir all nei Indexen gëlt. Et setzt d'Verdeelung vu waarme Indexen, d'Zuel vun de Schnëtt, Repliken, asw. D'Gewiicht vun der Schabloun gëtt vun der Optioun bestëmmt order. Schabloune mat méi héije Gewiichter iwwerschreiden existéierend Schablounparameter oder addéiere nei.

Laangfristeg Datelagerung an Elasticsearch
Laangfristeg Datelagerung an Elasticsearch

GET_template/default

{
  "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" : { }
  }
}

Da gëllen d'Mapping op Indexen k8s-ingress-* mat enger Schabloun mat engem méi héije Gewiicht.

Laangfristeg Datelagerung an Elasticsearch
Laangfristeg Datelagerung an Elasticsearch

GET _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" : { }
  }
}

Nodeems mir all Templates applizéiert hunn, gëlle mir d'ILM Politik an fänken un d'Liewe vun den Indexen ze iwwerwaachen.

Laangfristeg Datelagerung an Elasticsearch

Laangfristeg Datelagerung an Elasticsearch

Laangfristeg Datelagerung an Elasticsearch

GET _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" : { }
          }
        }
      }
    }
  }
}

Problem

Et waren Probleemer am Setup- an Debuggingstadium.

Hot Phase

Fir richteg Rotatioun vun Indizes, d'Präsenz um Enn vun index_name-date-000026 Format Zuelen 000001. Et gi Linnen am Code déi Indizes iwwerpréift mat engem reguläre Ausdrock fir Zuelen um Enn. Soss gëtt et e Feeler, Politik gëtt net op den Index ugewannt an et wäert ëmmer an der waarmer Phase sinn.

Warm Phase

Schrëft verklengeren (Ausschneiden) - d'Zuel vun de Schnëtt reduzéieren, well mir 4 Wirbelen an de waarme a kale Phasen hunn D'Dokumentatioun enthält déi folgend Zeilen:

  • Den Index muss nëmme liesen.
  • Eng Kopie vun all Shard am Index muss um selwechten Node wunnen.
  • De Cluster Gesondheetszoustand muss gréng sinn.

Fir en Index ze trimmen, bewegt Elasticsearch all primär Shards op een Node, duplizéiert den ofgeschniddenen Index mat den néidege Parameteren an läscht dann den alen. Parameter total_shards_per_node muss gläich oder méi grouss sinn wéi d'Zuel vun den Haaptscharfen fir se op engem Node ze passen. Soss ginn et Notifikatiounen an d'Shards wäerten net op déi erfuerderlech Noden réckelen.

Laangfristeg Datelagerung an Elasticsearch
Laangfristeg Datelagerung an Elasticsearch

GET /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"
          }
        }
      }
    }
  }
}

Kale Phase

afréieren (afréieren) - mir afréieren den Index fir Ufroen op Basis vun historeschen Donnéeën ze optimiséieren.

Recherchen, déi op gefruerene Indizes gemaach ginn, benotzen de klenge, engagéierten, search_throttled threadpool fir d'Zuel vu gläichzäiteg Sichen ze kontrolléieren déi gefruerene Stécker op all Node treffen. Dëst limitéiert d'Quantitéit vun extra Erënnerung néideg fir déi transient Daten Strukturen entspriechend gefruer shards, déi konsequent Node schützt géint exzessiv Erënnerung Konsum.
Gefruer Indizes sinn nëmme liesen: Dir kënnt net an hinnen indexéieren.
Recherchen op gefruerene Indizes ginn erwaart lues auszeféieren. Frozen Indizes sinn net fir héich Sichbelaaschtung geduecht. Et ass méiglech datt eng Sich no engem gefruerenen Index Sekonnen oder Minutten dauere kann fir ze kompletéieren, och wann déiselwecht Sich a Millisekonnen ofgeschloss sinn wann d'Index net gefruer waren.

Resultater

Mir hunn geléiert wéi een Node virbereet fir mat ILM ze schaffen, eng Schabloun opzestellen fir d'Shards tëscht waarme Wirbelen ze verdeelen an ILM fir en Index mat all Liewensphasen konfiguréiert ze hunn.

Nëtzlech Adressen

Source: will.com

Kaaft zouverlässeg Hosting fir Site mat DDoS Schutz, VPS VDS Server 🔥 Kaaft zouverléissegt Websäithosting mat DDoS-Schutz, VPS VDS Server | ProHoster