Перейти к основному содержимому

Уровень 2.0

Предусловие: изучен модуль «Работа в среде psql» данного курса

В этой главе мы рассмотрим внутреннее устройство СУБД Pangolin – как организованы процессы, память, хранение данных и выполнение запросов.

Архитектура​

Работа СУБД Pangolin основана на деятельности отдельных процессов postgres, работающих скоординированно. Первым запускается процесс postgres, называемый далее postmaster. Он порождает одноименные дочерние процессы (backend), обслуживающие клиентов и выполняющие служебные задачи. Процессы взаимодействуют и имеют доступ к общей памяти.

Команда initdb создает в каталоге данных PGDATA файлы и каталоги, необходимые для работы СУБД и хранения данных. СУБД обслуживает несколько баз данных — кластер баз данных. Процессы, файлы и структуры в памяти — экземпляр.

При запуске экземпляра головной процесс postmaster организует необходимые для межпроцессного взаимодействия IPC структуры, например, разделяемую память, и открывает средства сетевого взаимодействия. Далее с помощью системного вызова fork() запускаются копии этого процесса. Дочерние процессы выполняют работу асинхронно и независимо друг от друга, но под общим управлением postmaster.

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

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

Экземпляр​

Структура экземпляра.

В разделяемой памяти экземпляра, доступной серверным процессам (backend), находится несколько структур данных, главная из которых — буферный кеш. Он предназначен для размещения страниц данных, считанных с диска из файлов данных и обрабатываемых процессами.

При подключении клиента после успешной аутентификации для него создается персональный серверный процесс (client backend). Когда клиент выполняет запрос SQL, происходит следующее:

  1. На этапе планирования запроса определяется, какие страницы данных требуются (например, при полном сканировании таблицы нужны все ее страницы).
  2. Проверяется, есть ли нужные страницы в буферном кеше. Если страниц в кеше нет, они считываются с диска из файлов данных. Для определения, какие файлы надо читать, используются метаданные (данные о данных) из системного каталога. Считанные страницы помещаются в буферный кеш.
  3. Вся дальнейшая работа с данными (чтение, изменение) происходит в буферном кеше.
  4. Измененные страницы («грязные») позже записываются обратно на диск.
  5. Для исключения одновременного изменения данных разными процессами, работающими асинхронно, существует система блокировок.

Активность процессов​

Информацию о процессах экземпляра, порожденных головным процессом (postmaster) можно получить из представления pg_stat_activity:

postgres@postgres=# SELECT pid, backend_type FROM pg_stat_activity;
pid | backend_type
-----+------------------------------
921 | autovacuum launcher
922 | autounite launcher
924 | logical replication launcher
923 | integrity check launcher
2485 | client backend
907 | background writer
906 | checkpointer
919 | walwriter
(8 rows)

Где:

  • client backend — серверный процесс, обслуживающий клиента;
  • checkpointer — процесс контрольной точки, необходим для периодической записи «грязных» страниц на накопители;
  • background writer — записывает измененные страницы, которые могут быть вскоре вытеснены на диск обслуживающими процессами;
  • walwriter — записывает содержимое кеша WAL в журнал предзаписи;
  • autovacuum launcher — запускает рабочие процессы автоочистки;
  • logical replication launcher — запускает рабочие процессы для логической репликации.

Специфичные для Pangolin процессы:

  • autounite launcher — для объединения индексов в партиционированных таблицах;
  • integrity check launcher — для проверки целостности.

Подробнее о представлении pg_stat_activity будет рассказано в главе «Обслуживание СУБД».

Посмотрим на список процессов экземпляра средствами операционной системы:

postgres@postgres=# \! ps f -C postgres
PID TTY STAT TIME COMMAND
811 ? Ss 0:00 /usr/pangolin-{pangolin-version}/bin/postgres -D /pgdata/06
906 ? Ss 0:00 \_ postgres: checkpointer
907 ? Ss 0:00 \_ postgres: background writer
909 ? Ss 0:00 \_ postgres: idle sessions terminator
919 ? Ss 0:00 \_ postgres: walwriter
920 ? Ss 0:00 \_ postgres: license checker
921 ? Ss 0:00 \_ postgres: autovacuum launcher
922 ? Ss 0:00 \_ postgres: autounite launcher
923 ? Ss 0:00 \_ postgres: integrity check launcher
924 ? Ss 0:00 \_ postgres: logical replication launcher
2485 ? Ss 0:00 \_ postgres: postgres postgres [local] idle

Локальная память процессов​

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

Серверный процесс

Хранение данных​

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

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

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

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

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

Каталог данных кластера БД​

При инициализации кластера БД командой initdb в каталоге данных PGDATA создается набор файлов и каталогов для работы СУБД. Рассмотрим содержимое каталога данных (в нашем случае PGDATA = /pgdata/06/data):

