Поделиться через


Руководство: Шардирование данных на рабочих узлах в Azure Cosmos DB для PostgreSQL

Область применения: Azure Cosmos DB для PostgreSQL (с поддержкой расширения базы данных Citus для PostgreSQL)

В этом руководстве вы узнаете, как использовать Azure Cosmos DB для PostgreSQL:

  • создание шардов с хеш-распределением
  • определение расположения сегментов таблицы;
  • определение смещения распределения;
  • создание ограничения для распределенных таблиц;
  • выполнение запросов к распределенным данным.

Требования

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

Данные с хэш-распределением

Распределение строк таблицы между несколькими серверами PostgreSQL — это ключевой способ масштабирования запросов в Azure Cosmos DB для PostgreSQL. Вместе несколько узлов могут содержать больше данных, чем традиционная база данных, а во многих случаях для выполнения запросов могут параллельно использоваться ЦП рабочих узлов. Концепция хэш-распределенных таблиц также называется сегментированием на основе строк.

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

Координатор и два работника

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

select nodeid, nodename from pg_dist_node where isactive;
 nodeid | nodename
--------+-----------
      1 | 10.0.0.21
      2 | 10.0.0.23

Примечание.

Имена узлов в Azure Cosmos DB для PostgreSQL — это внутренние IP-адреса в виртуальной сети, а фактические адреса, которые вы видите, могут отличаться.

Строки, сегменты и размещение

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

-- create a table on the coordinator
create table users ( email text primary key, bday date not null );

-- distribute it into shards on workers
select create_distributed_table('users', 'email');

Azure Cosmos DB для PostgreSQL назначает каждую строку сегменту в зависимости от значения столбца распределения, который мы указали в нашем случае email. Каждая строка будет располагаться точно в одном сегменте, а каждый сегмент может содержать несколько строк.

Таблица

По умолчанию create_distributed_table() включает 32 сегмента, как можно увидеть, выполнив подсчет в таблице метаданных pg_dist_shard:

select logicalrelid, count(shardid)
  from pg_dist_shard
 group by logicalrelid;
 logicalrelid | count
--------------+-------
 users        |    32

Azure Cosmos DB для PostgreSQL использует pg_dist_shard таблицу для назначения строк сегментам на основе хэша значения в столбце распространения. Для работы с этим руководством не нужно вникать в детали хэширования. Важнее то, что мы можем отправить запрос и увидеть, какие значения сопоставлены с определенными идентификаторами сегментов:

-- Where would a row containing [email protected] be stored?
-- (The value doesn't have to actually be present in users, the mapping
-- is a mathematical operation consulting pg_dist_shard.)
select get_shard_id_for_distribution_column('users', '[email protected]');
 get_shard_id_for_distribution_column
--------------------------------------
                               102008

Сопоставление строк сегментам выполняется абсолютно логично. Сегменты должны быть назначены определенным рабочим узлам для хранения, что в Azure Cosmos DB для PostgreSQL называется размещением шардов.

Сегменты, назначенные рабочим узлам

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

-- limit the output to the first five placements

select
	shard.logicalrelid as table,
	placement.shardid as shard,
	node.nodename as host
from
	pg_dist_placement placement,
	pg_dist_node node,
	pg_dist_shard shard
where placement.groupid = node.groupid
  and shard.shardid = placement.shardid
order by shard
limit 5;
 table | shard  |    host
-------+--------+------------
 users | 102008 | 10.0.0.21
 users | 102009 | 10.0.0.23
 users | 102010 | 10.0.0.21
 users | 102011 | 10.0.0.23
 users | 102012 | 10.0.0.21

Неравномерное распределение данных

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

Для демонстрации создадим пример данных для таблицы users:

-- load sample data
insert into users
select
	md5(random()::text) || '@test.com',
	date_trunc('day', now() - random()*'100 years'::interval)
from generate_series(1, 1000);

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

-- sizes of the first five shards
select *
from
	run_command_on_shards('users', $cmd$
	  select pg_size_pretty(pg_table_size('%1$s'));
	$cmd$)
