Озеро данных 93
Система хранения данных
1d345g67j8.parquet
date=20230101
1ed34fge67.parquet
b5r6j4456y.parquet
mytable
date=20230102
1a3dd556gl.parquet
Табличный
формат
0001.json
logs
0002.json
0003.json
Рис. 5.2 Табличные форматы
Apache Hudi
Формат был разработан компанией Uber, чтобы добавить к озеру данных
транзакционную функциональность. Существует утилита Hudi DeltaS-treamer с открытым исходными кодом, преобразующая данные из популярных форматов, например из реляционных баз данных, в формат Hudi.
Для Presto есть коннектор к Hudi, но на момент написания книги он поддерживает только чтение данных. За подробностями обращайтесь к документации Presto1.
Apache Iceberg
Этот формат был разработан корпорацией Netflix. Перед разработчиками
стояла задача быстро извлекать данные из массивов объемом в несколько
петабайт, хранящихся в S3-совместимых хранилищах. Общедоступных
утилит, позволяющих загружать данные в Iceberg из популярных источников, не существует. Но коннектор Presto позволяет не только читать
данные этого формата, но и записывать их. Подробности, как обычно, –
в документации Presto2.
Delta Lake
Этот формат изначально разработан в Databricks, а сегодня его разработку
курирует Фонд Linux. Его первоначальной целью также было добавление
к озеру данных ACID-транзакций. Использование Delta Lake обеспечивает согласованное чтение данных из объектного хранилища, благодаря
чему пользователи многочисленных читающих сеансов видят одну и ту
же версию данных. Фреймворк Delta Lake содержит проприетарное ПО для
1
2
94 Open Data Lakehouse
загрузки данных из некоторых типов источников, например из реляционных БД. Для Presto существует коннектор Delta Lake, который на момент
написания книги поддерживает только чтение. За дальнейшими деталями
добро пожаловать в официальную документацию1.
Движок запросов
SQL-движки позволяют пользователям извлекать из данных информацию.
С точки зрения сложности и стоимости именно движок запросов является
важнейшим компонентом хранилища. Мы используем в качестве основного
движка для нашего модельного хранилища Presto.
Особенность движков, используемых в хранилище-озере, в том, что они
должны работать с любыми данными: уровень хранения данных полностью
отделен от уровня обработки. Такое разделение обязанностей позволяет независимо масштабировать вычислительные мощности и систему хранения
данных, что обеспечивает не только дополнительную гибкость по сравнению
с традиционными хранилищами, но и позволяет существенно снизить затраты.
Управление метаданными
Термином «управление метаданными» (metadata management) мы обычно
обозначаем управление техническими метаданными, позволяющими вы-шележащим компонентам (например, SQL-движкам) корректно работать
с данными, например обновлять их. Для управления метаданными, описыва-ющими глобальные свойства хранилища (например, правила разграничения
доступа), существует отдельный термин – стратегическое управление (data governance).
Обычно в озерах данных хранятся данные из множества источников. Каталог метаданных позволяет не только отслеживать изменения в загружен-ных данных, но и обнаруживать новые источники. Метаданные необходимы, чтобы понимать, какие данные доступны, где они расположены и как движок
может получить к ним доступ.
Один из самых популярных каталогов метаданных – Hive Metastore (HMS).
Он обеспечивает централизованное хранение информации о таблицах Hive и об их физическом расположении. У него есть специализированный интерфейс, metastore service API, при помощи которого клиенты могут запросить
хранящуюся информацию. В Presto есть коннектор Hive, поддерживающий
в том числе и работу с метаданными. Подробности можно найти в документации2.
1 .
2 .

Стратегическое управление данными 95
На рис. 5.3 показано, как Presto выполняет запрос к таблице, находя ее
данные при помощи каталога метаданных. На первом шаге клиент отправляет в Presto запрос, извлекающий данные из таблицы transactions, которая находится в схеме pq каталога glue. Получив запрос, Presto запрашивает в каталоге метаданных информацию о физическом расположении
таблицы transactions и получает в ответ путь к объекту в хранилище. Затем
Presto выполняет собственно запрос и возвращает результат выполнения
клиенту.
На самом деле каталог метаданных содержит гораздо больше информации, чем просто пути к файлам. Метаданные таблицы состоят как минимум из
списка полей и их типов, а также иной информации, полезной при оптимизации запросов, например списка индексов и проекций.
Клиент
Озеро
Presto
Presto
Каталог
метаданных
данных
> SELECT category,
sum(amt) as total
FROM glue.pq.transactions
GROUP BY category;
Поиск (transactions)
s3://anypath/glue/pq/tranactions
s3://anypath/glue/pq/tranactions
Результат
Результат
Рис. 5.3 Как работает каталог метаданных
Стратегическое управление данными
Одна из важнейших функций хранилища данных, включая и хранилища-озера, – стратегическое управление данными (data governance). К страте-гическому управлению относят разграничение доступа к данным и защиту
информации, обеспечение качества данных, поддержку целостности и кон-фиденциальности данных, выполнение регуляторных требований... Вот примеры вопросов, которыми занимаются механизмы стратегического управления данными.
Разграничение доступа
Кто может получить доступ к данным? К каким именно данным (таблицы, поля, строки) получает доступ конкретный пользователь? Каков уровень
доступа – чтение, запись, изменение модели данных?
96 Open Data Lakehouse
Поиск
Как пользователи находят нужные данные?
Определение семантики
Какую именно информацию содержат те или иные данные? Какие опреде-
лены сущности? Какие функции бизнеса описывает данная информация?
Доступность данных
Насколько данные пригодны к использованию? Насколько они качественные и согласованные?
О стратегическом управлении данными можно было бы написать отдель-
ную книгу. Мы подробно остановимся только на разграничении доступа.
Разграничение доступа к данным
Разграничение доступа – комплекс мер и технических средств, призванных
защитить данные от несанкционированного чтения и изменения. Владельцы
хранилищ данных жестко контролируют, кто может получить доступ к данным и какие именно операции можно выполнить. Цель любой организации –
не допустить утечки конфиденциальной информации.
Администраторы предоставляют пользователям привилегии на доступ
к данным. Привилегии могут предоставляться на любом из уровней, перечисленных в табл. 5.1.
Таблица 5.1. Объекты разграничения доступа
Объект
Привилегии
База данных Пользователь может изменять базу данных, создавая, удаляя и изменяя
таблицы
Таблица
Пользователь может изменять базу данных, создавая, удаляя и изменяя
таблицы1
Поле
Пользователь может читать и изменять только определенные поля
в таблице
Строка
Пользователь может читать и изменять только определенные строки
в таблице
На рис. 5.4 приведены примеры различных уровней управления доступом.
На уровне БД пользователь имеет право доступа только к базе данных A. На
уровне таблиц он может работать только с таблицей С. На уровне полей пользователи могут обращаться лишь к полям E и F, и наконец на уровне строк
им доступны только строки G и H.
1 Описания привилегий на уровне БД и таблицы не отличаются. В других источниках, как правило, привилегии на уровне таблицы позволяют читать и изменять
данные в таблице, но не позволяют создавать новые таблицы, а также удалять
существующие таблицы или изменять их структуру. – Прим. перев.

Построение модельного хранилища-озера 97
Управление доступом
Управление доступом
Управление доступом
на уровне БД
на уровне таблиц
на уровне полей
E
F
A
C
D
Управление доступом
на уровне строк
B
G
H
Рис. 5.4 Разные уровни разграничения доступа к данным
Построение модельного
хранилища-озера
В главе 1 мы уже упоминали наше модельное хранилище, остановившись
лишь на подключении Presto к озеру данных, изображенному на рис. 1.7.
Пришло время рассмотреть этот вопрос подробнее.
Архитектура той части нашего модельного хранилища, которую мы построим в этом разделе, показана на рис. 5.5. Главные компоненты обозначе-ны более темными блоками, а вспомогательные – более светлыми. В качестве
системы хранения бы будем использовать MinIO, а таблицы будем создавать
в формате Apache Hudi. Инициализировать хранилище будем при помощи
клиента MinIO, а для записи данных создадим поток в Spark. Использовать
Presto для записи данных мы не сможем, потому что в настоящее время
Presto не поддерживает запись в таблицы формата Hudi. Но на следующем
шаге мы подключим Presto к Hive Metastore, чтобы извлечь данные из MinIO.
Hive Metastore для хранения метаданных будет использовать базу данных
MySQL. И под конец мы подключимся к Presto при помощи клиентского приложения и запросим данные, которые хранятся в MinIO. Каждый компонент
нашего хранилища будет работать как отдельный под в кластере Kubernetes из главы 2.

