Распределение данных по удаленным точкам с помощью георазметки таблиц

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

Мы продолжим на примере крупной сети пиццерий. Эта сеть пиццерий имеет филиалы в Нью-Йорке, Лондоне и Гонконге. Она также использует один централизованный кластер базы данных для отслеживания заказов своих восхищенных клиентов.

На этот раз геораспределенный кластер баз данных работает на YugabyteDB. Для тех, кто еще не знаком с этой базой данных, YugabyteDB — это PostgreSQL-совместимая распределенная база данных, которая равномерно распределяет данные по кластеру узлов. Кроме того, она масштабирует операции чтения и записи, используя все ресурсы кластера. YugabyteDB поддерживает несколько многорегиональных развертываний, однако в этой статье мы остановимся на варианте с георазделами.

Таблица с георазметкой

Давайте снова возьмем таблицу PizzaOrders, но теперь разделим ее по столбцу Region. Таблица отслеживает ход выполнения заказа (представленного в первой статье), а вновь добавленный столбец Region определяет местоположение заказа:

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

  • Это хорошо для производительности и удобства пользователей — скорость и отзывчивость вашего приложения для пиццы будет одинаковой для всех клиентов, независимо от их местонахождения. Например, заказы из Гонконга будут проходить через таблицу Orders_APAC, где данные хранятся на узлах базы данных в APAC.
  • Это хорошо для регулирования данных — все заказы и персональные данные европейских клиентов не покинут пределов ЕС. Данные, принадлежащие разделу Orders_EU, будут находиться на узлах базы данных в Европе, что удовлетворяет требованиям GDPR.
  • Это хорошо с точки зрения бизнеса — головной офис сети пиццерий имеет полный контроль над единым кластером баз данных, который можно масштабировать в определенных географических регионах при увеличении нагрузки. Кроме того, приложение может легко запрашивать и соединять геораспределенные данные через единую конечную точку базы данных.

Запуск геораспределенного кластера

Теперь давайте поэкспериментируем с геораспределенными таблицами. Сначала разверните экземпляр YugabyteDB с геораспределением. Здесь у вас есть два варианта.

Вариант №1: Вы можете развернуть и настроить кластер с географическими разделами через интерфейс YugabyteDB Managed:

Вариант №2: Вы можете смоделировать кластер с географическим разделением на локальной машине с помощью YugabyteDB с открытым исходным кодом и Docker.

mkdir ~/yb_docker_data

docker network create yugabytedb_network
# Starting a node in the US
docker run -d --name yugabytedb_node_us --net yugabytedb_network -p 7001:7000 -p 9000:9000 -p 5433:5433 
  -v ~/yb_docker_data/node_us:/home/yugabyte/yb_data --restart unless-stopped 
  yugabytedb/yugabyte:latest bin/yugabyted start --listen=yugabytedb_node_us 
  --base_dir=/home/yugabyte/yb_data --daemon=false 
  --master_flags="placement_zone=A,placement_region=US,placement_cloud=CLOUD" 
  --tserver_flags="placement_zone=A,placement_region=US,placement_cloud=CLOUD"

# Starting a node in Europe
docker run -d --name yugabytedb_node_eu --net yugabytedb_network 
  -v ~/yb_docker_data/node_eu:/home/yugabyte/yb_data --restart unless-stopped 
  yugabytedb/yugabyte:latest bin/yugabyted start --join=yugabytedb_node_us --listen=yugabytedb_node_eu 
  --base_dir=/home/yugabyte/yb_data --daemon=false 
  --master_flags="placement_zone=A,placement_region=EU,placement_cloud=CLOUD" 
  --tserver_flags="placement_zone=A,placement_region=EU,placement_cloud=CLOUD"

# Starting a node in APAC
docker run -d --name yugabytedb_node_apac --net yugabytedb_network 
  -v ~/yb_docker_data/node_apac:/home/yugabyte/yb_data --restart unless-stopped 
  yugabytedb/yugabyte:latest bin/yugabyted start --join=yugabytedb_node_us --listen=yugabytedb_node_apac 
  --base_dir=/home/yugabyte/yb_data --daemon=false 
 --master_flags="placement_zone=A,placement_region=APAC,placement_cloud=CLOUD" 
  --tserver_flags="placement_zone=A,placement_region=APAC,placement_cloud=CLOUD"

# Updating the nodes’ placement
docker exec -i yugabytedb_node_us 
yb-admin -master_addresses yugabytedb_node_us:7100,yugabytedb_node_eu:7100,yugabytedb_node_apac:7100 
modify_placement_info CLOUD.US.A,CLOUD.EU.A,CLOUD.APAC.A 3
Вход в полноэкранный режим Выйти из полноэкранного режима

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

