Мы активно готовимся к PG Day'17, расширяем тематику конференции, поэтому в скором времени вас ждет большое количество интереснейших постов не только о PostgreSQL, но и о других широко используемых базах данных. Сегодня хотим предложить вашему вниманию перевод статьи Gulcin Yildirim, которая послужила основой для ее доклада на PG Conf Europe'16.

«Как бы парадоксально это ни звучало, но истина заключается в том, что чем больше мы узнаём, тем более невежественными становимся в абсолютном смысле, ибо только через просветление мы осознаём нашу ограниченность. Если говорить конкретнее, то одним из наиболее отрадных результатов интеллектуальной эволюции является постоянное открытие новых и более широких перспектив». Никола Тесла



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

PostgreSQL в двух словах


PostgreSQL отказоустойчив по своей природе. Во-первых, это продвинутая система управления базами данных с открытым исходным кодом, и в этом году отпразднуется её 20-летний юбилей [прим. пер.: юбилей состоялся в 2016 году, торжественное поздравление от русского сообщества прошло на заключительном вечере PG Day’16 Russia]. Следовательно, это проверенная технология с активным сообществом, благодаря которому она активно развивается.

PostgreSQL является SQL-совместимым (SQL: 2011) и полностью соответствует требованиям ACID (атомарность, согласованность, изолированность, надежность).

Примечание: A(tomicity) C(onsistency) I(solation) D(urability) в PostgreSQL

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

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

PostgreSQL позволяет выполнять синхронные и асинхронные транзакции, PITR (Point-in-time Recovery — восстановление на момент времени) и MVCC (Multiversion concurrency control — Управление конкурентным доступом с помощью многоверсионности). Все эти концепции в определённой степени относятся к отказоустойчивости, и я постараюсь описать их воздействие в процессе объяснения основных понятий и их приложений в PostgreSQL.

PostgreSQL надежен!


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

Опционально можно создавать базы данных с блоками данных с контрольными суммами (data block checksums) для диагностики аппаратных неисправностей. Существует множество механизмов резервного копирования с полным и детализированным PITR на случай, если потребуется детальное восстановление. Также доступны различные инструменты для диагностики.

Репликация баз данных поддерживается изначально. Синхронная репликация, при правильной настройке и управлении, обеспечивает более высокую, по сравнению с “5 девятками” (99.999%), степень доступности и защиту данных.

Принимая во внимание все вышеперечисленные факты, можно с лёгкостью утверждать, что PostgreSQL надежен!

Отказоустойчивость PostgreSQL: WAL


WAL — write ahead logging — является основной системой отказоустойчивости для PostgreSQL.

WAL состоит из серии бинарных файлов, записанных в субдиректории pg_xlog директории данных PostgreSQL. Каждое изменение, внесенное в базу данных, сначала записывается в WAL, отсюда и название «упреждающий» журнал, созвучное «журналу транзакций». Когда транзакция завершается, поведением по умолчанию — и наиболее безопасным — будет форсировать записи WAL на диск.

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

Транзакция? Commit?


Изменения в базе данных сами по себе не записываются на диск в момент завершения транзакции. Они записываются спустя какое-то время фоновыми процессами writer & checkpointer на хорошо настроенном сервере. (Посмотрите описание WAL выше)

Транзакции — это фундаментальное понятие всех систем баз данных. Отличительной чертой транзакции является то, что она связывает несколько шагов в единую «всё-или-ничего» операцию.

Примечание: Транзакции в PostgreSQL

PostgreSQL фактически рассматривает каждый SQL запрос как выполняемый внутри транзакции. Если вы не пишете команду BEGIN, то каждый отдельный запрос будет иметь неявные команды BEGIN и (в случае успеха) COMMIT в начале и в конце соответственно. Группа запросов, обернутая в BEGIN и COMMIT, иногда называется блоком транзакции.

Промежуточные состояния между шагами не видны другим транзакциям, выполняемым параллельно, поэтому, если возникнет какой-либо сбой, мешающий транзакции завершиться, ни один шаг не повлияет на базу данных в целом. PostgreSQL не поддерживает «грязные» чтения (dirty-readsтранзакция считывает данные, записанные параллельной незавершенной транзакцией).

Примечание: Изолированность транзакций

Стандарт SQL определяет 4 уровня изолированности транзакций: Чтение незавершенного, Чтение завершенного, Повторное чтение, Сериализация.

Таблица 1: Уровни изолированности стандартной SQL транзакции
Уровень изолированности «Грязное» чтение Неповторяемое чтение Фантомное чтение Аномалия сериализации
Чтение незавершенного Разрешено, но не в PG Возможно Возможно Возможно
Чтение завершенного Невозможно Возможно Возможно Возможно
Повторное чтение Невозможно Невозможно Разрешено, но не в PG Возможно
Сериализация Невозможно Невозможно Невозможно Невозможно

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

