Перейти к основному содержимому
Версия: 2.0.x

Data Cache

Понимание основных принципов Data Cache и способов ускорения запросов данных с помощью Data Cache.

Data Cache используется для кэширования данных нативных таблиц и внешних таблиц. Эта функция включена по умолчанию начиная с версии v1.5.2. Начиная с версии v2.0.0, кэш в памяти и дисковый кэш были объединены в единую систему Data Cache для удобства управления.

Data Cache состоит из двух компонентов: Page Cache (кэш в памяти) и Block Cache (дисковый кэш).

Принципы работы Page Cache

Как кэш в памяти, Page Cache отвечает за хранение страниц данных нативных и внешних таблиц после декомпрессии. Размер этих страниц не фиксирован. В настоящее время Page Cache поддерживает кэширование следующих типов данных:

  • Страницы данных и индексные страницы нативных таблиц
  • Информация footer файлов данных внешних таблиц
  • Частично декомпрессированные страницы данных внешних таблиц

Page Cache в настоящее время использует стратегию LRU (Least Recently Used) для вытеснения данных.

Принципы работы Block Cache

Block Cache — это дисковый кэш, основная функция которого заключается в кэшировании файлов данных (из внешних таблиц, а также из cloud-native таблиц в shared-data cluster) на локальные диски. Это снижает задержку доступа к удалённым данным и повышает эффективность запросов. Размер каждого блока данных фиксирован.

Предпосылки и ценность

В сценариях аналитики Data Lake и cloud-native таблиц Selena, выступая в роли OLAP-движка запросов, должна сканировать файлы данных, хранящиеся в HDFS или объектном хранилище (далее — «удалённая система хранения»). Этот процесс сталкивается с двумя основными узкими местами производительности:

  • Чем больше файлов нужно прочитать запросу, тем больше накладные расходы на удалённый I/O.
  • В сценариях ad-hoc запросов частый доступ к одним и тем же данным приводит к избыточному потреблению удалённого I/O.

Для решения этих проблем в версии v1.5.2 была введена функция Block Cache. Она разделяет исходные данные из удалённой системы хранения на несколько блоков по определённой стратегии и кэширует эти блоки на локальных дисках узлов BE или CN. За счёт избежания повторного получения удалённых данных значительно повышается производительность запросов к горячим данным.

Сценарии использования

  • Запросы к данным из удалённых систем хранения с использованием внешних catalog (кроме JDBC Catalog).
  • Запросы к cloud-native таблицам в shared-data cluster.

Основной механизм

Разбиение данных и единица кэширования

Когда система кэширует удалённые файлы, она разбивает исходные файлы на блоки равного размера в соответствии с настроенной стратегией. Блок — это минимальная единица кэширования, и его размер настраивается.

Пример:

Если размер блока настроен как 1 МБ, при запросе файла Parquet размером 128 МБ на Amazon S3 файл будет разбит на 128 последовательных блоков (то есть [0, 1 МБ), [1 МБ, 2 МБ), ..., [127 МБ, 128 МБ)).

Каждому блоку присваивается глобально уникальный идентификатор кэша (cache key), который состоит из следующих трёх частей:

hash(filename) + fileModificationTime + blockId
КомпонентОписание
filenameИмя файла данных.
fileModificationTimeВремя последнего изменения файла данных.
blockIdID, присвоенный каждому блоку при разбиении файла данных. Этот ID уникален в пределах одного файла, но не глобально уникален.

Попадание в кэш и процесс чтения

Предположим, запрос попадает в блок в диапазоне [1 МБ, 2 МБ), Block Cache действует следующим образом:

  1. Система сначала проверяет, существует ли блок в Block Cache локального узла BE (путём сопоставления cache key).
  2. Если найден (попадание в кэш), блок читается напрямую с локального диска.
  3. Если не найден (промах кэша), блок извлекается из удалённого хранилища и синхронизируется в Block Cache локального узла BE для повторного использования в последующих запросах.

Среда хранения кэша

Block Cache использует локальные диски узлов BE или CN в качестве среды хранения, и эффект ускорения кэша напрямую связан с производительностью диска:

  • Рекомендуется использовать высокопроизводительные локальные диски (например, NVMe-диски) для минимизации задержки чтения/записи кэша.
  • Если производительность диска неоптимальна, вы можете увеличить количество дисков для достижения балансировки нагрузки и снижения нагрузки I/O на отдельные диски.

