A-Tune

A-Tune — «магия», которая ускорит ваш сервер

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

Поставленная задача

Сегодня мы постараемся показать, как можно поднять производительность СУБД PostgreSQL методом тюнинга параметров конфигурации. В начале тестирования мы снимем показания на конфигурации PGSQL с которой данная СУБД поставляется в дистрибутиве, а затем, применим методы A-Tune и посмотрим насколько улучшатся измеряемые при тестировании показатели. При этом мы сразу оговоримся, что тюнинг параметров мы будем вести в двух направлениях: увеличение производительности PGSQL для выполнения mixed запросов и отдельно увеличение производительности PGSQL для выполнения SELECT запросов (если СУБД используется в основном для аналитики).

Подготовка стенда

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

Сервер Huawei 1288H V5:

  • 2 CPU (Intel(R) Xeon(R) Silver 4210R CPU @ 2.40GHz)
  • 128 Гб ОП
  • 2 SSD диска (INTEL SSDSC2KG480G8)
  • Версия ОС: OpenScaler 24.03 LTS
  • Ядро: 6.6.0-28.0.0.34.os2403.x86_64
  • Версия A-Tune: 1.2.0-3
  • Версия СУБД: postgresql-server-15.6-1

Давайте установим СУБД PQSQL из стандартного репозитория:

dnf install postgresql-server

После установки, нам надо создать базовые каталоги для размещения данных СУБД и, собственно, запустить pgsql:

/usr/bin/postgresql-setup --initdb
systemctl enable --now postgresql

Теперь давайте создадим тестовую БД (размером приблизительно 90 Гб):

su - postgres -c "pgbench -i -U postgres -s 4000"

Это займёт какое-то время. После окончания создания, давайте увеличим до 1024 количество возможных подключений к нашей БД:

postgres=# ALTER SYSTEM SET max_connections TO '1024';

И перезапускаем postgresql

Сразу приведём перечень команд, которые мы будем давать после каждого перезапуска сервиса postgres (этими командами мы делаем так называемый «прогрев данных») – разместим их в файле pre_warm.sql в домашнем каталоге пользователя postgres:

psql -U postgres
CREATE EXTENSION pg_prewarm;
select pg_prewarm('pgbench_accounts'::regclass);
select pg_prewarm('pgbench_accounts_pkey'::regclass);
select pg_prewarm('pgbench_tellers'::regclass);
select pg_prewarm('pgbench_history'::regclass);
select pg_prewarm('pgbench_branches'::regclass);

Для удобства проведения наших тестов напишем маленький скрипт на bash:

#!/bin/bash
NAME_TEST="default"
su - postgres -c "psql -U postgres < ~/pre_warm.sql"
for i in 50 100 200 300 400 500 600 700 800 900 1000
do
su - postgres -c "pgbench -j 20 -c $i -T 60 > /test/$NAME_TEST/pgbench-"${NAME_TEST}"-$i-mixed.log"
su - postgres -c "pgbench -j 20 -c $i -T 60 -S > /test/$NAME_TEST/pgbench-"${NAME_TEST}"-$i-select.log"
done

И по мере проведения тестов будем просто менять переменную NAME_TEST.

То есть дефолтные значения (до проведения тюнинга) мы получим запустив этот скрипт с NAME_TEST установленным в значение “default_settings”.

Тестирование — применение профиля

Давайте снимем показатели производительности, полученные утилитой pgbench при дефолтной конфигурации postgresql и запишем их в таблицу:

Количество
клиентов

latency average
(mixed запросы)

TPS
(mixed запросы)

latency average
(SELECT-only)

TPS
(SELECT-only)

50

3,944

12677,980011

0,220

227454,023008

100

7,618

13127,280346

0,403

248080,543429

200

16,405

12191,123731

0,827

241755,477216

300

23,513

12758,770475

1,398

214543,968116

400

34,813

11489,839948

1,774

225465,242580

500

35,493

14087,424670

2,413