order by shardid
limit 5;
 shardid | success | result
---------+---------+--------
  102008 | t       | 16 kB
  102009 | t       | 16 kB
  102010 | t       | 16 kB
  102011 | t       | 16 kB
  102012 | t       | 16 kB

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

Строки в нашем примере users распределены равномерно благодаря свойствам столбца распределения email.

  1. Количество адресов электронной почты было больше или равно количеству фрагментов.
  2. Число строк на адрес электронной почты было похожим (в нашем случае использовалась точно одна строка на адрес, так как мы объявили его ключом).

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

Добавление ограничений к распределенным данным

Использование Azure Cosmos DB для PostgreSQL позволяет продолжать пользоваться безопасностью реляционной базы данных, включая ограничения базы данных. Однако есть ограничение. Из-за характера распределенных систем Azure Cosmos DB для PostgreSQL не будет перекрестно ссылаться на ограничения уникальности или ссылочной целостности между рабочими узлами.

Давайте рассмотрим наш пример таблицы users с соответствующей таблицей.

-- books that users own
create table books (
	owner_email text references users (email),
	isbn text not null,
	title text not null
);

-- distribute it
select create_distributed_table('books', 'owner_email');

Для повышенной эффективности мы распределим books так же, как users: по адресу электронной почты владельца. Распределение по аналогичным значениям столбцов называется колокацией.

У нас не возникло проблем с распределением книг пользователям с внешним ключом, так как ключ находился в столбце распределения. Но если мы попытаемся сделать из isbn ключ, возникнут сложности:

-- will not work
alter table books add constraint books_isbn unique (isbn);
ERROR:  cannot create constraint on "books"
DETAIL: Distributed relations cannot have UNIQUE, EXCLUDE, or
        PRIMARY KEY constraints that do not include the partition column
        (with an equality operator if EXCLUDE).

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

-- a weaker constraint is allowed
alter table books add constraint books_isbn unique (owner_email, isbn);

Приведенное выше ограничение всего лишь делает isbn уникальным для пользователя. Другой вариант — сделать таблицу books ссылочной таблицей (а не распределенной) и создать отдельную распределенную таблицу, связывающую данные о книгах с данными о пользователях.

Запрашивание распределенных таблиц

Из предыдущих разделов мы узнали, как строки распределенной таблицы размещаются в сегментах в рабочих узлах. Большую часть времени вам не нужно знать, как или где хранятся данные в кластере. Azure Cosmos DB для PostgreSQL имеет распределенный исполнитель запросов, который автоматически разбивает регулярные запросы SQL. Он запускает их параллельно в рабочих узлах, расположенных близко к данным.

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

select avg(current_date - bday) as avg_days_old from users;
    avg_days_old
--------------------
 17926.348000000000

Запрос к сегментам через координатор

За кулисами исполнитель Azure Cosmos DB для PostgreSQL создает отдельный запрос для каждого сегмента, запускает их на рабочих местах и объединяет результат. Это можно увидеть, если воспользоваться командой EXPLAIN PostgreSQL:

explain select avg(current_date - bday) from users;
                                  QUERY PLAN
----------------------------------------------------------------------------------
 Aggregate  (cost=500.00..500.02 rows=1 width=32)
   ->  Custom Scan (Citus Adaptive)  (cost=0.00..0.00 rows=100000 width=16)
     Task Count: 32
     Tasks Shown: One of 32
     ->  Task
       Node: host=10.0.0.21 port=5432 dbname=citus
       ->  Aggregate  (cost=41.75..41.76 rows=1 width=16)
         ->  Seq Scan on users_102040 users  (cost=0.00..22.70 rows=1270 width=4)

В выходных данных приведен пример плана выполнения для фрагмента запроса, выполняющегося в сегменте 102040 (таблица users_102040 в рабочем узле 10.0.0.21). Другие фрагменты не отображаются, так как они похожи. Рабочий узел сканирует таблицы шардов и выполняет агрегатное вычисление, как мы видим. Узел координатора объединяет агрегированные данные для получения окончательного результата.

Следующие шаги

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