98 Open Data Lakehouse
Хранилище-озеро
MySQL
Каталог метаданных
Движок запросов
Hive metastore
Presto
Клиент Presto
Presto CLI
Поток данных
Spark
Табличный
формат
Hudi
СХД
MinIO
Клиент MinIO
mc
Рис. 5.5 Часть модельного хранилища
Весь код модельного хранилища вы можете найти в папке 05/ нашего репозитория.
Процесс развертывания хранилища будет состоять из следующих шагов: 1) настройка MinIO;
2) настройка HMS;
3) настройка Spark;
4) регистрация таблиц Hudi в HMS;
5) подключение Presto и выполнение запросов.
Настройка MinIO
Файл конфигурации MinIO вы найдете под именем 05/data_lakehouse/minio.
yaml. Для развертывания контейнера MinIO используется шаблон ReplicationController, а образ мы возьмем на Docker Hub: путь к этому образу – quay.
io/minio/minio:RELEASE.2022-06-17T02-00-35Z. Подготовив конфигурацию, запустите сервис minio командой server /data --console-address :9090.
Добавьте эту команду в файл minio.yaml:
spec:
containers:
- name: minio
image: quay.io/minio/minio:latest
command:
- /bin/bash
- -c
args:
- minio server /data --console-address :9090
Построение модельного хранилища-озера 99
Для доступа к MinIO необходимы имя пользователя и пароль. Чтобы их
задать, заведем в конфигурационном файле две переменные, значения которых использует Docker-образ, – MINIO_ROOT_USER и MINIO_ROOT_PASSWORD: env:
- name: MINIO_ROOT_USER
valueFrom:
secretKeyRef:
key: minio_root_user
name: minio-secrets
- name: MINIO_ROOT_PASSWORD
valueFrom:
secretKeyRef:
key: minio_root_password
name: minio-secrets
Секреты MinIO сохраним в специальном объекте кластера Kubernetes под
названием minio-secrets. Содержимое этого объекта вы найдете в файле
minio-secrets.yaml.
MinIO ожидает клиентских запросов через порт 9000, и в файл описания
сервиса minio.yaml мы добавим сервис, работающий с двумя портами: 9000
для данных и 9090 для консоли управления:
apiVersion: v1
kind: Service
metadata:
name: minio
spec:
ports:
- name: minio-console
port: 9090
targetPort: 9090
- name: minio-api
port: 9000
targetPort: 9000
type: LoadBalancer
selector:
app: minio
Чтобы развернуть подготовленный дистрибутив MinIO в кластере, выполните следующие команды:
kubectl create -f minio-secrets.yaml --namespace presto
kubectl apply -f minio.yaml --namespace presto
Откройте в браузере страницу по адресу http://localhost:9090, и вы увидите
веб-интерфейс MinIO. Для входа используйте логин и пароль, сохраненные
в minio-secrets. Пока в MinIO нет никаких данных.
100 Open Data Lakehouse
Заполнение хранилища данными
Чтобы создать структуру нашего хранилища, мы будем использовать клиентское приложение MinIO, в нашем примере – mc. Мы создадим две корзины
(buckets): в warehouse будут лежать сырые данные, а в metastore – таблицы
в формате Hudi. Кроме того, мы создадим простую таблицу, назовем ее customers.csv и загрузим по адресу warehouse/data.
Пример данных из таблицы customers приведен в табл. 5.2.
Таблица 5.2. Данные из таблицы customers
id
first
last
gender
dob
zip
city
state
6895
Valirie
Whitney
F
1959-03-31
99160
Orient
WA
4509
Crystal
Smith
F
1974-01-03
96135
Vinton
CA
8045
Christine
Maxwell
F
1985-08-21
91321
Newhall
CA
8593
Sharon
Mclaughin F
1954-07-05
95015
Daly City CA
Это пока еще не таблица в формате Hudi. Чтобы преобразовать таблицу
в нужный формат и загрузить в хранилище metastore, мы будем использовать
Spark.
Клиентское приложение MinIO развернем в отдельном поде. Его конфигурацию вы найдете в файле 05/data_lakehouse/mc.yaml.
Для развертывания клиента MinIO также будем использовать шаблон ReplicationController, а образ minio/mc возьмем с Docker Hub. Чтобы под с клиентским приложением не завершался, добавим в его описание команду sleep infinity:
containers:
- name: mc
image: minio/mc
command: [ "sleep" ]
args: [ "infinity" ]
Чтобы получить доступ к хранилищу MinIO, посмотрите значения пере-
менных MINIO_USERNAME и MINIO_PASSWORD, которые находятся внутри объекта
minio-secrets:
env:
- name: MINIO_USERNAME
valueFrom:
secretKeyRef:
key: minio_root_user
name: minio-secrets
- name: MINIO_PASSWORD
valueFrom:
secretKeyRef:
Построение модельного хранилища-озера 101
key: minio_root_password
name: minio-secrets
И наконец, смонтируйте в контейнер папку /data, в которой находятся
файлы с данными:
containers:
- name: mc
# ...
volumeMounts:
- name: data
mountPath: "/data/"
# ...
volumes:
- name: data
hostPath:
path: "/absolute/path/to/data/storage"
Чтобы развернуть контейнер с клиентом MinIO в кластере Kubernetes, выполните команду
kubectl apply -f mc.yaml --namespace presto
Откройте сеанс в контейнере, где работает клиент MinIO, и создайте две
корзины – warehouse для сырых данных и metastore для HMS:
/usr/bin/mc config host add minio http://minio:9000 ${MINIO_USERNAME} ${MINIO_PASSWORD}
/usr/bin/mc mb minio/warehouse;
/usr/bin/mc mb minio/metastore;
Наконец, загрузите в корзину warehouse данные из файлов, которые хранятся в папке data:
/usr/bin/mc cp --recursive /data minio/warehouse;
Еще раз откройте веб-интерфейс MinIO. Вы должны увидеть две корзины, которые были созданы только что: пустая корзина metastore и корзина warehouse с таблицей data/customers.csv. Примерный вид консоли показан на рис. 5.6.
Настройка HMS
Мы будем использовать Hive Metastore в качестве посредника между MinIO
и Presto. В нашей конфигурации ему будет доступна только корзина metastore, куда мы будем записывать таблицы в формате Hudi.
Чтобы сконфигурировать HMS, начнем с создания сервера MySQL, который
будет использоваться для хранения данных. Конфигурационный файл вы
найдете по адресу 05/data_lakehouse/mysq-metastore.yaml.
kubectl apply -f mysql-metastore.yaml --namespace presto

102 Open Data Lakehouse
Рис. 5.6 Содержимое корзин MinIO после запуска клиентского приложения
Затем откройте файл 05/dockerfiles/hive-metastore/conf/hive-site.xml. В нем
вы найдете следующую информацию:
адрес для доступа к MinIO:
<property>
<name> fs.s3a.endpoint</name>
<value> http://minio:9000</value>
</property>
данные для доступа к Minio, jdo.option.ConnectionUserName и jdo.option.
ConnectionPassword:
<property>
<name> javax.jdo.option.ConnectionUserName</name>
<value> admin</value>
</property>
<property>
<name> javax.jdo.option.ConnectionPassword</name>
<value> admin</value>
</property>

Построение модельного хранилища-озера 103
настройку папки для хранилища данных HMS. Задайте ей значение
s3a://metastore/warehouse/;
параметры настройки MySQL:
<property>
<name>javax.jdo.option.ConnectionDriverName</name>
<value>com.mysql.cj.jdbc.Driver</value>
</property>
<property>
<name>javax.jdo.option.ConnectionURL</name>
<value>jdbc:mysql://mysql-metastore:3306/metastore_db?createDatabaseIfNotExist=tr ue</value>
</property>
Создайте Docker-образ, описание которого находится в папке 05/dockerfiles/hive-metastore:
docker build -t hive-metastore .
И наконец, разверните этот образ в кластере Kubernetes, используя в качестве конфигурации файл 05/data_lakehouse/hive-metastore.yaml: kubectl apply -f hive-metastore.yaml --namespace presto
На рис. 5.7 показано, как организованы данные в MinIO. Напомним, что
там создано две корзины – warehouse для сырых данных и metastore для таблиц
в формате Hudi.
Объектное хранилище
MinIO
Warehouse
Metastore
( сырые данные)
( таблицы Hudi)
• customer.csv
• hudi_customer
Рис. 5.7 Данные в MinIO
Настройка Spark
Мы запустим Spark, чтобы сделать из простой таблицы customers.csv в корзине warehouse/data таблицу hudi_customer в корзине metastore/warehouse.
Начнем с того, что соберем Docker-образ, описание которого находится
в папке 05/dockerfiles/spark:
docker build -t spark .

104 Open Data Lakehouse
Затем мы развернем собранный образ в кластере Kubernetes, воспользовавшись конфигурацией из файла spark.yaml, находящегося в папке 05/
data_lakehouse:
kubectl apply -f spark.yaml --namespace presto
На рис. 5.8 показана архитектура системы, которую мы успели построить.
Мы развернули три основных компонента (MinIO, HMS, Spark) и два вспомогательных – MySQL и клиент MinIO:
Хранилище-озеро
MySQL
Каталог метаданных
Hive metastore
Поток данных
Spark
СХД
MinIO
Клиент MinIO
mc
Рис. 5.8 Архитектура системы, развернутой к текущему моменту
Регистрация таблиц Hudi в HMS
Итак, в корзине warehouse/data находится единственная таблица customers.
csv. Мы запустим Spark и сделаем из этой таблицы таблицу в формате Hudi.
Подключитесь к контейнеру, в котором развернут Spark, и запустите
коман ду, корректно указав параметры доступа к MinIO и HMS:
spark-shell \
--packages org.apache.hadoop:hadoop-aws:3.3.1, \
org.apache.hudi:hudi-spark3.2-bundle_2.12:0.11.1 \
--conf spark.hadoop.fs.s3a.access.key="dbuser" \
--conf spark.hadoop.fs.s3a.secret.key="minio123" \
--conf spark.hadoop.fs.s3a.endpoint=http://minio:9000 \
--conf spark.hadoop.fs.s3a.path.style.access=true \
--conf spark.hadoop.hive.metastore.uris=\
"thrift://hive-metastore:9083" \
--conf spark.sql.warehouse.dir="s3a://metastore/" \
--conf spark.sql.catalog.spark_catalog.type=hive \
Построение модельного хранилища-озера 105
--conf spark.sql.catalog.spark_catalog.uri=thrift://hive-metastore:9083 \
--conf spark.sql.catalog.spark_catalog.warehouse=s3a://metastore/ \
--conf spark.sql.catalog.spark_catalog\
=org.apache.spark.sql.hudi.catalog.HoodieCatalog \
--conf spark.sql.extensions\
=org.apache.spark.sql.hudi.HoodieSparkSessionExtension \
--conf spark.serializer=org.apache.spark.serializer.KryoSerializer \
"${@-}"
При создании заданий для Spark shell мы используем язык программирования Scala. Изучить задание можно, открыв файл 05/data_lake-house/scripts/
hudi-customers-create.scala.
Для начала мы импортируем все необходимые библиотеки:
import org.apache.hudi.QuickstartUtils._
import scala.collection.JavaConversions._
import org.apache.spark.sql.SaveMode._
import org.apache.hudi.DataSourceReadOptions._
import org.apache.hudi.DataSourceWriteOptions._
import org.apache.hudi.config.HoodieWriteConfig._
import org.apache.spark.sql.functions.monotonicallyIncreasingId Затем загружаем таблицу customers.csv из корзины warehouse/data: val df = spark.read.options(Map("header" -> "true")
).csv("s3a://warehouse/data/customers.csv")
После этого добавляем поле uuid – это требование HMS:
val df2 = df.withColumn("uuid", monotonicallyIncreasingId) И наконец, сохраните данные в MinIO в виде таблицы Hudi:
df2.write.format("hudi").
options(getQuickstartWriteConfigs).
option(RECORDKEY_FIELD_OPT_KEY, "id").
option(PRECOMBINE_FIELD_OPT_KEY, "dob").
option(TABLE_NAME, tableName).
option(TABLE_TYPE, "COPY_ON_WRITE").
option(OPERATION, "upsert").
mode(Overwrite).
saveAsTable("hudi_customers2")
Откройте веб-интерфейс и посмотрите корзину metastore/warehouse. Вы
должны увидеть таблицу customer, но уже в формате Hudi, как это показано
на рис. 5.9.
Подключение Presto и выполнение запросов
Следующим шагом мы подключим Presto к HMS, чтобы выполнить запрос
к таблице hudi_customer. С версии 0.275 Presto поддерживает Hudi, и доста-

