Книга: f12a87a0b5fe4f8382918b93f042a313
Назад: Движок запросов
На главную: Предисловие

--truststore-path /opt/presto/etc/presto-keystore.jks \

--truststore-password password \

--user clientC \

--password

Password:

presto> show catalogs;

Error running command: Authentication failed: Access Denied: Invalid credentials

Запуск консоли Presto

Введите в браузере адрес узла-координатора ( https://localhost:8443). Вы увидите диалоговое окно с приглашением ввести логин и пароль. Введите одно

из корректных имен, clientA или clientB, и соответствующий пароль, который вы создали на предыдущем шаге (см. рис. 7.2).

Аутентификация   139

Рис. 7.2  Диалог аутентификации в консоли Presto

LDAP

LDAP – это стандартный протокол аутентификации с использованием службы каталогов. Presto также поддерживает аутентификацию через LDAP. Схема

взаимодействия Presto со службой LDAP изображена на рис. 7-3. Клиент при

соединении с узлом-координатором указывает логин и пароль, а затем координатор проверяет предоставленные учетные данные с помощью внешней

службы. Развертывание LDAP-каталога выходит за рамки данной книги. Для

тестирования вы можете воспользоваться, например, пакетом FreeIPA1.

LDAPкаталог

Клиент Presto A

Узелкоординатор

Рабочий узел

Каталоги

Клиент Presto B

Доверенное хранилище данных

Рис. 7.3  Интеграция Presto и LDAP

1

140  Безопасность Presto

После того как служба LDAP сконфигурирована и запущена, настройте

координатор Presto для использования LDAP-каталога. Для этого добавьте

в файл password-authenticator.properties следующие строки: password-authenticator.name=ldap

ldap.url=ldaps://<url_to_the_ldap_service>:636

ldap.user-ldap.user-bind-pattern=<your_bind_pattern>

Например, в качестве LDAP-каталога вы используете Active Directory, шаблон для построения имени пользователя будет выглядеть так:

ldap.user-ldap.user-bind-pattern=${USER}@<your domain name>

Когда Presto будет обращаться к каталогу, вместо переменной ${USER} будет

подставлено имя пользователя, введенное при попытке аутентификации.

Еще один вариант настройки – определить идентификатор пользователя так: ldap.user-ldap.user-bind-pattern=

+uid=${USER},cn=users,cn=accounts,dc=ipa,dc=test

Чтобы начать использовать LDAP-каталог, требуется перезапуск узла-координатора.

Kerberos

Протокол Kerberos обеспечивает взаимную аутентификацию между клиентом и сервером с помощью системы квитанций ( tickets), удостоверяющих

предъявителя. Presto поддерживает как внешнюю, так и внутреннюю аутентификацию с использованием Kerberos. Внешней называется аутентификация клиента (точнее, взаимная аутентификация клиента и узла-координатора), а внутренней – взаимная аутентификация координатора и рабочих

узлов. Установка сервера Kerberos выходит за рамки данной книги, поэтому

мы предполагаем, что служба Kerberos у вас уже настроена и запущена.

Kerberos и LDAP

Оба протокола, и LDAP, и Kerberos, используются для аутентификации. Но устрой-ство этих протоколов и цели их создания – разные. Главной целью Kerberos было 

обеспечение универсального удостоверения для множества сервисов, SSO (single sign-on), и он решает задачу безопасной передачи данных аутентификации в недо-веренной среде. LDAP же обеспечивает доступ к каталогу, где хранится информация 

о пользователях, узлах сети, сервисах и других объектах и субъектах сетевого взаимодействия.

Условия функционирования Kerberos

На рис. 7.4 показана схема взаимодействия Presto со службой Kerberos. На

всех узлах, участвующих в процессе аутентификации, должен быть настроен

доступ к серверу Kerberos. Настройки состоят из двух файлов – keytab и etc/

Аутентификация   141

krb5.conf. В файле keytab хранятся пары из зашифрованных ключей и соответствующих им субъектов аутентификации – пользователей или узлов. Файл

etc/krb5.conf содержит настройки доменной аутентификации, шифрования

и т. д.

Сервер

аутентификации

Kerberos

keytab

keytab

keytab

/etc/krb5.conf

/etc/krb5.conf

/etc/krb5.conf

Узелкоординатор

Клиент Presto

C подключением

Рабочий узел

клиента Kerberos

Доверенное хранилище данных

Рис. 7.4  Интеграция хранилища на базе Presto со службой Kerberos В файле /etc/krb5.conf должен быть раздел [realms], содержащий как минимум параметр kdc:

[realms]

PRESTO.MYDOMAIN.COM = {

kdc = kdc.mydomain.com

}

[domain_realm]

.presto.mydomain.com = PRESTO.MYDOMAIN.COM

presto.mydomain.com = PRESTO.MYDOMAIN.COM

В разделе [domain_realm] вы можете также указать сетевой домен, в котором находится кластер Presto.

Настройка узла-координатора и рабочих узлов

Первым делом сконфигурируйте кластер так, чтобы он использовал протокол

HTTPS. Для этого следуйте инструкциям из предыдущего раздела. Затем раз-решите использование Kerberos, внеся соответствующие настройки в файл

config.properties для узла-координатора и для рабочих узлов: http-server.authentication.type=KERBEROS

http.server.authentication.krb5.service-name=presto

http.server.authentication.krb5.service-hostname=presto.mydomain.com http.server.authentication.krb5.keytab=</path/to/keytab>

http.authentication.krb5.config=/etc/krb5.conf

142  Безопасность Presto

Если вы хотите использовать Kerberos только для внешней аутентификации (т. е. аутентификации клиентов), не добавляйте эти строки в config.

properties рабочих узлов и оставьте возможность соединения по HTTP. В документации Presto1 вы найдете дополнительную информацию об использо-вании Kerberos.

Настройка клиента Presto

При запуске клиента Presto укажите в командной строке параметры, начинающиеся с krb5-:

presto \

--server https://presto-coordinator:8443 \

--truststore-path /opt/presto/etc/presto-keystore.jks \

--truststore-password password \

--krb5-config-path /etc/krb5.conf \

--krb5-principal [email protected] \

--krb5-keytab-path /path/to/keytab \

--krb5-remote-service-name presto

Более детальные инструкции по настройке клиентских приложений, как

обычно, – в официальной документации2.

Создание нестандартного аутентификатора

При помощи Presto SPI вы можете интегрировать Presto с любым сервисом

аутентификации. В главе 3 вы уже научились разрабатывать коннекторы.

Если вы хотите написать расширение для работы с сервисом аутентификации, вам следует применить специализированные интерфейсы3, которые

также входят в Presto SPI. Например, чтобы создать расширение, исполь-зующее парольную аутентификацию, реализуйте интерфейс PasswordAuthenticator:

public class MyAuthenticator

implements PasswordAuthenticator{

...

}

В качестве образца можете взять исходный код расширения для LDAP-аутентификации4. И не забудьте, что для включения аутентификации узлы

должны общаться по протоколу HTTPS.

1 .

2

3 .

4

 Авторизация   143

Авторизация

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

только с теми ее объектами и функциями, к которым ему предоставлен доступ.

Авторизация доступа к REST API

Авторизация в Presto выполняется на двух уровнях – на системном уровне и на уровне каталога (коннектора). Авторизация на системном уровне

определяет глобальные политики доступа и выполняется до авторизации

на уровне каталога. Для авторизации вы можете либо использовать одно из

встроенных расширений Presto, либо реализовать свое собственное, следуя

инструкциям в соответствующем разделе документации1. Встроенных модулей у Presto три: allow-all (аутентифицированный пользователь может

выполнять любые действия, такая авторизация включается по умолчанию), read-only (любой пользователь может только читать данные и метаданные) и file access (можно создать конфигурационные файлы с настройками доступа).

В главе 4 мы рассмотрели различные способы подключения клиента Presto, включая REST API. Настроим авторизацию на уровне API, т. е. укажем каждому пользователю, какие функции он может вызывать.

В Presto определены три роли:

User – пользователь, которому необходим доступ к данным;

Internal – узлы кластера, как координатор, так и рабочие узлы; вызовы

API требуются им для запуска задач на рабочих узлах или для обмена

данными между рабочими узлами;

Admin – администратор, которому требуется доступ к системным функциями, например «получить состояние узла».

Чтобы сконфигурировать авторизацию, сначала настройте аутентифика-

цию – как это сделать, рассказано в предыдущем разделе. В этом разделе мы

будем использовать аутентификацию, основанную на файлах. Для авторизации можно либо использовать встроенный класс ConfigurationBasedAuthorizer, либо создать собственное расширение, как это описано в документации2.

Настройка управления доступом

Presto позволяет подключать расширения, обеспечивающие авторизацию

пользователей на глобальном уровне. Вы можете создать собственные рас-1

2

144  Безопасность Presto

ширения или использовать одно из встроенных. Встроенных расширений

три: allow-all, read-only и file. Последнее позволяет задавать правила доступа

в файле конфигурации. Более подробную информацию об управлении до-

ступом можно найти в документации Presto1.

Рассмотрим сценарий, показанный на рис. 7-1. Наша задача – создать правила, позволяющие пользователю clientA читать каталог tpch, а пользователю ClientB – каталог mysql. Полный код рассматриваемых здесь примеров

находится в папке 07/presto-authorization нашего репозитория. Чтобы включить управление доступом, добавьте файл access-control.properties в папку etc координатора Presto. Если включено управление доступом на основе файлов, Presto запрещает любые операции над каталогами, если только они явно не

разрешены соответствующим правилом. В файле access-control.properties укажите тип управления доступом, который вы хотите использовать (в нашем

случае – файловый), и путь к файлу с правилами:

access-control.name=file

security.config-file=/path/to/rules.json

Сами правила указываются в файле формата JSON, подробно описанном

в документации2. Мы хотим разрешить пользователю clientA читать данные

из каталога tpch, а пользователю clientB – из каталога mysql. Создадим соответствующие правила:

{

"catalogs": [

{

"user": "clientA",

"catalog": "tpch",

"allow": "read-only"

},

{

"user": "clientB",

"catalog": "mysql",

"allow": "read-only"

}

]

}

В раздел catalogs мы записали правила, определяющие доступ к каталогам. После создания файла перезапустите кластер и запустите клиент Presto, подключившись к системе как пользователь clientA. Presto должен позво-лить вам выполнять запросы к каталогу tpch, но не к каталогу mysql. Если вы

подключитесь как пользователь clientB, то наоборот – сможете обращаться

к каталогу mysql, но не к каталогу tpch.

presto \

--server https://presto-coordinator:8443 \

1

2

 Авторизация   145

--truststore-path /opt/presto/etc/presto-keystore.jks \

--truststore-password password \

--user clientA \

--password

Password:

presto> show catalogs;

Catalog

---------

system

tpch

(2 rows)

Авторизация и управление доступом

Система  управления  доступом  в Presto  регулирует  доступ  к ресурсам –  каталогам, схемам, таблицам, столбцам и строкам. Вы можете настроить политики управления 

доступом на любом из этих уровней. С другой стороны, авторизация в Presto – это 

набор правил, которые Presto автоматически применяет к доступным ресурсам.

Пусть у нас есть таблица с тремя столбцами: пользователь, пароль и количество купленных товаров. Политика авторизации гарантирует, что только авторизованные со-трудники компании могут подключаться к кластеру и читать данные из таблицы. Система управления доступа позволяет выполнить более тонкую настройку, определив 

более детальную политику. Например, команда инженеров может читать и изменять 

значения всех столбцов, а команда аналитиков – только читать столбец с количеством 

купленных товаров.

Авторизация при помощи Apache Ranger

Управлять доступом пользователей можно на уровне коннектора. Для этого

используются или возможности самой СУБД, с которой работает коннектор, или внешний сервис авторизации, например Apache Ranger, подключенный

через расширение для Hive. В этом разделе мы покажем, как настроить доступ на уровне коннектора при помощи Apache Ranger.

Apache Ranger1 – сервис авторизации с открытым исходным кодом, поддерживающий детальные настройки управления доступом и возможность

аудита. Сервис работает с разными платформами и обеспечивает централизованное управление. Открытая модель данных и система расширений

Apache Ranger позволяет управлять доступом к платформам экосистемы

Hadoop. Сервис активно используется ведущими облачными провайдерами, такими как AWS, Azure и Google Cloud Platform.

На рис. 7.5 показана архитектура системы, где интегрированы Presto и Ranger. Ranger использует базу данных для репозитория политик и предоставляет модуль управления аудитом. Чтобы подключить Ranger к Presto, требуется установить соответствующее расширение к Presto. Кроме того, надо настроить Presto, чтобы он записывал журнал аудита в базу данных.

1

146  Безопасность Presto

Apache Ranger

Репози

Сервис

Сервис аудита

торий

администрирования

Расширение Presto

для Ranger

Журнал

аудита

Presto

Рис. 7.5  Интеграция Presto и Ranger

Для Ranger существует расширение Presto-Hive, с помощью которого его

можно подключить к Presto. Это расширение можно использовать только

для каталогов, подключенных при помощи коннектора Hive, например Hive Metastore и AWS Glue. Коннектор Hive поддерживает Apache Ranger 2.1.0

и старше. Подробные инструкции по настройке расширения Ranger для Hive можно найти в соответствующем разделе документации Presto1.

Разработка функции аудита

Задача аудита – отслеживать действия пользователей хранилища данных

и сохранять их в журнале, чтобы убедиться, что пользователи работают

в соответствии с политиками, стандартами и нормативными актами. Прежде чем разрабатывать собственную функцию аудита, необходимо описать

требования, а именно список событий, которые должны попасть в журнал

(чтение и изменение данных, подключение и отключение пользователей

и т. д.), и уровень детализации журнальной информации. Следующий шаг –

определить местоположение журнала аудита. Это может быть, например, журнал Presto или журнал Ranger. Наконец, имея подробное техническое

задание, можно создавать функцию аудита – желательно с использованием

такого сервиса, как Apache Ranger. Примеры настроек и детальные инструкции можно найти в документации Ranger2.

Заключение

Из этой главы вы узнали, как обеспечить безопасность Presto. Для этого нужно сконфигурировать безопасный обмен данными, а также настроить аутентификацию и авторизацию.

1 .

2

 Заключение   147

Безопасный обмен данными обеспечивается шифрованием данных, пере-

даваемых по сети, что предотвращает несанкционированный доступ к этим

данным. Для обеспечения безопасного обмена данных в Presto следует настроить HTPS/TLS.

Аутентификация позволяет предоставить доступ к кластеру Presto только

авторизованным пользователям. Presto дает возможность настроить аутентификацию, основанную на файлах, а также аутентификацию по протоколам LDAP и Kerberos. Вы можете разработать и собственное расширение для

аутен тификации.

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

при помощи встроенной системы управления доступом, а также при помощи

внешних сервисов, например Apache Ranger.

Глава 8

Настройка

производительности

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

или уменьшает объем используемых ресурсов, тем самым повышая общую

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

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

можем вносить в систему изменения.

Эта глава разделена на пять частей. В первой части мы изложим общие

понятия, относящиеся к настройке производительности, включая описание

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

места. Затем мы познакомимся с традиционными подходами к настройке

производительности Presto, включая распределение ресурсов, настройку системы хранения и оптимизацию запросов. В четвертой части мы познакомимся с продуктом Aria Scan, который позволяет повысить эффективность

чтения данных в Presto. В пятой, последней, части мы рассмотрим пример, в котором будем решать практическую задачу настройки кластера и менять

его конфигурацию.

Введение в настройку

производительности

Как вы уже знаете, Presto – это распределенный движок SQL-запросов, который позволяет одновременно обрабатывать данные из множества разных

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

времени выполнения запросов до величины, приемлемой для пользователя.

Введение в настройку производительности   149

В процессе настройки производительности эксперт находит проблемные

места, которые замедляют систему, уменьшают ее общую пропускную способность или дестабилизируют ее.

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

производительности

Настройка производительности – это циклический процесс, в течение которого администратор наблюдает за состоянием системы и изменяет ее конфигурацию, когда это необходимо. Для того чтобы запустить этот процесс, есть множество причин, а именно:

возможность обрабатывать больше данных. Вы сможете выполнять

сложные запросы к большому количеству разнородных данных за при-

емлемое время;

уменьшение времени ответа. Правильно настроенная система выдает

ответ быстрее. Это особенно важно в тех приложениях, где требуется

аналитика в режиме, близком к реальному времени;

экономия ресурсов. Правильно настроенная система обходится меньшим количеством ресурсов – серверов и сетевого оборудования.

Жизненный цикл настройки производительности

Цикл настройки производительности состоит из трех шагов, как показано

на рис. 8.1.

Нагрузочное

Анализ

Настройки

тестирование

Мониторинг системы

Оптимизация

по умолчанию

Измерение

(реактивный

Изменение настроек

производительности

и проактивный)

системы

Рис. 8.1  Цикл настройки производительности Presto

Базовая конфигурация

Кластер Presto запускается с настройками по умолчанию.

Тестирование производительности

Первый шаг цикла заключается в измерении производительности систе-

мы. Метриками могут служить время выполнения запросов, количество

узлов в кластере или объем ресурсов, используемых для выполнения запроса.

Анализ

Второй шаг – мониторинг системы в поисках узких мест. Мониторинг

включает в себя исследование планов запросов, в особенности тех, вы-

150  Настройка производительности

полнение которых занимает много времени, а также поиск запросов, по-требляющих много ресурсов. Есть два типа мониторинга – проактивный

и реактивный. Проактивный мониторинг заключается в постоянном сборе

метрик производительности, включая загрузку процессоров и утилизацию

оперативной памяти. Задача реактивного мониторинга – поиск узких мест

и причин их возникновения.

Оптимизация

Наконец, на третьем шаге администратор изменяет конфигурацию класте-ра, основываясь на выводах, сделанных на шаге анализа.

Модель выполнения запроса

Прежде чем говорить об увеличении производительности кластера, необходимо разобраться, как Presto выполняет запросы. Понимание принципов

работы Presto позволит вам понять возможные причины возникновения

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

Механизм выполнения запросов в Presto показан на рис. 8.2.

Токенизация

Анализ

SQL

AST

Логический план

Оптимизация

Деление

на фрагменты

Физический план

Этапы выполнения

Рис. 8.2  Механизм выполнения запросов в Presto

Когда узел-координатор получает запрос от клиентского приложения, он

разбирает и анализирует текст запроса. В результате этого шага он создает

внутреннее представление, называемое абстрактным синтаксическим де-ревом (AST, Abstract Syntax Tree), из которого затем создается план запроса.

Построение плана состоит из двух шагов: сначала строится логический план, а затем – физический. Логический план – это высокоуровневая модель запроса, не учитывающая особенности источников данных (каталогов) и конкретного кластера. Главная задача построения логического плана – составить

последовательность операций, которые должны быть выполнены для полу-

 Модель выполнения запроса   151

чения результата. Физический план – это уже более детальное представление, в котором учтены все особенности среды выполнения: количество узлов, доступные ресурсы, сетевая топология и т. д.

План выполнения состоит из этапов (stages), фрагментов (splits) и задач

(tasks):

этап – это часть плана, которая может быть выполнена параллельно.

Каждый этап состоит из одной или нескольких задач. Обычно коорди-

натор разбивает запрос на несколько этапов;

фрагмент – набор данных, который рабочий узел может обработать

независимо. Фрагмент – наименьшая единица обработки в Presto;

задача ( task) – объем работы, выполняемый одним рабочим узлом. Задача обрабатывает один или несколько фрагментов.

Координатор составляет план и распределяет задачи между рабочими

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

только выполнение очередной задачи заканчивается, координатор обнов-ляет статус запроса. Получив результат запроса, координатор возвращает

его клиенту.

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

и выдающий 10 клиентов, потративших наибольшие суммы в порядке убывания суммы. Запрос выполняется над схемой tpch.tiny:

SELECT c.custkey, c.name, sum(o.totalprice)

FROM customer c

JOIN orders o ON c.custkey = o.custkey

GROUP BY c.custkey, c.name

ORDER BY sum(o.totalprice)

DESC LIMIT 10;

Запустите консоль Presto по инструкции из главы 6, запустите запрос, затем найдите его в списке запросов и перейдите в пункт live plan. Один из

возможных планов состоит из четырех этапов:

этап 3 – состоит из единственной задачи, которая читает таблицу customers;

этап 2 – состоит из пяти задач (см. рис. 8.3), которые читают таблицу

orders (ScanProject), соединяют ее с таблицей customer (LocalExchange) при помощи задачи InnerJoin и, наконец, выполняют проекцию (Project) и частичную агрегацию (Aggregate);

этап 1 – состоит из четырех задач, выполняющих окончательную агрегацию и частичную выборку 10 первых строк;

этап 0 – состоит из трех задач, вычисляющих окончательный результат

и возвращающих его пользователю.

Обратите внимание, что количество фрагментов и задач на каждом этапе

зависит от конфигурации кластера, распределения данных и настроек па-раллельного выполнения.

152  Настройка производительности

Рис. 8.3  Структура этапа 3 в консоли Presto

Подходы к настройке

производительности Presto

Существует три общепринятых метода настройки производительности: выделить больше ресурсов, оптимизировать хранение данных или оптимизировать запрос.

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

в исключительных случаях. Третий подход не гарантирует успеха, поскольку

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

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

Выделение ресурсов

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

 Подходы к настройке производительности Presto   153

ся самым быстрым, но отнюдь не всегда самым дешевым способом ускорить

выполнение запросов. Существует два подхода к увеличению мощности:

вертикальное масштабирование ( scale up) . Представляет собой увеличение мощности отдельного узла – добавление процессорных ядер, памяти, дисков. Этот подход следует использовать, когда единственный узел оптимальным образом справляется с текущей нагрузкой, но

мощности этого узла не хватает;

горизонтальное масштабирование ( scale out). Заключается в добавле-нии к кластеру новых узлов, чтобы координатор мог распределять на-

грузку по большему количеству серверов. Используйте этот подход, когда один сервер заведомо не справится с нагрузкой и увеличение его

мощности нецелесообразно.

Независимо от того, какой подход вы выберете, важно понимать, какие

именно ресурсы нужно добавлять. Это зависит от характера запросов, выполняемых в системе. В табл. 8.1 приведена сводная информация о том, каким

запросам какие ресурсы необходимы.

Таблица 8.1. Необходимые ресурсы в зависимости от типа запросов

Тип запроса

Примеры

Требуемые ресурсы

Запросы, требующие Сортировка или агрегация больших

Память (например,

хранения большого наборов, соединения больших таблиц

если вы работаете

объема данных

или большого количества таблиц

в облаке AWS,

в памяти

используйте узлы

типа R)

Запросы, требующие Вычисления сложных функций, запросы Процессор (например, интенсивных

с многочисленными преобразованиями если вы работаете

вычислений

данных, рекурсивные операции,

в облаке AWS,

множество подзапросов и вложенных

используйте узлы

запросов, соединения больших таблиц

типа C)

Итак, есть два типа ресурсов, которые мы можем наращивать, – процессорные ядра и память.

Память

Чтобы добавить памяти узлу Presto (либо координатору, либо рабочему

узлу), измените в файле jvm.config параметр -Xmx16G. Например, чтобы выделить узлу 60 Гбайт оперативной памяти, поменяйте его на -Xmx60G.

Не забудьте исправить параметр query.max-memory-per-node в файле config.

properties. Значение этого параметра по умолчанию – 10 % от максималь-ного объема памяти, выделенного виртуальной машине Java параметром

-Xmx. Высокой производительности можно добиться, установив значение

query.max-memory-per-node в половину максимально доступного объема. Но

разумеется, если в вашем кластере одновременно работает много запросов, то значение этого параметра должно быть меньше1.

1 Авторы не упоминают, что если узел Presto работает в контейнере Docker, то нужно

также увеличить объем памяти, выделяемой контейнеру. Прим. перев.

154  Настройка производительности

Полную информацию о параметрах, управляющих выделением памяти

в Presto, можно найти в документации1.

Процессорные ядра

Если ваши запросы выполняют много вычислений, положительно повли-

ять на общую производительность кластера может уменьшение паралле-

лизма, т. е. количества одновременно исполняемых запросов. Параметр

task.concurrency в файле config.properties задает количество «виртуальных

процессоров» на узле. По умолчанию это значение равно 16, но если нагрузка на процессор велика, можно его уменьшить. Справочник по другим

параметрам с префиксом task., управляющим распределением вычисли-

тельных ресурсов, можно найти в документации2.

Уменьшение параллелизма снижает нагрузку на процессор, но, с другой

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

параллелизма.

Система хранения данных

Presto не управляет форматами данных, которые обрабатывает, и не имеет

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

стороны Presto мало что можно изменить.

Чтобы решить проблемы со скоростью доступа, вы должны настраивать

хранилище данных. Например, вы можете использовать форматы данных

со сжатием и с мощной системой метаданных, такие как ORC и Parquet. Выполняя запрос, Presto обращается к метаданным, и если по результатам этого

обращения очевидно, что данных, удовлетворяющих запросу, в файле нет, Presto не читает файл.

Для увеличения производительности полезно также настроить секционирование ( partitioning) на уровне хранилища. Секционированием называется

деление набора данных на подмножества, называемые секциями. Каждая

секция представляет собой отдельный объект хранения и может размещаться как на тех же узлах, что остальные секции этого же набора, так и на отдельных. В Presto вы можете создать секционированную копию несекцио-нированной таблицы с помощью команды CREATE TABLE AS (CTAS), добавив

к команде предложение partitioned_by. Подробные инструкции по созданию

секционированных таблиц можно найти в документации3.

Оптимизация запросов

Оптимизатор работает на узле-координаторе в момент запуска запроса. Для

построения наилучшего плана запроса используются как эвристический, 1 .

2

3

 Подходы к настройке производительности Presto   155

так и стоимостной оптимизатор. В процессе поиска оптимального плана

оптимизатор перебирает множество вариантов. Он использует два основных

приема – проталкивание предикатов и стоимостную оптимизацию.

Проталкивание предикатов

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

раннего уменьшения количества обрабатываемых данных уменьшается

объем ввода-вывода и сетевого трафика, что ведет к ускорению выполнения запросов. Как правило, проталкивание предикатов помогает ускорить

соединение таблиц с условиями WHERE за счет того, что значительное количество данных просто не доходит до операции соединения.

Presto поддерживает проталкивание предикатов, но для того, чтобы оптимизатор мог использовать этот прием, его должен поддерживать коннектор. О том, как написать коннектор, поддерживающий проталкивание

предикатов, вы можете прочитать в статье «Совершенствование оптимизатора Presto для эффективной обработки данных» («Improving the Presto planner for better push down and data federation»)1. Например, чтобы включить проталкивание предикатов в коннекторе Hive, работающем с системой хранения с интерфейсом S3, в конфигурационный файл каталога (например, hive.properties) надо добавить следующую строку:

hive.s3select-pushdown.enabled=true

Подробности – как обычно, в документации Presto2.

Стоимостной оптимизатор

Стоимостной оптимизатор выбирает оптимальный план запроса, основываясь на оценках затрат ресурсов на выполнение того или иного плана.

Оптимизатор учитывает профиль данных, сохраненный в виде статистики.

Статистика включает такие показатели, как количество строк в таблице, средний размер столбца данных и др. Опираясь на статистику, оптимизатор выбирает оптимальный порядок соединения таблиц.

Presto поддерживает стоимостную оптимизацию, но чтобы она работала

с конкретным каталогом, ее должен поддерживать и коннектор. Детальная

информация о статистике и стоимостной оптимизации – в документации3.

Presto поддерживает такие стратегии стоимостной оптимизации, как пе-ребор соединений (join enumeration) и выбор распределения соединений

(join distribution selection). Перебор соединений перебирает все возможные последовательности выполнения соединений, чтобы найти оптимальный порядок. Выбор распределения соединений определяет, как вычис-

лять хеш-таблицы для соединения хешированием. Стратегии включаются

установкой параметров в файле config.properties или в соответствующих

настройках сеанса. В табл. 8.2 приведены поддерживаемые стратегии CBO, параметры config.properties, соответствующие настройки сеанса и допусти-мые значения.

1

2 .

3 .

156  Настройка производительности

Как всегда, в документации1 можно найти более подробное описание стои-мостного оптимизатора Presto.

Таблица 8.2. Стратегии стоимостной оптимизации и соответствующие

параметры

Стратегия

config.properties Настройки сеанса

Допустимые значения

Перебор

optimizer.join-

join_reordering_strategy AUTOMATIC (default),

соединений

reordering-strategy

ELIMINATE_CROSS_JOINS, NONE

Выбор

optimizer.join-

join_distribution_type

AUTOMATIC (default),

распределения distribution-type

BROADCAST, PARTITIONED

соединений

Aria Scan

В 2019 году Facebook запустил проект Aria2, который позволил достичь двух-трехкратного уменьшения нагрузки на процессор при выполнении запросов

Hive над таблицами в формате ORC. Авторы проекта сосредоточились на двух

направлениях – сканирование таблиц и перераспределение задач.

Сканирование таблицы

По умолчанию если в таблице не определены индексы, то операция скани-рования таблицы читает всю таблицу целиком. Независимо от того, нужна

строка или нет, она читается с диска. Из-за такого подхода сканирование

таблиц, особенно больших, оказывается медленным и ресурсоемким.

Aria уменьшает затраты процессорного времени на сканирование таблицы

за счет двух приемов – исключения столбцов и проталкивания фильтров.

Исключение столбцов

Оптимизатор определяет, какие столбцы выбираются в запросе, и читает

только их, пропуская неиспользуемые столбцы.

Чтобы включить исключение столбцов в Presto, следует задать в файле config.properties параметру experimental.pushdown-subfields-enabled значение

true. Можно также воспользоваться параметром pushdown_subfields_enabled в настройках сеанса.

Проталкивание фильтров

Этот прием позволяет фильтровать данные не в самом Presto, а в коннекторе Hive. Это снижает нагрузку на процессор за счет того, что ненужные

данные не передаются в Presto и не хранятся во временных структурах

в памяти.

1 .

2

 Практическая настройка производительности   157

Чтобы включить проталкивание фильтров, установите в true параметр

<hive_catalog>.pushdown-filter-enabled в файле config.properties. Если, например, каталог называется hive, то полное название параметра будет

hive.pushdown-filter-enabled. Можно также воспользоваться параметром

<hive_catalog>.pushdown_filter_enabled в настройках сеанса.

Адаптивный порядок фильтрации эффективен для запросов, содержащих

несколько соединений. Он позволяет выбирать порядок соединений на

основе дополнительных критериев, тем самым сокращая общее время

выполнения запроса.

Перераспределение задач

Перераспределение заключается в изменении набора задач, выдаваемого

каждому рабочему узлу. Если расширение Aria не включено, Presto распределяет задачи в два шага – вычисление и сериализация. На шаге вычисления

рассчитывается хеш-функция от значения колонки, являющейся ключом

распределения, а затем на шаге сериализации страницы с данными записы-ваются в буфер вывода. Aria позволяет исключить фазу вычисления и сразу

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

в некоторых случаях позволяет снизить нагрузку на процессор вдвое.

Чтобы включить оптимизацию распределения данных, установите в true значение параметра experimental.optimized-repartitioning в файле config.

properties или соответствующую ему настройку сеанса optimized_repartitio-ning.

Чтобы управлять размером буферов вывода, используйте параметр driver.

max-page-partitioning-buffer-size. Этот параметр устанавливает максимальный объем всех буферов, и по умолчанию его значение составляет 32 МБайта.

Размер каждого буфера не может превышать 1 МБайта.

Практическая настройка

производительности

В этом разделе мы разберем реальный сценарий настройки производительности. Мы возьмем систему, архитектура которой изображена на рис. 5.5, с параметрами конфигурации по умолчанию, затем проведем несколько

тестов и подберем значения некоторых параметров, описанных в этой главе, чтобы ускорить выполнение запроса. Поскольку Aria scan поддерживает

только файлы в формате ORC, мы создадим таблицу в этом формате ORC

1 Авторы не указывают, в каких случаях возможна такая оптимизация. Если, например, ключ распределения участвует в операции GROUP BY, то исключение фазы

вычисления, наоборот, замедлит выполнение запроса. Прим. перев.

158  Настройка производительности

и загрузим ее в MinIO. Для наблюдения за кластером будем использовать

консоль Presto, описанную в главе 6.

Наш сценарий будет состоять из четырех шагов:

1) построение таблицы в формате CSV и ее загрузка в MinIO;

