Comments 119
Ещё мы очень хотим нормальную работу с диском. В плане дискового I/O PostgreSQL сильно проигрывает Oracle.
А кто-нибудь может "развернуть" это предложение, что именно не так с I/O PostgreSQL?
P.S. Давно это было… мог и соврать.
у оракла есть многоблочное чтение (scattered read), когда по DMA одной SCSI командой достает 128 блоков напрямик в память.
А под какой ОС он это умеет? В linux например можно работать с блочными устройствами напрямую минуя кэши из user-space, но штатного интерфейса для работы с DMA из user-space не предусмотренно.
Под нашей нагрузкой postgres по I/O проигрывал в 4 раза. И как показал PGCon 2016, разработчики postgres'а в курсе всех проблем.
Например, нельзя отдать без малого всю память под разделяемый кэш, потому что алгоритм вытеснения буфера очень паршивый. Приходится активно использовать page cache, которым сложно управлять + двойное кэширование. Или нет нормального асинхронного I/O, потому что поддерживается 100500 платформ, во многих из которых этого и близко нет.
Вот только… Практический каждый параграф просто просится развернуться в отдельную техническую статью :)

Т.е. вас не менее 4-ёх человек.
Команда бэкенда почты сильно больше. Но во время миграции сделали и запустили много несвязанного с переездом, потому и человеко-годы.
Ребята из Oracle не приходили с предложениями возобновить сотрудничество на новых условиях?
явно было бы на порядок дешевле переезда на постгрес
а менять одну рсубд на другую путь в никуда, яндексу явно надо было куда-то в сторону бигдата смотреть, hadoop/spark скорее всего
У них явно не 30 ядер работают, а раза в 2-3 больше. 15-20 процев, на пальцах.
Стоимость SE на несколько лет все равно была бы под полляма.
Минус партиции, которых на SE никогда не будет, минус стэндбай.
по партишанам во первых у них партиций и так нет, во вторых в SE есть partition view (PARTITION_VIEW_ENABLED)
http://www.sql.ru/forum/actualutils.aspx?action=gotomsg&tid=801747&msg=9747235
т.е. эти лапти могли бы на SE архивированные года уносить на HDD свежие года на SSD, объединять вьюшкой и оптимизатор оракла сам бы догадывался (partition elimination) не трогать таблицы 2010 года, если обращение идет к 2017 году.
SE мы рассматривали как альтернативу, но сейчас можно уверенно сказать, что мы сделали правильный выбор.
Да, это был более сложный путь, но не надо думать, что для SE не пришлось бы ничего переделывать. И потом оно, конечно, дешевле EE, но прямо скажем, не бесплатно :)
ИМХО, надо вообще убрать тогда все упоминания NOSQL из текста статьи 2017 года, т.к. в те годы оно было никакое.
А сейчас эффективность утилизации железа у того же Mongo на порядки круче, чем у Oracle (а не в 3 раза хуже, как у PG). По крайней мере на моих проектах.
Впрочем, подозреваю, что информация о том, что PG в 3 раза неэффективнее Oracle тоже устарела.
Вся история происходила в 2012-2016 гг. И утверждение про слабую применимость NoSQL (особенно нахваливаемой вами MongoDB) для нашей задачи всё ещё актуально и в 2017-м.
5 лет (даже с 2012) в мире ИТ это разные эпохи.
Mongo 2.1 из 2012 примерно такой же монго 3.4 как и mysql3 и mysql10 :)
Поэтому мнение про слабую применимость остается лишь мнением. Ещё и поданным без тезисов. :)
Я, как диванный эксперт и хэйтер кустарных решений, вообще бы максимально использовал промышленные решения: линуксовый dm-cache для разделения горячих и холодных данных и гибридные НЖМД. А не патчи, скрипты, хранимочки и синюю изоленту. Вполне возможно что работало бы не хуже, а время разработки было бы не десяток человеко лет, а несколько месяцев.
Скажем так, в Яндекс.Диске самая большая инсталляция MongoDB в мире. Да, версия 3.0 была большим шагом вперёд, но наш опыт (а не пустое мнение, как вы пишите) говорят о слабой применимости монги для задачи Яндекс.Почты. Да и сейчас ребята из 10gen ещё детские болячки долечивают — https://jepsen.io/analyses/mongodb-3-4-0-rc3.
Разделение данных на горячие/холодные внутри шарда мы только хотим сделать, а не сделали. И кучу времени мы потратили совсем не на это. Рекомендую вам сначала почитать статью/посмотреть презентацию или видео, прежде чем писать комментарии про синюю изоленту у нас.
1) Откуда и почему появилась мешанина бекэндов?
2)
Остальные проблемы связаны не столько с Oracle, сколько с тем подходом, который мы использовали.
То есть все причины к отказу от Oracle по сути сводятся к дороговизне? Или все же у варианта PostgreSQL есть инструменты которые решили проблему автоматизации, а у Oracle нет?
3) Перед решением о переезде считали ли итоговые затраты Oracle+железо+доработки с PostgreSQL+железо+доработки? Получился ль реальный экономический выигрыш?
«Яндекс.Почта» — сервис достаточно старый: он был запущен в 2000 году, и потому мы накопили много legacy.
Но главная причина перехода — это деньги. Oracle стоит дорого.
У нас сейчас в 3 раза больше железа под PostgreSQL, но это ничто по сравнению со стоимостью Oracle.
Про стоимость возник вопрос из-за:
Мы не придумали ничего лучше и запатчили barman, вот pull request. Уже почти год прошел, как мы их просим запилить эту киллер-фичу, а они просят с нас денег, чтобы замержить её.
Сравнивать стоимость одного железа с стоимостью лицензии Oracle как-то абстрактно и не показательно.
Мне приходят на ум варианты, когда итоговая стоимость переноса выше из-за суммы: покупок доработок к PostgreSQL, стоимости разработки переноса и самого переноса, стоимости оборудования с учетом его обслуживания (больше места, электроэнергии, охлаждение, замена вышедшего из строя, больше техников).
Неужели нереально было было сделать перенос с Oracle на Oracle с исправлением легаси?
Видимо, не смогли убедить начальство. «У нас всё и так работает, а мы влупим кучу денег и переделаем, и всё будет снова работать, но хуже, пока все баги не вычистим». Догадываюсь, куда их послали. А вот на экономию за счёт отказа от Оракла купились.
Не было задачи избавиться от legacy. Просто решили, что переезд на postgres — это хороший шанс упростить себе жизнь в будущем.
Вам уже ответили комментарием ниже. Сложный проект за долгие годы активного развития умеет обрастать костылями.
В докладе честных два слайда про причины и слайд с результатами, там ведь всё расписано. Кроме денег получили более простой deploy кода и нормальные разработческие окружения. Попробуйте, например, оракл в докер засунуть.
- Считали, получился.
Ну, мы вроде и так вклад вносим. В barman, pg_repack, pg_rewind есть наше участие. В самом postgres'е при нашем активном участии в 9.6 появились зачатки wait interface'а. Надеюсь, дальше будет больше :)
Время у меня правильное…
Вся логика переноса — это ~ 5k строчек кода на питоне.
Перенос можно запустить либо руками (скрипт/jenkins job), либо это делает автоматика по весьма тупым критериям (не шевелился никак кроме покладки полгода — в sata и т.п.). Сейчас думаем в это место вкрячить ML, чтобы критерии самим не прописывать.
FK, конечно же есть, многие из них deferrable. Потому данные переносятся потаблично в правильном порядке. Параллелизма для пользователя нет (один пользователь — один поток). Потребление памяти константное, потому что копирование делается поточно с помощью COPY пачками фиксированного размера.
Глобально же перенос выглядит так. Открываются транзакции в шард-источник, где пользователь блокируется на запись, в шард приёмник и в шарпей. В случае успешного переноса всё коммитится с 2PC. В случае ошибок откатывается. Во время переноса ящик пользователя в read-only, но это в общем случае не проблема, потому что ящик на 10**5 писем переносится за единицы секунд.
Существуют ли внешние ссылки на данные в базе (например мыло или другие ключи), я так понимаю когда происходит перенос, то кто-то внешний знает где лежит конкретный ключик?
Можете подсказать что такое `шарпей` :)?
Шарпей — это наш сервис шардирования, который хранит соответствие пользователя и шарда. И в нём, конечно, при переезде происходит обновление данных. Про это есть в презентации.
Что касается разделения данных на горячие и холодные внутри шарда, то стоит об этом подумать, хотя я бы предпочёл, чтобы база про это знала при планировании запросов. А подскажите какое-нибудь программное решение для linux'а?
Неужели SAN медленнее, чем просто диски в сервере? Там же FC, кеши, вот это всё… Или вопрос сугубо экономический?
По поводу программного тиринга на Linux говорят что-то про lvmts, но личного опыта не имею, поэтому советовать ничего не стану
Удивительный вопрос от людей, которые «всё учли» и «10 человеколет переписывали скрипты». А Dm-cache ещё в 2013 в ванилле (3.9) появился.
И снова я вам порекомендую внимательно почитать, в этот раз комментарий от Botkin. В нём есть ссылка, по которой можно увидеть, что нахваливаемый вами dm-cache не является решением для automated tiering.
Ещё раз повторю, что 10 человеко-лет мы потратили совсем не на "скрипты". И фраз "всё учли" я что-то тоже не припоминаю.
Опять же. Говорю только на основе скриншота и слов того форумного собеседника.
Скоро я чувствую придется съезжать с Yandex.PDD обратно на свой почтовый сервер, пусть нас зальет спам, но это лучше, чем не получать или не отправлять вовремя почту клиентам.
До Gmail Yandex.Почте как до китая пешком.
PostGreSQL хорош своими коммьюнити, но это будет не всегда. Чем больше будет серьезных проектов, где «большие деньги»крутятся и отвественность большая, все захотят, что бы советчики «отвечали» за свои советы. И все разом махнет из открытой коммьюнити на какой-нибудь платный сервис. Хотя не спорю — у Оракл поддержка — это нечто запредельное. И тогда вот станет не понятно, стоило ла овчинка выделки, тем более, что железа уже сейчас стала в 3 раза больше: «Без ложек дёгтя не бывает. У нас сейчас в 3 раза больше железа под PostgreSQL, но это ничто по сравнению со стоимостью Oracle.»
Начнём с того, что речь не про сообщество PostgreSQL, а про mainteiner'ов одного околопостгрешного проекта (barman). И все эти ребята работают строго в одной компании (2ndQuadrant-it).
И мы (люди снаружи) прислали им патч с реализацией крутой фичи, в лучших традициях open source разработки. А они не удосужились за год на него посмотреть. Имеют право, конечно, но IMHO как-то некрасиво.
Все последующие ваши рассуждения мне не очень понятны.
В PostgreSQL мы используем barman, и в нём под бэкапы нужно места минимум в 5 раз больше, чем размер базы
Интересно, а нельзя логировать именно запросы к БД в виде журнала? Такое должно хорошо сжиматься. То есть создать один неикрементный бэкап, а потом накапливать историю изменений. Можно какой-то велосипед было соорудить, который бы такое делал, или неэффективно?
Нет, нельзя, это сломает point in time recovery. Кроме того, уже есть WAL (в postgres'е бинарный), который мы храним.
1. Бэкендов, которые что-то модифицируют в базе, много. Время на них, конечно, синхронизируется, но NTP не даёт нужной точности.
2. Даже если предположить, что время идеально синхронизировано, в READ COMMITTED (уровень изоляции по-умолчанию и мы используем его) видны изменения уже закомиченных конкурентных транзакций. Транзакция А могла прочитать что-то, что было закомичено в транзакции B, но завершиться после транзакции C, которая изменений в B не видела в момент чтения. Потому 100% консистентности достичь будет сложно.
3. Накатывать такой логический лог запросов с параллелизмом сложно, а в один поток оно упрётся в одно ядро при хоть какой-то нагрузке. Именно потому в postgres'е WAL бинарный и накат на репликах легко справляется одним ядром, не отставая, упираясь в ядро.
Транзакция А могла прочитать что-то, что было закомичено в транзакции B, но завершиться после транзакции C, которая изменений в B не видела в момент чтения
И в чём суть конфликта? Не очень понял пример. Вы наверное имелди в виду наоборот, что C со своими устаревшими данными завершится после A?
Например, в транзакции B в табличке foo заменили какое-то поле с 1 на 2 во всех строчках. Транзакция C читает чиселку из foo и получает 1, потому что B ещё не закоммитилась. Транзакция C записывает вычитанную чиселку в табличку bar и делает что-то ещё, повисая на блокировке. Транзакция B коммитится, транзакция А читает чиселку из foo (получает уже 2), пишет её в табличку baz и коммитится. Транзакция C успешно коммитится. Итого на мастере получается следующая картина маслом:
foo: 2,
bar: 1,
baz: 2.
Если же теперь повторить транзакции на реплике по времени коммита, то получится вот так:
foo: 2,
bar: 2,
baz: 2.
Отсюда вывод, что применять такой лог запросов по timestamp'у коммита нельзя, а другого timestamp'а у вас как бы и нет. Можно было бы писать timestamp каждого statement'а (вернее, когда БД вернула ответ на него), но во-первых, это уже включает в себя передачу по сети, которая может вносить произвольный лаг, а во-вторых, это не покрывает работы триггеров или хранимую логику.
Короче, реализовать свою логическую репликацию сильно сложнее, чем кажется. Не стоит так делать.
partitioned view + partition elimination замечательно бы развели бы старые майлы на HDD, свежие на SSD. выглят что в яндексе просто не было хардкорного ораклойда.
Вы правда считаете, что Яндекс много лет жил почтой на оракле и до сих пор живёт другими сервисами без хорошей экспертизы в оракле!? Если да, то я вас разочарую, вы ошибаетесь.
Что касается архитектуры, то не всё мы рассказывали/рассказываем. И потому это всё было в формате доклада на конференциях, а не статьи на Хабре, чтобы на какие-то вопросы можно было ответить в кулуарах, а не публично.
опять же по своему опыту, если бы у вас были бы хардкорный ораклойды, они бы бились за оракл до последнего (как я) и вариант с SE1 edtion + partitioned view как минимум серьезно бы продемонстрировали бы.
наверно стоит оговориться что это не потому что постгрес тормозной, а потому что стали горизонтально масштабироваться
Мне уже давно интересно, как настолько отличный сервис могут отдавать просто так.
У Постгресса партиции настраиваются вручную и им можно указать tablespace, который физически м.б. размещен хоть на харде, хоть на ssd, хоть в ОП. Я так и делаю, вынося горячие данные в оперативку.
Или вы что-то другое имеете ввиду?
Во-первых, партиций много не создашь, время планирования сильно деградирует. Во-вторых, нужен триггер на insert.
Эти проблемы решает pg_pathman, который мы используем в одном проекте (на наш взгляд он пока сыроват, но ребята оперативно его штопают), и нормальный partitioning, который закоммитили в 10-ую версию.
В-третьих, теряется ссылочная целостность на секционируемые таблицы, что не есть хорошо.
В-четвёртых, далеко не все запросы в таблички с письмами делаются с фильтром по полю, по которому производится секционирование. И эту проблему без изменения логики приложения не победить.
Но что для вас «нормальный partitioning»?
Решение проблем 1-3 из моего предыдущего комментария.
Declarative partitioning — https://www.depesz.com/2017/02/06/waiting-for-postgresql-10-implement-table-partitioning/ — в 10-й версии должен решать первые две проблемы.
Для тех, кто впервые увидел этот материал, очень рекомендую посмотреть слайды — https://simply.name/ru/slides-pgday2016.html — или лучше видео (только на английском) — https://simply.name/video-pgcon2016.html.
А то редакторы и копирайтеры местами поломали смысл. Ну и откровенные ошибки есть. Например, trench вместо range или web-интерфейс вместо wait-интерфейса.
Это — не первая наша попытка избавиться от Oracle. В начале нулевых была попытка переехать на MySQL, она провалилась. В 2007 или 2008 была попытка написать что-то своё, она тоже провалилась. В обоих случаях был провал не столько по технически причинам, сколько по организационным.
Ящик у меня с 2000 или 2001 года, а вот письма с 30 марта 2006… обидно ж!
i_box_uid_lids
воспользоваться расширением btree_gin
и создать другой индекс с аналогичным назначением: gin (uid, lids)
. Или такой индекс будет в чем то уступать «чистому» gin?
История успеха «Яндекс.Почты» с PostgreSQL