[postgres@ServerName ~] ls -F /pgdata/06/data
base/ pg_multixact/ pg_snapshots/ pg_xact/
global/ pg_notify/ pg_stat/ postgresql.auto.conf
pg_commit_ts/ pg_perf_insights/ pg_stat_tmp/ postgresql.conf
pg_dynshmem/ pg_commit_ts/ pg_subtrans/ postmaster.opts
pg_hba.conf pg_prep_stats/ pg_subtrans/ postmaster.opts
pg_ident.conf pg_quota.conf pg_twophase/ PRODUCT_VERSION
pg_integrity/ pg_replslot/ PG_VERSION tracing/
pg_logical/ pg_serial/ pg_wal/

По умолчанию команда initdb устанавливает на этот каталог права доступа 700 (drwx------), то есть полные права для владельца postgres. Однако при инициализации команде initdb можно добавить опцию -g, в результате чего права на каталог данных будут установлены 750 (drwxr-x---), с правами на чтение для членов группы postgres. Такие права могут потребоваться некоторым утилитам резервного копирования.

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

Этапы выполнения запроса​

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

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

  1. Разбор (parse) — построение дерева запроса.
  2. Переписывание (rewriting) — преобразование запроса в соответствии с правилами. Это делается автоматически, но с помощью правил переписывания на этот процесс потенциально можно влиять (не рекомендуется).
  3. Планирование — планировщик выбирает минимально затратный способ выполнения запроса.
  4. Выполнение – исполнительный механизм выполняет запрос по выбранному плану.

Результаты выполнения или сообщения об ошибках отправляются клиенту.

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

Расширенный протокол​

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

При подготовке оператора (PREPARE) или создании курсора (DECLARE CURSOR) выполняются разбор и переписывание. Результаты кешируются в локальной памяти процесса вместо повторения этих фаз при каждом выполнении запроса.

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

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

Кеш буферов​

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

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

Кеш буферов

Измененные («грязные») страницы сохраняются на диске позже, например, при наступлении контрольной точки или при нехватке свободного пространства в кеше. Такая отложенная запись обеспечивается механизмом журнала предзаписи (WAL) для защиты данных от сбоев.

Заголовок буфера​

Заголовок буфера

У каждого буфера в кеше имеется заголовок. В этом заголовке находятся сведения о состоянии страницы в этом буфере:

  • buffer_id — идентификатор буфера;
  • buffer pin_lock — признак закрепление буфера за процессом (пока процесс работает со страницей, она не может быть вытеснена);
  • usage count — счетчик количества обращений (используется для алгоритма вытеснений);
  • filenode+blocknumber — название сегмента и номер страницы;
  • isdirty — признак наличия изменений (буфер грязный).

Чтение в свободный буфер​

Чтение в свободной форме

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

Вытеснение​

Вытеснение

Для определения того, какую страницу из кеша буферов можно вытеснить, используются счетчик прикреплений Pin count и счетчик использований Usage count. Счетчик Usage count увеличивается при обращении любого процесса к этому буферу до значения 5. Но по алгоритму LRU регулярно происходит обход всех буферов в кеше, на каждом круге (clock sweep) которого происходит уменьшение счетчика Usage count на единицу.

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

Имеется специальный «указатель на следующую жертву» (next victim), который указывает на страницу, у которой Usage count = 0 и Pin count = 0. Это редко используемая страница, и ее можно вытеснить.

Записью «грязных» страниц могут заниматься различные процессы (checkpointer, backgroud writer, client backend). Стоит отметить, что если процессу client backend часто приходиться заниматься записью «грязных» страниц, то это свидетельствует о неправильной конфигурации экземпляра.

Итоги​

  • Экземпляр представлен скоординированно работающими процессами, общей памятью и каталогом данных.
  • Кластер баз данных состоит из нескольких баз данных, обслуживаемых экземпляром.
  • Процессы обслуживают клиентов и отвечают за выполнение служебных действий в СУБД.
  • Каждый процесс обладает собственной локальной памятью.
  • Клиентские запросы разбираются, переписываются, планируются и выполняются сервером СУБД.
  • Данные в виде строк размещаются на страницах в файлах данных.
  • Работа со страницами производится через кеш буферов.
  • При отсутствии в кеше буферов места для размещения страницы происходит вытеснение давно неиспользуемой незакрепленной страницы.

Самопроверка​

Вопрос 1

Какая команда создает каталог данных кластера?

Вопрос 2

Выберите верные утверждения:

Вопрос 3

Какие права доступа допустимы для каталога данных кластера? Выберите все верные варианты ответа:

Вопрос 4

Какая команда SQL применяется при использовании расширенного протокола выполнения запросов?