2) преобразование таблицы в формате CSV в ORC;

3) определение параметров, влияющих на производительность и подле-жащих модификации;

4) запуск тестов.

Создание CSV-таблицы и загрузка в MinIO

Для нашего эксперимента мы выгрузим одну из таблиц теста TPC-H и загрузим ее в хранилище MinIO. Чтобы сделать это, надо подключиться к каталогу tpch, прочитать таблицу customer из схемы sf1 и экспортировать ее

в CSV-файл. Если мощности не хватает, вы можете выбрать схему с меньшим

количеством данных. Затем мы загрузим полученный файл в MinIO, при помощи Spark выгрузим его в формате ORC и снова загрузим в MinIO файл – на

этот раз в оптимизированном формате.

Вы можете пропустить этот раздел и взять готовый CSV-файл в нашем

репозитории по адресу 08/data/customer.csv.

1. Запустите все компоненты хранилища данных командой ./deploy.sh

-d и подключитесь к контейнеру, в котором выполняется узел-коорди-

натор Presto. В папку /opt/presto-server/etc/catalog добавьте файл tpch.

properties, в котором содержится строка connector.name=tpch.

2. Перезапустите узел:

cd /opt/presto-server/bin

./launcher restart

После выполнения этой команды вы будете отключены от терминала,

