Прежде, чем пытаться получить максимально возможную производительность СУБД PostgreSQL с помощью оптимизации параметров управления памятью и подключениями, можно получить очень хороший прирост скорости работы за счёт правильного распределения ресурсов по физическим устройствам хранения.
Не стоит для нагруженных СУБД использовать простейший "RAID 5" из трёх дисков. Потенциально более высокая сохранность данных ни как не оправдывает потери производительности от неиспользования доступных ресурсов. Лучше всего выделить каждой задаче, активно работающей с устройствами хранения, по одному диску. Например: выносим данные на один диск, индексы - на второй, а логи транзакций - на третий. Практически при любой операции записи магнитной головке диска придётся метнуться для выполнения всех трёх вышеперечисленных операций по нескольку раз и задачи будут выполняться, в лучшем случае, последовательно. В случае использования трёх физических дисковых устройств все они будет исполнять работу одновременно, ускоряя прохождения процедуры чуть ли не в три раза.
Было бы отлично выделить под каждую из трёх вышеперечисленных задач даже не по одному дисковуму устройству, а по "RAID 1+0", что позволит как увеличить скорость записи/чтения, так и уровень надёжности хранения данных.
Файловые системы на выделенных дисковых устройствах следует монтировать с опцией "noatime", что хоть совсем не намного, но ускорит работу.
Для начала заведём пару "табличных пространств" на скоростных устройствах хранения. Одно из них будет предназначено для хранения данных, как таковых, а второе - для индексов:
# mkdir -p /path.to.0/postgresql/data0
# mkdir -p /path.to.1/postgresql/help0
# mkdir -p /path.to.2/postgresql/pg_xlog
# chown -R postgres:postgres /path.to.0/postgresql/data0 /path.to.1/postgresql/help0 /path.to.2/postgresql/xlog0
# chmod -R go-rwx /path.to.0/postgresql/data0 /path.to.1/postgresql/help0 /path.to.2/postgresql/xlog0
# mkdir -p /path.to.1/postgresql/help0
# mkdir -p /path.to.2/postgresql/pg_xlog
# chown -R postgres:postgres /path.to.0/postgresql/data0 /path.to.1/postgresql/help0 /path.to.2/postgresql/xlog0
# chmod -R go-rwx /path.to.0/postgresql/data0 /path.to.1/postgresql/help0 /path.to.2/postgresql/xlog0
# psql -U postgres
postgres=# CREATE TABLESPACE space_data0 LOCATION '/path.to.0/postgresql/data0';
CREATE TABLESPACE
postgres=# CREATE TABLESPACE space_help0 LOCATION '/path.to.1/postgresql/help0';
CREATE TABLESPACE
CREATE TABLESPACE
postgres=# CREATE TABLESPACE space_help0 LOCATION '/path.to.1/postgresql/help0';
CREATE TABLESPACE
Теперь при создании объекта базы данных можно будет прямо указать, где именно мы хотели бы его разместить. Например:
# psql -U postgres
postgres=# CREATE TABLE foo(name character) TABLESPACE space_data0;
postgres=# CREATE INDEX foo_1 ON foo USING btree (name) TABLESPACE space_help0;
postgres=# CREATE INDEX foo_1 ON foo USING btree (name) TABLESPACE space_help0;
Можно попробовать заменить "табличное пространство", используемое по умолчанию ("pg_default"), нашим, хотя я и не вижу в этом настоятельной необходимости:
postgres=# SET default_tablespace = space_data0;
Узнать, какие "табличные пространства" уже имеются можно с помощью выборки из соответствующей таблицы:
postgres=# SELECT spcname FROM pg_tablespace;
spcname
------------
pg_default
pg_global
space_data0
space_help0
(4 rows)
------------
pg_default
pg_global
space_data0
space_help0
(4 rows)
Системная команда "\db" клиента PostgreSQL psql также выдаст нам информацию о имеющихся пространствах.
List of tablespaces
Name | Owner | Location
--------------+----------+----------------------------
pg_default | postgres |
pg_global | postgres |
space_data0 | postgres | /path.to.0/postgresql/data0
space_help0 | postgres | /path.to.1/postgresql/help0
(4 rows)
Name | Owner | Location
--------------+----------+----------------------------
pg_default | postgres |
pg_global | postgres |
space_data0 | postgres | /path.to.0/postgresql/data0
space_help0 | postgres | /path.to.1/postgresql/help0
(4 rows)
Удалить "табличное пространство" можно элементарно:
postgres=# DROP TABLESPACE IF EXISTS 'space_data0'
postgres=# DROP TABLESPACE IF EXISTS 'space_help0'
postgres=# DROP TABLESPACE IF EXISTS 'space_help0'
После создания табличных пространств не предусмотренных конфигурацией по умолчанию в служебной директории "/var/lib/postgresql/8.3/main/pg_tblspc/" появятся символические ссылки, указывающие на реальное месторасположение директорий с файлами. Если я правильно понял, PostgreSQL оперирует именно с этими ссылками при обращении к данным. Именно потому перенос "табличного пространства" на новое место действительно прост. Для этого достаточно остановить СУБД, перенести данные на новое место и откорректировать символические ссылки в соответствии с новым месторасположением. После запуска СУБД нужно будет вручную откорректировать значения полей в таблице "pg_tablespace", содержащие пути к перемещённым "табличным пространствам".
Перенос месторасположения журналов транзакций на выделенное физическое устройство хранения даёт существенный прирост производительности, на практике - от 5% до 25%. Для этого необходимо остановить сервер PostgreSQL, перенести каталог "/var/lib/postgresql/8.3/main/pg_xlog/" на новое место, создать на прежнем месте расположения символическую ссылку на новое месторасположение и запустить сервер:
# /etc/init.d/postgresql-8.3 stop
# mv /var/lib/postgresql/8.3/main/pg_xlog /path.to.2/postgresql/
# ln -s /path.to.2/postgresql/pg_xlog /var/lib/postgresql/8.3/main/pg_xlog
# /etc/init.d/postgresql-8.3 start
# mv /var/lib/postgresql/8.3/main/pg_xlog /path.to.2/postgresql/
# ln -s /path.to.2/postgresql/pg_xlog /var/lib/postgresql/8.3/main/pg_xlog
# /etc/init.d/postgresql-8.3 start
Не стану приводить примеры того, насколько выросла производительность СУБД - не замерял. Но в реальной работе сервер, после описанной здесь оптимизации используемого пространства, буквально обрёл новую жизнь. Скажем так: до оптимизации СУБД не успевала отрабатывать все обращённые к ней запросы, после - смогла освоить вдвое большую нагрузку.
13 ноября 2010 в 00:11
13 ноября 2010 в 12:44