Политики замены кэша

Block Cache поддерживает две стратегии кэширования и вытеснения данных: LRU и SLRU (Segmented LRU).

LRU

Стратегия LRU основана на принципе «Наименее недавно использованный» — вытесняются блоки, к которым не обращались дольше всего. Она проста в реализации и подходит для сценариев со стабильными паттернами доступа.

SLRU

Стратегия SLRU делит пространство кэша на сегмент вытеснения и сегмент защиты, оба следуют правилам LRU:

  1. Данные попадают в сегмент вытеснения при первом доступе.
  2. Данные в сегменте вытеснения перемещаются в сегмент защиты при повторном доступе.
  3. Данные, вытесненные из сегмента защиты, возвращаются в сегмент вытеснения, в то время как данные, вытесненные из сегмента вытеснения, полностью удаляются из кэша.

Стратегия SLRU может эффективно противостоять внезапному разреженному трафику, предотвращая прямое вытеснение горячих данных в сегменте защиты «временными данными, к которым обращались только один раз». Она обеспечивает лучшую стабильность, чем LRU.

Включение и настройка Data Cache

Data Cache включён по умолчанию, управляется параметром конфигурации BE datacache_enable (по умолчанию: true). Page Cache и Block Cache, как два независимых компонента, также включены по умолчанию. Установка datacache_enable в false отключит Data Cache целиком, то есть и Page Cache, и Block Cache.

Вы также можете активировать или деактивировать Page Cache и Block Cache по отдельности, используя различные параметры конфигурации BE.

  • Page Cache (включён по умолчанию) управляется параметром disable_storage_page_cache (по умолчанию: false).
  • Block Cache (включён по умолчанию) управляется параметром block_cache_enable (по умолчанию: true).

Вы можете дополнительно использовать следующие конфигурации BE для установки максимальных лимитов использования памяти и диска для Data Cache, предотвращая чрезмерное потребление ресурсов:

  • datacache_mem_size: Устанавливает максимальный лимит использования памяти для Data Cache (используется для хранения данных в Page Cache).
  • datacache_disk_size: Устанавливает максимальный лимит использования диска для Data Cache (используется для хранения данных в Block Cache).

Заполнение Block Cache

Правила заполнения

Начиная с версии v1.5.2, для повышения коэффициента попадания в Block Cache система заполняет Block Cache в соответствии со следующими правилами:

  • Кэш не будет заполняться для операторов, отличных от SELECT, например, ANALYZE TABLE и INSERT INTO SELECT.
  • Запросы, сканирующие все partition таблицы, не будут заполнять кэш. Однако, если таблица имеет только один partition, заполнение выполняется по умолчанию.
  • Запросы, сканирующие все столбцы таблицы, не будут заполнять кэш. Однако, если таблица имеет только один столбец, заполнение выполняется по умолчанию.
  • Кэш не будет заполняться для таблиц, которые не являются Hive, Paimon, Delta Lake, Hudi или Iceberg.

Просмотр поведения заполнения кэша

Вы можете просмотреть поведение заполнения для конкретного запроса с помощью команды EXPLAIN VERBOSE.

Пример:

mysql> EXPLAIN VERBOSE SELECT col1 FROM hudi_table;
...
| 0:HudiScanNode |
| TABLE: hudi_table |
| partitions=3/3 |
| cardinality=9084 |
| avgRowSize=2.0 |
| dataCacheOptions={populate: false} |
| cardinality: 9084 |
+-----------------------------------------+

dataCacheOptions={populate: false} указывает, что кэш не будет заполняться, поскольку запрос будет сканировать все partition.

Вы также можете точно настроить поведение заполнения Block Cache через сессионную переменную populate_datacache_mode.

Режим заполнения

Block Cache поддерживает два режима: синхронное заполнение и асинхронное заполнение. Вы можете выбирать между ними в зависимости от бизнес-требований к «производительности первого запроса» и «эффективности кэша».

Синхронное заполнение

  • Основная логика: Когда удалённые данные читаются для первого запроса, данные немедленно кэшируются локально. Последующие запросы могут напрямую использовать кэш.
  • Преимущества: Высокая эффективность кэша, поскольку кэширование данных завершается за один запрос.
  • Недостатки: Операции кэширования выполняются синхронно с операциями чтения, что может увеличить задержку для первого запроса.

