Настройка логирования серверных компонент

Серверные компоненты кластера YTsaurus пишут подробные логи, которые можно использовать для аудита и анализа проблем при эксплуатации. В продакшн-инсталляциях рекомендуется выделять под логи отдельные локации на персистентных томах. Отсутствие логов может существенно ограничить возможности поддержки.

Для анализа работы подсистемы логирования можно воспользоваться prometheus-метриками с префиксом yt_logging_*.

Отладочные логи

Отладочные логи описываются в секции loggers спецификации компонент YTsaurus.

Таблица 1 — Настройки отладочных логгеров YTsaurus

Поле Возможные значения Описание
name произвольная строка Имя логгера; рекомендуется выбирать короткие и понятные названия debug, info и т. п.
format plain_text (default), yson, json Формат строки лога.
minLogLevel trace, debug, info, error Минимальный уровень записей, попадающих в лог.
categoriesFilter Фильтр, позволяющий писать логи только от некоторых подсистем, см. ниже.
writerType file, stderr Писать логи в файл или в stderr. При записи в stderr настройки ротации будут игнорироваться.
compression none (default), gzip, zstd Если задано значение, отличное от none, сервер YTsaurus будет писать сжатые логи.
useTimestampSuffix true, false (default) Если true, к имени файла в момент открытия или ротации дописывается timestamp. При этом механизм нумерации старых сегментов при ротации не используется. Имеет смысл только при записи в файл.
rotationPolicy Настройки ротации логов, см. ниже. Имеет смысл только при записи в файл.

Путь к каталогу, куда будут записываться логи с writerType=file , задаётся в описании локации типа Logs. В случае, если локация Logs не указана, логи будут записываться в каталог /var/log.

Имена файлов с логом формируются следующим образом: [component].[name].log(.[format])(.[compression])(.[timestamp_suffix]). Примеры:

  • controller-agent.error.log
  • master.debug.log.gzip
  • scheduler.info.log.json.zstd.2023-01-01T10:30:00

Записи отладочных логов содержат следующие поля:

  • instant — время в локальной временной зоне;
  • level — уровень записи: T — trace, D — debug, I — info, W — warning, E — error;
  • category — имя подсистемы, к которой относится запись, например ChunkClient, ObjectServer или RpcServer;
  • message — тело сообщения;
  • thread_id — id (или имя) треда, породившего запись; пишется только в формате plain_text;
  • fiber_id — id файбера, породившего запись; пишется только в формате plain_text;
  • trace_id — trace_context id, в контексте которого появилась запись; пишется только в формате plain_text.
Пример записи
2023-09-15 00:00:17,215385      I       ExecNode        Artifacts prepared (JobId: d15d7d5f-164ff08a-3fe0384-128e0, OperationId: cd56ab80-d21ef5ab-3fe03e8-d05edd49, JobType: Map)      Job     fff6d4149ccdf656    2bd5c3c9-600a44f5-de721d58-fb905017

Рекомендации по настройке категорий

Существует два вида фильтра по категориям (categoriesFilter):

  • включающий — пишутся записи только тех категорий, которые были явно перечислены;
  • исключающий — пишутся записи любых категорий, кроме тех, которые были перечислены.

Зачастую, в больших инсталляциях приходится исключать категории Bus и Concurrency.

Примеры фильтров
categoriesFilter:
  type: exclude
  values: ["Bus", "Concurrency"]

categoriesFilter:
  type: include
  values: ["Scheduler", "Strategy"]

Структурированные логи

Некоторые компоненты YTsaurus способны писать структурированные логи, которые можно использовать впоследствии для аудита, аналитики и автоматической обработки. Структурированные логи описываются в секции structured_loggers спецификации компонент YTsaurus.

Для описания структурированных логгеров используются те же поля, что и для отладочных логов, кроме:

  • writerType — не задаётся; структурированные логи всегда пишутся в файл;
  • categoriesFilter — вместо него задаётся обязательное поле category — равно одна категория.

Структурированные логи рекомендуется всегда писать в одном из структурированных форматов — json или yson. События в структурированный лог обычно пишутся на уровне info. Набор полей структурированного лога зависит от конкретного типа лога.

