Как стать автором
Обновить

Комментарии 58

можно ссылку на то, где их препарируют?
Вот несколько навскидку:
* http://use-the-index-luke.com/blog/2016-07-29/on-ubers-choice-of-databases
* https://blog.2ndquadrant.com/thoughts-on-ubers-list-of-postgres-limitations/
* http://rhaas.blogspot.ru/2016/08/ubers-move-away-from-postgresql.html
Действительно интересно, спасибо!
Только дискуссия у них что-то быстро заглохла: проблемы признали, а что делать не решили.
А за три года до этого, Убер перешел с MySQL на PostgreSQL
Да, есть такое дело.
Тот же самый автор — Evan Klitzke — писал об этом переходе: https://www.yumpu.com/en/document/view/53683323/migrating-uber-from-mysql-to-postgresql
Он, видимо, всё никак он не определится.
три года воздух толкает решая проблемы которые сам и создал. герой

Как водится, нет абсолютно плохих или абсолютно хороших систем, у каждой есть плюсы и минусы. А на разных этапах развития бизнеса вес плюсов и минусов может меняться.

Хорошо сказано!
Интересно еще бы узнать порядок цифр ежедневного объема обрабатываемых данных и финансовые выгоды/затраты при миграции с одной СУБД на другую
Немножко неочевидно вот это утверждение: "В Postgres на каждое соединение создается отдельный процесс. По сравнению с использованием потоков это более ресурсоемкое решение. На создание нового процесса требуется больше памяти, нежели на порождение нового потока."

Насколько знаю, fork() на сегодняшних компьютерах не копирует всю память — а только лениво копирует только те страницы, в которых что-то изменяется. Где-то на ютубе была лекция, в которой рассказывали, что это очень быстро и эффективно и используется в некоторых базах данных для практически мгновенного создания атомарного слепка базы: делаем fork- и имеем атомарный слепок, которых потихоньку пишем на диск, и при этом основной процесс может менять свою область памяти не опасаясь изменить еще не записанные данные.
Чем больше резидентная память процесса, тем дольше будет идти форк. На одном из тестовых серверов с более-менее современными процессором я намерял, что форк 1-гигабайтного процесса занимает порядка 7мс:

$ php -r '$a = str_repeat("ololo", 200 * 1024 * 1024); var_dump(getrusage()["ru_maxrss"]); $start = microtime(true); $pid = pcntl_fork(); if ($pid == 0) die; echo (microtime(true) - $start) . " sec\n";'
int(1031604)
0.0074088573455811 sec



Если у вас резидентный набор процесса будет 100 гигабайт, то это будет уже 750 мс.
По всей видимости, чтобы пометить каждую страницу памяти как copy-on-write — их надо все пробежать, возможно с подтягиванием каждой страницы в L0. Это конечно не копировать — но все равно какое-то время.

Навскидку:
#include <stdint.h>
#include <stdio.h>
#include <inttypes.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>

__inline__ uint64_t rdtsc() {
   uint64_t x;
  __asm__ volatile ("rdtscp\n\tshl $32, %%rdx\n\tor %%rdx, %%rax" : "=a" (x) : : "rdx");
   return x;
}

void test(size_t size){
    char * mem = (char *) malloc(size);

    uint64_t p;
    for(p=0; p<size; p++){
	mem[p] =(char) p%17;
    }

    uint64_t x = rdtsc();
    pid_t pid = fork();
    uint64_t diff = rdtsc() - x;

    free(mem);
    if (0==pid) exit(0);

    printf("%" PRIu64 "M -> %" PRIu64 "\n", size/(1024*1024), diff);
}

int main(){
int i;
for(i=0; i<14; i++)
    test(1024*1024LL*(1<<i) );
return 0;
}


результат(в тиках):

1M -> 378173
2M -> 421121
4M -> 429324
8M -> 438039
16M -> 447977
32M -> 477917
64M -> 554516
256M -> 980945
512M -> 1457601
1024M -> 2484345
2048M -> 4366125
4096M -> 7856287
8192M -> 15170437