После запуска вы можете подключиться к экземпляру базы данных с помощью следующей команды psql:

psql -h 127.0.0.1 -p 5433 yugabyte -U yugabyte -w
Войти в полноэкранный режим Выйти из полноэкранного режима

Создание табличных пространств

Пространства таблиц — это удобная функция PostgreSQL. Она позволяет определить места в файловой системе, где хранятся файлы, представляющие объект базы данных. Будучи Postgres-совместимой базой данных, YugabyteDB поддерживает эту функцию и позволяет вам использовать пространства таблиц для гео-разметки.

Итак, следующим шагом будет создание табличных пространств для таблицы PizzaOrders с географическим разделением:

CREATE TABLESPACE us_tablespace WITH (
  replica_placement='{"num_replicas": 1, "placement_blocks":
  [{"cloud":"CLOUD","region":"US","zone":"A","min_num_replicas":1}]}'
);

CREATE TABLESPACE eu_tablespace WITH (
  replica_placement='{"num_replicas": 1, "placement_blocks":
  [{"cloud":"CLOUD","region":"EU","zone":"A","min_num_replicas":1}]}'
);

CREATE TABLESPACE apac_tablespace WITH (
  replica_placement='{"num_replicas": 1, "placement_blocks":
  [{"cloud":"CLOUD","region":"APAC","zone":"A","min_num_replicas":1}]}'
);
Войдите в полноэкранный режим Выйти из полноэкранного режима

Эти команды создают табличное пространство для каждого местоположения: США, ЕС и APAC. Каждая табличная область назначается узлу с аналогичной информацией о размещении. Например, us_tablespace будет назначен узлу yugabytedb_node_us, который вы запустили ранее, если информация о размещении этого узла (placement_zone=A,placement_region=US,placement_cloud=CLOUD) соответствует размещению us_tablespace.

Создание разделов

Последним шагом настройки является разбиение таблицы PizzaOrders на три ранее рассмотренных раздела: Orders_US, Orders_EU и Orders_APAC. Для этого можно воспользоваться командами, приведенными ниже:

CREATE TYPE status_t AS ENUM('ordered', 'baking', 'delivering', 'yummy-in-my-tummy');

CREATE TABLE PizzaOrders
 (
   order_id   int,
   order_status   status_t,
   order_time   timestamp,
   region text,
   PRIMARY KEY (order_id, region)
 ) PARTITION BY LIST (region);

CREATE TABLE Orders_US
    PARTITION OF PizzaOrders
    FOR VALUES IN ('US') TABLESPACE us_tablespace;

CREATE TABLE Orders_EU
    PARTITION OF PizzaOrders
    FOR VALUES IN ('EU') TABLESPACE eu_tablespace;

CREATE TABLE Orders_APAC
    PARTITION OF PizzaOrders
    FOR VALUES IN ('APAC') TABLESPACE apac_tablespace;
Войти в полноэкранный режим Выйти из полноэкранного режима

На самом деле, комбинация нескольких возможностей позволяет осуществлять гео-разделение в YugabyteDB:

  • Во-первых, исходная таблица (PizzaOrders) разбивается с помощью метода LIST Partitioning (PARTITION BY LIST (region)).
  • Во-вторых, каждый раздел назначается одному из табличных пространств. Например, в приведенной выше команде раздел Orders_APAC назначается на TABLESPACE apac_tablespace.
  • Наконец, каждая табличная область с ее разделами автоматически отображается на узлы YugabyteDB из соответствующей географии (т.е. размещается на них).

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

d+ PizzaOrders;
                                       Partitioned table "public.pizzaorders"
    Column    |            Type             | Collation | Nullable | Default | Storage  | Stats target | Description 
--------------+-----------------------------+-----------+----------+---------+----------+--------------+-------------
 order_id     | integer                     |           | not null |         | plain    |              | 
 order_status | status_t                    |           |          |         | plain    |              | 
 order_time   | timestamp without time zone |           |          |         | plain    |              | 
 region       | text                        |           | not null |         | extended |              | 
Partition key: LIST (region)
Indexes:
    "pizzaorders_pkey" PRIMARY KEY, lsm (order_id HASH, region ASC)
Partitions: orders_apac FOR VALUES IN ('APAC'),
            orders_eu FOR VALUES IN ('EU'),
            orders_us FOR VALUES IN ('US')
Войти в полноэкранный режим Выход из полноэкранного режима

Тестирование георазметки таблицы