Для более подробной информации по этой теме изучите документацию Постгреса об изолированности транзакций.

Контрольная точка


Аварийное восстановление воспроизводит WAL, но с какого момента начинается восстановление?

Восстановление начинается с точек в WAL, известных как контрольные точки (checkpoints). Длительность аварийного восстановления зависит от количества изменений в журнале транзакций с момента последней контрольной точки. Контрольная точка — это известная безопасная точка начала восстановления, поскольку она гарантирует, что предыдущие изменения базы данных уже были записаны на диск.

Контрольная точка может быть немедленной или запланированной. Немедленные контрольные точки появляются вследствие каких-либо действий привилегированного пользователя (суперюзера), например, командой CHECKPOINT или другими. Запланированные контрольные точки выставляются Постгресом автоматически.

Заключение


В этом посте мы перечислили важные функции PostgreSQL, связанные с его отказоустойчивостью. Были упомянуты упреждающее журналирование, транзакция, уровни изолированности, контрольные точки и аварийное восстановление. В следующем посте мы продолжим тему рассказом о репликации в PostgreSQL.
Поделиться с друзьями
-->

Комментарии (23)


  1. kaamos
    08.12.2016 13:23
    +4

    PostgreSQL является SQL-совместимым (SQL: 2011) и полностью соответствует требованиям ACID

    Меня тут сейчас заминусуют как обычно, но это всё неправда, конечно:
    • С примерами несоответствия PostgreSQL SQL стандарту можно ознакомиться здесь
    • пример несоответствия D в ACID — печально известные bitmap индексы
    • с примерами несоответствия I в ACID можно ознакомиться здесь

    И это навскидку, наверняка можно накопать ещё примеров. Просто никто этим никогда не занимался. Все больше любят громкие красивые утверждения.


    1. kshvakov
      08.12.2016 15:22
      +3

      Аргументированная критика это хорошо и, возможно, это все действительно неправда, но вы действительно считаете что данные ссылки все разъясняют:

      START TRANSACTION;
      CREATE TABLE t (s1 SMALLINT);
      INSERT INTO t VALUES (1);
      INSERT INTO t VALUES (32768); /* This causes an error. */
      COMMIT;
      SELECT * FROM t;
      


      Result:
      MySQL finds a row containing 1. PostgreSQL finds nothing.
      Reason:
      PostgreSQL rolls back the entire transaction when it encounters a syntax error. MySQL only cancels the statement.


      CREATE TABLE t (s1 INT);
      INSERT INTO t VALUES (1);
      COMMIT;
      START TRANSACTION;
      SELECT CURRENT_TIMESTAMP FROM t;
      /* Pause 1 second. */
      SELECT CURRENT_TIMESTAMP FROM t;
      


      Result: PostgreSQL shows the same timestamp twice. MySQL shows two different timestamps.
      Reason:
      PostgreSQL keeps the same time throughout a transaction; MySQL keeps the same time throughout a statement.
      The key sentences in the standard say that the result of a datetime value function should be the time when the function is evaluated, and «The time of evaluation of a datetime value function during the execution of S and its activated triggers is implementation-dependent.»

      * при этом замечу что как раз функции (пример: clock_timestamp()) ведут себя ожидаемым образом

      и т.д.

      ps: я бы еще не отказался почитать о печальной известности bitmap-индексов постгреса


      1. kaamos
        08.12.2016 15:53

        Я перечитал это сообщение несколько раз, но так и не понял, что вы хотели сказать. Что я не прав, то есть по ссылке есть примеры несоответсвия PostgreSQL стандарту SQL? Или что я не прав, то есть по ссылке нет примеров несоответствия PostgreSQL стандарту SQL? Или смешная третья опция?

        Про bitmap индексы всё просто: они не журналируются в WAL. Поэтому для них durability не существует. И репликации тоже.


        1. kshvakov
          08.12.2016 16:06
          +2

          1. у постгреса транзакционный DDL, он откатывает транзакцию полностью
          2. функции для получения timestamp в транзакции есть и работают корректно
          3. у постгреса нет bitmap индексов
          4. и т.д.


          очень, мягко скажем, противоричивый источник правды


          1. kaamos
            08.12.2016 16:15

            Источник правды там нормальный. Я знаком с человеком лично — это ходячая энциклопедия по SQL стандарту. Это человек, которого можно разбудить ночью, и спросить про любой произвольный аспект SQL стандарта. И он подробно расскажет, с примерами и аспектами реализации в разных СУБД. А ещё этот человек автор книг по SQL стандарту. Просто вы в статье пытаетесь прочитать то, чего там нет. Статья утверждает, что MySQL в некоторых вещах лучше соответствует SQL стандарту. А я статью привёл потому, что там действительно есть примеры несовместимости SQL стандарта и PostgreSQL.

            Да, я говорил про hash индексы, естественно, просто закоротило провода. Но на Хабре нельзя редактировать комментарии. И т. д.


            1. Bozaro
              09.12.2016 11:19
              +1

              Статья все равно жёлтая: обсуждение соответствия стандарту без ссылок не то что, на сам стандарт, а даже на его название.


              1. kaamos
                09.12.2016 11:35
                -2

                Ну не учёл человек, что к нему строгие эксперты с Хабра придут. Иначе бы он конечно по всей форме доложился. С ссылками, цитатами и названиями стандарта.


          1. zubrabubra
            10.12.2016 18:57

            А можно немного подробнее почему в первом примере вообще должно произойти сохранение записей в таблицу? Даже если DDL транзакционный у Postgresql, а Mysql нет, ожидаемое поведение вероятно откатывание всех операций DML.


        1. JSmitty
          08.12.2016 16:17
          +1

          А можно оффтоп вопрос в студию — MySQL уже научился каскадно триггеры запускать? Или каскадно удалять? Сравнивать базы, для одной из которых можно привести пример, как она НЕ соблюдает стандарт, со второй, к которой обычно приводят примеры как она МОЖЕТ соблюдать — минимум странно.

          PS И да, что там с документацией, какой-нибудь прогресс есть? Без подначки, может у кого-то из форков выправили ситуацию? Год назад у оригинала было так же всё плохо.


          1. kaamos
            08.12.2016 17:08
            +1

            А я здесь никаким сравнением MySQL и PostgreSQL не занимаюсь. Это у вас какой-то каскадный триггер на ключевые слова сработал. Я говорю, что два утверждения из статьи не соответствуют действительности и привожу примеры. PostgreSQL сообщество любит тиражировать такие байки.

            По поводу оффтопа — я могу вам рассказать о гораздо более серьёзных проблемах в MySQL, чем каскадные триггеры. Собственно, я это уже делал на Хабре и в докладах. Но действительно оффтоп же.


    1. printercu
      08.12.2016 17:04

      Пришлось тут связаться с mysql, после уже долгой работы с postgresql. Как же я рад, что постгре "не саблюдает" стандарт, и DDL тоже транзакционно выполняет. Очень не удобно откатывать половину миграции, если 2я половина дала сбой.


      И case-sensitivity тоже радует.


    1. Bozaro
      09.12.2016 11:03

      У меня, кстати, сложилось впечатление, что ни одна СУБД полностью не соответствует SQL стандарту.


      Касательно статьи, можно упомянуть более простой случай, где MySQL не соответствует SQL92.
      Речь идет про абзац:


      13.9 <update statement: positioned>
      
      6) The <value expression>s are effectively evaluated before updat-
         ing the object row. If a <value expression> contains a reference
         to a column of T, then the reference is to the value of that
         column in the object row before any value of the object row is
         updated.

      И иллюстрируется запросом:


      UPDATE foo SET a = b, b = a WHERE id = 42;

      Беда в том, этот запрос в MySQL эквивалентен:


      UPDATE foo SET a = b, b = b WHERE id = 42;


      1. kaamos
        09.12.2016 11:22

        А я кстати совершенно не спорю с утверждением «PostgreSQL лучше соответствует SQL стандарту, чем MySQL». Я кстати уже об этом писал.

        Но это же совсем не то, что PostgreSQL сообщество любит говорить. PostgreSQL сообщество любит говорить «PostgreSQL является SQL-совместимым» («PostgreSQL is SQL-compliant» в оригинале). Это враньё. И rdruzyagin это знает, но старательно это враньё переводит.


        1. rdruzyagin
          09.12.2016 11:51

          Как главный провокатор и распространитель вранья, прокомментирую)

          Алексей, рад вас видеть, мы тут как раз планировали вас пригласить к нам в гости предстоящим летом :) Надеюсь, что вы согласитесь.

          По существу теперь. Соглашусь, что утверждение про полноценный ACID является преувеличенным, и, вероятно, мне стоило добавить примечание переводчика на этом месте. Посыпаю голову пеплом)

          Насчет стандарта, в тексте написано, что «PG является SQL-совместимым», а не «PG строго соответствует стандарту SQL». Или я не прав, и эти два выражения надо отождествлять? Какова позиция строгих экспертов Хабра по данному вопросу (by the way, наименование стандарта, SQL:2011, он же ISO/IEC 9075:2011, все-таки упоминается в тексте, пускай и без прямой ссылки)?

          Насколько я могу судить, примерно то же самое пытаются изложить разработчики СУБД в этом разделе документации: https://www.postgresql.org/docs/current/static/features.html

          Я безмерно благодарен за вашу критику, Алексей, в будущем наша команда будет более внимательна в подборе материалов)


          1. Bozaro
            09.12.2016 11:54

            наименование стандарта, SQL:2011, он же ISO/IEC 9075:2011, все-таки упоминается в тексте, пускай и без прямой ссылки

            Извиняюсь, если я был не правильно понят.
            Когда я говорил про отсутствие наименования стандарта, речь шла про статью: http://ocelot.ca/blog/blog/2013/09/30/sometimes-mysql-is-more-standards-compliant-than-postgresql/


            1. rdruzyagin
              09.12.2016 12:09

              Понял, значит это я некорректно истолковал ваши комментарии. Внезапно развернувшаяся баталия на тему MySQL vs. PostgreSQL сбила меня с толку.


          1. kaamos
            09.12.2016 12:00

            Роман, спасибо за развёрнутый ответ!

            На мой взгляд, нельзя соответствовать стандарту «нестрого». Стандарту можно либо соответствовать, либо нет. Поэтому утверждение «PostgreSQL is SQL-compliant (SQL:2011)» из оригинальной статьи ложно. А утвеждение из официальной документации «PostgreSQL supports most of the major features of SQL:2011» истинно. С другой стороны, утверждения «It is fully ACID compliant» и «Its SQL implementation strongly conforms to the ANSI-SQL:2008 standard» отсюда снова ложные.

            Про упоминания названия стандарта — это претензия относилась не к данной статье, а моей ссылке. Если я правильно понял.


            1. rdruzyagin
              09.12.2016 12:13

              ОК, позиция ясна и аргумент принимается. По вопросу ACID я полностью согласен, по вопросу конформирования стандарту — не совсем, но смысла спорить не вижу :)

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


              1. kaamos
                09.12.2016 12:33

                Хотел бы пояснить своё мнение по соответствию стандарту. Если принять, что фраза «PostgreSQL является SQL-совместимым (SQL:2011)» на самом деле означает «PostgreSQL соответствует SQL:2011 нестрого, в некоторой степени», то в этом же самом смысле можно сказать и «MySQL является SQL-совместимым (SQL:2011)». Ведь соответствует же. Нестрого, в некоторой степени, хоть и в меньшей, чем PostgreSQL. Поэтому я считаю, что с терминами нужно аккуратнее, это важный вопрос.


  1. merlin-vrn
    09.12.2016 10:36

    Поясните, в каком месте в статье описана именно эволюция отказоустойчивости? Эта статья — описание конкретной технологии, основанной на широко распространённой идее бинарных логов транзакций, вовсе не уникальной для PostgreSQL — та же MySQL, с которой его постоянно зачем-то сравнивают, умеет Point-In-Time Recovery с помощью своих Binary Log.


    Под эволюцией я бы понял, например, такое: была тупая база, крошилась при неожиданном убивании процесса. Потом это она научилась переживать, стала крошиться только при переполнении диска. Потом с этим научились бороться, но при внезапном отключении питания всё-таки данные портились. Потом и с этим научились бороться. А потом появился мульти-мастер кластер, можно писать на любую ноду, читать с любой ноды, если одна из них выйдет из строя — никто не заметит, т.к. остальные ноды подхватят всю нагрузку. Но в статье же ничего похожего нет.


    1. rdruzyagin
      09.12.2016 10:48

      Эта статья — первая из цикла статей, посвященных вопросу. В ней рассматриваются более фундаментальные аспекты архитектуры СУБД. Следующие выпуски будут освещать развитие иных средств из числа доступных пользователям PostgreSQL, не охваченных в текущем выпуске. Всего будет 4 публикации. Но того уровня детализации, который вы ожидаете, точно не предвидится, вынужден разочаровать.


      1. merlin-vrn
        09.12.2016 11:08
        +1

        Я заметил, что предполагается цикл статей. Я протестую против слова "эволюция" в заголовке. Эволюция — это то, как что-то там изменялось со временем. Вы про это, как менялось, собираетесь рассказывать? Если нет, то это не эволюция.


        Ну и, какой бы там ни предполагался цикл статей, вот этот заголовок относится к этой конкретной статье. И ей не соответствует.


        1. rdruzyagin
          09.12.2016 11:26
          -1

          Собираемся, конечно. Например, в следующей статье будет короткий экскурс в историю становления возможностей репликации в PostgreSQL.

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