Перейти к содержимому
Последнее обновление

Memory Tracker

Doris BE использует Memory Tracker для учёта потребления памяти процессом, включая память, используемую в течение жизненного цикла таких задач, как выполнение запросов, загрузка, compaction и изменение схемы, а также различными кэшами. Статистику можно просматривать в реальном времени на веб-страницах; при возникновении ошибок, связанных с памятью, она выводится в журналы BE. Это помогает анализировать использование памяти и диагностировать проблемы с ней.

Способы просмотра данных Memory Tracker, причины чрезмерного потребления памяти, отражаемого различными Memory Tracker, и методы анализа для его снижения описаны в разделе Обзор в контексте структуры памяти Doris BE. В этой статье рассматриваются только принципы работы, структура и некоторые распространённые проблемы Memory Tracker.

Принцип отслеживания памяти​

Memory Tracker использует Doris Allocator для отслеживания каждого выделения и освобождения памяти. Подробнее о Doris Allocator см. в разделе Стратегия управления памятью.

Память процесса: Doris BE периодически получает из системы данные о потреблении памяти процессом Doris BE. Поддерживается работа с Cgroup.

Память задач: при инициализации каждого запроса, загрузки, compaction и других задач создаётся собственный уникальный Memory Tracker, который во время выполнения помещается в TLS (Thread Local Storage). Основные структуры данных Doris для работы с памятью наследуются от Allocator. Allocator регистрирует каждое выделение и освобождение памяти в Memory Tracker, находящемся в TLS.

Память операторов: различные операторы выполнения задач, такие как Join/Agg/Sink, также создают собственные Memory Tracker. Они поддерживают ручной учёт памяти; кроме того, их можно поместить в TLS, чтобы учёт вёл Doris Allocator. Эти данные используются для управления логикой выполнения и анализа потребления памяти различными операторами в Query Profile.

Глобальная память: глобальная память в основном включает Cache и метаданные, совместно используемые разными задачами. У каждого Cache есть собственный уникальный Memory Tracker, в котором учёт ведётся с помощью Doris Allocator или вручную; память метаданных пока учитывается не полностью, поэтому её анализ в большей степени опирается на различные счётчики метаданных, собираемые Metrics и Bvar.

Данные о потреблении памяти процессом Doris BE поступают из операционной системы и могут считаться полностью точными. Из-за ограничений реализации другие Memory Tracker обычно отслеживают лишь часть фактически используемой памяти, поэтому в большинстве случаев сумма значений всех Memory Tracker меньше объёма физической памяти, занимаемой процессом Doris BE. Несмотря на некоторые пропуски, в большинстве случаев данные Memory Tracker достаточно надёжны и могут уверенно использоваться для анализа памяти. Кроме того, Memory Tracker фактически отслеживает виртуальную память, а не физическую, которая обычно представляет больший интерес; между этими величинами есть определённые расхождения.

Структура Memory Tracker​

По назначению Memory Tracker делятся на две категории. Первая категория, Memory Tracker Limiter, представлена отдельным экземпляром для каждого запроса, загрузки, Compaction и других задач, а также для глобальных Cache и TabletMeta. Она используется для наблюдения за потреблением памяти и его ограничения. Вторая категория, Memory Tracker, в основном служит для отслеживания мест наибольшего потребления памяти во время выполнения запроса, таких как HashTable в Join/Aggregation/Sort/оконных функциях, сериализованные промежуточные данные и т. д. Это позволяет анализировать потребление памяти различными операторами запроса, а также управлять памятью при сбросе загружаемых данных.

Связь между родительским и дочерним объектами этих категорий используется только для вывода снимков состояния. Она устанавливается по имени метки и аналогична символической ссылке. Синхронный учёт потребления памяти не зависит от этой связи, а жизненные циклы объектов не влияют друг на друга, что упрощает понимание и использование. Все Memory Tracker хранятся в наборе отображений и предоставляют методы для вывода снимков состояния всех типов Memory Tracker, вывода снимков задач, таких как запросы/загрузки/compaction, получения группы запросов/загрузок, которые сейчас используют больше всего памяти, а также группы запросов/загрузок с наибольшим превышением потребления памяти.

Реализация Memory Tracker

Неполная статистика Memory Tracker​

Неполнота статистики Memory Tracker проявляется по-разному в версиях до и после Doris 2.1.

Признаки неполной статистики Memory Tracker​

  1. Начиная с Doris 2.1 неполная статистика Memory Tracker проявляется двумя способами.
  • Слишком большая разница между значениями Memory Tracker Label=process resident memory и Memory Tracker Label=sum of all trackers.

  • Слишком большое значение Orphan Memory Tracker.

  1. В версиях до Doris 2.1 слишком большое значение Orphan Memory Tracker означает, что статистика Memory Tracker неполна.

Анализ неполной статистики Memory Tracker​