Теперь вы готовы к последнему тесту. Продолжайте и добавьте несколько заказов в базу данных. На данный момент поместите некоторые данные в сеть пиццерий, расположенных в США:

INSERT INTO PizzaOrders VALUES 
(1, 'yummy-in-my-tummy', '2021-12-27 22:00:00', 'US'),
(2, 'yummy-in-my-tummy', '2022-05-15 13:00:00', 'US'),
(6, 'baking', '2022-06-24 8:45:00', 'US'),
(7, 'baking', '2022-06-24 9:00:00', 'US'); 
Войти в полноэкранный режим Выйдите из полноэкранного режима

Дважды проверьте, что данные попали в раздел Orders_US (обратитесь к столбцу tableoid в результате):

SELECT tableoid::regclass,* from PizzaOrders 
  ORDER BY order_id;

 tableoid  | order_id |   order_status    |     order_time      | region 
-----------+----------+-------------------+---------------------+--------
 orders_us |        1 | yummy-in-my-tummy | 2021-12-27 22:00:00 | US
 orders_us |        2 | yummy-in-my-tummy | 2022-05-15 13:00:00 | US
 orders_us |        6 | baking            | 2022-06-24 08:45:00 | US
 orders_us |        7 | baking            | 2022-06-24 09:00:00 | US
Войдите в полноэкранный режим Выйдите из полноэкранного режима

Далее попытайтесь разместить заказы пиццы но клиентам из Лондона (регион ЕС) и Гонконга (регион АТР):

INSERT INTO PizzaOrders VALUES 
(3, 'yummy-in-my-tummy', '2022-05-23 10:00:00', 'EU'),
(4, 'yummy-in-my-tummy', '2022-06-23 19:00:00', 'APAC'),
(5, 'delivering', '2022-06-24 8:30:00', 'APAC'),
(8, 'ordered', '2022-06-24 10:00:00', 'EU'); 

ERROR:  Illegal state: Nonlocal tablet accessed in local transaction: tablet 49fb2ab17298424096d215f5f1f32515
Войти в полноэкранный режим Выйдите из полноэкранного режима

Если вы следовали этим инструкциям, вы получите приведенное выше сообщение об ошибке. Это происходит потому, что наша psql-сессия открыта через узел YugabyteDB, развернутый в США (yugabytedb_node_us). А по умолчанию YugabyteDB не позволяет выполнять транзакции, которые охватывают несколько географических регионов. Итак, какие у вас есть варианты? Вы можете подключиться к узлам в ЕС и АТР и вставлять данные оттуда. Или вы можете включить опцию force_global_transaction и вставить данные с узла, расположенного в США:

SET force_global_transaction = TRUE;

INSERT INTO PizzaOrders VALUES 
(3, 'yummy-in-my-tummy', '2022-05-23 10:00:00', 'EU'),
(4, 'yummy-in-my-tummy', '2022-06-23 19:00:00', 'APAC'),
(5, 'delivering', '2022-06-24 8:30:00', 'APAC'),
(8, 'ordered', '2022-06-24 10:00:00', 'EU'); 
Войти в полноэкранный режим Выйти из полноэкранного режима

После успешного выполнения команды убедитесь, что заказы размещены правильно по разделам и соответствующим географическим регионам (снова обратитесь к столбцу tableoid в выводе):

SELECT tableoid::regclass,* from PizzaOrders 
  ORDER BY order_id;
  tableoid   | order_id |   order_status    |     order_time      | region 
-------------+----------+-------------------+---------------------+--------
 orders_us   |        1 | yummy-in-my-tummy | 2021-12-27 22:00:00 | US
 orders_us   |        2 | yummy-in-my-tummy | 2022-05-15 13:00:00 | US
 orders_eu   |        3 | yummy-in-my-tummy | 2022-05-23 10:00:00 | EU
 orders_apac |        4 | yummy-in-my-tummy | 2022-06-23 19:00:00 | APAC
 orders_apac |        5 | delivering        | 2022-06-24 08:30:00 | APAC
 orders_us   |        6 | baking            | 2022-06-24 08:45:00 | US
 orders_us   |        7 | baking            | 2022-06-24 09:00:00 | US
 orders_eu   |        8 | ordered           | 2022-06-24 10:00:00 | EU
Войти в полноэкранный режим Выйдите из полноэкранного режима

Подведение итогов…

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

Эта статья завершает наш цикл статей, посвященный теме разделения таблиц для разработчиков приложений. Получайте удовольствие от создания этих приложений и следите за новыми материалами, связанными с базами данных, распределенными системами и Java!

Оцените статью
devanswers.ru
Добавить комментарий