и вам надо будет подключиться вновь.

3. Чтобы экспортировать таблицу customer в файл, запустите следующую

команду:

presto-cli \

--execute "SELECT * FROM tpch.sf1.customer;" \

--output-format CSV_HEADER > customer.csv

В таблице содержится примерно 150 тысяч строк, но если это слишком

большая нагрузка для вашего компьютера, замените sf1 на другое имя

схемы.

4. Чтобы скопировать файл customer.csv из контейнера на локальную машину, установите в контейнере пакет tar, воспользовавшись командой

yum install tar. Затем отключитесь от контейнера узла-координатора

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

 Практическая настройка производительности   159

kubectl cp\

presto-coordinator-nm87g:/opt/presto-server/customer.csv\

./customer.csv

Замените presto-coordinator-nm87g на имя контейнера, в котором работает узел-координатор. Узнать это имя можно, выведя список запущенных подов командой kubectl get pods -n presto.

5. Подключитесь браузером к консоли MinIO по адресу http://localhost:9090/, введите логин и пароль для доступа и создайте в корзине

warehouse новый путь1 tpch. Загрузите по этому пути файл customer.csv.

Преобразование CSV-таблицы в ORC

Для преобразования таблицы из формата CSV в формат ORC используйте

Spark.

1. Подключитесь к контейнеру, где работает клиент Spark, и запустите

