Storio data hirdymor yn Elasticsearch

Storio data hirdymor yn Elasticsearch

Fy enw i yw Igor Sidorenko, rwy'n arweinydd technegol yn y tîm o weinyddwyr sy'n cynnal seilwaith cyfan Domclick.

Rwyf am rannu fy mhrofiad wrth sefydlu storfa ddata ddosbarthedig yn Elasticsearch. Byddwn yn edrych ar ba osodiadau ar y nodau sy'n gyfrifol am ddosbarthu darnau, sut mae ILM yn gweithio ac yn gweithio.

Mae'r rhai sy'n gweithio gyda logiau, un ffordd neu'r llall, yn wynebu'r broblem o storio hirdymor i'w dadansoddi'n ddiweddarach. Yn Elasticsearch, mae hyn yn arbennig o wir, oherwydd roedd popeth yn anffodus ag ymarferoldeb y curadur. Cyflwynodd fersiwn 6.6 ymarferoldeb ILM. Mae'n cynnwys 4 cam:

  • Poeth - Mae'r mynegai wrthi'n cael ei ddiweddaru a'i holi.
  • Cynnes - Nid yw'r mynegai bellach yn cael ei ddiweddaru, ond mae'n dal i gael ei gwestiynu.
  • Oer - Nid yw'r mynegai bellach yn cael ei ddiweddaru ac anaml y caiff ei holi. Rhaid dal i allu chwilio'r wybodaeth, ond gall ymholiadau fod yn arafach.
  • Dileu - Nid oes angen y mynegai mwyach a gellir ei ddileu yn ddiogel.

Wedi rhoi

  • Data Elasticsearch Poeth: 24 prosesydd, cof 128 GB, 1,8 TB SSD RAID 10 (8 nod).
  • Cynnes Data Elasticsearch: 24 prosesydd, cof 64 GB, 8 TB Polisi SSD NetApp (4 nod).
  • Elasticsearch Data Cold: 8 prosesydd, cof 32 GB, 128 TB HDD RAID 10 (4 nod).

Nod

Mae'r gosodiadau hyn yn unigol, mae'r cyfan yn dibynnu ar le ar y nodau, nifer y mynegeion, logiau, ac ati. Mae gennym 2-3 TB o ddata y dydd.

  • 5 diwrnod - Cyfnod poeth (8 prif / 1 replica).
  • 20 diwrnod - Cyfnod cynnes (crebachu-mynegai 4 prif / 1 replica).
  • 90 diwrnod - cyfnod oer (rhewi-mynegai 4 prif / 1 replica).
  • 120 diwrnod - Dileu cam.

Sefydlu Elasticsearch

I ddosbarthu darn ar draws nodau, dim ond un paramedr sydd ei angen arnoch chi:

  • poeth- nodau:
    ~]# cat /etc/elasticsearch/elasticsearch.yml | grep attr
    # Add custom attributes to the node:
    node.attr.box_type: hot
  • Cynnes- nodau:
    ~]# cat /etc/elasticsearch/elasticsearch.yml | grep attr
    # Add custom attributes to the node:
    node.attr.box_type: warm
  • Oer- nodau:
    ~]# cat /etc/elasticsearch/elasticsearch.yml | grep attr
    # Add custom attributes to the node:
    node.attr.box_type: cold

Sefydlu Logstash

Sut mae'r cyfan yn gweithio a sut y gwnaethom roi'r nodwedd hon ar waith? Gadewch i ni ddechrau trwy gael logiau i mewn i Elasticsearch. Mae dwy ffordd:

  1. Mae Logstash yn nôl boncyffion o Kafka. Yn gallu codi'n lân neu drosi ar eich ochr chi.
  2. Mae rhywbeth ei hun yn ysgrifennu at Elasticsearch, er enghraifft, gweinydd APM.

Ystyriwch enghraifft o reoli mynegeion trwy Logstash. Mae'n creu mynegai ac yn berthnasol iddo patrwm mynegai ac yn cyfateb TYWYDD.

k8s-mynediad.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
    }
}

Gosodiad Kibana

Mae patrwm sylfaenol sy'n berthnasol i bob mynegai newydd. Mae'n gosod dosbarthiad mynegeion poeth, nifer y darnau, replicas, ac ati. Mae pwysau'r templed yn cael ei bennu gan yr opsiwn order. Mae templedi â phwysau uwch yn diystyru paramedrau templed presennol neu'n ychwanegu rhai newydd.