Начиная с некоторого размера fork() с ростом размера время растет линейно. Когда размер памяти мал, то вероятно, работают кэши. На самом деле это может означать, что мой тест некорректен в этой части, но вцелом суть зависимости — ясна.
Еще было бы неплохо проверить, не включены ли transparent huge pages и просто huge pages. Потому что с большими страницами время форка будет минимально, но зато изменение любого участка памяти в чилде или в родителе будет приводить к копированию огромного (по сравнению с 4к) куска памяти, и соответственно будет быстрее кончаться память в системе, да и производительность будет оставлять желать лучшего.
худжпэджэсы не включены.

Что означает в этом контексте «да и производительность будет оставлять желать лучшего»? Про особенности копирования вы рассказали, очевидно, вы предполагали нечто еще.

Насколько понял из моей тестовой проги, производительность проседает после хипа 4гб: 8гиг заполнялось раз 10дольше, чем 4. Видимо, аппаратная TLB-таблица, или какая-то другая таблица заканчивается — и оно переходит на полусофтварный способ трансляции физических адресов в логические.
Только вот, с форком это уже никак не связано. Но очевидно, гигансткие хипы тормозные сами по себе. Интересно, где этот порог у ксеонов.

Кэши собственно данных, типа L0, в этом не участвуют, читать-писать основное содержимое страниц не нужно. А вот создать копию VM map процесса — задача достаточно затратная, включая карты physical maps с инкрементом счётчиков использования (вот тут наверняка кэш и насилуется).

Плюс к этому, при форке вся память помечается, как copy-on-write, и если будет, например, следующее, то рано или поздно родителя (или чилда) прибьют SIGKILL по OOM:

— системе доступно 10 Гб ОЗУ
— процесс жрет 8 Гб ОЗУ
— процесс форкается
— чайлд долго пишет свой снапшот на диск
— родительский процесс достаточно быстро модифицирует свою память и в итоге свободная память в системе кончается
fork, copy-on-write поможет

популярное заблуждение, посмотрите на популярность pgbouncer — это костыль именно для решения проблемы fork и вымывания набраного бакендом кэша (например дескрипторы открытых файлов ), но pgbouncer не решает проблемы полностью, например приходиться отказываться от prepared-statement

поднятие нового коннекcта в постгрессе где-то 500-1500ms (особой памяти там нет, кэш постгреса в разделяемой памяти — ее трогать не надо). когда в пулаз кончаются коннекты и начинают подыматься новые — заметно
так же детали обсуждаются в этом эпизоде SE Radio
https://softwareengineeringdaily.com/2016/09/09/ubers-postgres-problems-with-evan-klitzke/
имхо мое мнение человека не являющегося спецом ни в PostgreSQL ни в MySQL
вывод о недостатках при потерях быстродействия при модификациях данных входящих в кластерный индекс весьма надуманы т.к. назначение кластерного индекса физический порядок хранения данных, то есть в кластерный индекс нужно первично заложить константу, то есть данные которые не будут изменяться, при построении любого индекса предусматривающего модификации нужно запланировать необходимый процент заполнения, т.е. свободного места необходимого под быстрые модификации до процедуры реиндексации.

в противном случае все эти выводы с употреблением высокопарных научных терминов выглядят как некое самооправдание.но сработает оно только «для начальства». любой спец подвох раскусит.

а вот если постгри допускает вывод дублирующей записи при условии нарушения уникальности заданного для таблицы ключа — то это недочет критического уровня. если этот баг реально есть -значит эту субд просто нельзя использовать вообще нигде и никогда.

я полагаю что поле id определенное как примари кей в постгри предоплагает что оно уникально без каких либо дополнительных действий (как это в других, нормальных субд)
очень и очень много ковырял приложения как водительское так и пользовательское… могу сказать, что код писали индусы… криво, косо, не эффективно и иногда вообще адски! Планирую об этом статью написать

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

Напишите, пожалуйста. Очень интересно почитать.
Я как вспомню необходимость использования в качестве PK не автоинкрементируемое число, а строку (GUID) и метод LAST_INSERT_ID() — так мурашки по коже идут и плакать хочется. Возможно сейчас ситуация совсем другая, давно не использовал MySQL.
Не понял почему инженеры из Uber не воспользовались Slony или Bucardo для репликации…
Беглым поиском не смог найти информацию об объёмах данных с которыми им приходится работать, количество запросов к БД на чтение/запись. А интересно было бы знать такое :)
Думаю, следует ждать через несколько лет статью о том как они мигрировали с MySQL на PostgreSQL.
вы слишком сложно ударились в тему.