оболочку, как описано в главе 5.

2. Подключите требуемые библиотеки:

import org.apache.hudi.QuickstartUtils._

import scala.collection.JavaConversions._

import org.apache.spark.sql.SaveMode._

3. Загрузите таблицу customer в формате CSV:

val tableName = "customer"

val basePath = "s3a://warehouse/tables/customer"

val df = spark.read.options(Map("header" -> "true")).

csv("s3a://warehouse/tpch/customer.csv")

4. Преобразуйте таблицу в формат ORC и сохраните ее под именем orc_

customer:

df.write.format("orc").

options(getQuickstartWriteConfigs).

option(RECORDKEY_FIELD_OPT_KEY, "id").

option(PRECOMBINE_FIELD_OPT_KEY, "dob").

option(TABLE_NAME, tableName).

mode(Overwrite).

saveAsTable("orc_customer")

Теперь мы готовы к тому, чтобы определить, какие параметры будем изменять.

1 Авторы используют термин path вместо термина catalog (или folder, или directory), поскольку структура хранилища S3 не иерархическая, а плоская. Прим. перев.

160  Настройка производительности

Определение параметров настройки

Ранее в этой главе мы разобрали некоторые наиболее популярные параметры настройки Presto. Их можно разделить на два типа – бинарные параметры, принимающие значение «вкл.» или «выкл.», и параметры с числовыми