106 Open Data Lakehouse
точно просто сконфигурировать коннектор. Воспользуемся «песочницей»1
Presto, созданной нами до этого. Конфигурацию узла-координатора вы найдете в файле 05/data_lakehouse/presto-coordinator.yaml. Подготовьте папку
с конфигурационными файлами Presto ( 05/data_lakehouse/conf) и смонтируйте ее к контейнеру Presto. Чтобы читать из Presto таблицы Hudi, настройте
коннектор. Ему требуются следующие параметры:
connector.name=hudi
hive.metastore.uri=thrift://hive-metastore:9083
Рис. 5.9 Таблица customer в MinIO в формате Hudi
Кроме названия коннектора, необходимо указать точку доступа к MinIO
(hive.s3.endpoint) и указать, что это точка доступа к системе хранения, под-держивающей интерфейс S3 (hive.s3.path-style-access=true).
Для доступа к MinIO Presto потребуются параметры подключения – имя
пользователя и пароль. Задайте их в файле presto-coordinator.yaml: spec:
containers:
...
env:
- name: AWS_ACCESS_KEY_ID
valueFrom:
secretKeyRef:
key: minio_root_user
name: minio-secrets
- name: AWS_SECRET_ACCESS_KEY
valueFrom:
secretKeyRef:
key: minio_root_password
name: minio-secrets
1
Построение модельного хранилища-озера 107
Если мощности вашей машины не хватает для запуска полноценного
кластера Presto, запустите единственный узел-координатор. После запуска
разверните клиентское приложение, как описано в главе 4. В этом разделе
мы будем использовать утилиту командной строки, поставляемую вместе
с Presto и развернутую в том же контейнере, что и узел-координатор.
Подключитесь к контейнеру с координатором и запустите клиент командой presto-cli:
sh-4.2# presto-cli
Обратите внимание, что до сих пор мы использовали для запуска клиента
команду presto. Здесь команда другая, поскольку для запуска Presto мы применяем иной Docker-образ.
Запустив клиент, задайте базу данных (каталог), к которой ваши запросы
будут обращаться по умолчанию:
presto> use hudi.default;
USE
Выведите список доступных таблиц:
presto:default> show tables;
Table
----------------
hudi_customers
(1 row)
Query 20230202_115014_00002_xpzub, FINISHED, 1 node
Splits: 19 total, 19 done (100.00%)
0:14 [2 rows, 60B] [0 rows/s, 4B/s]
И наконец, запустите запрос, обращающийся к таблице:
presto:default> SELECT last,gender,dob,zip,city,state
FROM hudi_customers
WHERE first = 'Sharon';
last | gender | dob | zip | city | state
------------+--------+------------+-------+------------+-------
Mclaughlin | F | 1954-07-05 | 94015 | Daly City | CA
Ayala | F | 1956-09-01 | 94619 | Oakland | CA
Harper | F | 1978-06-21 | 95827 | Sacramento | CA
Clark | F | 1976-09-17 | 99160 | Orient | WA
(4 rows)
Query 20230203_062422_00005_93snn, FINISHED, 1 node
Splits: 17 total, 17 done (100.00%)
0:06 [86 rows, 427KB] [15 rows/s, 75.9KB/s]
Результат выполнения этого запроса показывает нам, что наше хранилище
работает!
108 Open Data Lakehouse
Заключение
В этой главе мы рассмотрели основные компоненты хранилища-озера, включая систему хранения, табличные форматы, SQL-движок, каталог метаданных
и механизм разграничения доступа как один из компонентов стратегического управления данными. Озеро данных позволяет использовать объектную
систему хранения, эффективную для больших объемов данных. Примерами
таких систем хранения могут служить MinIO и Amazon S3. Табличный формат
позволяет поддерживать согласованность данных, обеспечивая ACID-транзакции. Примером табличного формата является Apache Hudi. Presto, движок
SQL-запросов, предоставляет единую точку доступа к хранилищу данных. Каталог метаданных предоставляет озеру данных эффективный механизм поиска данных. В качестве каталога мы использовали Hive Metastore. Наконец, механизмы разграничения доступа позволяют определить правила, согласно
которым доступ к данным получают только авторизованные пользователи.
Механизм разграничения может быть гранулярным, позволяя определять
привилегии доступа не только на уровне каталогов и таблиц, но и на уровне
отдельных полей и строк.
Во второй части главы мы построили хранилище-озеро данных с помощью
Presto, MinIO, HMS, Spark и Hudi. Мы преобразовали простой текстовый файл
в таблицу Hudi, сохранили ее в каталог метаданных HMS и получили доступ
к таблице через Presto.
В главе 6 вы узнаете об администрировании Presto.
Глава 6
Администрирование
Presto
Под «администрированием» платформы (например, Presto) обычно понимают набор инструментов, навыков и регламентов, которые позволят поддерживать платформу в рабочем состоянии. Цикл администрирования состоит из трех шагов: конфигурирования, мониторинга и управления. На этапе
конфигурирования вы должны решить, какие параметры задать программ-ному обеспечению. Мониторингом называется наблюдение за поведением
работающей платформы. Наконец, управление – это адаптация к текущим
условиям, заключающаяся в исправлении конфигурации по результатам мониторинга.
Эта глава состоит из трех частей. Первая часть посвящена конфигурированию. Вы узнаете о конфигурационных файлах, настройках сеансов и виртуальной машины Java. Во второй части мы расскажем о средствах мониторинга Presto – консоли и REST API, а также о метриках, по которым можно делать
выводы о состоянии кластера. Из третьей части вы узнаете, как управлять
кластером Presto в разрезе ресурсов, сеансов и пространств имен.
Введение в администрирование Presto
В этой главе мы будем говорить о задачах и обязанностях администратора, связанных с настройкой и сопровождением кластера Presto.
Ваша цель как администратора базы данных заключается в обеспечении
эффективной работы платформы, или, другими словами, в том, чтобы ваш
кластер справлялся с нагрузкой, которую создают пользователи. Как мы уже
говорили, администрирование включает мониторинг производительности
системы, настройку параметров конфигурации и управление данными, хра-нящимися в системе.
На рис. 6.1 показан цикл администрирования. Он начинается с конфигурирования – первоначальной установки параметров кластера. На шаге
мониторинга мы следим, что настройки верны, а кластер работоспособен.