Основные типы структурированных логов:

  • master_access_log — лог доступа к данным; пишется на мастере, категория Access;
  • master_security_log — лог событий безопасности, например добавление пользователя в группу или изменение ACL; пишется на мастере, категория SecurityServer;
  • structured_http_proxy_log — лог запросов к http proxy, по одной строке на запрос; пишется на http proxy, категория HttpStructuredProxy;
  • chyt_log — лог запросов к CHYT, по одной строке на запрос; пишется на http proxy, категория ClickHouseProxyStructured;
  • structured_rpc_proxy_log — лог запросов к rpc proxy, по одной строке на запрос; пишется на rpc proxy, категория RpcProxyStructuredMain;
  • scheduler_event_log — лог событий планировщика; пишется планировщиком, категория SchedulerEventLog;
  • controller_event_log — лог событий контроллер-агента; пишется на контроллер-агенте, категория ControllerEventLog.

Лог доступа к таблице

Иногда возникает необходимость узнать, кто пользуется той или иной таблицей, — например, чтобы оценить последствия ее удаления или перемещения. Задача осложняется тем, что доступ может осуществляться посредством ссылок.

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

Лог пишут мастер-серверы, причем в силу технических особенностей несколько различных серверов производят одинаковую последовательность записей, так что дублирования стоит ожидать. Кроме того, некоторая активность (например, запись в таблицы) выглядит как последовательность нескольких разных событий на разных мастер-серверах (из разных шардов). Подробнее об этом далее.

Каждая запись в логе (каждая строка в таблице) фиксирует одну команду, примененную к тому или иному кипарисному узлу.

Журналируются только команды, примененные к следующим типам узлов:

  • таблица;
  • файл;
  • документ;
  • журнал.

Стоит явно отметить, что директории не входят в данный перечень.

Журналируются следующие команды:

  • базовые (CRUD):
    • Create
    • Get
    • GetKey
    • Exists
    • List
    • Set
    • Remove
  • создание символической ссылки:
    • Link
  • блокировки:
    • Lock
    • Unlock
  • копирование и перемещение:
    • Copy
    • Move
    • BeginCopy, EndCopy
  • чтение и запись данных:
    • GetBasicAttributes
    • Fetch
    • BeginUpload
    • EndUpload
  • изменение состояния динамической таблицы:
    • PrepareMount, CommitMount, AbortMount
    • PrepareUnmount, CommitUnmount, AbortUnmount
    • PrepareRemount, CommitRemount, AbortRemount
    • PrepareFreeze, CommitFreeze, AbortFreeze
    • PrepareUnfreeze, CommitUnfreeze, AbortUnfreeze
    • PrepareReshard, CommitReshard, AbortReshard
  • прочие:
    • CheckPermission

Некоторые комментарии касательно семантики команд можно найти далее.

Содержательная часть записи в логе имеет поля (колонки в таблице), представленные в таблице 1.

Таблица 1 — Описание полей лога

Поле Описание
instant Время события в формате YYYY-MM-DD hh:mm:ss,sss
cluster Короткое имя кластера
method Команда (см. список выше)
path (см. примечание) Путь, переданный команде в качестве аргумента
original_path (см. примечание) Путь, переданный команде в качестве аргумента
destination_path (см. примечание) Для команд «Copy», «Move» и «Link» — путь назначения (для других команд отсутствует)
original_destination_path (см. примечание) Для команд «Copy», «Move» и «Link» — путь назначения (для других команд отсутствует)
user Пользователь, давший команду
type Для команды «Create» — тип создаваемого узла (для других команд отсутствует)
transaction_info Сведения о транзакции, в контексте которой была выполнена команда (если команда выполнялась вне транзакции, поле отсутствует)

Примечание

Отличие поля original_path от path (а также original_destination_path от destination_path) заключается в следующем:

  • если в качестве пути была указана ссылка (симлинк), в original_path будет путь к ссылке, а в path — «настоящий» путь к узлу;
  • далее, если этот путь ведет в шард, то в логе этого шарда в качестве original_path будет указан «настоящий» путь, а в качестве path — путь относительно корня шарда.

В общей сложности это означает, что условный grep по пути к симлинку всегда найдёт записи, содержащие настоящий путь к узлу, а grep по настоящему пути найдёт обращения в том числе и через симлинки. Важно лишь выполнять поиск как по path, так и по original_path.

Структура поля transaction_info представлена в таблице 2.

Таблица 2 — Структура поля transaction_info

Поле Описание
transaction_id ID транзакции
transaction_title Человекочитаемое описание транзакции (указывается клиентом при запуске транзакции; поле отсутствует, если описание не было указано)
operation_id ID операции, ассоциированной с транзакцией
operation_title Человекочитаемое описание операции, ассоциированной с транзакцией
parent Для вложенной транзакции — описание ее родителя (для верхнеуровневой транзакции поле отсутствует)

