Radiofisik

my knowledge base

ElasticSearch

Анализ логов

Допустим есть некоторый инстанс ElasticSearch который хранит логи от приложения с микро сервисной архитектурой. Каждый день создается новый индекс с логами. Известно что на некоторую дату мониторинг обнаружил повышенную нагрузку на сервер. Задача состоит в том чтобы понять что пошло не так.

Для удобства можно экспортировать URL в переменную

export ES_URL=http://docker:19202
export ES_INDEX=production_log-2019.07.10
export ES_TYPE=logevent

#проверим доступность
curl -X GET $ES_URL

Если не известен точное имя индекса найдем его отобразив все

curl -X GET $ES_URL/_cat/indices?v
#если примерное имя известно
curl -X GET $ES_URL/_cat/indices/log-2019.07*?v

Индекс найден, чтобы понять какие поля есть в индексе получим маппинг этого индекса

curl -X GET  $ES_URL/$ES_INDEX/_mappings?pretty

Из маппинга знаем что есть поле содержащее имя сборки fields.AssemblyName попытаемся ответить на вопрос на какой микросервис пришлась нагрузка. для этого агрегируем количество запросов по имени сборки. Так как в маппинге fields это nested документ то запрос

curl -XGET "$ES_URL/$ES_INDEX/_search?pretty" -H 'Content-Type: application/json; charset=UTF-8' -d'
{
  "aggs": {
    "microservice": {
      "nested": {
        "path": "fields"
      },
      "aggs": {
        "microservicein": {
          "terms": {
            "field": "fields.AssemblyName"
          }
        }
      }
    }
  }
}'

Ответ указывает на то что проблема в микросервисе аутентификации