110 Администрирование Presto
На этапе управления мы принимаем решение о необходимых изменениях
параметров Presto и возвращаемся к конфигурированию.
Управление
Конфигурирование
Изменение параметров кластера
Задание параметров
в соответствии с текущей нагрузкой
кластера Рresto
при развертывании
Мониторинг
Наблюдение за состоянием узлов кластера
и фиксация значений метрик
Рис. 6.1 Цикл администрирования Presto
Конфигурирование
Presto поддерживает три типа настроек: конфигурационные файлы, настройки сеансов и настройки виртуальной машины Java.
Конфигурационные файлы Presto
Конфигурационные файлы Presto позволяют настроить несколько сотен различных параметров, комбинация значений которых дает возможность достичь наилучшей производительности. Как правило, основанием для задания параметров является объем доступных ресурсов сервера. При настройке
промышленного кластера мы рекомендуем запускать экземпляры Presto на
выделенных узлах, физических или виртуальных. Экземпляру Presto желательно предоставить полный контроль над ресурсами сервера; кроме него, не рекомендуется ставить на сервер ничего, кроме, может быть, агентов мониторинга. В Kubernetes мы рекомендуем запускать по одному контейнеру
на узел.
Все параметры в файле config.properties делятся на несколько категорий:
общие параметры. Это набор общих настроек, например join-distribution-type и redistribute-writes. Первый параметр позволяет вам указать алгоритм выполнения распределенных соединений. Возможные
Конфигурирование 111
значения – AUTOMATIC, PARTITIONED и BROADCAST. Второй параметр, redistribute-writes, разрешает или запрещает перераспределение данных
перед записью. Возможные значения – TRUE и FALSE;
управление памятью. Это набор параметров, управляющих объемом
памяти, доступным для выполнения запросов. Обычно названия этих
параметров начинаются с ключевого слова query. В Presto различают
два типа памяти – пользовательская память ( user memory) и системная
память ( system memory). Пользовательская память используется под
временные области для операций сортировки и агрегации, а систем-
ная память – под буферы для дисковых операций, таких как чтение
и запись . Примерами параметров, отвечающих за распределение па-
мяти, могут служить query.max-memory и query.max-total-memory-per-node;
подкачка ( spilling) . Подкачкой1 называется процесс вытеснения информации из памяти на диск. Если вы планируете запускать объемные за-
просы, для которых не хватает памяти, необходимо включить подкачку.
Естественно, подкачка замедляет выполнение запроса. Чтобы включить
подкачку, установите параметр experimental.spill-enabled в true. Клю-чевое слово experimental говорит о том, что пока поддержка подкачки
в Presto находится в экспериментальной стадии. Более подробное описание возможностей подкачки вы найдете в документации Presto2;
обмен данными. Эта группа параметров отвечает за то, как узлы кластера Presto обмениваются данными друг с другом. Обычно названия
этих параметров начинаются с ключевого слова exchange. Примерами
таких параметров могут служить exchange.max-buffer-size и exchange.
max-response-size;
задачи. Задача – это некоторый объем работ, назначенный рабочему
узлу узлом-координатором. Параметры, начинающиеся с ключевого
слова task, управляют нагрузкой рабочих узлов. Примеры таких пара-
метров: task.max-worker-threads и task.concurrency;
планировщик. Планировщик Presto разбивает план выполнения запроса
на небольшие фрагменты ( splits). Параметры планировщика позволяют
управлять распределением фрагментов между узлами. Они начинают-
ся с ключевого слова node-scheduler, а в качестве примера можно привести параметры node-scheduler.max-splits-per-node и node-scheduler.
include-coordinator;
оптимизатор. Это параметры, начинающиеся с ключевого слова optimizer и указывающие оптимизатору, какие приемы следует или не
следует применять при оптимизации реляционных операций – соеди-
нений, агрегаций и т. д. Примеры таких параметров: optimizer.optimize-metadata-queries и optimizer.push-aggregation-through-join.
Еще одна группа параметров, относящихся к оптимизатору запросов,
начинается с ключевого слова planner, например параметр planner.
query-analyzer-timeout;
1 Обычно для обозначения этого процесса в англоязычной литературе используется
термин swapping, но в Presto это называется spilling. – Прим. перев.
2 .
112 Администрирование Presto
регулярные выражения. Это набор параметров, управляющих обработкой регулярных выражений. Presto поддерживает две библиотеки –
JONI и RE2J. С помощью параметра regex-library можно выбрать, какую
библиотеку будет использовать ваш кластер. Кроме того, существуют
и другие параметры, специфические для каждой библиотеки.
Как сконфигурировать кластер
Вопрос на миллион долларов, который мы многократно слышали, звучит так:
«Как же правильно выбрать размер и конфигурацию кластера?» Обычно мы
отвечаем: «Это зависит от». Зависит от того, какие задачи будет решать кластер и какую нагрузку будут создавать эти задачи. Каждый профиль нагрузки
уникален: разное количество пользователей, разная сложность запросов, разные объемы данных. Даже запросы одинаковой сложности могут создавать
разную нагрузку: одним важнее большой объем памяти, другим – скорость
вычислений. В общем, начинать рекомендуется с кластера разумного размера.
Хорошим выбором для начала будет выбор узлов типа r5 в облаке Amazon, рассчитанных на интенсивное использование памяти, или аналогичных серверов у других облачных провайдеров. Здесь мы сошлемся на статью в блоге
Amazon «Пять параметров, на основе которых стоит принимать решение
о сайзинге кластера Amazon ElastiCache на базе Redis» («Five workload cha-racteristics to consider when right sizing Amazon ElastiCache Redis clusters»)1, а в табл. 6.1 приведем предлагаемые типы узлов AWS и количество узлов
в зависимости от значений этих параметров.
Таблица 6.1. Рекомендуемые типы узлов AWS и их количество в зависимости
от предполагаемой нагрузки
Нагрузка Транзакций в секунду Объем данных Тип узла
Количество узлов
Низкая
< 2000
< 10 ГБ
r5.8xlarge 5–10
Средняя
от 2000 до 20000
от 2 ГБ до 100 ГБ r5.4xlarge 20–40
Высокая
> 20000
> 100ГБ
r5.16xlarge 50+
Запустите типовую нагрузку и измерьте производительность кластера
с разными настройками. Затем вы можете как увеличивать, так и уменьшать мощность кластера. Универсального решения не существует. Более того, ваши рабочие нагрузки неизбежно будут меняться, и вам будет необходимо
либо создать новый кластер для новых задач, либо расширить существующий
кластер, чтобы он эффективно справлялся и со старой, и с новой нагрузкой.
Настройки сеансов
Так же, как и все современные платформы, Presto позволяет настраивать поведение систем хранения, в роли которых могут выступать и СУБД, используя
1 .
Конфигурирование 113
настройки сеанса. Но разумеется, настройки сеанса регулируют только часть
параметров производительности, остальные параметры настраиваются через файлы config.properties и node.properties.
Как правило, по имени параметра легко определить, к чему он относится: в названиях собственных настроек Presto части слов разделены минусом (-), а в названиях свойств сеанса – символом подчеркивания (_). Так, например, join-distribution-type – это собственная настройка, а join_distribution_type –
соответствующая настройка сеанса.
Чтобы увидеть все настройки сеанса, запустите клиент Presto и введите
команду
presto> SHOW SESSION;
В ответ Presto выдаст длинный список настроек сеанса – примерно как
в листинге ниже:
Name | Value
-------------------------------------------------+------------------------
aggregation_if_to_filter_rewrite_strategy | DISABLED
aggregation_operator_unspill_memory_limit | 4MB
aggregation_partitioning_merging_strategy | LEGACY
aggregation_spill_enabled | true
allow_window_order_by_literals | true
check_access_control_on_utilized_columns_only | false
check_access_control_with_subfields | false
colocated_join | true
...
Чтобы изменить настройки сеанса, используйте команду SET SESSION:
SET SESSION <property> = <value>;
Например, следующая команда устанавливает значение параметра join_
distribution_type в PARTITIONED:
SET SESSION join_distribution_type="PARTITIONED";
Чтобы вернуть значение параметра к значению по умолчанию, используйте команду SET без значения, а вернуть к значениям по умолчанию все
параметры можно командой RESET:
SET SESSION <property>;
RESET SESSION;
Работа с сеансами
Чтобы посмотреть, как работают настройки сеансов, проведем эксперимент: 1) подключитесь к клиенту Presto, развернутому вместе с узлом-координатором, а затем запустите запрос:
SELECT * FROM tpch.tiny.customer LIMIT 5;
114 Администрирование Presto
2) кроме результатов запроса, в выводе вы увидите служебную информацию, в том числе скорость извлечения данных (в нашем примере –
166 строк в секунду):
Query 20221129_085214_00002_i3xsn, FINISHED, 1 node
Splits: 21 total, 21 done (100.00%)
0:09 [1.5K rows, 0B] [166 rows/s, 0B/s]
3) попытаемся ускорить выполнение запроса, включив одну из возможностей оптимизатора:
SET SESSION join_reordering_strategy='AUTOMATIC';
4) повторно запустим запрос:
SELECT * FROM tpch.tiny.customer LIMIT 5;
5) скорость извлечения данных должна увеличиться (в нашем примере –
до 296 строк в секунду), и второй раз запрос выполняется быстрее:
Query 20230406_212505_00007_3htmf, FINISHED, 1 node
Splits: 21 total, 21 done (100.00%)
0:05 [1.5K rows, 0B] [296 rows/s, 0B/s]
JVM
Официально Presto поддерживает только Java 8. Однако на практике PrestoDB
прекрасно работает и с использованием JRE 11. Эта версия Java содержит
множество оптимизаций и позволяет выполнять более тонкую настройку
памяти благодаря более совершенному механизму сборки мусора.
Параметры для виртуальной машины Java, как мы уже упоминали в гла-
ве 2, задаются в файле jvm.config. Главным образом параметры относятся
к настройкам памяти и сборщика мусора.
Память
Обычно объем памяти, доступной виртуальной машине Java, устанавливается в 70 % от объема памяти на сервере (30 % остаются для внутренних задач
операционной системы). Однако серверы становятся все мощнее, а потребление памяти процессами операционной системы ограничено, поэтому можно выделить для виртуальной машины и больше памяти. Полезно бывает
выделить память заранее (memory pre-allocation). Такой подход имеет несколько важных преимуществ:
память по возможности выделяется одним большим куском, а не множеством мелких фрагментов. За счет этого виртуальная машина Java
может управлять памятью гораздо эффективнее, в частности эффек-
тивнее работает сборка мусора;
Конфигурирование 115
в процессе работы не происходит выделения памяти, а следовательно, выполнение запросов не откладывается на время, пока будут выделены
новые области, а часть данных из старых областей не будет скопиро-
вана.
Установите параметрам -Xms (минимально доступный объем памяти для
виртуальной машины Java) и –Xmx (максимально доступный объем) одно
и то же значение: такая настройка выделит всю необходимую память сразу
же при старте виртуальной машины и позволит избежать изменения объема
в процессе работы. Также крайне рекомендуется поддерживать на всех узлах
кластера одинаковые настройки (как, впрочем, и для любой распределенной
системы). Разные настройки узлов могут привести к нежелательным спец-эффектам, например скорость выполнения одних и тех же запросов будет
отличаться в зависимости от того, на какие узлы их отправил планировщик.
Ошибки переполнения памяти
Чтобы корректно обрабатывать ошибки переполнения памяти, установите
следующие параметры:
-XX:+HeapDumpOnOutOfMemoryError – в случае ошибки сделать дамп памяти
в файл;
-XX:+ExitOnOutOfMemoryError – в случае ошибки памяти выполнить команду exit;
-XX:+UseGCOverheadLimit – ограничить время работы сборщика мусора
перед выбросом исключения OutOfMemory.
Сборка мусора
Чтобы наблюдать за состоянием экземпляра Presto как Java-приложения, включите журналирование процесса сборки мусора, как это показано в листинге ниже:
-Xloggc:/opt/presto/log/gc-%t.log
-XX:+PrintGCDetails
-XX:+PrintGCDateStamps
-XX:+PrintGCApplicationConcurrentTime
-XX:+PrintGCApplicationStoppedTime
-XX:+PrintGCCause
-XX:+PrintGCTimeStamps
-XX:+PrintReferenceGC
-XX:+PrintClassHistogramAfterFullGC
-XX:+PrintClassHistogramBeforeFullGC
Выполнив рекомендованные настройки, перезапустите узлы Presto. Для
удобства наблюдения за состоянием памяти и сборкой мусора рекомендуем
использование специальных инструментов, например GCEasy1:
1

