Зачем Trino использует внешние таблицы при запросах к данным в объектных хранилищам и удаленных файловых системах, чем они отличаются от внутренних и как повысить производительность таких SQL-запросов с помощью кэширования.
Доступ из Trino к данным в объектных хранилищах
Помимо реляционных и нереляционных баз данных, Trino позволяет делать распределенные запросы и к файлам, хранящимся в объектных хранилищам AWS S3, Google Cloud Storage, Azure Storage, а также в распределенных файловых системах HDFS и Alluxio. Обычно объектные хранилища используются для создания озер данных или гибридных архитектур типа LakeHouse. Они предоставляют методы для хранения объектов в структурированном виде и средства для доступа к ним, например, с помощью HTTP API. Объекты – это файлы в различных форматах, включая ORC, Parquet, Iceberg и пр.
Trino напрямую получает доступ к файлам в объектном хранилище и удаленной файловой системе с помощью коннекторов, которые поддерживают протоколы и форматы данных удаленных систем-источников. Чтобы подключиться к источнику данных, надо настроить параметры конфигурации коннектора в каталоге Trino, о чем мы писали здесь. Изначально поддержка файловой системы для пользовательского каталога не активирована. Необходимо выбрать и настроить одно из следующих свойств, чтобы определить поддержку различных файловых систем в каталоге. Каждый каталог поддерживает только одну файловую систему. Это означает, что для работы с несколькими удаленными объектными хранилищами надо настроить несколько коннекторов в разных каталогах.
Доступ к хранилищу объектов осуществляется через метахранилище, которое предоставляет информацию о структуре удаленных каталогов, формате файлов и метаданных о хранимых данных. Коннекторы объектных хранилищ поддерживают использование одного или нескольких метахранилищ. Чтобы определить тип используемого метахранилища, каждый файл каталога объектных хранилищ Delta Lake, Apache Hive или Hudi должен устанавливать соответствующее значение свойству конфигурации hive.metastore. Каталоги Iceberg вместо этого используют свойство конфигурации iceberg.catalog.type. Также доступны дополнительные свойства конфигурации, специфичные для хранилищ Thrift и AWS Glue. Кроме того, коннекторы объектного хранилища поддерживают один или несколько форматов файлов, поддерживаемых базовым источником данных: ORC или Parquet. При отправке SQL-запросов к файлам в объектном хранилище Trino использует внешние таблицы, которые отличаются от внутренних (управляемых), что мы рассмотрим далее.
Внешние и внутренние таблицы
Как уже отмечено ранее, для интеграции с объектными хранилищами и удаленными файловыми системами, Trino использует внешние таблицы. MPP-движок не управляет их жизненным циклом этих таблиц: данные останутся на месте, даже при удалении таблицы в Trino. В Trino внешние таблицы по сути представляют собой таблицы, данные которых хранятся во внешних системах-источниках: объектных хранилищах или базах данных. Trino подключается к этим источникам через специальные коннекторы и выполняет запросы к данным напрямую. При этом данные не перемещаются в Trino, а остаются в исходных системах. Таким образом, внешние таблицы позволяют Trino взаимодействовать с различными хранилищами данных, предоставляя унифицированный интерфейс для выполнения запросов.
Внутренние или управляемые таблицы в Trino – условный термин, поскольку MPP-движок не хранит данные, а выполняет SQL-запросы к данным в системах-источниках без копирования. Внешние и внутренние таблицы в Trino больше связаны с понятием каталогов и схем, чем с физическим расположением данных. Поскольку Trino сам по себе не хранит данные, понятие внутренних таблиц может относиться к временным таблицам, которые могут создаваться в ходе выполнения запросов и существовать только в течение сеанса. Также можно говорить о таблицах, которые находятся в локальных системах хранения данных, например в той же Apache Hive, которые Trino может использовать для выполнения запросов. При этом в случае внутренних управляемых таблиц, Trino сам управляет файлами, в которых хранятся эти временные данные. Это означает, что при удалении таблицы данные также будут удалены. Такие таблицы обычно создаются в Hive-совместимом хранилище.
Оба варианта таблиц (внешние и внутренние) в Trino создаются с помощью SQL-запроса CREATE TABLE. Однако в случае внешних таблиц добавляется выражение WITH с параметрами external_location, который указывает на местоположение данных, и format, задающего формат данных.
Например, так можно создать внешнюю таблицу в Hive, которая ссылается на данные, хранящиеся в формате Parquet на на AWS S3:
CREATE TABLE hive.default.external_table ( id INT, name STRING, age INT ) WITH ( external_location = 's3a://your-bucket/path/to/data/', format = 'PARQUET' );
Эта команда создает логическую структуру таблицы в Hive, но данные остаются в S3 и не перемещаются в Hive. Это позволяет использовать таблицу для запросов и анализа данных, находящихся в облачном хранилище.А для создания аналогичной управляемой, т.е. внутренней, таблицы в Hive, когда Hive будет отвечать за управление данными, включая их удаление при удалении таблицы, запрос в Trino будет выглядеть так:
CREATE TABLE hive.default.managed_table ( id INT, name STRING, age INT );
Возвращаясь к интеграции Trino с объектными хранилищами и удаленными файловыми системами, отметим, что для повышения производительности движок поддерживает кэширование файлов. Как это реализуется, рассмотрим далее.
Кэширование файловой системы
Trino обращается к файлам напрямую в объектном хранилище и удаленной файловой системе. Это часто подразумевает передачу больших объемов данных. Файлы извлекаются из системы-источника несколькими рабочими процессами на разных узлах и обрабатываются на них. Повторные запросы с разными параметрами или даже разные запросы от разных пользователей часто обращаются к одним и тем же объектам. Поэтому для повышения скорости выполнения SQL-запросов Trino поддерживает кэширование файлов с помощью библиотек Alluxio с открытым исходным кодом и каталогами, использующими коннекторы для подключения к Delta Lake, Hive и Iceberg.
Кэширование удаленной файловой системы в Trino является частью механизма обработки SQL-запросов, распределенной на этапы, где задачи и разделения обрабатываются различными узлами в кластере. Разделения самого низкого уровня извлекают данные из источника данных с помощью коннектора определенного каталога. Для кэширования файловой системы эти разделения приводят к извлечению файлов из объектного хранилища. Различные узлы обрабатывают разделения с данными из объектного хранилища случайным образом, но с предпочтением использования фиксированного набора узлов для данного файла. Если предпочтительные узлы слишком заняты, разделение и кэширование происходят на другом, менее загруженном узле.
Кэширование файловой системы сохраняет копии извлеченных файлов в локальном хранилище кэша, отдельно для каждого узла. Со временем те же файлы из объектного хранилища кэшируются на любых узлах, которым требуется файл данных для обработки определенной задачи. Каждый кэш на каждом узле управляется отдельно, следуя конфигурации TTL и ограничениям размера, по превышении которых кэшированные файлы вытесняются из кэша.
Можно вручную ограничить количество предпочтительных хостов для задач с помощью параметра конфигурации fs.cache.preferred-hosts-count. Обработка SQL-запросов по-прежнему использует все остальные узлы, необходимые для параллельной обработки задач, и потенциально кэширует файлы на большем количестве узлов. По умолчанию значение параметра fs.cache.preferred-hosts-count равно 2. Это значит, что Trino будет пытаться читать данные с двух узлов, которые считаются наиболее подходящими для получения данных, с учётом близости данных и доступности ресурсов. Это помогает оптимизировать производительность, уменьшая задержки и повышая пропускную способность за счёт распределения нагрузки между несколькими узлами кластера.
Уменьшение общего размера кэша может снизить частоту кэширования одного и того же файла на нескольких узлах. Увеличение значения параметра fs.cache.preferred-hosts-count, вплоть до количества узлов в кластере, распределяет рабочую нагрузку по умолчанию между большим количеством рабочих узлов. Это повышает отказоустойчивость, однако увеличивает объем сетевого трафика из-за передачи данных между узлами.
По умолчанию кэширование файловой системы в Trino отключено. Чтобы включить его, нужно задать параметру fs.cache.enabled значение true. Это может дать следующие преимущества:
- снижение нагрузки на удаленное хранилище, поскольку каждый извлеченный и кэшированный файл позволяет избежать повторного извлечения в последующих запросах к тому же рабочему узлу;
- повышение производительности из-за отсутствия повторных сетевых передач: запросы получают доступ к копиям файлов из локального кэша. Прирост производительности будет особенно заметен при обращению к хранилищу в другой сети, другом ЦОД или в другом регионе облачного провайдера. С другой стороны, если удаленное хранилище уже работает с очень высокой производительностью ввода-вывода и сетевого доступа, а локальное кэш-хранилище работает на схожих скоростях или даже медленнее, выигрыш в производительности может быть минимальным.
- Снижение затрат на запросы за счет сокращения сетевого трафика. Сетевой трафик и доступ к удаленному хранилищу по API, часто являются наиболее значительным фактором затрат, особенно при работе с публичными облаками.
В заключение отметим, что ключевым фактором для принятия решения о включении кэширования является скорость локального кэш-хранилища. Наиболее распространенный и экономически эффективный подход — подключение высокопроизводительного SSD- или RAM-диска для кэширования в памяти. При этом вместо использования корневого раздела и диска узла рекомендуется подключить одно или несколько выделенных устройств хранения для кэша на каждом узле. Хранилище должно быть локальным, выделенным на каждом узле кластера Trino, и не общим.
Освойте работу с Trino на специализированных курсах в нашем лицензированном учебном центре обучения и повышения квалификации для разработчиков, менеджеров, архитекторов, инженеров, администраторов, Data Scientist’ов и аналитиков Big Data в Москве:
Источники