Асинхронное заполнение

  • Основная логика: Для первого запроса чтение данных имеет приоритет и выполняется первым. Запись в кэш выполняется асинхронно в фоновом режиме, не блокируя текущий процесс запроса.
  • Преимущества: Не влияет на производительность первого запроса и предотвращает задержку операций чтения из-за кэширования.
  • Недостатки: Более низкая эффективность кэша, поскольку один запрос может не полностью кэшировать все данные, к которым обращались. Требуется несколько запросов для постепенного улучшения покрытия кэша.

Начиная с версии v1.5.2, асинхронное заполнение кэша включено по умолчанию. Вы можете изменить режим заполнения, установив сессионную переменную enable_datacache_async_populate_mode.

Персистентность

Кэшированные данные на дисках по умолчанию являются персистентными, и эти данные могут быть повторно использованы после перезапуска BE или CN.

Проверка попадания запроса в Data Cache

Вы можете проверить, попал ли запрос в Data Cache, анализируя следующие метрики в профиле запроса:

  • DataCacheReadBytes: размер данных, которые система читает напрямую из памяти и с дисков.
  • DataCacheWriteBytes: размер данных, загруженных из удалённой системы хранения в память и на диски.
  • BytesRead: общий объём прочитанных данных, включая данные, которые система читает из удалённой системы хранения, а также из памяти и с дисков.

Пример 1: В этом примере система читает большой объём данных (7,65 ГБ) из удалённой системы хранения и лишь немного данных (518,73 МБ) с дисков. Это означает, что попадание в Block Cache было минимальным.

 - Table: lineorder
- DataCacheReadBytes: 518.73 MB
- __MAX_OF_DataCacheReadBytes: 4.73 MB
- __MIN_OF_DataCacheReadBytes: 16.00 KB
- DataCacheReadCounter: 684
- __MAX_OF_DataCacheReadCounter: 4
- __MIN_OF_DataCacheReadCounter: 0
- DataCacheReadTimer: 737.357us
- DataCacheWriteBytes: 7.65 GB
- __MAX_OF_DataCacheWriteBytes: 64.39 MB
- __MIN_OF_DataCacheWriteBytes: 0.00
- DataCacheWriteCounter: 7.887K (7887)
- __MAX_OF_DataCacheWriteCounter: 65
- __MIN_OF_DataCacheWriteCounter: 0
- DataCacheWriteTimer: 23.467ms
- __MAX_OF_DataCacheWriteTimer: 62.280ms
- __MIN_OF_DataCacheWriteTimer: 0ns
- BufferUnplugCount: 15
- __MAX_OF_BufferUnplugCount: 2
- __MIN_OF_BufferUnplugCount: 0
- BytesRead: 7.65 GB
- __MAX_OF_BytesRead: 64.39 MB
- __MIN_OF_BytesRead: 0.00

Пример 2: В этом примере система читает большой объём данных (46,08 ГБ) из Data Cache и не читает данные из удалённой системы хранения, что означает, что данные читаются только из Block Cache.

Table: lineitem
- DataCacheReadBytes: 46.08 GB
- __MAX_OF_DataCacheReadBytes: 194.99 MB
- __MIN_OF_DataCacheReadBytes: 81.25 MB
- DataCacheReadCounter: 72.237K (72237)
- __MAX_OF_DataCacheReadCounter: 299
- __MIN_OF_DataCacheReadCounter: 118
- DataCacheReadTimer: 856.481ms
- __MAX_OF_DataCacheReadTimer: 1s547ms
- __MIN_OF_DataCacheReadTimer: 261.824ms
- DataCacheWriteBytes: 0.00
- DataCacheWriteCounter: 0
- DataCacheWriteTimer: 0ns
- BufferUnplugCount: 1.231K (1231)
- __MAX_OF_BufferUnplugCount: 81
- __MIN_OF_BufferUnplugCount: 35
- BytesRead: 46.08 GB
- __MAX_OF_BytesRead: 194.99 MB
- __MIN_OF_BytesRead: 81.25 MB

I/O Adaptor

Для предотвращения значительной хвостовой задержки при доступе к диску из-за высокой нагрузки I/O на диск кэша, что может привести к негативной оптимизации системы кэширования, Data Cache предоставляет функцию I/O Adaptor. Эта функция направляет некоторые запросы кэша в удалённое хранилище при высокой нагрузке на диск, используя как локальный кэш, так и удалённое хранилище для повышения пропускной способности I/O. Эта функция включена по умолчанию.