116 Администрирование Presto
1) скачайте файл журнала. Для этого запустите терминал и выполните
следующую команду, чтобы скопировать файл из внутренней файло-
вой системы запущенного контейнера в локальную папку:
docker cp <container_id>:/opt/presto/log/gc-<date>.log .
2) загрузите полученный файл в GCeasy, и GCeasy покажет отчет, включа-ющий различную статистику и диаграммы. На графике, изображенном
на рис. 6.2, GCeasy показывает размер памяти виртуальной машины
Java. В отчете вы найдете и другие графики.
Рис. 6.2 График объема памяти виртуальной машины Java
Мониторинг
Мониторинг кластера Presto состоит в наблюдении за состоянием узлов
клас тера – их работоспособностью, производительностью и использованием ресурсов. Мониторинг помогает выявить потенциальные проблемы или
неполадки в системе и предпринять соответствующие действия для их устранения.
Для мониторинга Presto вы можете использовать консоль, а также любые
средства, работающие с интерфейсами REST и JMX.
Консоль
Консоль Presto – это веб-приложение, предоставляющее подробную информацию о текущем состоянии кластера. Подключиться браузером к этому ин-терфейсу можно через узел-координатор. В зависимости от настроек используется протокол HTTP или HTTPS. По умолчанию порт для HTTP – 8080, но
вы можете его изменить, задав в файле config.properties значения параметра
http-server.http.port. Вы можете также включить аутентификацию пользователей консоли. Как это сделать, мы расскажем в главе 7.
На рис. 6.3 показана заглавная страница консоли Presto. На ней отображаются общие сведения о кластере, такие как версия, название кластера
и время безотказной работы (т. е. время с момента последнего перезапуска

Мониторинг 117
координатора). Консоль также показывает сводную информацию о запросах – запланированных, заблокированных, завершенных, неудачных и т. д.
Щелкните по запросу, чтобы увидеть его подробное описание.
Рис. 6.3 Заглавная страница консоли Presto
Подробное описание запроса включает:
Session – все параметры, значения которых отличаются от значений
по умолчанию, а также все настройки сеанса, которые были заданы
в момент запуска запроса;
Execution – временные метки запуска и окончания запроса, время, про-шедшее с момента начала выполнения, и т. д.;
Resource utilization summary and timeline – показывает объем ресурсов, использованных при выполнении запроса: процессорное время, время
ожидания блокировок, максимальное использование памяти и т. д.;
RuntimeStats – дополнительные метрики для каждой стадии выполнения запроса. Стадия – это шаг плана запроса, составленного узлом-коор динатором;
Query – детальная информация для каждого шага запроса – объем ресурсов и время выполнения.
Использование консоли для мониторинга
Покажем мониторинг кластера Presto с помощью консоли на примере:
1) запустите кластер Presto;
2) подключитесь к контейнеру, где выполняется узел-координатор, при
помощи терминала и запустите клиент Presto командой presto;
3) запустите запрос:
SELECT * FROM tpch.tiny.customer LIMIT 5;

118 Администрирование Presto
4) откройте в браузере страницу по адресу http://localhost:8080; 5) на закладке QUERY DETAILS нажмите Finished. Вы увидите подробную
информацию о вашем запросе, как показано на рис. 6.4;
6) чтобы увидеть все подробности, нажмите на ссылку с идентификатором запроса (в нашем примере – 20221126_223520_00008_i3xsn).
Рис. 6.4 Информация о запросе в консоли Presto
Отладка при помощи консоли
Возьмем запрос с синтаксической ошибкой, например такой: SELECT * FROM
tpch.tiny.customers LIMIT 5;. В схеме tiny нет таблицы customers. Запустите
этот запрос в клиенте Presto – и получите ошибку.
Теперь в верхнем меню консоли на странице query details нажмите Failed, а потом – User Error. Затем выберите идентификатор, соответствующий
вашему запросу. В поле Error Information вы увидите детальное описание
ошибки, включая тип и код ошибки, а также трассировку стека.
Консоль Presto можно использовать и для отладки более сложных запросов.
Просмотр интерактивных планов в консоли
Запустите в клиенте все тот же запрос:
SELECT * FROM tpch.tiny.customer LIMIT 5;
В верхнем меню консоли на странице query details нажмите Finished, а затем выберите свой запрос. Чтобы запустить интерактивный просмотр плана
(см. рис. 6.5), нажмите Live Plan. Подробнее о планах запросов мы поговорим
в главе 8.
REST API
Для мониторинга Presto можно также использовать REST API. Ниже вы найдете краткий список доступных функций:
/v1/node
/v1/node/failed
/v1/execute