Storio data hirdymor yn Elasticsearch
Storio data hirdymor yn Elasticsearch

GET _template/diofyn

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

Yna cymhwyswch y mapio i'r mynegeion k8s-ingress-* defnyddio templed gyda phwysau uwch.

Storio data hirdymor yn Elasticsearch
Storio data hirdymor yn 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" : { }
  }
}

Ar ôl cymhwyso'r holl dempledi, rydym yn cymhwyso polisi'r ILM ac yn dechrau monitro oes y mynegeion.

Storio data hirdymor yn Elasticsearch

Storio data hirdymor yn Elasticsearch

Storio data hirdymor yn 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" : { }
          }
        }
      }
    }
  }
}

Problemau

Roedd problemau yn y cam gosod a dadfygio.

Cyfnod poeth

Ar gyfer cylchdroi mynegeion yn gywir, mae presenoldeb ar y diwedd yn hollbwysig index_name-date-000026 rhifau fformat 000001. Mae llinellau yn y cod sy'n gwirio mynegeion gan ddefnyddio mynegiant rheolaidd ar gyfer presenoldeb rhifau ar y diwedd. Fel arall, bydd gwall, ni fydd unrhyw bolisïau yn cael eu cymhwyso i'r mynegai, a bydd bob amser yn y cyfnod poeth.

Cyfnod cynnes

Chrebacha (toriad) — lleihau nifer y darnau, oherwydd mae gennym 4 nod yn y cyfnodau cynnes ac oer Mae'r ddogfennaeth yn cynnwys y llinellau canlynol:

  • Rhaid i'r mynegai fod yn ddarllenadwy yn unig.
  • Rhaid i gopi o bob darn yn y mynegai fod ar yr un nod.
  • Rhaid i statws iechyd y clwstwr fod yn wyrdd.

I docio mynegai, mae Elasticsearch yn symud yr holl ddarnau cynradd i un nod, yn dyblygu'r mynegai cwtogi â'r paramedrau angenrheidiol, ac yna'n dileu'r hen un. Paramedr total_shards_per_node rhaid iddo fod yn hafal i neu'n fwy na nifer y prif ddarnau i'w ffitio ar un nod. Fel arall, bydd hysbysiadau ac ni fydd darnau yn symud i'r nodau cywir.

Storio data hirdymor yn Elasticsearch
Storio data hirdymor yn 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"
          }
        }
      }
    }
  }
}

Cyfnod oer

Rhewi (rhewi) - Rydym yn rhewi'r mynegai i wneud y gorau o ymholiadau ar ddata hanesyddol.

Mae chwiliadau a gyflawnir ar fynegeion wedi'u rhewi yn defnyddio'r pwll edau search_throttled bach, pwrpasol i reoli nifer y chwiliadau cydamserol sy'n taro darnau wedi'u rhewi ar bob nod. Mae hyn yn cyfyngu ar faint o gof ychwanegol sydd ei angen ar gyfer y strwythurau data dros dro sy'n cyfateb i ddarnau wedi'u rhewi, sydd o ganlyniad yn amddiffyn nodau rhag gor-ddefnyddio cof.
Mae mynegeion wedi'u rhewi yn rhai darllen-yn-unig: ni allwch fynegeio iddynt.
Disgwylir i chwiliadau ar fynegeion wedi'u rhewi gyflawni'n araf. Nid yw mynegeion wedi'u rhewi wedi'u bwriadu ar gyfer llwyth chwilio uchel. Mae’n bosibl y bydd chwiliad o fynegai wedi’i rewi yn cymryd eiliadau neu funudau i’w gwblhau, hyd yn oed os cwblhawyd yr un chwiliadau mewn milieiliadau pan na chafodd y mynegeion eu rhewi.

Canlyniadau

Dysgon ni sut i baratoi nodau ar gyfer gweithio gydag ILM, sefydlu templed ar gyfer dosbarthu darnau rhwng nodau poeth, a sefydlu ILM ar gyfer mynegai gyda phob cyfnod o fywyd.

Dolenni defnyddiol

Ffynhonnell: hab.com