значениями. Первые вы можете либо включить, либо выключить, а вот выбирать значения вторых можно из достаточно широкого диапазона. В табл. 8.3

приведены параметры конфигурации, разделенные на колонки по типам.

Жирным шрифтом выделены параметры, которые мы будем настраивать

в этом примере. Мы сосредоточимся только на некоторых важнейших параметрах, но вы можете использовать приведенный подход и для настройки

других параметров.

Таблица 8.3. Настройки производительности по типам

«Вкл.»/«Выкл»

Диапазон значений

hive.s3select-pushdown.enabled

query.max-memory-per-node

experimental.pushdown-subfields-enabled

task.concurrency

hive.pushdown-filter-enabled

optimizer.join-reordering-strategy

experimental.optimized-repartitioning

optimizer.join-distribution-type

Нагрузочное тестирование

Для нагрузочного тестирования будем использовать такой запрос:

SELECT count(*) as total, nationkey

FROM orc_customer

WHERE nationkey NOT IN ('23', '6')

GROUP KEY nationkey;

Мы протестируем несколько вариантов настройки. В каждом из тестов мы

зададим соответствующие значения параметров и затем выполним тестовый

запрос. Вот эти варианты:

настройки по умолчанию;

уменьшение нагрузки на процессор;

оптимизация запроса;

Aria scan.

Мы будем задавать значения параметров через настройки сеанса, и когда

найдем оптимальные настройки, распространим их на весь кластер через

файл config.properties.

Параметры по умолчанию

Запустите клиент Presto в контейнере с узлом-координатором и выполните

тестовый запрос. Затем откройте в браузере консоль Presto. Потом на вклад-ке Query Details нажмите Finished и найдите информацию о выполненном

Практическая настройка производительности   161

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

выполнения каждого этапа. На рис. 8.4 показана информация, относящаяся

к запросу, выполненному с настройками по умолчанию. Время выполнения

запроса составляет 8,14 секунды. Это базовое значение, которое мы поста-раемся уменьшить.

Рис. 8.4  Результат выполнения запроса 

с настройками по умолчанию

Уменьшение нагрузки на процессор

Чтобы уменьшить время выполнения, мы можем уменьшить нагрузку на

процессор, уменьшив количество «виртуальных процессоров» на узле. Значение параметра task.consurrency по умолчанию – 16, а мы попытаемся уменьшить его до 8:

SET SESSION task_concurrency = 8;

Изменив значение параметра, запустим запрос еще раз. Информация из

консоли показана на рис. 8.5. Теперь время выполнения составляет 6,67 секунды, то есть мы уменьшили его почти на полторы секунды.

Оптимизация запроса

Для оптимизации запроса мы можем разрешить проталкивание предикатов, оставив при этом уровень параллелизма как в предыдущем запуске:

SET SESSION hudi.s3_select_pushdown_enabled=true; Снова запустим запрос. Результаты его выполнения можно увидеть на

рис. 8.6. Время выполнения теперь составляет 6,89 секунды. Это медленнее,

162  Настройка производительности

чем в предыдущем запуске, то есть для этого конкретного запроса проталкивание предикатов не помогло.

Рис. 8.5  Работа тестового запроса 

после уменьшения нагрузки на процессор

Рис. 8.6  Результат выполнения запроса 

с включенной оптимизацией

Aria scan

Теперь попробуем включить проталкивание фильтров, сохраняя установленный ранее уровень параллелизма:

Заключение   163

SET SESSION hudi.pushdown_filter_enabled = true; Еще раз запустим запрос и посмотрим на статистику выполнения на

рис. 8.7. Теперь время работы запроса составляет 6,20 секунды, что почти на

полсекунды меньше предыдущего значения.

Рис. 8.7  Результат выполнения запроса с включенным Aria scan По результатам нашего эксперимента мы выяснили, что для выполнения

этого запроса оптимальным набором настроек в config.properties будет такой: task.concurrency = 8;

hudi.pushdown-filter-enabled = true;

Заключение

В этой главе вы научились настраивать производительность Presto. Настройка производительности крайне важна для обеспечения максимальной эффективности и скорости работы вашего кластера Presto.

Мы обсудили основы настройки производительности и рассмотрели мо-

дель выполнения запросов Presto. Мы также рассмотрели некоторые методы

оптимизации производительности: распределение ресурсов, настройку хранилища, оптимизацию запросов, Aria scan.

В конце главы мы разобрали практический пример настройки некоторых

параметров конфигурации в Presto.

Глава 9

Масштабирование

Presto

Масштабирование заключается в возможности обрабатывать возрастающую

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

становится значительно больше.

Здесь у нас не будет практического задания, и поэтому в нашем репозитории нет папки для этой главы. Подход к масштабированию всегда инди-видуален и зависит от конкретной нагрузки на кластер. Вместо этого мы

обсудим общую стратегию масштабирования и методы, комбинация которых

позволит вам адаптировать кластер к растущей нагрузке.

Глава состоит из четырех частей. В первой мы поговорим об общих по-нятиях, относящихся к масштабированию, таких как причины, вызывающие

необходимость масштабирования, и проблемы, которые обычно возникают

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

подходы к масштабированию кластера Presto, включая использование нескольких координаторов, установку Presto на Spark и подкачку. Последняя

часть посвящена масштабированию Presto в облаках.

Введение в масштабирование

Реакцией на увеличение нагрузки в Presto является добавление ресурсов по

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

разница: настройка производительности – это уменьшение времени ответа

системы, а масштабирование – увеличение ее пропускной способности.

Введение в масштабирование   165

Когда требуется масштабирование?

Масштабирование необходимо, если произошло хотя бы одно из следующих

событий: возросло количество пользователей, увеличилось количество запросов или вырос объем данных (рис. 9.1).

Рост количества

Рост интенсивности

Рост

пользователей

запросов

объема данных

Кластер Presto

Кластер Presto

Кластер Presto

Рис. 9.1  Основные причины увеличения мощности Presto

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

указанных выше причин производительность падает ниже некоторой отметки, ресурсы кластера необходимо увеличивать. Лучше делать это чуть-чуть

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

Часто возникающие проблемы

Перед тем как переходить к описанию конкретных приемов масштабирования Presto, обозначим несколько наиболее часто возникающих проблем

и ограничений, которые надо учитывать при масштабировании. К таким

проблемам относят единые точки отказа (SPOF, Single Point Of Failure), некорректное состояние рабочего узла или бессмысленные запросы.

Единая точка отказа

Когда мы разворачивали учебный кластер, в нем был единственный узел-координатор. Координатор в Presto поддерживает связность кластера и ко-ординирует все коммуникации между узлами. Также он отвечает за разбор запросов и управление их выполнением. Узел-координатор является

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

выполняются только этим узлом. При отказе координатора весь кластер

будет недоступен.

166  Масштабирование Presto

Некорректное состояние рабочего узла

Если узел попытается загрузить данных больше, чем объем доступной

памяти, произойдет ошибка переполнения памяти (out-of-memory error).

Подобная ошибка может перевести рабочий узел в некорректное состояние. В этом состоянии все задачи, относящиеся к тому же запросу, что

и «упавшая» задача, завершаются с ошибкой. Однако Presto продолжает

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

Бессмысленные запросы

Бессмысленный запрос – тот, который не возвращает желаемого результата или выполняется слишком долго. Такие запросы расходуют вычис-

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

• неэффективность: запрос плохо написан и не оптимизирован;

• ресурсоемкость: для выполнения запроса нужно больше ресурсов, чем

физически есть в кластере;

• конкуренция за метаданные: слишком много запросов одновременно об-ращаются к хранилищу метаданных за информацией о схеме.

В табл. 9.1 собраны наиболее часто встречающиеся причины неэффективности, ресурсоемкости или высокой конкуренции.

Таблица 9.1. Некоторые часто встречающиеся проблемы запросов

Конкуренция

Неэффективность

Ресурсоемкость

за метаданные

Неверные соединения

Большие

Высокая интенсивность

несекционированные

запросов

таблицы

к system.information_schema

Неэффективные операции

Секции разного размера

сравнения

Пропущенные фильтры