Мониторинг 119
/v1/statement
/v1/query
/v1/query/<query_id>
/v1/thread
/ui/thread
/v1/task
/v1/task/<task_id>
/v1/jmx/mbean/<object_name>
Рис. 6.5 Пример интерактивного плана запроса
Вот описание некоторых методов:
POST /v1/statement запускает запрос, текст которого передается в теле
запроса, и возвращает JSON с результатами выполнения. Если резуль-
тат возвращен не целиком, то в JSON-документе будет поле nextUri;
запрос GET по адресу nextUri вернет следующую часть результата;
запрос DELETE по адресу nextUri прекратит выполнение запроса и осво-бодит связанные с ним ресурсы кластера.
В главе 4 мы уже видели, как можно обращаться к кластеру Presto через
REST API. Например, при помощи функции /query можно получить инфор-
120 Администрирование Presto
мацию о последних запущенных запросах. Чтобы получить информацию
о конкретном запросе, укажите его идентификатор:
http://presto-coordinator:8080/v1/query/20211109_165830_00006_zadq6
В этом примере 20211109_165830_00006_zadq6 – это идентификатор запроса.
Метрики мониторинга
Presto предоставляет доступ к метрикам мониторинга через интерфейс JMX
MBeans. Получить значения метрик можно тремя способами: через JMX-коннектор, через REST API и через JMX-экспортер.
JMX-коннектор
В дистрибутиве Presto есть коннектор для JMX (Java Management Extensions), который позволяет создать каталог и обращаться к метрикам, выставляемым
через JMX, при помощи обычных SQL-запросов. Доступ через JMX – хороший
способ для отладки в целом и для просмотра метрик только что запущенного
запроса в частности.
Чтобы сконфигурировать каталог для JMX, добавьте в файл presto-config-map.yaml следующие строки:
jmx.properties: |
connector.name=jmx
Добавьте точку для монтирования тома и том для коннектора JMX в файлы
presto-coordinator.yaml и presto-workers.yaml, как описано в главе 2, а затем
перезапустите кластер.
Для примера давайте получим объем свободной памяти в стандартном
пуле:
SELECT
freebytes, node
FROM
jmx. current." com.facebook.presto.memory:*type=memorypool*";
REST API
Доступ к JMX-метрикам можно получить через метод jmx:
http://<coordinator>:<port>/v1/jmx/
В отличие от функции query, эта функция не разбивает результат на страницы, возвращая значения сразу всех метрик для всех запросов. Чтобы не
получить за один раз огромный объем данных, запрашивайте метрики по
конкретному объекту.
Мониторинг 121
Подробно о том, как использовать JMX-коннектор, можно прочесть в документации Presto1.
JMX-экспортеры
Технология JMX – это стандарт для мониторинга Java-приложений и управления этими приложениями. При помощи программ-экспортеров вы може-
те передавать метрики, отдаваемые приложениями через JMX, во внешние
системы мониторинга, например Prometheus2 или Grafana3.
Что касается конкретно Presto, вы также можете подключить его к внешним системам управления и мониторинга при помощи экспортеров.
Чтобы подключить к Presto Prometheus, загрузите с веб-сайта Prometheus4
экспортер для JMX, представляющий собой JAR-файл. Затем создайте файл
prometheus.yaml, укажите в нем все метрики, которые желаете экспортировать, и поместите файл в папку с конфигурационными файлами узла-координатора. Минимальный конфигурационный файл состоит из двух строк: rules:
- pattern: ".*"
Синтаксис описания правил вы найдете в документации Prometheus5. Чтобы Prometheus мог подключиться к Presto, добавьте в конфигурационный
файл jvm.config на узле-координаторе строку:
javaagent:<path/to/jmx_prometheus_javaagent.jar=8081:<path/to/prometheus.yaml> Prometheus будет ожидать соединений на порт 8081, но если вы предпочитаете другой порт, можете изменить строку. Наконец, запустите узел-координатор, зайдите в терминал в контейнере, где он запущен, и введите команду
curl 0.0.0.0:8081
Вы увидите длинную простыню текста, содержимое которой будет примерно таким:
# HELP com_facebook_presto_execution_RemoteTaskFactory_Executor_TaskCount
[...]
# TYPE com_facebook_presto_execution_RemoteTaskFactory_Executor_TaskCount untyped com_facebook_presto_execution_RemoteTaskFactory_Executor_TaskCount 0.0
Полноценный работающий пример можно взять в папке 06/jmx-exporter нашего репозитория. Сначала вам надо будет собрать новый Docker-образ
1
2 .
3
4 .
5 .
122 Администрирование Presto
в папке presto-docker, а затем запустить кластер Presto, используя файлы из
папки kubernetes.
Управление
Управление кластером Presto заключается в выполнении некоторого набора действий, обеспечивающего эффективную работу системы. Инструмен-ты управления Presto включают ресурсные группы, верификатор (средство
управления версиями и регрессионного тестирования), инструменты настройки сеансов и пространства имен.
Ресурсные группы
Ресурсные группы используются для распределения ресурсов в многопользовательской среде и позволяют устанавливать для каждой группы квоты
(ограничения). Когда координатор распределяет задачи, из которых состоит
выполнение запроса, он учитывает эти ограничения. Механизм ресурсных
групп основан на изменении приоритета задачи в зависимости от объема
ресурсов, выделенных группе владельца задачи.
Ресурсные группы в Presto образуют древовидную иерархическую структуру. Ресурсные ограничения назначаются только подгруппам самого низкого
уровня, находящимся в листах этого дерева.
Настройка ресурсных групп
Чтобы начать использовать ресурсные группы, добавьте файл resource-groups.
properties в папку etc узла-координатора. Этот файл содержит указатель на
другой файл в формате JSON, в котором описаны ресурсные группы и их
ограничения.
Чтобы начать пользоваться ресурсными группами в вашем локальном кластере Presto, добавьте в файл presto-config-map.yaml следующие строки: resource-groups.properties: |
resource-groups.configuration-manager=file
resource-groups.config-file=etc/resource_groups.json
resource_groups.json: |
<put_here_the_resource_groups_and_the_selector_rules>
Затем добавьте точки монтирования и тома для обоих файлов в файл presto-coordinator.yaml, а потом перезапустите кластер. Добавление томов и точек
монтирования мы рассматривали в главе 2.
Управление 123
Управление ресурсами
Используя ресурсные группы в Presto, вы можете управлять самыми разными ресурсами. Важнейшими, конечно, являются процессор и оперативная
память, а полный список ресурсов можно найти в документации Presto1.
Процессор
Presto управляет использованием процессора в терминах затраченного
процессорного времени. Как только затраченное время превышает порог
(softCpuLimit), Presto начинает уменьшать количество запросов, пока их
выполнение совсем не прекратится. Выполнение запросов прекращается, когда затраченное процессорное время достигнет значения, заданного
в hardCpuLimit, которое всегда больше, чем значение softCpuLimit.
Параметр cpuQuotaPeriod определяет интервал, к которому относится квота
на использование процессора. Если в течение этого периода будет превы-шен hardCpuLimit, то выполнение запросов пользователей из этой ресурсной группы прекратится до окончания периода. В нашем примере весь
кластер как будто состоит из единственного процессорного ядра. Если же
в кластере, например, 20 узлов, в каждом из которых по 16 ядер, то в каждом часе у него есть 320 часов процессорного времени.
Расчет квот требует внимательного отношения. Параметры hardCpuLimit и softCpuLimit задаются как время, которое запрос занимает на одном
процессоре, а cpuQuotaPeriod – это время всего кластера. По мере того как
кластер растет, имеет смысл увеличивать квоты, поскольку доступное процессорное время растет пропорционально количеству ядер.
Память
Общий объем памяти, используемый запросами пользователей ресурсной
группы, не может превышать softMemoryLimit. Как только это произойдет, Presto блокирует все запросы от пользователей этой группы, пока объем
используемой памяти не упадет ниже softMemoryLimit.
Пример
Пусть у нас есть две группы пользователей – online и offline.
Чтобы создать в JSON-файле список групп, используйте ключ rootGroups:
{
"rootGroups": [
{
"name": "offline"
},
{
1
124 Администрирование Presto
"name": "online"
}
]
}
Группа offline может использовать не более 30 % памяти, ее очередь не
должна быть длиннее, чем 1000 запросов, а одновременно может выполняться не более 50 запросов:
{
"name": "offline",
"softMemoryLimit": "30%",
"maxQueued": 1000,
"hardConcurrencyLimit": 50
}
Группа online может использовать до 70 % памяти и запускать до 200 запросов одновременно, но длина очереди также не может превышать 1000 запросов:
{
"name": "online",
"softMemoryLimit": "70%",
"maxQueued": 1000,
"hardConcurrencyLimit": 200
}
Теперь, когда мы создали группы, надо определить селекторы для них:
{
"rootGroups": [ ... ],
"selectors": [
{
"name": "offline",
"source": "spark-etl" ;
"queryType" : "SELECT"
},
{
"name": "online",
"user": "web application"
}
]
}
Группа offline – это запросы, приходящие из источника spark-etl, причем
только команды SELECT. Группа online – это все запросы, выполняемые от
имени пользователя web application.
Наконец, надо установить периодичность применения квоты на процес-
сорное время:
{
"rootGroups": [ ... ],

Управление 125
"selectors": [ ... ],
"cpuQuotaPeriod": "2h"
}
Верификатор
Проект Presto активно развивается, и в результате почти каждый месяц выходит новая версия, а исправления порой выходят дважды в неделю. Прежде
чем установить новую версию, хорошо бы убедиться, что результаты запросов не изменились, а производительность действительно выросла. Если вы
не используете Presto как сервис в облаке, то вам стоит озаботиться регрес-сионным тестированием обновлений своего кластера.
Верификатор (verifier) управляет версиями Presto и проверяет, что новая
версия на старых данных возвращает те же результаты, что и предыдущая.
Есть и специальные инструменты, позволяющие убедиться, что производительность по крайней мере не снизилась. Примером такого инструмента
может служить Benchto1.
На рис. 6.6 показана система, использующая верификатор:
MySQL
Верификатор (verifier)
Промышленный
Тестовый
кластер
кластер
Рис. 6.6 Архитектура системы с верификатором
Для работы с верификатором вы должны поддерживать два кластера:
промышленный кластер ( control cluster) – кластер, обрабатывающий текущую нагрузку;
тестовый кластер – кластер, на котором установлена новая версия
Presto.
Верификатор сравнивает два кластера, запуская на них набор запросов, который вы должны сохранить в базе-репозитории под управлением MySQL.
Настройка системы
Создайте два кластера Presto с каталогами MySQL и TPC-H, руководствуясь
инструкциями из главы 2. Если мощности вашей машины не хватает, чтобы
1 .
126 Администрирование Presto
запустить оба кластера, ограничьте мощность каждого кластера единственным узлом-координатором или разверните кластеры на разных серверах: 1) создайте Docker-образ со старой версией Presto и назовите его
presto:<old_version>;
2) измените файлы presto-coordinator.yaml и presto-workers.yaml, чтобы они
ссылались на этот образ;
3) разверните кластер в пространстве имен presto-control;
4) повторите шаги 1–3 для тестового кластера. Обратите внимание, что
образ надо собирать со свежей версией Presto. Назовите этот образ
presto:<new_version>. В файле presto-coordinator.yaml измените порты, на которых координатор будет принимать подключения, например на
8081 и 8088. Разверните кластер с новой версией Presto в пространстве
имен presto-test;
5) скачайте приложение-верификатор в виде JAR-файла и переименуйте
его в presto-verifier.jar. Ссылку на последнюю версию приложения найдете в документации Presto1.
Настройка базы данных MySQL
Верификатор использует репозиторий, который хранит в базе данных под
управлением MySQL:
1) настройте экземпляр MySQL:
docker run --name testmysql -p 3306:3306\
-e MYSQL_ROOT_PASSWORD=root -d mysql:5.7
2) подключитесь к работающему контейнеру, запустите клиент БД командой mysql и создайте базу данных для верификатора:
CREATE DATABASE verify;
USE verify;
3) создайте таблицу, в которой содержится информация о кластерах
и о запросах, которые используются для их сравнения:
CREATE TABLE verify.verifier_queries (
id int(11) unsigned NOT NULL PRIMARY KEY AUTO_INCREMENT, suite varchar(256) NOT NULL,
name varchar(256) DEFAULT NULL,
control_catalog varchar(256) NOT NULL,
control_schema varchar(256) NOT NULL,
control_query text NOT NULL,
control_username varchar(256) DEFAULT NULL,
control_password varchar(256) DEFAULT NULL,
control_session_properties text DEFAULT NULL,
test_catalog varchar(256) NOT NULL,
test_schema varchar(256) NOT NULL,
test_query text NOT NULL,
1
Управление 127
test_username varchar(256) DEFAULT NULL,
test_password varchar(256) DEFAULT NULL,
test_session_properties text DEFAULT NULL
)
Настройка верификатора
Чтобы запустить верификатор, создайте файл config.properties и запишите
в него следующие настройки:
1) коннектор к MySQL:
source-query.suites=suite
source-query.database=\
jdbc:mysql://localhost:3306/verify?user=root&password=root
2) адрес (хост и порт) для промышленного кластера:
control.hosts=localhost
control.http-port=8080
control.jdbc-port=8080
3) адрес (хост и порт) для тестового кластера:
test.hosts=localhost
test.http-port=8081
test.jdbc-port=8081
4) настройте вывод журнала. Если вам нужна более детальная диагности-ка, установите параметр event-clients в json.
test-id=1
event-clients=human-readable
human-readable.log-file=event-log.log
Запуск теста
Типичный сценарий тестирования выглядит так: верификатор выбирает тек-сты запросов из таблицы MySQL, выполняет эти запросы на двух кластерах
Presto и сравнивает полученные результаты. В зависимости от того, совпали
ли результаты, запрос помечается как успешный или как ошибочный.
Запросы должны гарантированно выполняться на одном и том же наборе
данных в одном и том же окружении, поэтому вместо того, чтобы выполнять запросы непосредственно в каталоге TPC-H, вам следует скопировать
таблицу customer в каталог MySQL. Подключитесь при помощи клиента Presto к одному из кластеров и выполните команду
CREATE DATABASE testdb;
CREATE TABLE mysql.testdb.customer
AS SELECT
*
FROM tpch.tiny.customer
LIMIT 5;
128 Администрирование Presto
Затем подключитесь к базе данных MySQL, работающей в Docker-кон тейнере testmysql. Это совершенно отдельная база данных, в которой хранится
репозиторий верификатора; она не имеет никакого отношения к каталогу
MySQL, с которым работает кластер Presto.
1. Вставьте в таблицу с тестовыми запросами текст запроса, который будет использован для сравнения:
INSERT INTO verify.verifier_queries (
suite, name, control_catalog, control_schema, control_query,
control_username, test_catalog, test_schema, test_query, test_username
) VALUE (
"suite", "presto_test", "mysql", "testdb",
"select * from mysql.testdb.customer", "mysql-user",
"mysql", "testdb",
"select * from mysql.testdb.customer", "mysql-user"
);
2. Запустите верификатор:
java -Xmx1G -jar presto-verifier.jar verify config.properties
3. Когда верификатор завершит работу, результат можно посмотреть
в файле event-log.log:
presto_test: SUCCEEDED
В документации Presto1 можно найти более подробные инструкции по использованию верификатора.
Управление настройками сеансов
Настройки сеансов используются, чтобы управлять потреблением ресурсов, включать и отключать дополнительные возможности и другими способами
влиять на выполнение запросов. Чтобы изменять настройки сеансов, добавьте в папку etc узла-координатора файл session-property-config.properties и впишите в него следующие строки:
session-property-config.configuration-manager=file
session-property-manager.config-file=etc/session-property-config.json Так же, как и менеджер ресурсных групп, менеджер настроек сеанса читает
конфигурацию из внешнего JSON-файла. Этот файл содержит набор правил, каждое из которых содержит список условий, которым должен удовлетворять
запрос, и список настроек сеанса, которые применяются к такому запросу.
Узнать, как выглядят правила, и найти примеры правил и настроек сеанса
можно в документации Presto2.
1 .
2
Управление 129
Конфигурирование менеджера настроек сеанса
Добавьте в файл presto-config-map.yaml следующие строки:
session-property-config.properties: |
session-property-config.configuration-manager=file
session-property-manager.config-file=etc/session-property-config.json session-property-config.json: |
<put_here_the_match_rules>
Затем создайте в файле presto-coordinator.yaml том и точку монтирования
для обоих файлов, указанных в конфигурации, следуя инструкции из главы 2, а после этого перезапустите кластер.
Пространства имен функций
Presto позволяет писать код для часто используемых действий и сохранять их
в виде функций; эта возможность особенно полезна для больших организа-ций со множеством пользователей. Для управления хранимыми функциями, включая разграничение доступа к ним, используется менеджер пространств
имен.
Применение различных пространств имен позволяет определять функ-
ции с одинаковыми именами, но с разным поведением. Конкретная реализация функции будет выбрана в зависимости от того, какой пользователь
ее запускает. Например, для одной команды логика преобразования даты
и времени может учитывать переход на летнее время, а для другой – нет.
Синтаксически пространства имен выглядят так же, как каталоги, но их
семантика различна.
Presto привязывает любую функцию (кроме встроенных функций) к про-
странству имен и регистрирует ее в этом пространстве, сохраняя метаданные, описывающие эту функцию. Чтобы вызвать функцию, нужно указать ее
пространство, функции и параметры. Примеры вызова функций приведены
в этом разделе.
Пространства имен функций доступны только для чтения, поэтому вы не
можете создать новую функцию или удалить пространство имен во время
выполнения.
Пространства имен функций и функции SPI Функции, о которых мы будем говорить в этом разделе, отличаются от функций SPI, о которых мы говорили в главе 3. Это высокоуровневые функции, позволяющие про-граммировать логику обработки данных, в то время как SPI – это низкоуровневые
функции, которые транслируют запросы Presto в запросы к СУБД, обеспечиваю-щей работу каталога. Предположим, что вы определили функцию тангенса: tan(x) =
sin(x)/cos(x). Эту функцию можно использовать только с теми каталогами, которые
поддерживают функции sin(x) и cos(x).
130 Администрирование Presto
Настройка системы
Presto хранит пространства имен функций в каталоге MySQL. Мы будем использовать каталог, который был сконфигурирован в главе 2. Код, который
нам понадобится, можно найти в папке 06/function-namespace нашего репозитория.
1. Presto хранит конфигурационные файлы с параметрами пространств
имен функций в папке etc/function-namespace. Чтобы включить возможность создания пространств имен функций, добавьте следующие строки
в файл presto-secrets.yaml. Имя пользователя и пароль должны быть те
же самые, которые вы использовали при настройке каталога MySQL.
funcatalog.properties: |
function-namespace-manager.name=mysql
database-url=\
jdbc:mysql://mysql:3306/functionsdb?user=root&password=dbuser
function-namespaces-table-name=example_function_namespaces
functions-table-name=example_sql_functions
2. Смонтируйте файл funcatalog.properties в файлах presto-coordinator.yaml и presto-workers.yaml:
containers:
- name: presto-coordinator
[ ... ]
volumeMounts:
- name: funcatalog
mountPath: "/opt/presto/etc/function-namespace/funcatalog.properties"
subPath: funcatalog.properties
[ ... ]
volumes:
- name: funcatalog
secret:
secretName: presto-mysql-secrets
3. Убедитесь, что файл mysql.properties содержит корректные настройки, позволяющие подключить каталог MySQL.
4. Перезапустите кластер.
Создание функции
Мы создадим простую функцию tan(), которая получает один параметр типа
double и вычисляет тангенс числа. Эту функцию мы поместим в пространство
math.
Запустите клиент Presto и создайте в каталоге пространств имен новое
пространство под названием math:
INSERT INTO
mysql.functionsdb.example_function_namespaces
(catalog_name, schema_name)
VALUES ('funcatalog', 'math');
Заключение 131
Этим запросом вы создали каталог funcatalog, а в нем – схему math. Данный
процесс похож на создание обычных каталогов и схем, которые содержат
обычные таблицы.
Определите функцию tan(x):
CREATE OR REPLACE FUNCTION
funcatalog.math.tan(x double)
RETURNS double DETERMINISTIC
RETURNS NULL ON NULL INPUT
RETURN sin(x)/cos(x);
Запуск теста
Запустите запрос:
SELECT funcatalog.math.tan(totalprice)
FROM tpch.tiny.orders
LIMIT 1;
Результат выполнения должен быть следующим:
_col0
---------------------
-1.2274920493551589
(1 row)
Query 20221229_162154_00003_u6833, FINISHED, 1 node
Splits: 37 total, 37 done (100.00%)
0:35 [15K rows, 0B] [427 rows/s, 0B/s]
Заключение
Из этой главы вы узнали об администрировании Presto, состоящем из трех
последовательных шагов: конфигурирование, мониторинг, управление.
Конфигурирование состоит в задании параметров кластера в процессе его
развертывания. Presto предоставляет три инструмента конфигурирования: конфигурационные файлы, настройки сеансов и настройки виртуальной машины Java.
Мониторинг позволяет выявлять потенциальные проблемы и принимать
меры к их недопущению и устранению. Для получения метрик мониторинга
Presto вы можете использовать консоль, REST API или JMX.
Управление позволяет наиболее эффективно применять ваш кластер. Мы
рассмотрели такие задачи управления, как управление ресурсами кластера, обновление программного обеспечения, управление сеансами и создание
хранимых функций.
Глава 7
Безопасность Presto
Настройка безопасности в Presto заключается в построении безопасного
обмена данными, а также аутентификации пользователей и авторизации
всех субъектов, включая и пользователей. Безопасный обмен данными подразуме вает, что в процессе передачи неавторизованный доступ к данным
невозможен. Механизмы аутентификации позволяют системе убедиться
в том, что пользователь действительно тот, за кого себя выдает, а авторизация заключается в наделении пользователей полномочиями в соответствии
с ролевой моделью хранилища данных.
Эта глава состоит из четырех частей. В первой части мы подробно опишем
задачу, которую будем решать. Затем вы узнаете, как обезопасить обмен
данными, используя шифрование, хранилище секретов и протокол HTTP/
TLS. В третьей части мы рассмотрим различные механизмы аутентификации – файловую аутентификацию, а также LDAP и Kerberos. Наконец, в четвертой части мы настроим авторизацию при помощи системного механизма
управления доступом и Apache Ranger.
Введение в безопасность Presto
В предыдущих главах мы считали, что все узлы нашего кластера доверяют друг
другу, а угрозы извне не существует. Наше предположение вполне оправдано, поскольку все узлы работают на нашей локальной машине и находятся под
полным нашим контролем, но в реальном мире это, конечно же, не так. Кластер может подвергаться различным атакам, целью которых может являться
несанкционированный доступ к данным, кража либо повреждение данных или
даже отказ в обслуживании, вызванный сбоями в работе кластера. В худшем
случае злоумышленники могут полностью вывести кластер из строя, что по-влечет за собой убытки от простоя или потерю данных. Для защиты кластера от
перечисленных угроз и существуют механизмы безопасного обмена данными.
Рассмотрим систему, представленную на рис. 7.1. Пусть у нас есть хранилище данных, состоящее из кластера Presto и двух каталогов – TPC-H и MySQL.
Кластер Presto, в свою очередь, состоит из узла-координатора и единственного рабочего узла. Есть два клиента, мы назовем их A и B. Наша задача –