207212,182059

600

43,287

13860,986056

3,009

199424,010650

700

51,580

13571,252112

3,360

208308,786568

800

57,525

13907,009814

3,990

200503,613603

900

77,332

11638,085873

4,627

194499,040098

1000

74,484

13425,712709

5,286

189181,357890

Теперь давайте применим профиль A-Tune, который предназначен для изменения параметров ОС, и проведём тестирование заново.

Список всех доступных профилей можно увидеть в выводе команды:

atune-adm list

Давайте применим профиль для postgresql:

atune-adm profile database-postgresql-2p-sysbench-ssd

Результаты замеров после установки профиля:

Количество
клиентов

latency average
(mixed запросы)

TPS
(mixed запросы)

latency average
(SELECT-only)

TPS
(SELECT-only)

50

4,162

12012,943663

0,263

189792,693575

100

9,443

10589,508094

0,405

246623,830077

200

17,340

11533,804112

0,806

248130,800872

300

25,096

11954,192161

1,381

217310,076854

400

36,267

11029,402926

1,937

206491,063924

500

44,067

11346,320620

2,382

209881,779758

600

50,430

11897,725031

3,418

175539,929994

700

76,271

9177,747531

3,267

214290,891374

800

72,177

11083,826736

3,890

205667,109445

900

75,332

11947,045593

4,448

202331,132525

1000

85,441

11703,937123

4,953

201896,809307

Давайте посмотрим как это выглядит на графиках:

Давайте теперь сравним (на 1000 соединений) как изменилась производительность.

Из данных приведённых таблиц, мы видим, что latency и TPS при mixed запросах у нас просела на 14%, а вот производительность SELECT-only увеличилась на 6%. Не сказать, чтобы прямо мы были довольны результатом, но давайте теперь попробуем «пошаманить» именно с параметрами конфигурации postgresql.

Тестирование — перебор значений параметров конфигурации

Для начала кратко опишем суть этого метода. Мы подготавливаем два конфигурационных файла A-Tune (yaml-манифесты), один для сервера, другой для клиента тюнинга. В серверном файле мы описываем какие параметры postgresql мы будем менять и какие значения этих параметров мы хотим попробовать при тюнинге. А в клиентском файле мы описываем утилиты тестирования производительности (наш pgbench) и какие параметры из выхлопа pgbench нас интересуют в качестве ориентиров для анализа производительности.

Приведём файл серверной конфигурации (файл размещаем по пути /etc/atuned/tuning/postgresql_pgbench_server.yaml):

project: "postgresql_pgbench"

maxiterations: 5000

startworkload: "systemctl start postgresql"

stopworkload: "systemctl stop postgresql"

object :

-

name : "kernel.numa_balancing"

info :

desc : "Specifies whether to enable NUMA automatic balancing."

get : "sysctl -n kernel.numa_balancing"

set : "sysctl -w kernel.numa_balancing=$value"

needrestart : "false"

type : "discrete"

options :

- "0"

- "1"

dtype : "string"

-

name : "kernel.sched_autogroup_enabled"

info :

desc : "When enabled, the kernel creates task groups to optimize desktop program scheduling."

get : "sysctl -n kernel.sched_autogroup_enabled"

set : "sysctl -w kernel.sched_autogroup_enabled=$value"

needrestart : "false"

type : "discrete"

options :

- "0"

- "1"

dtype : "string"

-

name : "shared_buffers"

info :

desc : "PostgreSQL 'shared_buffers' param."

get : "cat /var/lib/pgsql/data/postgresql.conf | grep '^shared_buffers =' | awk -F '=' '{print $2}'"

set : "sed -i 's/^shared_buffers.*$/shared_buffers = $value/g' /var/lib/pgsql/data/postgresql.conf"

needrestart : "true"

type : "discrete"

options :

- "128MB"

- "8GB"

- "16GB"

- "32GB"

dtype : "string"

-

name : "effective_cache_size"

info :