Вы можете включить I/O Adaptor, установив следующую системную переменную:

SET GLOBAL enable_datacache_io_adaptor=true;

Динамическое масштабирование

Data Cache поддерживает ручную настройку ёмкости кэша без перезапуска процесса BE, а также поддерживает автоматическую настройку ёмкости кэша.

Ручное масштабирование

Вы можете изменить лимит памяти или дисковую ёмкость Data Cache, динамически настраивая параметры конфигурации BE.

Примеры:

-- Настройка лимита памяти Data Cache для конкретного экземпляра BE.
UPDATE be_configs SET VALUE="10G" WHERE NAME="datacache_mem_size" and BE_ID=10005;

-- Настройка лимита соотношения памяти Data Cache для всех экземпляров BE.
UPDATE be_configs SET VALUE="10%" WHERE NAME="datacache_mem_size";

-- Настройка дискового лимита Data Cache для всех экземпляров BE.
UPDATE be_configs SET VALUE="2T" WHERE NAME="datacache_disk_size";
примечание
  • Будьте осторожны при настройке ёмкостей таким способом. Убедитесь, что вы не пропустили предложение WHERE, чтобы избежать изменения несвязанных параметров конфигурации.
  • Настройки ёмкости кэша, сделанные таким образом, не будут сохранены и будут потеряны после перезапуска процесса BE или CN. Поэтому вы можете сначала динамически настроить параметры, как описано выше, а затем вручную изменить файл конфигурации BE или CN, чтобы гарантировать, что изменения вступят в силу после следующего перезапуска.

Автоматическое масштабирование

Selena в настоящее время поддерживает автоматическое масштабирование дисковой ёмкости. Если вы не указываете путь к диску кэша и лимит ёмкости в конфигурации BE, автоматическое масштабирование включается по умолчанию.

Вы также можете включить автоматическое масштабирование, добавив следующий параметр конфигурации в файл конфигурации и перезапустив процесс BE или CN:

datacache_auto_adjust_enable=true

После включения автоматического масштабирования:

  • Когда использование диска превышает порог, указанный в конфигурации BE disk_high_level (значение по умолчанию 90, то есть 90% дискового пространства), система автоматически вытесняет данные кэша для освобождения дискового пространства.
  • Когда использование диска постоянно ниже порога, указанного в конфигурации BE disk_low_level (значение по умолчанию 60, то есть 60% дискового пространства), и текущее дисковое пространство, используемое Data Cache, заполнено, система автоматически расширяет ёмкость кэша.
  • При автоматическом масштабировании ёмкости кэша система будет стремиться настроить ёмкость кэша до уровня, указанного в конфигурации BE disk_safe_level (значение по умолчанию 80, то есть 80% дискового пространства).

Совместное использование кэша (Cache Sharing)

Поскольку Data Cache зависит от локального диска узла BE, при масштабировании cluster изменения в маршрутизации данных могут вызвать промахи кэша, что легко может привести к значительному снижению производительности во время эластичного масштабирования.

Cache Sharing используется для поддержки доступа к данным кэша между узлами через сеть. Во время масштабирования cluster, если происходит промах локального кэша, система сначала пытается получить данные кэша с других узлов в пределах того же cluster. Только если все кэши промахнулись, система повторно получит данные из удалённого хранилища. Эта функция эффективно снижает колебания производительности, вызванные инвалидацией кэша во время эластичного масштабирования, и обеспечивает стабильную производительность запросов.

cache sharing workflow

Вы можете включить функцию Cache Sharing, настроив следующие два параметра:

  • Установите параметр конфигурации FE enable_trace_historical_node в true.
  • Установите системную переменную enable_datacache_sharing в true.

Кроме того, вы можете проверить следующие метрики в профиле запроса для мониторинга Cache Sharing:

  • DataCacheReadPeerCounter: Количество чтений с других узлов.
  • DataCacheReadPeerBytes: Количество байтов, прочитанных с других узлов.
  • DataCacheReadPeerTimer: Время, затраченное на доступ к данным кэша с других узлов.

Конфигурации и переменные

Вы можете настроить Data Cache, используя следующие системные переменные и параметры.

Системные переменные

Конфигурации FE

Конфигурации BE