Важно: данный пост написан разработчиком YDB и основан на совместном исследовании с Евгением Ефимкиным, экспертом в области PostgreSQL, не работающим в YDB.
Общеизвестно, что PostgreSQL - крайне эффективная СУБД с богатой функциональностью. Энергичное сообщество PostgreSQL значительно повлияло на то, какие возможности современные СУБД должны предоставлять разработчикам и пользователям. При этом не секрет, что PostgreSQL масштабируется только вертикально и её производительность ограничена возможностями одного сервера.
Написано много хороших постов, в которых сравнивают архитектуру монолитных и распределенных СУБД. Например, рекомендуем этот. К сожалению, обычно авторы ограничиваются теоретическим сравнением и не приводят конкретные цифры. Данный пост же наоборот основан на эмпирическом исследовании с использованием бенчмарка TPC-C, который является промышленным стандартом для оценки производительности транзакционных СУБД (On-Line Transaction Processing, OLTP).
Наш подход крайне прост. Есть три сервера, в каждом из которых 128 ядер CPU, 512 GiB RAM и четыре NVMe-диска. Настраиваем СУБД так, чтобы переживать выход из строя одного из серверов. Размер датасета должен быть не менее 1 ТиБ. Запускаем бенчмарк TPC-C на 12 часов (мы покажем, что даже это не так уж и много, чтобы тщательно проверить работу СУБД).
Учитывая, что не существует универсальной общепринятой конфигурации PostgreSQL, нам пришлось попробовать разные варианты. Мы начали с менее надежного, но наиболее производительного без лога записи (WAL) и репликации. Постепенно мы пришли к варианту конфигурации с двумя синхронными репликами, менее производительному, но соответствующему нашим требованиям в плане отказоустойчивости. Затем мы сравнили полученные результаты TPC-C на PostgreSQL с результатами двух хорошо известных распределенных СУБД с открытым исходным кодом: CockroachDB и YDB.
Пост получился достаточно большой, поэтому сначала мы расскажем о результатах, а потом погрузимся в технические детали. Но сперва вспомним, что такое TPC-C.
TPC-C
TPC-C - это «Единственная объективная методика оценки производительности OLTP», — CockroachDB.
«Наиболее реалистичное и объективное измерение производительности OLTP-систем», — PingCAP.
«На протяжении нескольких десятилетий TPC-C является одним из наиболее популярных бенчмарков OLTP-систем и используется для определения стоимости и эффективности системы. Он полезен в оценке общей производительности OLTP СУБД», - YugabyteDB.
Мы уже писали о TPC-C и его реализации для YDB. Кроме того, мы рассказали об особенностях TPC-C для PostgreSQL. С тех пор единственное значимое изменение в TPC-C для PostgreSQL - замена c3p0 на HikariCP. Мы не стали повторять уже написанное, ниже лишь кратко опишем метрики TPC-C, необходимые для понимания результатов наших тестов.
Цель TPC-C - выполнять как можно большее число транзакций "новый заказ" в минуту (метрика называется tpmC) при заданных ограничениях на время выполнения (latency) этих транзакций. Например, на 90-м персентиле время выполнения транзакций "новый заказ" не должно превышать 5 секунд. Важной особенностью бенчмарка является то, что максимальный tpmC на один склад ограничен: чтобы получить больше tpmC, надо добавить больше складов, а каждый склад это дополнительно 100 МиБ данных. В данном посте в случаях, когда число tpmC близко к максимально возможному, для простоты вместо tpmC мы указываем число складов и эффективность - сколько набрано tpmC от максимального для данного числа складов.
Важно не забывать, что TPC-C - это только стандарт, описывающий бенчмарк, у которого нет официальной реализации. Ни одна из используемых нами реализаций TPC-C, включая реализацию для CockroachDB, официально не сертифицирована организацией TPC. Но все реализации очень точно следуют спецификации TPC-C версии v5.11.0. Это означает, что результаты, опубликованные нами, не являются официально принятыми TPC результатами и несопоставимы с другими результатами теста TPC-C, опубликованными на сайте TPC.
Тестовый стенд
Наш стенд для тестирования производительности — это кластер из трех физических машин со следующей конфигурацией каждой из них:
128 логических ядер: два 32-ядерных процессора Intel Xeon Gold 6338 с частотой 2,00 ГГц с включенным гипертредингом;
512 ГБ ОЗУ;
4xNVMe диска Intel-SSDPE2KE032T80;
скорость передачи данных в сети 50 Гбит/с;
в случае Postgres включены huge pages, при тестировании распределенных СУБД включены transparent huge pages;
Ubuntu 20.04.3 LTS;
Ядро Linux версии 5.4.161-26.3.
Настройки PostgreSQL
Мы используем PostgreSQL версии 16.2 (Ubuntu 16.2-1.pgdg20.04+1). В итоговой версии стенда мы используем два RAID-0, каждый из двух NVMe-дисков. Один RAID 0 используется для WAL, второй - под данные. Ниже приведены настройки Linux:
# we have a write intensive workload:
# background ratio is decreased, dirty ratio is increased
sudo sysctl -w vm.dirty_background_ratio=5
sudo sysctl -w vm.dirty_ratio=40
# Based on our config, see https://www.postgresql.org/docs/current/kernel-resources.html#LINUX-HUGE-PAGES
# sudo -u postgres /usr/lib/postgresql/16/bin/postgres \
# -D /opt/postgres/postgres/16/main \
# -c config_file=/etc/postgresql/16/main/postgresql.conf \
# -C shared_memory_size_in_huge_pages
sudo sysctl -w vm.nr_hugepages=67129
# disable overcommit
sudo sysctl -w vm.overcommit_memory=2
# max GHz
sudo tuned-adm profile throughput-performance
Создание RAID 0:
sudo mdadm --create /dev/md/md_db --assume-clean -l0 --raid-devices=2 /dev/nvme1n1p2 /dev/nvme0n1p2
sudo mdadm --create /dev/md/md_wal --assume-clean -l0 --raid-devices=2 /dev/nvme2n1p2 /dev/nvme3n1p2
Форматирование RAID-дисков:
mkfs.ext4 -F -m 0 -E lazy_itable_init=0,lazy_journal_init=0,discard
При монтировании дисков мы используем noatime
.
Здесь можно посмотреть на полный конфиг PostgreSQL. TPC-C запускается на 5 клиентах, каждый по 60 сессий.
Настройки YDB
YDB версии 24.1.10. На одной машине работает 1 узел хранения данных (с привязкой к 32 ядрам CPU) и 6 вычислительных узлов (каждый привязан к своим 16 ядрам). Полную конфигурацию (близка к конфигу по умолчанию) можно найти здесь. Мы запускаем 3 клиента TPC-C, в сумме используется 3000 соединений с базой.
Настройки CockroachDB
Мы используем CockroachDB 23.1.10. К сожалению, в более свежей версия 23.2.2 мы нашли [проблему]((https://github.com/cockroachdb/cockroach/issues/119924), из-за которой у нас не получилось провести тесты TPC-C. Похожая проблема присутствует и в 23.1.10, но согласно мнению команды CockroachDB, в 23.1.10 она вызвана перегрузкой кластера.
Для каждого диска мы запускаем один экземпляр CockroachDB в привязке к 32 ядрам. Каждый инстанс использует 37,5 ГБ оперативной памяти для кэша и еще 37,5 для SQL. Мы применяем рекомендуемые настройки базы. Здесь представлена конфигурация, используемая нашими установочными скриптами. Отметим, что мы не используем partitioning, который является коммерческой фичей CockroachDB. Мы избегаем этого, так как существуют сценарии, когда partitioning данных, как в TPC-C, невозможен.
Результаты
Напомним, что цель TPC-C - достичь максимального tpmC, оставаясь в пределах ограничений на время выполнения транзакций. На диаграмме видно, что PostgreSQL победил, набрав в 1.05 раз больше tpmC при обслуживании 18K складов с эффективностью 92.37%, чем YDB, обслуживающий 16K складов с эффективностью 98.57%. При этом YDB набрал в 1.29 раз больше tpmC, чем CockroachDB (12K складов, эффективность 97.8%). Однако, важно отметить, что время выполнения транзакций в PostgreSQL хотя и в пределах ограничений, но намного хуже, чем у обеих распределенных СУБД:
Обычно существует размен (trade-off) между пропускной способностью (tpmC) и временем выполнения транзакций: чем больше значение tpmC, тем выше время выполнения транзакций. Так, при обслуживании 16K складов YDB достигает своего самого высокого значения tpmC, сохраняя время выполнения транзакций в пределах ограничений, заданных TPC-C. Но для некоторых продакшен сценариев такие задержки могут быть слишком большими. Поэтому мы также привели результаты для YDB и 13K складов (эффективность 99.24%): при уменьшении числа складов (и соответственно tpmC) время выполнения транзакций значительно улучшилось и стало сопоставимым с CockroachDB, при этом YDB все равно набрала немного больше tpmC, чем CockroachDB.
Ниже приведено время выполнения транзакций "Новый заказ", измеренное клиентом PostgreSQL TPC-C:
Хорошо видно, что задержки не смогли выйти на плато и график по форме напоминает синусоиду. Каждый пик совпадает с началом записи чекпоинта, и мы видим, что сессии "висят" в ожидании IPC: SyncRep
. Несмотря на все наши старания, у нас не получилось решить эту проблему. В случае PostgreSQL мы смогли получить более адекватное время выполнения транзакций, только уменьшив число складов до значений, ниже 10K. В следующем разделе мы подробно опишем, как мы решали различные проблемы с производительностью Postgres'a и занимались тюнингом.
Если сравнить эффективность, то PostgreSQL на машине с лидером потребляет всего 15% CPU. Мы пришли к выводу, что репликация является единственным узким местом - мы наглядно покажем это в следующем разделе. Это означает, что скорее всего PostgreSQL показал бы точно такой результат на серверах, где меньше ядер CPU, чем у нас. Распределенные СУБД наоборот менее эффективны в плане CPU и загружают почти все ядра на 100%, но при этом показывают гораздо лучшее время выполнения транзакций, что отчасти можно считать разменом CPU на лучшие задержки.
Таким образом, с одной стороны наши результаты показывают исключительную эффективность PostgreSQL. Но с другой стороны они сильно ниже наших ожиданий, основанных на общепринятом мнении, что распределенные СУБД показывают себя во всей красе только при большом количестве машин в кластере. В какой-то степени мы развенчали этот миф.
Стоит отметить, что все рассматриваемые в данном посте распределенные СУБД достигают больше одного миллиона tpmC на обычном железе путем добавления дополнительных машин в кластер. Ниже приведен пример предварительных тестов масштабируемости YDB. Мы постепенно увеличивали размер кластера до 9, 18 и 36 машин, не меняя конфигурацию YDB. Результаты получены на версии, которая в разработке, но мы ожидаем аналогичные цифры у YDB версии 23. Хотя эти результаты неокончательные и могут быть улучшены, они хорошо подтверждают наше утверждение о масштабируемости распределенных СУБД:
В начале поста мы обозначили, что СУБД должна переживать отказ одной из машин, что в зависимости от расположения машин подразумевает возможность пережить выход из строя датацентра. Кроме того, мы подразумеваем, что при отказе одной из машин, клиентская нагрузка должна сразу переключиться на другую машину, чтобы избежать даунтайма. В некоторых случаях это слишком жесткие требования. Поэтому далее мы рассмотрим отказонеустойчивые ("fault intolerant") конфигурации PostgreSQL, которые при этом показывают беспрецедентную производительность.
Отказонеуcтойчивые, но фантастически высокопроизводительные конфигурации PostgreSQL
Настройка PostgreSQL уже давно стала отдельной инженерной специальностью. В случае бенчмаркинга основная проблема заключается в том, что если ты не уперся в железо, то трудно понять, достаточно ли хорош твой конфиг или надо продолжать тюнить PostgreSQL и Linux. А настроек бесчисленное количество, начиная от ввода-вывода и параллельного выполнения (I/O and concurrency) и заканчивая планами выполнения SQL запросов.
Чтобы с чего-то начать, мы решили сначала попробовать "unlogged"-таблицы без репликации (конфигурация "NoWAL"). При таком подходе нет накладных расходов на WAL и устраняется потенциальный ботлнек с репликацией, что максимально снижает время коммитов и позволяет достичь наибольшей производительности. Такая конфигурация помогает оценить эффективность операций чтения-записи данных базы с диска и реализацию выполнения SQL.
Затем мы добавили WAL, но настроили его так, чтобы максимально распределить ввод-вывод во времени. Для этого выставлен большой размер WAL и чекпоинты пишутся редко. Мы назвали эту конфигурацию "HugeWAL": из-за огромного времени восстановления (десятки минут, исходя из нашего опыта) после падения базы/ОС данная конфигурация не подходит для использования в проде, но дает ценную информацию для дальнейшей оценки производительности различных частей PostgreSQL.
В самом конце наших экспериментов мы, наконец, добавили две синхронные реплики ("R1"), на которые можно переключиться, если сломается лидер. Во всех трех конфигурациях мы использовали три NVMe диска в RAID 0 для хранения данных базы и один NVMe диск для хранения WAL. Пора посмотреть на результаты:
Согласно нашим наблюдениям во время всех прогонов было достаточно много свободного CPU и у диска оставалась пропускная способность на запись. Эксперименты показали следующее:
Благодаря конфигурации "NoWAL" мы узнали потенциальные ограничения производительности, вызванные либо выполнением SQL, либо задержками диска (RAID 0) при записи данных базы. Потребление CPU составляет 40 ядер, PostgreSQL пишет 1,5-2 ГБ/с (200-250K операций записи в секунду) и читает 2,3 ГБ/c (275K чтений/c).
Сравнение "HugeWAL" и "NoWAL" указывает, что снижение производительности вызвано накладными расходами на WAL. PostgreSQL пишет 800 МБ/c данных WAL (примерно 6.7K операций записи в секунду, т.е. размер записи 128 КиБ, что является лимитом нашей модели диска).
Относительно плохой результат "R1" вызван исключительно репликацией и никак не связан ни с ограничениями на выполнение SQL, ни WAL.
35K складов (450K tpmC) - это выдающийся результат, но только у "NoWAL" совсем нет отказоустойчивости. 29K складов, полученные "HugeWAL", тоже очень хорошо, и это именно тот результат, который мы ожидали получить в "R1". Зная, что Postgres точно может больше, мы занялись поиском проблемы с репликацией.
Первое, что бросилось нам в глаза, это то, что реплики пишут в 1.5-2 раза больше WAL, чем лидер. Например, когда лидер пишет 250-450 МБ/с (в среднем 4K записей/c), реплики пишут 500-800 МБ/с. К сожалению, точного объяснения этому у нас пока нет.
Но зато это подсказало нам сосредоточиться на WAL. Мы воспользовались procstat, чтобы получать в реальном времени данные о работе дисков. Очень рекомендуем procstat, потому что этот инструмент крайне полезен и при этом прост в использовании. Посмотрим внимательно на скриншоты procstat, показывающие работу диска с WAL.
Лидер:
Реплика:
Хорошо видно, когда Postgres пишет чекпоинты. Но самое интересное, что реплики не только пишут больше, но еще и с задержками выше в 10-30 раз: единицы миллисекунд против сотен микросекунд на лидере. Это натолкнуло нас на мысль, что у реплик узким местом является именно WAL.
Чтобы как-то решить эту проблемы, мы попробовали следующие настройки:
bgwriter_delay = 20
bgwriter_lru_maxpages = 4192
wal_buffers = 256MB
wal_writer_delay = 400
commit_delay = 200
checkpoint_completion_target = 0.99
checkpoint_flush_after = 2MB
Это не помогло и мы зашли с другой стороны: стали использовать два диска в RAID 0 (вместо трех) для данных базы и другие два диска в RAID 0 для WAL. Более того, чтобы ускорить коммиты, мы переключили synchronous_commit
с on
на remote_write
. При такой настройке коммиты на репликах могут потеряться в случае падения машины (например, из-за проблем ОС). Но при этом уменьшение времени коммита должно ощутимо улучшить производительность - в некоторых случаях допустимый компромисс.
При такой конфигурации у нас получилось выполнить двухчасовой прогон TPC-C с 20K складами. Однако, когда мы увеличили время до 12 часов, мы обнаружили ряд проблем. СУБД работала 5 часов, после чего на репликах заканчивалось место под WAL. В следующие 3 часа дайнтайма, они усердно применяли и чистили свой WAL. Если уменьшить число складов до 17K, то можно добиться успешного выполнения бенчмарка в течение 12 часов. Любопытно, что после окончания выполнения бенчмарка, реплики активно нагоняют лаг еще 3 часа:
tpcc=# SELECT pid,application_name,client_addr,client_hostname,state,sync_state,replay_lag FROM pg_stat_replication;
pid | application_name | client_addr | client_hostname | state | sync_state | replay_lag
---------+------------------+----------------------------------+-----------------+-----------+------------+-----------------
1250777 | s1 | 2a02:6b8:c34:14:0:5a59:eb1f:2ca6 | | streaming | sync | 02:56:10.114747
1250824 | s2 | 2a02:6b8:c34:14:0:5a59:eb1f:2956 | | streaming | sync | 02:52:11.340846
Из-за этого реплики не могут использоваться для горячей замены лидера: в случае его падения, им потребуется значительное время, чтобы нагнать лаг, а это потенциально часы даунтайма. Кроме того, если WAL постоянно растет, то рано или поздно место под него закончится. А когда заканчивается WAL, лидер перестает обрабатывать запросы пользователей, что согласно нашим экспериментам приводит к многочасовому даунтайму.
В итоге, для решения проблемы с лагом мы поставили synchronous_commit
в значение remote_apply
. Это финальный конфиг PostgreSQL, при котором он смог обслуживать 18K складов. replay_lag
при данной настройке пренебрежительно мал и можно быстро переключиться на реплики при возникновении проблем с лидером. В данной конфигурации лидер потребляет достаточно мало ресурсов:
20 ядер CPU;
400 МБ/с (6K записей/с) пишется WAL и 600 МБ/с данных базы (80K записей/с);
чтение данных базы составляет 700 МБ/с;
пиковое потребление сети составляет 9 Гбит/с.
Каждая из реплик:
пишет 800 МБ/с WAL и 500 МБ/с данных;
пиковое потребление сети 4 Гбит/с.
Заключение
Число вариантов оборудования, настроек PostgreSQL и видов нагрузки бесконечно. В этом посте мы изучили ограничения PostgreSQL на конкретном железе под нагрузкой TPC-C. Читатели нашего блога, возможно, помнят, что это наши стандартные серверы для исследования производительности. И, конечно, как и все разработчики СУБД, мы очень любим TPC-C.
Мы признаем, что PostgreSQL действительно очень эффективная СУБД в плане CPU, даже сильно выше наших ожиданий. Отказонеустойчивые конфигурации PostgreSQL показали фантастические результаты, что делает Postgres отличным выбором, когда отказ сервера (одного датацентра) и даунтайм не проблема. Это так же очевидно, как то, что Земля вертится.
Но если нужны надежность и отказоустойчивость, а даунтайм неприемлем для бизнеса, то для работы любой СУБД требуется несколько машин. Нас очень удивило, что репликация в PostgreSQL является настолько узким местом, что так сильно влияет на результаты TPC-C. Кроме того, в некоторых продакшен сценариях значительные пики задержек могут быть серьезной проблемой. Возможно, есть какое-то решение этой проблемы, о котором мы не знаем. Напишите, пожалуйста, в комментариях к посту, если знаете о каком-то волшебном переключателе, который мы не попробовали.
К счастью, когда одного Postgres'a становится мало, выход есть. Несмотря на распространенное заблуждение, распределенные СУБД показывают хорошие результаты даже на небольших трехнодных кластерах. Более того, на примере YDB мы показали, что распределенные СУБД предоставляют отличную возможность легко масштабироваться, позволяя сконцентрироваться на разработке приложения, а не нюансах настройки СУБД.
Благодарности
Это исследование выполнено при содействии и тесном сотрудничестве с Евгением Ефимкиным, экспертом в PostgreSQL.
Мы выражаем особую благодарность Андрею Бородину, активному контрибьютеру в PostgreSQL и разработчику Одиссея, масштабируемого пула сессий. На протяжении нашей работы Андрей оказывал нам всяческую поддержку.
Общение с Frits Hoogland было крайне продуктивным, и он поделился с нами очень полезным инструментом procstat.
Приложение: latency транзакций
PostgreSQL (18K)
Transaction |
50%, мс |
95%, мс |
99%, мс |
---|---|---|---|
NewOrder |
32 |
3000 |
3500 |
Payment |
32 |
3000 |
3500 |
Order-Status |
9 |
3000 |
3500 |
Delivery |
32 |
3000 |
3500 |
Stock-level |
16 |
3000 |
3500 |
YDB (16K)
Transaction |
50%, мс |
95%, мс |
99%, мс |
---|---|---|---|
NewOrder |
128 |
512 |
1000 |
Payment |
64 |
256 |
512 |
Order-Status |
64 |
128 |
256 |
Delivery |
512 |
2000 |
3500 |
Stock-level |
32 |
256 |
512 |
YDB (13K)
Transaction |
50%, мс |
95%, мс |
99%, мс |
---|---|---|---|
NewOrder |
64 |
256 |
256 |
Payment |
32 |
64 |
128 |
Order-Status |
32 |
128 |
128 |
Delivery |
256 |
512 |
1000 |
Stock-level |
16 |
128 |
256 |
CockroachDB (12K)
Transaction |
50%, мс |
95%, мс |
99%, мс |
---|---|---|---|
NewOrder |
36 |
105 |
193 |
Payment |
19 |
65 |
117 |
Order-Status |
9 |
26 |
50 |
Delivery |
65 |
184 |
302 |
Stock-level |
19 |
44 |
75 |
Комментарии (26)
ptr128
20.03.2024 17:34PostgreSQL масштабируется только вертикально и её производительность ограничена возможностями одного сервера
PostgreSQL имеет все необходимые средства для горизонтального масштабирования. Другой вопрос, что в ванильном PostgreSQL предоставляется только низкоуровневая поддержка. Но на её базе вполне работает тот же Greenplum.
eivanov Автор
20.03.2024 17:34Как разработчик СУБД, я бы с удовольствием послушал более конкретно об этих средствах.
ptr128
20.03.2024 17:34Мультимастер репликация и партиционирование, которое средствами FDW может быть шардировано.
P.S. Доказывание преимущества своего программного продукта методом минусования оппонентов говорит уже о многом. А ведь я ни слова не сказал о недостатках YDB.
eivanov Автор
20.03.2024 17:34Давайте попробуем разобраться, есть ли мультимастер в PostgreSQL. Вот статья в официальной вики postgresql: "As a result, current streaming replication in PostgreSQL provides only fault tolerance (HA), but not scaling performance". И это полностью совпадает с выводами нашего поста. Дальше в вики они предлагают Postgres-BDR (стороннее решение). Для полноты вот еще список альтернатив от Percona. И справедливости ради добавлю, что у postgres pro есть похожие решения. Все эти решения - самостоятельные сложные продукты. И причина их существования заключается именно в том, что PostgreSQL не масштабируется горизонтально. Очень странно, когда кто-то пытается доказать обратное.
Что касается минусов, то они не из-за YDB, а из-за того, что Ваши комментарии не совпадают с реальностью.
ptr128
20.03.2024 17:34Я написал десять слов в первом предложении. Почему Вы заметили из них только первые два?
provides only fault tolerance
Распределенное хранение данных - это не только шардирование, но и их дуплицирование для отказоустойчивости. И если первая задача решается партиционированием через FDW таблицы, то вторая - именно репликацей.
Ваши комментарии не совпадают с реальностью.
Ваши, как видите, тоже
eivanov Автор
20.03.2024 17:34В этой презентации (PGCon 2020) очень хорошо рассказывают о том, почему в FDW нет ACID распределенных транзакций.
К сожалению, наш диалог так и остался неконструктивным.
ptr128
20.03.2024 17:34К сожалению, наш диалог так и остался неконструктивным.
Само собой, если Вы ссылаетесь на презентацию четырехлетней давности, когда 2PC в PostgreSQL еще не было.
eivanov Автор
20.03.2024 17:34Само собой, если Вы ссылаетесь на презентацию четырехлетней давности, когда 2PC в PostgreSQL еще не было.
В презентации указано, что требуется не только 2PC. И за четыре года так все проблемы и не решили. Из описания atomic commit of distributed transactions на вики постгреса (в презентации это слайд "Atomic Visibility"):
Distributed transaction involves, atomic commit, atomic visibility, and global consistency. 2PC is the only practical solution for atomic commit.
...
-
Concurrent readers can see an inconsistent result, for example, when a reader starts a new foreign transactions on two foreign servers after the writer committed the prepared foreign transaction only on the one of the foreign server?
Yes. This feature ensures only atomic commit, but not atomic visibility. To support the globally consistent results, other mechanisms such as providing a globally consistent snapshot will be required.
ptr128
20.03.2024 17:34А Вы не обратили внимание, что эта страница не правилась с ноября 2020 года?
Описанная ситуация возможна только в случае, когда "reader" использует 2PC, а "writer" - нет. Только в этом случае "writer" не будет использовать GID. Именно по этой причине в документации указано, что "
PREPARE TRANSACTION
is not intended for use in applications or interactive sessions"Понятно, что руками с этим мало кто будет разбираться. Намного проще добавить расширение, которое это будет обеспечивать прозрачно. Или Вы считаете, что команда "CREATE EXTENSION citus;" превращает ванильный PostgreSQL сразу не в ванильный?
eivanov Автор
20.03.2024 17:34Авторы citus'a в статье, описывающей его архитектуру, очень чётко написали об ограничениях распределенных транзакций в citus (п. 3.7.4 Multi-node transaction trade-offs):
Multi-node transactions in Citus provide atomicity, consistency, and durability guarantees, but do not provide distributed snapshot isolation guarantees. A concurrent multi-node query could obtain a local MVCC snapshot before commit on one node, and after commit on another. Addressing this would require changes to PostgreSQL to make the snapshot manager extensible. In practice, we did not find a strong need for distributed snapshot isolation in the four workload patterns, and customers did not express a need for it yet. Most transactions in multi-tenant and CRUD applications are scoped to a single node, meaning they get isolation guarantees on that node. Analytical applications do not have strong dependencies between transactions and are hence more tolerant to relaxed guarantees.
Distributed snapshot isolation can be important in certain hybrid scenarios. However, existing distributed snapshot isolation techniques have a significant performance cost due to the need for additional network round trips or waiting for the clock, which increases response times and lowers achievable throughput. In the context of the synchronous PostgreSQL protocol, throughput is ultimately capped by #connections / response time. Since making a very large numberofdatabaseconnections is often impractical from the application perspective, low response time is the only way to achieve high throughput. Hence, we would likely make distributed snapshot isolation optional if we implement it in the future.
Фактически это eventual consistency. Вот отличный пример того, что это означает на практике. В конце поста приведены примеры задач, когда стоит использовать citus. И ещё один пост. Интересно, что в документации Citus это очень тяжело найти. Я нашёл только в одном месте про SELECT + COPY: "There is no notion of snapshot isolation across shards", только это касается и других случаев, а не только COPY.
Кроме того, шардирование не делает базу распределенной. Появляется координатор, который является единой точкой отказа. Кроме citus, надо ещё что-то типа Patroni (и etcd сбоку). И всё равно гарантии консистентности подойдут не всем приложениям.
ptr128
20.03.2024 17:34Вам не кажется, что Вы "откапываете стюардессу"?
2PC появился только в PostgreSQL 16. То есть, в сентябре 2023 года. Отсюда любые ссылки на статьи, вышедшие до этого - заведомо содержат устаревшую информацию.
До версии 11.2 Citus вообще отправлял на рабочие ноды исключительно TRANSACTION ISOLATION READ COMMITTED, научившись TRANSACTION ISOLATION REPEATABLE READ только в прошлом году. А вот поддержку SERIALIZABLE обещают только в следующей версии, так как ради нее потребуется отказаться от поддержки PostgreSQL до 15-ой версии включительно.
eivanov Автор
20.03.2024 17:34+1Вам не кажется, что Вы "откапываете стюардессу"?
"There is no notion of snapshot isolation across shards" из документации к citus 12.1. Самая свежая версия. И пост югабайта, который я привел в качестве примера, от 16 августа 2023 года.
До версии 11.2 Citus вообще отправлял на рабочие ноды исключительно TRANSACTION ISOLATION READ COMMITTED, научившись TRANSACTION ISOLATION REPEATABLE READ только в прошлом году.
Внимательно читаем changelog к 11.2:
By propagating the level Citus' semantics will be mostly correct for workloads without multi-shard queries (e.g. multi-tenant).
И это полностью совпадает с тем, что они писали о своей архитектуре в цитате, что я привел выше. Они определили для каких сценариев их продукт и продолжают работать в том же направлении.
2PC появился только в PostgreSQL 16. То есть, в сентябре 2023 года. Отсюда любые ссылки на статьи, вышедшие до этого - заведомо содержат устаревшую информацию.
Повторю ещё раз: 2PC решает проблему атомарного коммита, он не решает другие проблемы распределенных транзакций, о чем и написано в документации постгреса, когда бы она ни была написана: "Distributed transaction involves, atomic commit, atomic visibility, and global consistency. 2PC is the only practical solution for atomic commit." В статье о дизайне Citus пишут прямым текстом, почему они не хотят нормальные многошардовые транзакции - это размен на performance.
Если честно, я не понимаю, о чём мы спорим. Citus не поддерживает распределенные снепшоты: это специально заложено в архитектуру этой СУБД, это есть в документации к последней версии. Югабайт показали красивый пример, что это означает на практике, при этом честно рассказав, в каких случаях Citus хорошо подходит для использования.
ptr128
20.03.2024 17:34"There is no notion of snapshot isolation across shards"
which means that a multi-shard SELECT that runs concurrently with a COPY
Не профессионально обрубать предложения, существенно искажая их смысл.
И пост югабайта, который я привел в качестве примера, от 16 августа 2023 года.
И тем более не профессионально не знать, что август до сентября.
2PC решает проблему атомарного коммита
Но в сочетании с уникальным и последовательно возрастающим GID - решает.
Если честно, я не понимаю, о чём мы спорим.
О том, что если сравнивать распределенную шардированную СУБД, то тоже с распределенной шардированной конфигурацией.
eivanov Автор
20.03.2024 17:34Не профессионально обрубать предложения, существенно искажая их смысл.
Если внимательно перечитаете, то увидите, что я об этом написал:
Интересно, что в документации Citus это очень тяжело найти. Я нашёл только в одном месте про SELECT + COPY: "There is no notion of snapshot isolation across shards", только это касается и других случаев, а не только COPY.
Можете и дальше считать, что Citus полноценная распределенная СУБД без каких-либо скрытых нюансов. Начиная с сентября 2023-го года, конечно.
ptr128
20.03.2024 17:34только это касается и других случаев, а не только COPY
На что никаких пруфов в случае Citus на PostgreSQL 16 предоставлено не было. То есть, это осталось лишь гипотезой.
Можете и дальше считать, что Citus полноценная распределенная СУБД без каких-либо скрытых нюансов. Начиная с сентября 2023-го года, конечно.
Я так не считаю, о чем писал выше: "А вот поддержку SERIALIZABLE обещают только в следующей версии, так как ради нее потребуется отказаться от поддержки PostgreSQL до 15-ой версии включительно."
Но это никак не влияет на то, что сравнение YDB с PostgreSQL производилось с шардированем в первой и без шардирования во второй, так как в сценарии TPC-C SERIALIZABLE совершенно не требуется.
-
mishamota
20.03.2024 17:34+1Ссылка https://franckpachot.medium.com/monolithic-vs-distributed-sql-f07af959e1a4 не открывается. Есть где-то на других ресурсах эта статья?
5exi
Этот пост не шутка!? Постгрес масштабируется только вертикально? Вы серьёзно сейчас?
eivanov Автор
Как я понимаю, Вы имеете в виду различные расширения и продукты на основе postgres. Некоторые из них просто шардируют, другие же занимаются реализацией полноценной распределенной СУБД. Но это не ванильный Postgres. И все эти решения появились именно за счет того, что одного Postgres'a мало - о чём мы и написали пост. К сожалению, у нас не было возможности измерить все существующие СУБД, но мы стараемся :)
Tatikoma
Шардирование работает и без расширений.
eivanov Автор
Всё равно есть какая-то сущность, которая знает о шардах. Конечно, можно сделать шардирование прозрачно для базы, утянув всю логику в приложение. И тогда вместо разработки прикладной логики заниматься реализацией распределенных транзакций, решать вопросы, связанные с консистентностью, распределенным снепшотом, перешардированием и т.п. Это крайне сложные вещи и очень легко посадить баги.
mishamota
Вы путаете партиционирование и шардирование. Или шардирование и репликацию.
ptr128
Если партиции FDW таблицы, то это и получается шардирование.
mishamota
Было бы круто, но, к сожалению, в этом случае пожертвуете атомарностью и изоляцией (из ACID). Шардирование для ACID СУБД это немного больше, чем распределение записи и чтения. Как минимум распределённые транзакции еще нужны с соответствующим уровнем изоляции.
ptr128
Так поддержка распределённых транзакций в PostgreSQL уже появилась.
eivanov Автор
Существуют разные уровни изоляции. 2PC не решает все проблемы. См. ниже в параллельной ветке про Citus и распределенный снепшот.