desc : "PostgreSQL 'effective_cache_size' param."

get : "cat /var/lib/pgsql/data/postgresql.conf | grep '^effective_cache_size =' | awk -F '=' '{print $2}'"

set : "sed -i 's/^effective_cache_size.*$/effective_cache_size = $value/g' /var/lib/pgsql/data/postgresql.conf"

needrestart : "true"

type : "discrete"

options :

- "4GB"

- "19GB"

- "48GB"

- "96GB"

dtype : "string"

-

name : "work_mem"

info :

desc : "PostgreSQL 'work_mem' param."

get : "cat /var/lib/pgsql/data/postgresql.conf | grep '^work_mem =' | awk -F '=' '{print $2}'"

set : "sed -i 's/^work_mem.*$/work_mem = $value/g' /var/lib/pgsql/data/postgresql.conf"

needrestart : "true"

type : "discrete"

options :

- "3Mb"

- "4Mb"

- "13Mb"

- "32Mb"

- "45Mb"

- "64Mb"

dtype : "string"

-

name : "maintenance_work_mem"

info :

desc : "PostgreSQL 'maintenance work_mem' param."

get : "cat /var/lib/pgsql/data/postgresql.conf | grep '^maintenance_work_mem =' | awk -F '=' '{print $2}'"

set : "sed -i 's/^maintenance_work_mem.*$/maintenance_work_mem = $value/g' /var/lib/pgsql/data/postgresql.conf"

needrestart : "true"

type : "discrete"

options :

- "64MB"

- "1GB"

- "3GB"

- "6GB"

dtype : "string"

-

name : "min_wal_size"

info :

desc : "PostgreSQL 'min_wal_size' param."

get : "cat /var/lib/pgsql/data/postgresql.conf | grep '^min_wal_size =' | awk -F '=' '{print $2}'"

set : "sed -i 's/^min_wal_size.*$/min_wal_size = $value/g' /var/lib/pgsql/data/postgresql.conf"

needrestart : "true"

type : "discrete"

options :

- "80MB"

- "1GB"

- "2GB"

dtype : "string"

-

name : "max_wal_size"

info :

desc : "PostgreSQL 'max_wal_size' param."

get : "cat /var/lib/pgsql/data/postgresql.conf | grep '^max_wal_size =' | awk -F '=' '{print $2}'"

set : "sed -i 's/^max_wal_size.*$/max_wal_size = $value/g' /var/lib/pgsql/data/postgresql.conf"

needrestart : "true"

type : "discrete"

options :

- "1GB"

- "2GB"

- "3GB"

dtype : "string"

-

name : "effective_io_concurrency"

info :

desc : "PostgreSQL 'effective_io_concurrency' param."

get : "cat /var/lib/pgsql/data/postgresql.conf | grep '^effective_io_concurrency =' | awk -F '=' '{print $2}'"

set : "sed -i 's/^effective_io_concurrency.*$/effective_io_concurrency = $value/g' /var/lib/pgsql/data/postgresql.conf"

needrestart : "true"

type : "discrete"

options :

- "100"

- "200"

dtype : "string"

Мы видим, каким образом A-Tune будет получать (get) текущие значения параметров и как будет устанавливать (set) значение параметров, которые участвуют в тюнинге производительности.

Но так как у нас заточка параметров идёт под разные типы работы СУБД, то файлов клиента мы создадим 2: один будет замерять производительность mixed запросов, другой будет замерять производительность select запросов.

Для mixed запросов postgresql_pgbench_client-mixed.yaml:

project: "postgresql_pgbench"

engine : "gbrt"

iterations : 200

random_starts : 10

benchmark : "sh /root/pgsql-tuning/postgresql_pgbench_benchmark-mixed.sh"

evaluations :

-

name: "TPS"

info:

get: "grep 'tps = ' /a/pgbench-tuning-mixed.log | awk -F ' ' 'NR==1{print $3}'"

type: "negative"

weight: 100