Слишком много

обрабатываемых данных

Пропущенные предикаты

Неэффективные сортировки

(ORDER BY) или группировки

(GROUP BY)

Основные принципы

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

Основные принципы   167

Доступность

В некоторых случаях кластеру Presto требуется перезагрузка, например вам

необходимо обновить версию Presto, или возникла неустранимая проблема

с виртуальной машиной Java – нехватка памяти либо большие задержки при

сборке мусора. Во время перезапуска кластер недоступен. Отношение времени, когда кластер выполняет запросы пользователей, к общему времени

существования кластера называется доступностью. Для достижения высокой

доступности следует строить кластер таким образом, чтобы он переживал

потерю любого узла и продолжал выполнять пользовательские запросы.

Кластер Presto может не удовлетворять требованиям доступности, в особенности если на нем выполняются специфические запросы. Вы можете

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

доступность.

Чтобы поддерживать несколько кластеров Presto, вы можете использовать

Presto Gateway. Это роутер запросов для Presto, позволяющий задавать разные политики роутинга. Если вам, например, нужно перезагрузить один из

кластеров, то вы можете запретить на роутере обращение к этому кластеру, а когда кластер снова будет готов принимать и обрабатывать запросы – снова разрешить. Этот процесс можно автоматизировать, добавляя или убирая

кластеры Presto в зависимости от текущей нагрузки.

Чтобы разобраться, как работает Presto Gateway, рассмотрим рис. 9.2. Система, изображенная на нем, состоит из двух кластеров Presto, 1 и 2, и одного

роутера. Вы тоже можете развернуть и запустить роутер, следуя инструкции

из официальной документации1. Затем разверните два кластера Presto в разных пространствах имен Kubernetes, например presto1 и presto2. Узлы-координаторы этих кластеров должны принимать соединения на разных портах, например на 9001 и 9002. Чтобы развернуть эти кластеры, воспользуйтесь

инструкциями из главы 5, а если мощности вашей машины не хватает для

развертывания хранилища-озера, то инструкциями из главы 2.

Кластер 1

Namespace: presto1

HTTP service: http://localhost:9001

Presto Gateway

Кластер 2

Namespace: presto2

HTTP service: http://localhost:9002

Рис. 9.2  Система, состоящая из двух кластеров Presto и роутера

1 .

168  Масштабирование Presto

Когда вы запустите эту систему, роутер будет ожидать соединений по адресу http://localhost:8080/. Откройте терминал и добавьте роутеру информацию

о двух кластерах Presto следующей командой:

curl -X POST http://localhost:8080/entity?entityType=GATEWAY_BACKEND \

-d '{ "name": "presto1", \

"proxyTo": "http://localhost:9001",\

"active": true, \

"routingGroup": "adhoc" \

}'

curl -X POST http://localhost:8080/entity?entityType=GATEWAY_BACKEND \

-d '{ "name": "presto2", \

"proxyTo": "http://localhost:9002",\

"active": true, \

"routingGroup": "adhoc" \

}'

Оба кластера Presto активны. Если по каким-то причинам вы ходите от-ключить кластер presto2, выполните следующую команду:

curl -X POST http://localhost:8080/gateway/backend/deactivate/presto2

Недавно в проекте Presto появился собственный роутер, который так и называется – Presto router. Это более совершенное программное обеспечение, чем Presto Gateway, но с той же функциональностью. Инструкции по развер-тыванию можно найти в документации Presto1.

Несмотря на то что Presto router уже выпущен, мы осознанно выбрали

Presto Gateway, чтобы показать, как легко интегрировать Presto с компонен-тами, созданными независимыми разработчиками.

Управляемость

Управляемость – это характеристика системы, показывающая, насколько легко и эффективно вы можете наблюдать за состоянием системы и сохранять ее

работоспособность, безопасность и производительность. Из главы 6 вы уже

узнали, как администрировать кластер Presto. В дополнение к описанным

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

следует реализовать интерфейс EventListener, который перехватывает такие

события, как queryCreated, queryCompleted и splitCompleted:

package com.facebook.presto.spi.eventlistener;

public interface EventListener {

default void queryCreated(QueryCreatedEvent queryCreatedEvent) { }

default void queryCompleted(QueryCompletedEvent queryCompletedEvent) { }

default void splitCompleted(SplitCompletedEvent splitCompletedEvent) { }

}

1 .

 Основные принципы   169

Если вы хотите создать свой листенер, ознакомьтесь с официальной доку-ментацией1 и статьей в блоге AWS2, либо можете использовать готовый пример из репозитория aws-samples 3. Собранный JAR-файл расширения нужно

скопировать в папку plugin узла-координатора. Чтобы сконфигурировать

лис тенер, создайте файл event-listener.properties в папке etc узла-координатора и добавьте в него следующую строку:

event-listener.name=event-listener

Перезапустите кластер Presto, а затем в любом клиентском приложении

выполните запрос:

SELECT * FROM tpch.tiny.customer LIMIT 10;

Теперь найдите файл log/queries-YYYY-MM-DDTHH:MM:SS.0.log на файловой

системе узла-координатора, чтобы увидеть вывод расширения-листенера.

Файлы журнала, созданные листенером, позволяют следить за работоспособностью и производительностью кластера Presto. Например, событие

QueryCompleted содержит не только тип ошибки (ошибка пользователя или

ошибка сервера), но и дамп состояния стека (stack trace) на момент сбоя

запроса. Кроме того, в журналах можно найти множество дополнительной

информации о запросах: указаны ли в запросах фильтры, отсекающие секции

таблиц, как таблицы участвуют в соединениях, сколько исходных данных

читает каждый запрос и т. д.

Производительность

В главе 8 вы узнали, как настраивать производительность кластера Presto.

Для настройки промышленного кластера требуется создать такой же кластер

и запустить на нем промышленную нагрузку. В главе 6 вы узнали, как настроить и использовать верификатор, чтобы проверить функционирование

нового кластера. Однако верификатор тестирует только функциональность, но не производительность. Для проведения нагрузочного теста необходимо

использовать утилиту Replayer, позволяющую воспроизвести нагрузку промышленного кластера в тестовой среде.

На рис. 9.3 показан типичный сценарий, используемый при настройке

производительности. В промышленном кластере листенер записывает запросы, выполняемые пользователями, и сохраняет их в EventDB – репозитории запросов. В тестовой среде утилита нагрузочного тестирования читает

из репозитория запросы, запускает несколько клиентских сеансов и с их помощью воспроизводит сохраненную нагрузку. На тестовом кластере также установлен листенер, сохраняющий журнал выполнения запросов. По

окончании тестирования специальная утилита Replay Analytics and Reporting 1

2 .

3 .

170  Масштабирование Presto

Service сравнивает журналы, полученные на разных кластерах, и показывает

в отчете разницу в производительности.

Промышленная среда

Среда тестирования

Кластер Presto

Листенер

Клиент Клиент Клиент

(тестовый)

(тестовый)

Presto

Presto

Presto

Воспроиз-

Кластер Presto

ведение

(промышленный)

Клиенты

Листенер

Сервис

Аналитика

воспроизведения

и отчетность

БД событий

Рис. 9.3  Тестовая среда с использованием утилиты Replayer Защита

Presto – распределенная система, и это делает ее уязвимой для злоумышлен-ников, которые могут использовать ее для проведения атак на базовую инфраструктуру. В главе 7 вы узнали, как обезопасить кластер Presto и защитить

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

Реализовать блокировку нежелательных запросов можно не только при

помощи роутера, но и при помощи расширения-листенера. Блокировать запрос можно, выбросив исключение в методе queryCreated. Например, код, приведенный ниже, блокирует запросы к таблице system.information_schema.

columns, в которых нет ограничений на выбираемые данные, при помощи

фразы where:

public void queryCreated(QueryCreatedEvent queryCreatedEvent) {

String queryText =

queryCreatedEvent.getMetadata().getQuery().toLowerCase();

if (queryText.contains("system.information_schema.columns") &&

!queryText.contains("where")) {

logger.error("Rejected query from event listener: " + queryText); throw new PrestoException(StandardErrorCode.COMPILER_ERROR,

"Querying without predicates is not permitted.");

}

}

 Основные принципы   171

Настройка

Из главы 6 вы узнали, как конфигурировать кластер Presto, используя конфигурационные файлы, настройки сеансов и настройки виртуальной машины

Java. Однако для больших промышленных кластеров этих трех инструментов

может быть недостаточно. Кроме этого, вы должны выбрать правильную

конфигурацию (или, если вы заказываете серверы в облаке, правильный тип

сервера) каждого узла – как координатора, так и рабочего узла.

Выбор оптимальной конфигурации узла – непростая задача, поскольку он

зависит от характера запросов, выполняемых в системе. Чтобы верно указать

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

этого необходимо собрать метрики мониторинга виртуальной машины Java.

В идеале во время максимальной нагрузки на кластер память и процессор

узла-координатора должны быть загружены на 50–70 %. Процессоры рабочих

узлов должны быть загружены на 90 % или более, а память – минимум на