Безопасность коммуникаций 133
предотвратить доступ к кластеру неавторизованного клиента и рабочего
узла, не входящего в кластер. Кроме того, мы должны внедрить политику
авторизации, которая позволит клиенту A получать доступ только к каталогу
TPC-H, а клиенту B – только к каталогу MySQL.
Недоверенный
Недоверенный
клиент Presto
рабочий узел Presto
Клиент Presto A
TCPH
Узелкоординатор
Рабочий узел
Клиент Presto B
MySQL
Доверенное хранилище данных
Рис. 7.1 Доверенное хранилище данных
Безопасность коммуникаций
Безопасность обмена данными подразумевает сохранение конфиденциальности данных в хранилище. Безопасность обмена включает в себя шифрование данных, а также аутентификацию пользователей перед предоставлением
им доступа к данным.
Шифрование
Все алгоритмы шифрования делятся на два класса: симметричные и асимметричные. Симметричные алгоритмы используют для шифрования и расшиф-
ровки один и тот же ключ. Расшифровать и зашифровать данные может только
тот, кто знает этот ключ. Асимметричные алгоритмы используют два ключа: один – для шифрования (публичный), а другой – для расшифровки (приватный). Отправитель шифрует данные, используя публичный ключ получателя, а получатель расшифровывает их, используя приватный ключ. В Presto, как
и в других базах данных, используются симметричные алгоритмы для шифрования трафика (wire encryption) и данных на диске (encryption at rest1): 1 В данном случае rest – обычное слово, обозначающее «покой», а не аббревиатура
REST, representative state transfer. – Прим. перев.
134 Безопасность Presto
Шифрование трафика
Все данные, передаваемые по сети, шифруются, чтобы злоумышленник,
перехвативший данные, не мог их прочитать. Индустриальным стандар-
том шифрования трафика является использование протокола TLS (transport layer security) и HTTPS (HTTP поверх канала, защищенного TLS). Presto поддерживает как шифрование трафика между узлами, так и шифрование
трафика между клиентом и сервером (координатором).
Шифрование на диске
Данные, которые хранятся на диске, зашифрованы, и получить доступ
к ним может только тот, у кого есть ключ. Presto не контролирует шифрование данных в каталогах, однако если они зашифрованы, то у Presto должна
быть возможность читать эти данные. Требование не зависит от того, что
именно представляет собой каталог – реляционную БД, аналитическую
систему или объектное хранилище.
Описание шифрования на диске остается за рамками этой книги, поскольку его реализация зависит от конкретного хранилища, которое является для
Presto лишь источником. В оставшейся части раздела мы сосредоточимся
на шифровании трафика. Весь код, приведенный в этом разделе, доступен
в папке 07/presto-https нашего репозитория.
Хранилище ключей
Чтобы обеспечить шифрование трафика, вам необходимы сертификаты. Сертификат удостоверяет предъявителя – пользователя, сервер и т. п. Сертификат
можно получить у вашего провайдера, если он предоставляет такую услугу; можно воспользоваться сервисом Let’s Encrypt1, выпускающим бесплатные
сертификаты; можно также сгенерировать самоподписанный сертификат.
Мы будем использовать утилиту keytool для генерации самоподписанных
сертификатов. Главный недостаток самоподписанного сертификата в том, что большинство клиентов и устройств по умолчанию им не доверяет, что
может привести к появлению предупреждений при попытке соединения или
даже к отказу в обслуживании. Поэтому в промышленном кластере следует
устанавливать сертификаты, выпущенные доверенными удостоверяющими
центрами.
Утилита keytool позволяет вам управлять сертификатами, ключами и паролями. Чтобы сгенерировать сертификаты для узлов кластера, запустите
поочередно на каждом узле следующую команду, не забыв указать после
ключа -alias имя узла:
keytool -genkeypair -alias presto-coordinator \
-dname CN=presto-coordinator -keyalg RSA \
-keystore presto-coordinator-keystore.jks \
-ext "SAN=dns:presto-coordinator,dns:localhost"
1 .
Безопасность коммуникаций 135
Чтобы у вас была возможность доступа к узлу-координатору из локального клиента, при создании сертификата для узла-координатора добавьте
в поле SAN (Subject Alternative Name) localhost и 127.0.0.1. После выполнения команды у вас появится файл presto-keystore.jks – это хранилище ключей
в формате Java Keystore File.
Итак, теперь у каждого узла в вашем кластере есть сертификат. Чтобы устанавливать защищенные соединения, каждый узел должен импортировать
к себе сертификаты остальных узлов. Если, например, у вас есть три узла, A, B и C, то узел A должен загрузить к себе сертификаты узлов B и C, узел B – узлов A и C, а узел C – узлов A и B. Чтобы импортировать сертификаты, первым
делом вам надо выгрузить их из хранилища каждого узла:
keytool -exportcert -alias presto-coordinator \
-keystore presto-coordinator-keystore.jks -rfc -file presto-coordinator.pem Затем полученный файл с расширением *.pem нужно загрузить в хранилище другого узла:
keytool -importcert -alias presto-coordinator \
-keystore presto-worker-keystore.jks -file presto-coordinator.pem
Следующим шагом мы скопируем файл presto-keystore.jks на все узлы кластера. В нашем случае для этого достаточно внести изменения в конфигурационные файлы Kubernetes для узла-координатора и для рабочих узлов.
Для примера давайте добавим в presto-coordinator.yaml монтирование файла
presto-keystore.jks как отдельного тома:
spec:
containers:
- name: presto-coordinator
[ ... ]
volumeMounts:
- name: certificate
mountPath: "/opt/presto/etc/presto-keystore.jks"
volumes:
- name: certificate
hostPath:
path: "/path/to/presto-keystore.jks"
Настройка HTTPS/TLS
Давайте начнем с шифрования соединения между клиентом и узлом-координатором. Чтобы сделать это, для начала разрешим на узле-координаторе HTTPS. Отредактируем файл config.properties для узла-координатора, запретив HTTP и разрешив только HTTPS, а также зададим порт для HTTPS-соединений (http-server.https.port), путь к сертификату (http-server.https.
keystore.path) и пароль для доступа к сертификату (http-server.https.keystore.key):
136 Безопасность Presto
http-server.http.enabled=false
http-server.https.enabled=true
http-server.https.port=8443
http-server.https.keystore.path=/path/to/certificate.p12
http-server.https.keystore.key=password
Затем сконфигурируем узлы так, чтобы они обращались друг к другу только по полному имени (FQDN, fully qualified domain name). FQDN содержит
полный и уникальный адрес каждого узла:
node.internal-address-source=FQDN
node.internal-address=<node address>
Например, для узла-координатора установите значение параметра node.
internal-address в presto-coordinator.
Теперь мы можем сконфигурировать и шифрование трафика между узла-
ми кластера:
internal-communication.https.required=true
internal-communication.https.keystore.path=/path/to/presto-keystore.jks internal-communication.https.keystore.key=password
Выполнив все настройки, перезапустите узел-координатор.
Запуск клиента Presto
Клиент Presto запускается командой, в которой указаны адрес координатора
и порт:
presto --server https://presto-coordinator:8443 --truststore-path \
/opt/presto/etc/presto-keystore.jks --truststore-password password Поскольку используется самоподписанный сертификат, вы также должны
передать этот сертификат клиенту Presto. Если бы сертификат был выпущен
удостоверяющим центром, то он бы не понадобился, поскольку сервер пере-дал бы сертификат при попытке соединения и клиент смог бы убедиться в его
подлинности.
Деградация производительности
Использование шифрования может привести к падению производительности. Степень влияния зависит от выполняемых запросов и количества одновременно работающих клиентов.
Запуск консоли Presto
Откройте в браузере адрес https://localhost:8443. Поскольку сертификат самоподписанный, браузер выдаст предупреждение о том, что соединение может быть небезопасным. Игнорируйте предупреждение и начинайте работу
с консолью.
Аутентификация 137
Аутентификация
Цель аутентификации – проверить, что пользователь действительно тот, за
кого себя выдает. Аутентификация в Presto работает только в том случае, если
включено шифрование трафика.
Presto поддерживает три механизма аутентификации: аутентификацию
на основе файлов, аутентификацию через LDAP (Light-weight Directory Access Protocol) и аутентификацию на основе Kerberos. Первые два типа можно
использовать для аутентификации клиентов, а аутентификацию на основе
Kerberos можно использовать также и для аутентификации узлов кластера –
координатора и рабочих узлов.
Аутентификация, основанная на файлах
Этот механизм позволит вам аутентифицировать пользователей, имена и пароли которых перечислены в специальном файле. Чтобы файловая аутентификация работала, у вас должны быть настроены соединения по HTTPS.
Весь код, который мы будем писать в этом разделе, находится в папке
07/presto-file-based-authentication нашего репозитория.
Начнем с создания файла с именами пользователей и паролями. Для этого
воспользуемся командой htpasswd, которую можно взять в пакете apache-utils или bcrypt.
Где взять утилиту htpasswd?
Вы можете установить пакет bcrypt одной из перечисленных ниже команд: yum -y install bcrypt (CentOS), apt install bcrypt (Ubuntu и Debian) или brew install bcrypt (macOS). Либо вы можете установить библиотеку bcryps в Node.js.
Создайте пароли для двух пользователей A и B, которым мы договорились
предоставить доступ в предыдущем разделе (см. рис. 7-1), и сохраните их
в файл password.db:
touch password.db
htpasswd -B -C 10 password.db clientA
htpasswd -B -C 10 password.db clientB
Опция -C задает время работы алгоритма bcrypt. Presto принимает пароли, значение параметра при генерации которых не меньше 8. В файле password.
db содержатся хешированные пароли для всех пользователей. Выглядит файл
примерно так:
clientA:$2y$10$6/Z9xkk4XJYcUXP3xdHx9O3wZ/vtUz8uMZYlzOYwMJLAea0c3OLI2
clientB:$2y$10$WkrVISM7cX6rSttnWc5bFuH1mXMKUJ1GNOq9xUIpi1k3L.1dKW8.u После того как вы создали файл с паролями, включите файловую аутентификацию в Presto. Для этого добавьте в файл config.properties следующую
строку:
138 Безопасность Presto
http-server.authentication.type=PASSWORD,CERTIFICATE
Затем в папку etc вашей инсталляции Presto добавьте файл password-authenticator.properties:
password-authenticator.name=file
file.password-file=</path/to/password.db>
Вы можете прописать password-authenticator.properties отдельной стро-кой в объект configMap, используемый вашим кластером Presto в Kubernetes.
Затем в presto-coordinator.yaml смонтируйте строку password-authenticator.
properties как том, а файл password.db – как внешний том. Образец настроек
можно найти в репозитории.
Запуск клиента Presto
Если у вас настроена аутентификация, то при запуске клиента вы должны
указать аутентифицирующие данные, например логин и пароль. В клиенте
Presto, работающем из командной строки, их можно передать через параметры --user и --password:
presto \
--server https://presto-coordinator:8443 \
--truststore-path /opt/presto/etc/presto-keystore.jks \
--truststore-password password \
--user clientA \
--password
Запустив клиентское приложение таким образом, вы можете выполнять
запросы в кластере Presto. Если вы попытаетесь зайти с использованием ло-гина, которого нет в файле password.db, например clientC, то клиентское приложение все равно запустится, и вы получите приглашение ввести запрос.
Но после ввода запроса вы получите сообщение об ошибке аутентификации: presto \
--server https://presto-coordinator:8443 \