Вот для примера:
когда вы пассажир и смотрите в приложение, то вам показывается как движется автомобиль. На самом деле данные не реалтайм, а построены на фильтре Калмана. Слава богу что они додумались его использоваться. Но вместо того, чтобы открывать сокет и передавать в него данные, водительское приложение через HTTP запрос передает свои координаты, а сервер ему возвращает поллинг интервал когда сообщить в следующий раз.

В итоге получаем, что водитель уже на месте, а у пользователя по фильтру калмана водитель проехал дальше на пару километров вперед. А все потому что сервер ответил водителю передать свои координаты через 3 минуты, допустим. И это самый банальный пример.

А вы тут про guuid и инкременты.
Рассуждаю в контексте темы новости :)

А гуиды вам чем не угодили?

НЛО прилетело и опубликовало эту надпись здесь
В любой РСУБД надо понимать, что master-slave нужен для сохранения горячего резерва и использование реплики для получения всегда актуальных данных это из области фантастики. В том числе и в случае MySQL.

Большой ли смысл держать на одном сервере БД более сотни соединений (не говоря уже о тысячах)? TPS от этого не вырастет, зато накладные ресурсы от переключений контекстов и расхода памяти будут весьма велики (что в форках, что в потоках).

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

То нужно использовать PgBouncer, о чём написано в каждой доке по развертыванию постгреса в продакшене.
Так убер же написал, что итак используют pgbouncer, разве нет? И даже пишут об этом:

Accordingly, using pgbouncer to do connection pooling with Postgres has been generally successful for us. However, we have had occasional application bugs in our backend services that caused them to open more active connections (usually “idle in transaction” connections) than the services ought to be using, and these bugs have caused extended downtimes for us.


Собственно, странно зачем нужен отдельный pgBouncer, если можно было встроить это прямо в БД?
Очень интересно — они не пробовали «большие» СУБД типа оракула или MS?
слишком просто

Ещё и деньги платить надо. Откуда у Uber столько денег?

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

«Усиление записи» — несуразный термин, ближе по смыслу говорить «раздувание записи».
Согласен, «раздувание записи» по смыслу ближе, но мне лично слух режет.

«Усиление записи» достаточно часто встречается в Интернете (в том числе на Хабре, Гиктаймс, 3dnews и др.): https://yandex.ru/search/?lr=11&msid=1489328416.72813.22886.28344&text=«усиление записи».
Мне этот термин по душе, хоть и не очень точно отражает суть.

У англичан amplification, судя по http://www.oxfordlearnersdictionaries.com/definition/english/amplification?q=amplification, имеет два основных значения: «усиление» и «добавление комментариев, пояснений». Какой смысл они имели в виду при создании термина write amplification? Мне кажется, что у них это тоже «усиление» в переносном смысле.

Как вариант, у генетиков можно позаимствовать вариант «амплификация».
Раздувание, мне тоже режет слух, может быть что-то вроде «избыточная запись» или какой-то синоним?
Статья хоршо написано, но что будет если у MySQL нет в таблице первичного ключа, или такое невозможно?

Это больше относиться к движку, чем к MySQL.
В InnoDB если нет, явного PK или UNIQUE создается скрытый ключ.

MySQL давно не free. Звонили из Oracle и требовали денег, кроме шуток. Перешли на Percona.

Переход в Uber проплаченный — ради шумихи, стопудов.

Платили конечно не Uber, а кому-то из разработчиков.

Э-э-э, а можно поподробнее про требовали денег? Это как вообще?

В 2012 работал в компании, которая выпустила коробочный вебапп. Формата дистрибуции было два — исходники и образ для виртуалки. Во втором стоял MySQL. Звонили из Oracle, предлагали купить лицензию. Спросил, что нам за это будет — сказали, что опубликуют на сайте Oracle в каком-то далеком каталоге в числе партнеров. За сим все.

Поменяли БД.

Между "предлагали купить" и "требовали денег" есть разница, не находите?