70 %. Если показатели использования процессора или памяти слишком высоки или слишком низки, то сервер не сбалансирован с точки зрения ресурсов.

Ниже перечислены параметры виртуальной машины Java, влияющие на

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

jvm.config:

-server – устанавливает «серверный» режим работы виртуальной машины Java. Этот параметр активирует комплекс настроек, в основном

относящихся к сборке мусора, оптимальных для долгоживущих сер-верных приложений;

-Djdk.attach.allowAttachSelf=true – позволяет подключаться отладчи-ком к виртуальной машине Java;

-Xlog:gc:<path/to/log/dir>/gc.log – включает запись событий, связанных со сборкой мусора, в файл gc.log в папке <path/to/log/dir>;

-XX:+UseG1GC – включает модуль G1 для сборки мусора;

-XX:+AggressiveOpts – включает ряд агрессивных оптимизаций, способных в некоторых случаях существенно увеличить производительность;

-XX:ReservedCodeCacheSize=150M – устанавливает размер кеша JIT-ком пи-ля тора Java в 150 Мбайт;

-XX:ErrorFile={{ presto_log_dir }}/java_error.log – указывает имя файла, в который будет записана информация об ошибке в случае фаталь-

ной ошибки;

-Xms{{ 0.80 * available_node_memory_mb }}m – устанавливает начальный

размер кучи виртуальной машины равным 80 % доступной оператив-

ной памяти;

-Xmx{{ 0.80 * available_node_memory_mb }}m – устанавливает максимальный размер кучи виртуальной машины равным 80 % доступной опе-

ративной памяти;

-XX:MaxGCPauseMillis=400 – задает целевой показатель максимальной

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

172  Масштабирование Presto

-XX:InitiatingHeapOccupancyPercent=5 – устанавливает пороговое значение заполненности кучи в процентах, после которого виртуальная

машина переходит в режим смешанной сборки мусора1;

XX:OnOutOfMemoryError="kill -9 %p" – указывает команду, которая будет

запущена при ошибке переполнения памяти (OutOfMemoryError ). В данном случае процесс с идентификатором %p будет немедленно завершен

командой kill -9;

-XX:G1NewSizePercent=1 – задает начальный объем кучи, отведенный для

вновь создаваемых объектов (new generation), равным 1 % от общего

объема кучи.

Чтобы включить возможность удаленной отладки виртуальной машины

Java, добавьте следующие параметры:

-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005

Как масштабировать Presto

Для поддержки высокой рабочей нагрузки, при которой запросы могут работать по нескольку часов, сканируя петабайты данных, необходимо масштабировать кластер. В этом разделе мы рассмотрим три метода масштабирования: использование нескольких координаторов, запуск Presto в Spark и вытеснение. Правильное применение этих методов позволит вашей компании эффективно обрабатывать большие объемы данных.

Несколько координаторов

Одновременный запуск нескольких узлов-координаторов позволит вам масштабировать кластер Presto. В такой конфигурации координаторы только

управляют жизненным циклом запроса, а новый компонент, называемый менеджером ресурсов ( resource manager), управляет кластером. В кластере Presto может быть один или несколько менеджеров ресурсов. Узлы-координаторы

работают независимо друг от друга. На рис. 9.4 изображен кластер Presto с несколькими узлами-координаторами и с несколькими менеджерами ресурсов. Новый запрос отправляется произвольному координатору, который

отправляет его менеджеру ресурсов, где запрос становится в очередь на выполнение. Периодически координатор запрашивает запросы из очереди менеджера ресурсов и принимает решение об их запуске. Также координаторы

получают от менеджера ресурсов информацию об активных рабочих узлах.

Подробнее работа кластера с несколькими координаторами описана в статье

«Распределенный координатор» («Disaggregated Coordinator»)2.

1 Подробное описание сборщика мусора G1 можно найти в статье «Дюк, вынеси мусор! – часть 3». Ссылка на с. – Прим. перев.

2 .

Как масштабировать Presto   173

Узлы

Менеджеры

координаторы

ресурсов

Рабочие узлы

Рис. 9.4  Кластер Presto 

с несколькими координаторами

Чтобы сконфигурировать несколько координаторов, добавьте по одному

узлу для каждого менеджера ресурсов. Файл config.preperties для кластера

с единственным менеджером ресурсов будет выглядеть так:

resource-manager=true

resource-manager-enabled=true

coordinator=false

node-scheduler.include-coordinator=false

http-server.http.port=8080

thrift.server.port=8081

discovery-server.enabled=true

discovery.uri=http://<my_domain>:8080

thrift.server.ssl.enabled=true

Приведенные выше настройки выключают координатор (coordinator=false) и менеджер ресурсов (resource-manager=true). В параметре discovery.uri укажите адрес менеджера ресурсов.

Модифицируйте также config.properties узлов-координаторов и рабочих

узлов, добавив в них следующие настройки:

discovery.uri=http://<my_domain>:8080

resource-manager-enabled=true

Параметр discovery.uri должен содержать адрес ресурсной группы. Подробные инструкции по настройке кластера с несколькими координаторами, как обычно, можно найти в документации Presto1.

Presto на Spark

Apache Spark – это платформа для обработки больших данных с открытым исходным кодом, обладающая высокой масштабируемостью и отказоустойчи-востью. Вы можете развернуть ее как на отдельном сервере, так и на кластере

из нескольких сотен узлов. Поскольку Spark работает в виртуальной маши-1

174  Масштабирование Presto

не Java, вы можете легко интегрировать его с другими Java-приложениями, включая Presto.

Есть много веских причин запускать Presto на Spark. Во-первых, это может значительно повысить производительность Presto на пакетных задачах

(например, ETL-процессах) за счет увеличения степени параллелизма. Во-вторых, Spark – надежная и масштабируемая платформа, и Presto на Spark будет работать более стабильно. Наконец, такая интеграция позволит Presto пользоваться функциями экосистемы Apache Spark.

При запуске Presto на Spark используется только уровень Spark Resilient Distributed Dataset (RDD) и ниже, без применения Spark SQL engine. RDD позволяет Spark перепроверять данные в случае сбоя запроса.

На рис. 9.5 показана архитектура Presto на Spark. Драйвер Spark запускает

упрощенную версию узла-координатора Presto, которая анализирует и оптимизирует запросы, создает физические планы запросов и отправляет

задачи рабочим узлам. Рабочие узлы Presto совмещены с исполнителями

Spark (Spark executors). Функциональность узлов Presto, как координатора, так и рабочих узлов, доступна в виде библиотек, которые реализуют только

обработку запросов. Управление памятью, потоковая обработка и сетевое

взаимодействие реализуются кластером Spark. Архитектура Presto на Spark хорошо описана в статье «Масштабирование Presto с помощью Spark» («Scal-ing with Presto on Spark»)1.

Исполнитель Spark

Рабочий узел

Драйвер Spark

Библиотека

Координатор

Управление

Библиотека

кластером Spark

Исполнитель Spark

Рабочий узел

Библиотека

Рис. 9.5  Архитектура Presto на Spark

Чтобы запустить Presto на Spark, загрузите из Maven-репозитория пакет

Presto для Spark и jar-файл, запускающий Presto на Spark. Затем добавьте

следующие строки в config.properties:

task.concurrency=<N>

task.max-worker-threads=<N>

task.writer-count=<N>

1 .

 Как масштабировать Presto   175

Значение N зависит от возможностей вашего оборудования. Обычно до-

статочно 8 или 16.

Также необходимо сконфигурировать каталоги Presto. Их конфигурация

ничем не отличается от обычных инсталляций.

Напишите запрос и сохраните его в файле query.sql:

SELECT * FROM tpch.tiny.customer;

Чтобы запустить запрос, используйте команду spark-submit. Аргумент N

должен быть установлен в то же значение, что и в файле config.properties выше:

/spark/bin/spark-submit \

--master spark://<url-to-spark-master>:7077 \

--executor-cores <N> \

--conf spark.task.cpus=<N> \

--class com.facebook.presto.spark.launcher.PrestoSparkLauncher \

/path/to/presto-spark-launcher-0.280.jar \

--package /path/to/presto-spark-package-0.280.tar.gz \

--config /path/to/config.properties \

--catalogs /path/to/presto/catalog/directory \

--file query.sql

В официальной документации1 развертывание Presto на Spark описано

более детально.

Подкачка2

В главе 6 мы уже писали, что подкачка – это перемещение части данных из

оперативной памяти на диск. Подкачка позволяет Presto продолжать работу, даже если памяти не хватает. Когда у узла заканчивается доступная оперативная память, он автоматически записывает часть данных на диск, осво-бождая место для дополнительной обработки. Благодаря подкачке кластер

может обрабатывать большие объемы данных и одновременно обслуживать

большее количество пользователей.

Подкачка повышает надежность кластера за счет уменьшения количества

ошибок, связанных с нехваткой памяти. Она также снижает риск перегрузки

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

кластера. Однако следует учитывать, что обычно подкачка значительно снижает производительность.

