- В1. PG има ли способността да кешира/подгрява релация?
- В2. Възможно ли е да се върне към предишно състояние на кеша, където е бил оставен преди изключване на сървъра на базата данни поради поддръжка?
В по-ранните версии на PostgreSQL няма никакъв шанс за затопляне на релация или съхраняване на състояния на кеша, но от PostgreSQL 9.4 нататък всяка от горните заявки (Q1,Q2) се адресира с два модула за принос pg_prewarm и pg_hibernator . Въпреки самия факт, че те се отличават с практичност, комбинацията изглежда е изключително жизнеспособна и полезна в бъдеще за DBA. Накратко за приноса:
pg_prewarm contrib (Автор:Робърт Хаас), предоставя възможност за зареждане на релационни данни в буферния кеш на ОС или PG буферен кеш. Той има функционалността на номер на първи или последен блок за предварително затопляне. (Забележка:Няма специална защита за предварително затоплени данни от изваждане от кеша, а също и ако екземплярът на базата данни е рестартиран, тогава е необходимо повторно затопляне на връзките).
pg_hibernator contrib (Автор:Gurjeet Singh), предоставя възможност за автоматично запазване на списъка със съдържанието на споделен буфер на диск при изключване на базата данни и автоматично възстановява буферите при стартиране на базата данни, почти същото като запазване/възстановяване на моментна снимка на shared_buffers. Той използва модула PG 9.3 за регистриране на "фонов работен процес" и създава два процеса "Buffer Saver", "Buffer Reader" за запазване/възстановяване. Интересното е, че с малко хакване pg_hibernator може също така да позволи на резервния подчинен да започне да обслужва заявки с пълна скорост със същото съдържание на master, това ще се види след минута :).
И накрая, имаме нужда от pg_buffercache модул, за да разгледате текущото съдържание на PostgreSQL shared_buffers. Този модул помага да се разбере какъв процент буфер е зает от релация.
Нека вкараме всички тези приноси в игра и да видим как те служат на целта на два въпроса (Q1,Q2). Ще използвам таблица „foo“ с размер 885MB на моята локална виртуална машина, заедно със стандартна заявка pg_buffercache.
SELECT c.relname,
count(*) AS buffers
ОТ pg_class c
INNER JOIN pg_buffercache b ON b.relfilenode=c.relfilenode И c.relname='foo'
INNER JOIN pg_database d ON (b.reldatabase=d.oid И d.datname=current_database())
GROUP BY c.relname
ПОРЪЧАЙТЕ ОТ 2 DESC LIMIT 10;
предварително>Използване на pg_prewarm contrib и затопляща таблица „foo“.
postgres=# създаване на разширение pg_prewarm;
СЪЗДАВАНЕ НА РАЗШИРЕНИЕ
postgres=# dt+
Списък с връзки
Схема | Име | Тип | Собственик | Размер | Описание
-------+------+-------+----------+-------+- ------------
обществено | foo | таблица | postgres | 885 MB |
(1 ред)
postgres=# изберете pg_prewarm('foo');
pg_prewarm
-----------
113278
(1 ред)
--pg_buffercache изход на заявка
relname | буфери
--------+--------
foo | 113278
(1 ред)Много проста и ясна употреба на pg_prewarm с изход от блокове, затоплени в shared_buffers за релация „foo“. От pg_buffercache изход на заявка, можем да го оценим, че има 113278 (113278 * 8 / 1024 =884MB) буфери с размер на блок от 8KB на релация „foo“, който съвпада с pg_prewarm изход. Тук, ако сървърът на Postgres се рестартира поради някаква причина, shared_buffers са празни и DBA трябва да се затопли отново, за да се върне към миналия топъл етап. За една маса повторното затопляне винаги е лесно, с изключение на агонията на група маси.
В този момент можем да използваме pg_hibernator contrib, тъй като той има гъвкавостта да запази съдържанието на shared_buffer и да го възстанови обратно при стартиране. Нека активираме pg_hibernator/pg_prewarm заедно и да изпълним подобно упражнение, като просто включим една стъпка от рестартиране и да видим дали състоянието на кеша се връща обратно както е или не. Няма да разглеждам инсталацията на pg_hibernator, защото в git е описана много добре, но бих прескочил директно към частта за внедряване и бих стартирал сървъра с pg_hibernator.
postgres 24623 1 0 02:06 pts/4 00:00:00 /usr/local/pgpatch/pg/bin/postgres -D /usr/local/pgpatch/pg/data_10407
postgres 246237 04 02:06 ? 00:00:00 postgres:регистрационен процес
postgres 24631 24623 0 02:06 ? 00:00:00 postgres:процес на контролна точка
postgres 24632 24623 0 02:06 ? 00:00:00 postgres:процес на писане
postgres 24633 24623 0 02:06 ? 00:00:00 postgres:процес на wal writer
postgres 24634 24623 0 02:06 ? 00:00:00 postgres:процес на автоматично вакуумно стартиране
postgres 24635 24623 0 02:06 ? 00:00:00 postgres:процес на архивиране
postgres 24636 24623 0 02:06 ? 00:00:00 postgres:процес на събиране на статистика
postgres 24637 24623 0 02:06 ? 00:00:00 postgres:bgworker:Buffer Saver
postgres 24638 24623 11 02:06 ? 00:00:01 postgres:bgworker:Block Reader 2
В регистрационните файлове на сървъра на базата данни при стартиране:
-bash-4.1$ още postgresql-2014-06-02_083033. log
LOG:системата за база данни беше изключена в 2014-06-02 08:13:00 PDT
LOG:стартиране на фонов работен процес "Buffer Saver"
LOG:системата на базата данни е готова да приеме връзки
LOG:стартира автоматичното вакуумиранеТъй като първият път, когато pg_hibernator е в игра, можете да видите два процеса и също логове с известна информация относно стартирането на „Buffer Saver“. Сега нека загреем релацията „foo“ и рестартираме сървъра, по-късно проверете състоянието на буфера дали pg_hibernator е запълнил буфера обратно там, където е бил оставен.
-bash-4.1$ psql -p 10407
psql (9.4beta1)
Въведете "help" за помощ.
postgres=# изберете pg_prewarm('foo');
pg_prewarm
------------
113278
(1 ред)
--pg_buffercache изход на заявка
relname | буфери
--------+--------
foo | 113278
(1 ред)
postgres=# q
-bash-4.1$ /usr/local/pgpatch/pg/bin/pg_ctl -D /usr/local/pgpatch /pg/data_10407 stop
изчаква сървърът да се изключи.... готово
сървърът спря
-bash-4.1$ ls -l $PGDATA/pg_hibernator/
общо 12
-rw------- 1 postgres postgres 160 3 юни 01:41 1.global.save
-rw------- 1 postgres postgres 915 3 юни 01 :41 2.postgres.save
-bash-4.1$ /usr/local/pgpatch/pg/bin/pg_ctl -D /usr/local/pgpatch/pg/data_10407 start
сървър започванеРестартирахме сървъра на базата данни, нека да разгледаме регистрационните файлове
-bash-4.1$ още postgresql-2014-06-03_020601.log
LOG:системата за база данни беше изключена на 2014-06-03 02:05:57 PDT
LOG:стартиране на фонов работник процес "Buffer Saver"
LOG:системата на базата данни е готова за приемане на връзки
LOG:стартиращ автоматичен стартер
LOG:регистриране на фоновия работник "Block Reader 2"
LOG:стартиране на фоновия работник процес "Block Reader 2"
LOG:Block Reader 2:възстановени 113433 блока
LOG:Block Reader 2:всички блокове са прочетени успешно
LOG:работен процес:Block Reader 2 (PID 24638) е излязъл с изходен код 1
LOG:отмяна на регистрация на фонов работник "Block Reader 2"
LOG:регистриране на фонов работник "Block Reader 1"
LOG:стартиране на фонов работен процес "Block Reader 1"
LOG:Четец на блокове 1:възстановени 20 блока
LOG:Четец на блокове 1:всички блокове са прочетени успешно
LOG:работен процес:Блок Четец 1 (PID 24664) е излязъл с изходен код 1
LOG :дерегистриране на фоновия работник „Блокиране на четене er 1"И така, „Buffer Reader“ е възстановил блокове от 113433 + 20, от които 113278 принадлежи на релация „foo“. Страхотно, нека се свържем и да видим.
-bash-4.1$ psql -p 10407
psql (9.4beta1)
Въведете "help" за помощ.
--pg_buffercache изход на заявка
relname | буфери
--------+--------
foo | 113278
(1 ред)Cool... pg_hibernator върна затопленото състояние на кеша без намеса на DBA.
Друго добро нещо за pg_hibernator, новосъздаденият режим на готовност може да има същото споделено съдържание на буфер като главния, така че режимът на готовност да започне да обслужва заявки с пълна скорост. За да направя това упражнение, докато правя резервно копие на директория $PGDATA, предадох SIGTERM на процеса „Запазване на буфери“, така че той да запише текущото състояние shared_buffers съдържание на диск (директория $PGDATA/pg_hibernator) и след това последва настройка в режим на готовност.
postgres 24637 24623 0 02:06 ? 00:00:00 postgres:bgworker:Buffer Saver
postgres 24653 15179 0 02:06 ? 00:00:01 postgres:wal приемник процес стрийминг 1/6A000A10
postgres 24654 24623 0 02:06 ? 00:00:00 postgres:wal изпращач процес postgres ::1(65011) стрийминг 1/6A000A10След настройката моят подчинен стартира със същото съдържание на основното
-bash-4.1$ psql -p 10477
psql (9.4beta1)
Въведете "help" за помощ.
postgres=# изберете pg_is_in_recovery();
pg_is_in_recovery
------------------
t
(1 ред)
--pg_buffercache изход на заявка
relname | буфери
--------+--------
foo | 113278
(1 ред)Благодаря и на двамата автори за прекрасното разширение за кеширане.