Вы об этом?
Коммерческая лицензия позволяет производителям оборудования, независимым поставщикам и реселлерам распространять коммерческие исполняемые файлы программного обеспечения MySQL с их собственным коммерческим программным обеспечением, не подвергая, что программное обеспечение с лицензией GPL и его требование распространять исходный код.
[машинный перевод]

Источник.

Мне вот тоже интересно. Единственный случай при котором они имеют право требовать деньги — нарушение GPL лицензии. То есть переход на Percona ситуацию не меняет так как будет то же нарушение.

Есть еще люди, которые думают, что свободное ПО = бесплатное ПО. Это совсем не так.
Percona — не MySQL, и это меняет ситуацию в корне.

Старая тема но соображения такие:


  1. Да, проблеммы у Postgres есть, и Uber наткнулся только на маленькую часть. Но конкретно их проблемму вполне можно было бы сильно уменьшить если общаться с сообществом. (уже сейчас улучшения есть)
  2. Но главная проблемма Postrges которую никто не пытается исправить это дизайн >20 летней давности. Postgres развивается небольшими шажками без серьёзных рефакторингов из-за этого, код это ужасная лапша и архитектура сильно устарела, а у сообщество не может и не хочет что то менять. Отчасти из-за архитектуры и языка Си, развите postrges сейчас крайне сложное дело. Архитектурные пробелы это процессы, а не потоки и самопальный буфер менеджер вместо iommap. Не говоря уже про организацию tuple. На данный момент в аналитических запроссах большая часть времени уходит на процесс разбора тюплов. heap (сторадж данных) прибит гвоздями, индексы отваязаны но с ограничениями.

Простите за этот сумбур, я думаю тут надо писать целую статью, но общий вывод в том что postgres распространяется под BSD лицензией и его развитие это мягко говоря политическая игра между несколькими игроками… из-за этого реально нужные вещи просто не делаются.


PS но при этом, это хорошая СУБД и наверное одна из самых лучших, особенно что касается фичь SQL и расширябельности. Только вот насколько долго она такой останется?

Когда люди начинают писать мы начали использовать schemaless то сразу возникает вопрос зачем вам РСУБД?

Судя по профилю их нагрузки, им нужен был redis + что то для логов. (это если брать именно обновление позиции машины и статуса заказа) Им просто в большей части нагрузки MVCC нафиг не упёрся.

В свое время, решал такую же задачу — стали писать в Cassandr'у. Нафига им РСУБД — непонятно.
НЛО прилетело и опубликовало эту надпись здесь

Интересно было бы почитать обстоятельный разбор и других субд.


Я могу про OrientDB рассказать. Там, каждая нода (процесс на том или ином севере), содержит некоторое число "кластеров". Каждая нода может содержать разный набор кластеров, на этом основано партицирование и репликация. Каждая "таблица" (на самом деле класс документов) кладётся в один или несколько кластеров. Каждый кластер — 2 файла: один со страницами данных фиксированного размера, другой с маппингом идентифакаторов на номера страниц. Полный индентификатор записи (RID) имеет вид "#1:2", где первое число — номер кластера, а второе — помер записи. Именно этот идентификатор хранится в индексах и других таблицах. Благодаря распределённому конфигу, каждая нода знает какие кластеры на каких нодах лежат, так что по RID сразу понятно куда делать запрос, что даёт встроенный map-reduce. При обновлении, субд старается изменить данные на месте, если хватает места, предварительно записав, что собирается делать в WAL. Если выделенных страниц не хватает, то выделяются новые страницы, по всей видимости по принципу связанного списка. Индексы не распределённые, так что они и не реплицируются — каждая нода создаёт свои индексы по прилетевшим к ней данным. Соответственно MVCC идёт на каждой ноде свой, а уникальный индекс по партицированной базе будет уникальным лишь рамках одной ноды. OrientDB поддерживает распределённые транзакции, так что облом на одной из нод приведёт к откату транзакции, но какое-то время обновление будет доступно на тех репликах, где транзакция прошла. Короче уникальные индексы по партицированной базе лучше не делать. Рекликация, соответственно, происходит на уровне записей.

Зарегистрируйтесь на Хабре, чтобы оставить комментарий