...
"aggregations" : {
    "microservice" : {
      "doc_count" : 4062471,
      "microservicein" : {
        "doc_count_error_upper_bound" : 0,
        "sum_other_doc_count" : 27,
        "buckets" : [
          {
            "key" : "AuthServer",
            "doc_count" : 3948812
          },
          {
            "key" : "SomeService",
            "doc_count" : 58679
          },
          {
            "key" : "UserManagement",
            "doc_count" : 33077
          },
...

Отфильтруем события этого сервиса и агрегируем их по типу


curl -XGET "$ES_URL/$ES_INDEX/_search?pretty" -H 'Content-Type: application/json; charset=UTF-8' -d'
{
  "query": {
    "nested": {
      "path": "fields",
      "query": {
        "term": {
          "fields.AssemblyName": "AuthServer"
        }
      }
    }
  },
  "aggs": {
    "microservice": {
      "terms": {
        "field": "level"
      }
    }
  }
}'

Получим распределение

"aggregations" : {
    "microservice" : {
      "doc_count_error_upper_bound" : 0,
      "sum_other_doc_count" : 0,
      "buckets" : [
        {
          "key" : "Debug",
          "doc_count" : 3419486
        },
        {
          "key" : "Information",
          "doc_count" : 530368
        },
        {
          "key" : "Warning",
          "doc_count" : 744
        }
      ]
    }
  }

Подозрительно много Warning отфильтруем их

curl -XGET "$ES_URL/$ES_INDEX/_search?pretty" -H 'Content-Type: application/json; charset=UTF-8' -d'
{
    "query": {
        "bool": {
            "must": [
                {
                    "term": {
                        "level": "Warning"
                    }
                },
                {
                    "nested": {
                        "path": "fields",
                        "query": {
                            "term": {
                                "fields.AssemblyName": "AuthServer"
                            }
                        }
                    }
                }
            ]
        }
    }
}'

В результате получили Warning которые связаны с локализацией и не представляют интереса. Попытаемся зайти с другой стороны и агрегировать события по пользователям.


curl -XGET "$ES_URL/$ES_INDEX/_search?pretty" -H 'Content-Type: application/json; charset=UTF-8' -d'
{
  "query": {
    "nested": {
      "path": "fields",
      "query": {
        "term": {
          "fields.AssemblyName": "AuthServer"
        }
      }
    }
  },
      "aggs": {
        "microservice": {
            "nested": {
                "path": "fields"
            },
            "aggs": {
                "microservicein": {
                    "terms": {
                        "field": "fields.CompanyId"
                    }
                }
            }
        }
    }
}'

в результате получим id проблемной компании

...
"aggregations" : {
    "microservice" : {
      "doc_count" : 3955148,
      "microservicein" : {
        "doc_count_error_upper_bound" : 158,
        "sum_other_doc_count" : 29196,
        "buckets" : [
          {
            "key" : "bf34ca49-946a-42c0-a5b1-637e59ef7034",
            "doc_count" : 3540355
          },
          {
            "key" : "d04bcd39-076f-4293-b2c7-637e59ef7034",
            "doc_count" : 16380
          },
          {
            "key" : "aa225eef-fb63-4f6e-bb02-637e59ef7034",
            "doc_count" : 11193
          },
      ...

теперь известна проблемная компания, добавим ее в фильтр

curl -XGET "$ES_URL/$ES_INDEX/_search?pretty" -H 'Content-Type: application/json; charset=UTF-8' -d'
{
    "query": {
        "bool": {
            "must": [
                {
                    "nested": {
                        "path": "fields",
                        "query": {
                            "bool": {
                                "must": [
                                    {
                                        "term": {
                                            "fields.AssemblyName": "AuthServer"
                                        }
                                    },
                                    {
                                        "term": {
                                            "fields.CompanyId": "bf34ca49-946a-42c0-a5b1-637e59ef7034"
                                        }
                                    }
                                ]
                            }
                        }
                    }
                }
            ]
        }
    }
}'

далее ручным просмотром найдем CorrelationContext и добавим в поиск

{
  "query": {
    "bool": {
      "must": [
        {
          "nested": {
            "path": "fields",
            "query": {
              "bool": {
                "must": [
                  {
                    "term": {
                      "fields.AssemblyName": "AuthServer"
                    }
                  },
                  {
                    "term": {
                      "fields.CompanyId": "bf34ca49-946a-42c0-a5b1-637e59ef7034"
                    }
                  },
                  {
                    "term": {
                      "fields.CorrelationContext": "0HLNR8LB3PKEP:00000001"
                    }
                  }
                ]
              }
            }
          }
        }
      ]
    }
  }
}

Найдем первый запрос, в нем есть заголовки с информацией

{"Connection":["close"],"Content-Type":["application/x-www-form-urlencoded"],"Accept":["application/json, text/plain, */*"],"Accept-Encoding":["gzip, deflate, br"],"Accept-Language":["ru-RU,ru;q=0.9,en-US;q=0.8,en;q=0.7"],"Authorization":["Bearer __token was here__"],"Host":["auth"],"Referer":["https://domain.com"],"User-Agent":["Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36"],"Origin":["https://domain.com"],"Content-Length":["164"],"X-real-base-url":["https://domain.com/auth"],"X-Real-IP":["_ip was here_"],"X-Forwarded-For":["_ip was here_"],"X-User-CompanyId":["bf34ca49-946a-42c0-a5b1-637e59ef7034"],"x-request-id":["0HLNR8LB3PKEP:00000001"]}

Расшифровав jwt токен с помощью https://jwt.io/

{
  "nbf": 1562732742,
  "exp": 1562733642,
  "iss": "https://domain.com:443/auth",
  "aud": "https://domain.com:443/auth/resources",
  "client_id": "angular2client",
  "sub": "33d87afa-8a2c-4a08-964a-7c5c08413e44",
  "auth_time": 1562731599,
  "idp": "local",
  "email": "email was here",
  "scope": [
    "email",
    "openid",
    "offline_access"
  ],
  "amr": [
    "pwd"
  ]
}

Другие полезные команды

Действия диагностики кластера

curl -XGET "$ES_URL/_cat/health?v"
curl -XGET "$ES_URL/_cat/nodes?v"
curl -XGET "$ES_URL/_cat/shards?v"
curl -XGET "$ES_URL/_cat/allocation?v"

curl -XGET "$ES_URL/_cat/count?v"
curl -XGET "$ES_URL/_cat/indices?v"
curl -XGET "$ES_URL/_cluster/health?level=indices&pretty"
curl -XGET "$ES_URL/_nodes/hot_threads"

Backup и Restore


curl -X PUT \
  $ES_URL/_snapshot/backup-repo \
  -H 'Content-Type: application/json' \
  -d '{
	"type": "fs",
	"settings":{
		"location": "/home/user/backup/"
	}
}'

curl -X PUT $ES_URL/_snapshot/backup-repo/snapshot1 
curl -X POST  $ES_URL/_snapshot/backup-repo/snapshot1/_restore

Работа с шаблонами индекса

curl -X GET $ES_URL/_cat/templates?v&s=name
curl -X DELETE $ES_URL/_template/serilog-events-template

Удалить индекс

curl -X DELETE $ES_URL/$ES_INDEX?pretty

Решение проблемы `403Type: cluster_block_exception Reason: “blocked by: [FORBIDDEN/12/index read-only / allow fix’ возникшей когда кончилось место на диске https://discuss.elastic.co/t/forbidden-12-index-read-only-allow-delete-api/110282/4

curl -X  PUT $ES_URL/$ES_INDEX/_settings -H 'Content-Type: application/json'  -d '{"index": {"blocks": {  "read_only_allow_delete": "false"}}}'

curl -X  PUT $ES_URL/_settings -H 'Content-Type: application/json'  -d '{"index": {"blocks": {  "read_only_allow_delete": "false"}}}'

Работа с документом

# создадим документ
curl -XPUT "$ES_URL/$ES_INDEX/$ES_TYPE/1?pretty" -H 'Content-Type: application/json' -d'{"title": "тест"}'

# извлечем документ с id 1 типа $ES_TYPE из индекса $ES_INDEX
curl -XGET "$ES_URL/$ES_INDEX/$ES_TYPE/1?pretty"

# извлечем только поле title
curl -XGET "$ES_URL/$ES_INDEX/$ES_TYPE/1?_source=title&pretty"

Поиск

curl -XGET "$ES_URL/$ES_INDEX/_search?pretty" -H 'Content-Type: application/json; charset=UTF-8' -d'
{
	"size":"10",
	"_source": ["message", "@timestamp"],
	"sort": [{"@timestamp": "desc"}]
}'