Содержимое скрипта проверки: postgresql_pgbench_benchmark-mixed.sh:

#!/bin/bash

su - postgres -c "pgbench -U postgres -c 20 -j 100 -T 60 > /test/pgbench-tuning-mixed.log"

 

Для SELECT-only запросов postgresql_pgbench_client-select.yaml:

project: "postgresql_pgbench"

engine : "gbrt"

iterations : 200

random_starts : 10

benchmark : "sh /root/pgsql-tuning/postgresql_pgbench_benchmark-select.sh"

evaluations :

-

name: "TPS"

info:

get: "grep 'tps = ' /test/pgbench-tuning-select.log | awk -F ' ' 'NR==1{print $3}'"

type: "negative"

weight: 100

Содержимое скрипта проверки:  postgresql_pgbench_benchmark-select.sh

#!/bin/bash

su - postgres -c "pgbench -U postgres -c 20 -j 100 -T 60 -S > /test/pgbench-tuning-select.log"

Теперь давайте запустим тюнинг параметров (сначала под mixed запросы)

atune-adm tuning --project postgresql_pgbench --detail postgresql_pgbench_client-mixed.yaml

Дожидаемся окончания (это может занять несколько часов) и получаем в выводе на консоль рекомендацию по настройке:

The final optimization result is: kernel.numa_balancing=0,kernel.sched_autogroup_enabled=1,shared_buffers=8GB,effective_cache_size=48GB,work_mem=3Mb,maintenance_work_mem=6GB,min_wal_size=80MB,max_wal_size=3GB,effective_io_concurrency=100

The final evaluation value is: TPS=16061.66

Baseline Performance is: (TPS=8929.71)

Tuning Finished

Вносим данные изменения в конфигурацию postgresql, проводим тестирование и заносим полученные результаты в таблицу:

Количество
клиентов

latency average
(mixed запросы)

TPS
(mixed запросы)

50

3,069

16293,914528

100

7,940

12594,796517

200

13,861

14429,391032

300

21,989

13643,281346

400

24,251

16493,977954

500

28,269

17687,187097

600

45,535

13176,760065

700

50,990

13728,168308

800

53,307

15007,464651

900

61,941

14529,845177

1000

53,352

18743,346378

Посмотрим, как результаты выглядят на графиках:

Останавливаем postgresql, откатываем конфигурационный файл на дефолтный, запускаем заново и проводим тюнинг параметров под select-only:

atune-adm tuning --project postgresql_pgbench --detail postgresql_pgbench_client-select.yaml

Дожидаемся окончания (это может занять несколько часов) и получаем в выводе на консоль рекомендацию по настройке:

The final optimization result is: kernel.numa_balancing=0,kernel.sched_autogroup_enabled=0,shared_buffers=128MB,effective_cache_size=4GB,work_mem=32Mb,maintenance_work_mem=6GB,min_wal_size=80MB,max_wal_size=2GB,effective_io_concurrency=200

The final evaluation value is: TPS=257468.18

Baseline Performance is: (TPS=98132.72)

Tuning Finished

Вносим данные изменения в конфигурацию postgresql, проводим тестирование и заносим полученные результаты в таблицу:

Количество
клиентов

latency average
(SELECT-only)

TPS
(SELECT-only)

50

0,214

233226,807074

100

0,412

242572,764534

200

0,891

224428,346861

300

1,366

219572,992712

400

2,096

190841,017106

500

2,356

212212,868834

600

3,259

184130,161952

700

3,835

182526,163887

800

4,312

185513,283588

900

5,084

177028,533560

1000

4,855

205986,227712

Посмотрим, как это выглядит на графиках:

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

  • Прирост производительности в mixed запросах составил довольно ощутимые 39%
  • тюнинг производительности в select-only запросах добавил производительности без малого 9%

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

Итоги тестирования

Сегодня мы рассмотрели один из способов, при помощи которого A-Tune может существенно поднять производительность нашего программного обеспечения.

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