Следует отметить, что поле parent устроено так же, как и transaction_info. Таким образом, transaction_info содержит полное рекурсивное описание родословной транзакции, из-под которой была выполнена команда.

Замечания

  1. Стоит отличать чтение/запись метаданных от чтения/записи данных (чанков) в таблицы и файлы.
  2. С точки зрения мастера, чтение/запись данных выглядит как следующая последовательность команд:
    • чтение:
      • GetBasicAttributes — получение некоторых служебных атрибутов, без которых чтение невозможно;
      • Fetch — получение списка чанков, из которых состоит файл или таблица;
    • запись:
      • GetBasicAttributes — получение некоторых служебных атрибутов, без которых запись невозможна;
      • BeginUpload — открытие заливочной транзакции;
      • EndUpload — завершение заливочной транзакции.
  3. При чтении/записи данных команда GetBasicAttributes приходит на один селл, а Fetch, BeginUpload и EndUpload — на другой; это нормально.
  4. В подавляющем большинстве случаев копирование или перемещение таблицы выглядят как команды Copy или Move. Команды BeginCopy и EndCopy используются, когда копирование/перемещение пересекает границы шардирования Кипариса. На практике пользователи с таким должны сталкиваться редко.

Настройка ротации логов

Для отладочных и структурированных логов, которые пишутся в файл, можно настроить встроенный механизм ротации (поле rotationPolicy). Настройки ротации приведены в таблице. Если не используется опция useTimestampSuffix, в момент ротации файлы старых сегментов переименовываются, с дописыванием порядкового номера.

Таблица 2 — Настройки ротации логов

Поле Описание
rotationPeriodMilliseconds Период ротации, в миллисекундах. Может задаваться вместе с maxSegmentSize.
maxSegmentSize Ограничение на размер одного сегмента лога, в байтах. Может задаваться вместе с rotationPeriodMilliseconds.
maxTotalSizeToKeep Ограничение на размер всех сегментов, в байтах. В момент ротации, удаляются самые старые логи так, чтобы уложиться в заданное ограничение.
maxSegmentCountToKeep Ограничение на количество хранимых сегментов лога, в штуках. Самые старые сегменты сверх ограничения удаляются.

Динамическая конфигурация

Компоненты, поддерживающие динамическую конфигурацию, позволяют дополнительно уточнить настройки системы логирования с помощью динамического конфига в Кипарисе, секция logging.

Основные параметры:

  • enable_anchor_profiling — включает prometheus-метрики по отдельным префиксам записей;
  • min_logged_message_rate_to_profile — минимальная частота сообщения, для попадания в отдельную метрику;
  • suppressed_messaged — список префиксов сообщений отладочных логов, которые будут исключены из логирования.

Пример конфигурации:

{
  logging = {
    enable_anchor_profiling = %true;
    min_logged_message_rate_to_profile = 100;
    suppressed_messaged = [
      "Skipping out of turn block",
      "Request attempt started",
      "Request attempt acknowledged"
    ];
  }
}

Пример настройки логирования

  primaryMasters:
    ...
    loggers:
	  - name: debug
        compression: zstd
        minLogLevel: debug
        writerType: file
        rotationPolicy:
          maxTotalSizeToKeep: 50_000_000_000
          rotationPeriodMilliseconds: 900000
        categoriesFilter:
          type: exclude
          values: ["Bus", "Concurrency", "ReaderMemoryManager"]
      - name: info
        minLogLevel: info
        writerType: file
        rotationPolicy:
    	  maxTotalSizeToKeep: 10_000_000_000
          rotationPeriodMilliseconds: 900000
      - name: error
        minLogLevel: error
        writerType: stderr
    structuredLoggers:
      - name: access
        minLogLevel: info
        category: Access
        rotationPolicy:
          maxTotalSizeToKeep: 5_000_000_000
          rotationPeriodMilliseconds: 900000
    locations:
      - locationType: Logs
        path: /yt/logs
      - ...

    volumeMounts:
      - name: master-logs
        mountPath: /yt/logs
      - ...

    volumeClaimTemplates:
      - metadata:
          name: master-logs
        spec:
          accessModes: [ "ReadWriteOnce" ]
          resources:
            requests:
              storage: 100Gi
      - ...
Следующая