Чтобы включить подкачку в Presto, установите в true параметр experimental.spill-enabled.

1

2 Напомню, что вместо swapping в книге используется термин spilling. – Прим. перев.

176  Масштабирование Presto

Использование облачных сервисов

Самостоятельное развертывание кластера Presto с чистого листа требует

значительных усилий и компетенций в таких областях, как распределенные

системы, сети, настройка оборудования и программного обеспечения. Это

занятие:

долгое. Вам надо настроить узлы, установить программное обеспечение

и настроить сетевое взаимодействие;

дорогое. Вы должны приобрести оборудование и лицензии на программное обеспечение, а потом оплачивать сопровождение и техни-

ческую поддержку;

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

Существенно упросить развертывание Presto можно, развернув кластер

в облаке одного из провайдеров – AWS, Google Cloud Platform или Microsoft Azure.

Поставщики облачных услуг помогают сократить усилия и затраты на

развертывание кластера Presto, предоставляя готовые шаблоны и сценарии

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

безопасности. Все это еще больше упрощает управление кластером Presto.

В облаке вы получите:

гибкость. Облачные сервисы позволяют легко добавлять или удалять

ресурсы. Это означает, что вы можете расширять и уменьшать свой

кластер в зависимости от текущей нагрузки без каких-либо предвари-

тельных инвестиций в инфраструктуру;

экономию. В облаке вы платите только за те ресурсы, которые реально

используете, что делает кластер экономически эффективным. Кроме

того, подбирая подходящую конфигурацию для узлов (оптимизиро-

ванную для вычислительных нагрузок или для больших объемов дан-

ных), вы можете использовать еще меньше ресурсов, снизив тем самым

стои мость услуг;

надежность. Облачные сервисы предоставляют готовые механизмы

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

безопасность. Облачные сервисы поддерживают такие механизмы

обес печения безопасности, как шифрование и многофакторная аутен-

тификация. Применение этих механизмов поможет защитить ваши

данные и предотвратить несанкционированный доступ;

масштабирование. Облачные сервисы позволяют быстро и просто добавлять узлы в кластер или удалять их в зависимости от требований

к мощности кластера;

эластичность. Облачные сервисы могут автоматически увеличивать

или уменьшать объем выделенных ресурсов, что позволяет оптимизи-

ровать производительность и сократить расходы на поддержку клас-

тера.

 Заключение   177

Заключение

Из этой главы вы узнали, как масштабировать кластер Presto. Масштабируемость показывает, насколько хорошо кластер может справляться с возрас-тающей нагрузкой, источником которой может быть увеличение количества

пользователей, объема данных или сложности запросов.

Мы обсудили основы масштабирования и описали некоторые архитектур-

ные особенности Presto, обеспечивающие масштабирование его кластеров.

Мы также рассмотрели наиболее распространенные подходы к масштабированию Presto, включая использование нескольких узлов-координаторов, развертывание Presto на Spark и подкачку. В последней части главы мы рассказали, как масштабировать кластер Presto с помощью облачных сервисов.

Вы только что закончили читать эту книгу. На всем ее протяжении вы

изучали основные концепции Presto: его архитектуру, способы добавления

источников данных, выполнение запросов с использованием различных клиентов. Вы узнали, как построить хранилище-озеро и включить в него Presto в связке с самыми современными технологиями, такими как Hive и Hudi.

В последней части книги вы узнали, как администрировать, защищать, настраивать и масштабировать кластер Presto.

Глава за главой вы проверяли все концепции, описанные в книге, на практике. Код для решения всех рассмотренных задач доступен в репозитории, который мы создали специально для этой книги. Надеемся, что это позво-лило вам получить не только теоретическое представление о платформе, но

и практические навыки работы с ней.

Мы верим, что, прочитав эту книгу, вы продолжите знакомство с Presto и с каждым днем будете узнавать об этой платформе все больше, читая другие статьи и книги и активно участвуя в работе онлайн-сообществ.

Предметный указатель

A

Docker Desktop,

Docker Hub,

ACID-транзакция,

Altair,

ANSI SQL,

E

apache-util,

ELT,

API

ETL,

мониторинг,

EXPLAIN, оператор,

Data Location,

Data Stream,

G

Metadata,

REST,

Google Cloud,

Aria,

Google Guice,

Aria Scan,

ARM,

H

AWS,

HDFS,

узлы,

Hive,

Azure,

Hive Metastore, ,

Blob Storage,

HMS (Hive Metastore),

Hudi,

B

bcrypt,

I

Benchto,

Impala,

IntelliJ IDEA,

C

ConfigMap,

J

JDK,

D

JMX,

JRE,

Data governance. См. Стратегическое

управление данными

Data lake. См. Озеро данных

K

Data lakehouse. См. Хранилище-озеро

Kerberos, ,

Docker,

Kubernetes,

Предметный указатель   179

L

Trino,

LDAP,

А

M

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

дерево,

MapReduce,

Авторизация,

Maven,

Аудит,

MinIO, ,

Аутентификация, ,

взаимная,

N

основанная на файлах,

Kerberos,

Netflix,

LDAP,

O

Б

ORC,

База данных,

TPC-H,

P

Балансировщик нагрузки,

Pandas,

Parquet, ,

В

Pinot,

Ввод-вывод,

POJO,

Веб-интерфейс

Presto Gateway,

GCeasy,

Presto router,

MinIO,

Prometheus,

Presto,

Веб-приложение,

R

Верификатор,

Версионирование данных,

Ranger,

Внедрение зависимостей,

Replayer,

Д

S

Данные

S3,

неструктурированные,

Scheduler, См. Организатор

слабоструктурированные,

Secret,

структурированные,

Spark, ,

Доступность,

Spark SQL,

Драйвер,

SPI,

JDBC,

Spilling. См. Подкачка

ODBC,

Split. См. Фрагмент

Spark,

Stage. См. Этап

Streamlit,

Ж

T

Жизненный цикл

администрирования,

Task. См. Задача

запроса,

Thrift,

настройки производительности,

TLS,

узла,

180  Предметный указатель

З

М

Задача,

Масштабирование,

Запрос бессмысленный,

вертикальное,

горизонтальное,

И

Машинное обучение,

Идентификатор

Метаданные,

запроса,

каталог,

пользователя,

управление,

процесса,

Модуль разбора,

узел,

Мониторинг,

Интерфейс

метрики, ,

описание,

Монтирование

Connector,

локальной папки,

ConnectorFactory,

папки в Docker-контейнере,

ConnectorHandleResolver,

тома,

ConnectorRecordSetProvider,

файла,

ConnectorSplit,

ConnectorSplitManager,

О

MetaData,

Module,

Обмен данными,

Plugin,

Объектное хранилище,

RecordCursor,

Озеро данных,

RecordSet,

Оптимизатор,

RecordSetProvider,

стоимостной,

SplitManager,

эвристический,

Организатор,

К

Ошибка

аутентификации,

Каталог,

на этапе инициализации,

добавление,

переполнения памяти,

метаданных,

пространств имен,

синтаксическая,

службы обнаружения,

тайм-аут,

список,

фатальная,

LDAP,

system,

П

Квота,

Память,

Конкуренция,

максимальный общий объем,

Коннектор,

максимальный объем,

JMX,

максимальный объем

Координатор,

пользовательской области,

объем используемой,

Библиотека,

объем свободной,

несколько узлов,

Курсор,

пользовательская,

системная,

Л

управление,

Перераспределение данных,

Листенер,

Перераспределение задач,

Предметный указатель   181

Планировщик,

У

Подкачка,

Привилегии,

Узел, ,

Пространство имен

Управление доступом,

функций,

Kubernetes,

Ф

Проталкивание

Файловая система,

предикатов,

фильтров,

Федеративный запрос,

Процессор

Формат,

виртуальный,

колоночный,

нагрузка,

табличный,

Процессорное время, ,

файлов,

CSV,

Р

Delta Lake,

Hudi,

Расширение,

Iceberg,

Регулярные выражения,

Java Keystore File,

Ресурсные группы,

JSON,

Роли,

узла,

ORC,

Parquet,

С

Фрагмент,

Функция,

Сборка мусора,

аудита,

Сеанс,

изоляция,

Х

настройки, ,

Хранилище

Сертификат,

данных,

импорт,

ключей,

самоподписанный,

Хранилище-озеро,

удостоверяющих центров,

Стратегическое управление

Ш

данными,

Схема,

Шифрование,

на диске,

Т

трафика,

Тестирование

Э

нагрузочное,

регрессионное,

Эволюция схемы данных,

Тип данных,

Этап,

Анжелика Ло Дука, Тим Михан,

Вивек Бхаратан и Ин Су

Изучаем и используем Presto

Главный редактор Мовчан Д. А.

Перевод Комаров В. И.

Корректор Синяева Г. И.

Верстка Чаннова А. А.

Дизайн обложки Мовчан А. Г.

Гарнитура PT Serif. Печать цифровая.

Усл. печ. л. 14,79. Тираж 100 экз.

Веб-сайт издательства:

Назад: Движок запросов
На главную: Предисловие