В версиях до Doris 2.1.5, если статистика Memory Tracker неполна или потребление памяти процессом BE не снижается, обратитесь к разделу Анализ памяти кэшей, чтобы проанализировать потребление памяти SegmentCache, и попробуйте отключить Segment Cache, прежде чем продолжать тестирование.

В версиях до Doris 2.1.5 Memory Tracker для Segment Cache неточно учитывает память. Это связано с неточным учётом памяти некоторых индексов, включая Primary Key Index. В результате потребление памяти Segment Cache не удаётся эффективно ограничивать, и он часто занимает слишком много памяти, особенно при работе с большими широкими таблицами, содержащими сотни или тысячи столбцов. См. раздел Анализ памяти метаданных. Если значение doris_be_cache_usage{name="SegmentCache"} в Doris BE Metrics невелико, а значение doris_column_reader_num в Doris BE Bvar велико, стоит проверить потребление памяти Segment Cache. Если в Heap Profile в стеке вызовов с большим потреблением памяти присутствуют поля Segment и ColumnReader, можно с высокой уверенностью заключить, что Segment Cache занимает большой объём памяти.

Если наблюдается описанная выше ситуация, кластер можно без труда перезапустить и проблему можно воспроизвести, обратитесь к разделу Анализ памяти с помощью Heap Profile, чтобы проанализировать память процесса с помощью Jemalloc Heap Profile.

В противном случае можно сначала обратиться к разделу Анализ памяти метаданных, чтобы проанализировать память метаданных Doris BE.

Причины неполной статистики Memory Tracker​

Ниже описаны причины неполной статистики Memory Tracker. Они связаны с особенностями реализации Memory Tracker и обычно не требуют внимания.

Doris 2.1 и более поздние версии​

  1. Слишком большая разница между значениями Memory Tracker Label=process resident memory и Memory Tracker Label=sum of all trackers.

Если значение Memory Tracker Label=sum of all trackers составляет более 70% от значения Memory Tracker Label=process resident memory, это обычно означает, что Memory Tracker учёл большую часть памяти процесса Doris BE. В таком случае обычно достаточно проанализировать Memory Tracker, чтобы определить, где расходуется память.

Если значение Memory Tracker Label=sum of all trackers составляет менее 70% от значения Memory Tracker Label=process resident memory, это означает, что статистика Memory Tracker неполна и Memory Tracker может не позволить точно определить, где расходуется память.

Разница между значениями Memory Tracker Label=process resident memory и Memory Tracker Label=sum of all trackers соответствует памяти, выделенной без Doris Allocator. Основные структуры данных Doris для работы с памятью наследуются от Doris Allocator, но часть памяти, включая память метаданных, RPC и т. д., по-прежнему выделяется без Doris Allocator. Причиной расхождения также может быть утечка памяти. В этом случае, помимо анализа Memory Tracker с большим значением потребления памяти, обычно нужно проверить, обоснован ли объём памяти метаданных и нет ли утечки памяти.

  1. Слишком большое значение Orphan Memory Tracker
MemTrackerLimiter Label=Orphan, Type=global, Limit=-1.00 B(-1 B), Used=0(0 B), Peak=0(0 B)

Orphan Memory Tracker используется по умолчанию. Положительное или отрицательное значение означает, что память, выделенная Doris Allocator, отслеживается неточно. Чем больше это значение, тем ниже достоверность общей статистики Memory Tracker. Его значение формируется из двух источников:

  • Если при запуске потока Memory Tracker не привязан к TLS, Doris Allocator по умолчанию учитывает память в Orphan Memory Tracker. Это означает, что принадлежность этой части памяти неизвестна. Принцип учёта памяти в Doris Allocator описан выше в разделе [Принцип отслеживания памяти].

  • Если при уничтожении Memory Tracker задачи, такой как запрос или загрузка, его значение не равно 0, это обычно означает, что соответствующая память ещё не освобождена. Оставшаяся память учитывается в Orphan Memory Tracker, который продолжает её отслеживать. Благодаря этому сумма значений Orphan Memory Tracker и остальных Memory Tracker равна общему объёму памяти, выделенной Doris Allocator.

В идеале значение Orphan Memory Tracker должно быть близко к 0. Поэтому желательно, чтобы все потоки с самого начала привязывали Memory Tracker, отличный от Orphan, например Memory Tracker запроса или загрузки. Кроме того, значения всех Memory Tracker запросов и загрузок при уничтожении должны быть равны 0. Это означает, что к моменту уничтожения Memory Tracker память, использованная при выполнении запроса или загрузки, уже освобождена.

Если значение Orphan Memory Tracker не равно 0 и велико, это означает, что большой объём памяти неизвестного происхождения не освобождён либо большой объём памяти остался неосвобождённым после выполнения запросов и загрузок.

До Doris 2.1​

До Doris 2.1 вся память неизвестного происхождения учитывалась в Memory Tracker Label=Orphan, поэтому большое значение Orphan Memory Tracker означало, что статистика Memory Tracker неполна.