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

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

Некоторые сценарии, например продажа билетов, вообще невозможны без ACID гарантий.

Почему (применительно к продаже билетов)?
Нужно поддерживать уникальность пары — (сеанс\рейс, место) в масштабах всей системы. А CAP не рассматривает такую согласованность вообще, в CAP согласованность — прочитал то, что записал, не более того. Этого недостаточно для поддержки согласованности данных.
В MongoDB Cookbook есть пример надежного перевода денег с одного счета на другой, с возможностью отмены перевода, продажу билетов тоже можно сделать на двух-фазных коммитах. Поэтому это возможно.
Нужно поддерживать уникальность пары — (сеанс\рейс, место) в масштабах всей системы.
В MongoDB можно поддерживать уникальность.

Мне кажется вы сильно закапались в теорию.
Прочитал о ссылке и не понял: кто помешает двум параллельным транзакциям на шаге 2 попортить счета? Обеспечить независимость нельзя, поэтому и согласованность в смысле ACID будет страдать.

Кроме того такие «транзакции» требуют чтобы вся запись приходила в одну ноду, иначе две транзакции в разных нодах дадут рассогласованное состояние (см Факт №6).

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

Кроме того такие «транзакции» требуют чтобы вся запись приходила в одну ноду, иначе две транзакции в разных нодах дадут рассогласованное состояние.
Без разницы сколько нод, оно будет Eventual Consistency, так что все нормально.

Короче дока откровенно врет.
Вам нужно ознакомиться с инструментом прежде чем делать такие заявления.

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

А если эти записи пришли в разные ноды? Когда все чтения и записи выполняются в одной ноде, то мы получаем систему с C. Если несколько нод и возможны разделения, то или отказываемся от C и получаем AP или получаем CP систему. Причем в случае CP все чтения в итоге приходят в мастер-ноду и много надо становится бесполезными. Такая реализация CP была предложена Гилбертом и Линч в исследовании, другой, увы, я не встречал.

Без разницы сколько нод, оно будет Eventual Consistency, так что все нормально.

«Нормально» это как? Предположим что две транзации пришли в разные ноды, обе списали по $100 c баланса A и перевели на баланс Б. Обе завершились успешно, каждая на своей ноде. Но на балансе А было всего $150, а в минус естественно уходить нельзя. Корректность системы нарушена, более того, никаких хороших способов разрулить эту ситуацию нет.

Eventual Consistency работает только когда интервал межу операциями записи больше чем интервал достижения согласованности. Факт №7.
Рекомендую также прочитать исследование, ссылка в посте есть.

Вам нужно ознакомиться с инструментом прежде чем делать такие заявления.

Я знаком, более того, те баги, которые тут описываю видел вживую на монге. На этом знакомство и кончилось.
Вообще есть детальный разбор как оно в монге работает (вернее не работает) hackingdistributed.com/2013/01/29/mongo-ft/.

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


Извините, не понял что вы хотите сказать.
Предположим что две транзации пришли в разные ноды, обе списали по $100 c баланса A и перевели на баланс Б.
Это не возможная ситуация, потому что «Баланс А» в единственном экземпляре, и находится в одной ноде независимо от того на каких нодах находятся остальные данные (счета, транзакции, и пр. см. шардинг)
Тогда эта система будет не устойчива к разделениям, а монга позиционируется как AP система с eventual consistency. А если докрутить гарантии монги до строгой согласованности, то получится CP система, которая теряет доступность при пропадании связи, и даже выпадении отдельных нод.
монга позиционируется как AP система с eventual consistency
… и, как не трудно догадаться — это типичная маркетинговая чушь :)

По факту MongoDB
1) В каждый момент времени обрабатывает только один запрос (т.е. о параллельности там нет и речи). Как следствие тот же PostgreSQL выигрывает у MongoDB по скорости, если число операций записи высоко по сравнению с числом чтений.

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

3) Более того, в конфигурации по-умолчанию клиенту шлется ответ об успешности операции сразу после того, как мастер-нода обработалса запрос. Если получится так, что мастер-нода умерла и так и не вернулась потом обратно — информация о записи будет потеряна безвозвратно, а клиент так и останется уверен, что всё ОК.

Ну и опять же, если начинать крутить настройки Монги, чтобы она стала сопоставима по надежности/доступности с чем-то из обычных реляционных БД, то ВНЕЗАПНО оказывается, что Монга начинает работать во много раз медленнее и эти самые традиционные реляционные БД её обгоняют.
Монга практически всегда быстрее постгреса с полной сохранностью на запись, так как там действительно нельзя настроить полную сохранность :). Но все же можно добиться и хорошей скорости и надежности сделав кластер из монг. А вот сделать кластер из постгресов уже сложнее. Все таки на монгу нужно смотреть как на кластерную бд.
По поводу теории — именно так. После очередной отсылке к CAP я таки прочитал всю теорию и написал как теоретическая модель CAP выглядит и насколько расходится с реальным миром. Если конкретные СУБД опираются на это теоретическую модель, но проблемы встают в полный рост.
Нужно поддерживать уникальность пары — (сеанс\рейс, место) в масштабах всей системы.

А зачем для этого ACID, почему недостаточно eventual consistency?
А кто тогда помешает продать два билета на один и тот же сеанс? См факт №7
Именно продать не мешает никто, но вы и с ACID не сможете это сделать. А вот подтвердить продажу — то, что при попытке закоммитить вторую продажу будет обнаружен конфликт. Для этого, правда, требуется выполнение C из CAP — т.е. фиксированного порядка операций.
Да, с ACID будет ошибка и билет не будет продан, если его уже кто-то купил. А без acid — будет продано два билета на место.

Что касается Consistency из CAP, то это практически тоже самое, что Atomicity из ACID. См Факт №1
Давайте разберем последовательность действий. Сценарий покупки простой:
  • Пользователю показывается выбор свободных мест
  • Пользователь выбирает места
  • Пользователь совершает оплату (в современных реалиях это означает общение со внешней системой, не поддерживающей распределенные транзакции, причем время этой операции изменяется минутами)


Где будут границы ACID-транзакции(-транзакций)?
Обычно не такЖ
1) Пользователь выбирает места
2) Места бронируются (другой не может купить, но оплата еще не прошла)
3) Производится оплата
4) Места помечаются как оплаченные
5) Печатаются билеты

Гарантии нужны только на шаге 2.
Я описал сценарий с точки зрения пользователя, а не с точки зрения системы. Пользователь может и не знать про «бронирование мест».

Бронирование вечное?
Про какого пользователя речь? Кассира в кинотеатре ил покупателя билетов?

С точки зрения покупателя это все одна транзакция, и она таки должна быть ACID (или почти ACID):
1) A — должен одновременно потратить деньги и получить билет или не потратить и не получить.
2) C — должен получить столько билетов, сколько заказал
3) I — эти билеты не должны быть проданы кому-то еще
4) D — долговременность означает что он сможет по этим билетам попасть на сеанс

С точки зрения кассира — БД с билетами и платежная система — это разные системы. Как раз кассир обеспечивает их транзакционность, повторы и rollback_и. Если платежная система автоматическая (карты), то живой кассир не нужен, можно построить алгоритм, который даст гарантии покупателю.

Но для этого нужно чтобы нельзя было забронировать места двумя разными покупателями одновременно, а это требует ACID гарантий на уровне БД.

Бронирование не вечное, в автоматических платежных системах — 10-15 минут. Если места были забронированы, а ответ от платежной системы пришел после истечения интервала броинирования, то деньги покупателю возвращаются. Именно в возврате денег возможна согласованность в конечном счете, потому что возврат денег происходит ровно один раз и полностью независим от других транзакций. А вот при бронировании нужны ACID гарантии.
Покупателя билетов в интернете, конечно, 21 век на дворе.

Возьмем фрагмент сценария «Пользователь выбирает места — Пользователь совершает оплату», тот самый единственный, где, как вы говорите, нужна гарантия. Где-то между этими этапами пользователю показывают экран, на котором написано «вы выбрали места 1А, 1Б, 1В, сеанс 15:30, блаблабла, ОК?». Он нажимает на «ОК», в этот момент система показывает ему «ждите», после чего говорит «ок, идите оплачивать» или «упс, кто-то успел забронировать места, пока вы тупили». Так?

да, именно так.
И вероятно вы предполагаете, что между «ждите»/«ОК» система сделает честную ACID-транзакцию, внутри которой проверит, не забронированы ли места, и забронирует, если все хорошо, и ничего не сделает, если все плохо?
Проверка будет неявной. Сервис попытается в базу записать несколько строк, где ключом будет (сеанс, место), если хотя бы одна один ключ будет существовать, то транзакция откатится, а пользователь получит сообщение «простите, эти места уже куплены».
Прекрасно. А теперь посмотрите на два варианта реализации того же под eventual consistency:

Вариант 1:
(фронт)
— заслали команду «создать бронирование, id такой-то, места, сеанс, пользователь»
— зависли в ожидании событий
(бэк)
— получили команду на конкретной ноде, попробовали записать в БД
— если все ок — послали событие «бронирование id такой-то — ок»
— если получили дубль по ключу «сеанс-место» — послали событие «бронирование id такой-то — беда»
(фронт)
— дождались события с нужным id бронирования, обрадовали пользователя

Вариант 2:
(фронт)
— заслали команду «создать бронирование, id такой-то, места, сеанс, пользователь»
— начали поллить репозиторий бронирований на предмет статуса бронирования с нужным id
(бэк)
— получили команду на конкретной ноде, попробовали записать в БД
— если все ок — бронирование легло со статусом «ок»
— если получили дубль по ключу «сеанс-место» — бронирование легло со статусом «фейл»
(фронт)
— наконец-то получил ответ на поллинг, проверил статус, обрадовал пользователя

ACID нужен только внутри ноды (прямо скажем, для данного сценария — только внутри агрегата, отвечающего за бронь), между нодами достаточно гарантированного порядка выполнения операций.
Если вся запись приходит в одну и ту же ноду, то мы получаем систему, не устойчивую к разделению.
И в итоге ACID таки нужен.

Вы доказали то, что я писал.
А зачем нужно, чтобы вся запись была в одну и ту же ноду? Нужно только чтобы к ноде последовательно применялись либо все события (полное зеркалирование), либо события, удовлетворяющие критериям целостности в рамках БП (т.е., например, все события для одного сеанса; шардинг).

А ACID нужен не в системе целиком, а в рамках конкретной ноды, что совершенно не то же самое (собственно, насколько я понимаю, никто никогда и не утверждал, что можно построить систему, у которой нигде не будет ACID).
Полное зеркалирование неустойчиво к разделению, увы. Если разделений не случается, напрмиер в локальной сети — отличное решение.

Все билеты данные одного сеанса на одной ноде — вообще не распределенная система. Доступность её равна доступности базы.

Оба варианта дают строгую согласованность с точки зрения CAP.
Напомню что разговор начался с вашего вопроса:
А зачем для этого ACID, почему недостаточно eventual consistency?
Полное зеркалирование неустойчиво к разделению, увы.

Почему?

Все билеты данные одного сеанса на одной ноде — вообще не распределенная система. Доступность её равна доступности базы.

Вы забываете, что таких нод может быть бесконечное количество.

Оба варианта дают строгую согласованность с точки зрения CAP.

В рамках ноды. В рамках системы — eventual consistency.

Напомню что разговор начался с вашего вопроса:

… в котором я понимал ACID в рамках всей системы, а не одной ноды.
Почему?

Простой сценарий: два сервера, А и Б. Вся запись идет на A и зеркалируется на Б. Между А и Б прерывается связь, но оба сервера живы и доступны для клиента.

Варианты:
1) Продолжать писать в А, надеясь что скоро связь восстановится. Но если до сосстановления связи клиент переключится на Б по любой причине, то легко можно продать два билета на одно место. Теряем Согласованность.
2) Прекратить писать — теряем Доступность.

В этом плане нельзя обмануть CAP, нельзя создать одновременно доступную и согласованную систему при возможности разделений сети.

Вы забываете, что таких нод может быть бесконечное количество.

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

В рамках ноды. В рамках системы — eventual consistency.

В варианте с шардингом у вас нет одной системы, у вас несколько.

Если вы начинаете реплицировать данные между нодами, то у вас становится AP система, и появляется проблема как бы не продать два билета на одно место.

Если каждая нода может обращаться к каждому шарду, то у вас CP система, котора может быть недоступна при пропадании свзяи между узлами.

… в котором я понимал ACID в рамках всей системы, а не одной ноды.

Ну и вы сами в итоге предлагаете сделать ACID в рамках всей системы.
Простой сценарий: два сервера, А и Б. Вся запись идет на A и зеркалируется на Б. Между А и Б прерывается связь, но оба сервера живы и доступны для клиента.

[...]

В этом плане нельзя обмануть CAP, нельзя создать одновременно доступную и согласованную систему при возможности разделений сети.

Ну так CAP никто и не обманывает. Речь идет о том, что можно обойтись без глобального ACID.

Если вы начинаете реплицировать данные между нодами, то у вас становится AP система, и появляется проблема как бы не продать два билета на одно место.

Это почему?

Ну и вы сами в итоге предлагаете сделать ACID в рамках всей системы.

Отнюдь. Операции в рамках системы не атомарны, и именно вся система целиком будет консистентна только в какой-то момент времени.
Ну так CAP никто и не обманывает. Речь идет о том, что можно обойтись без глобального ACID.


Глобальный ACID вообще очень сложная штука, которая стоит сильно дороже, чем сама система. Но и eventual consistency не поможет, так как не дает гарантий. Поэтому обычно все забивают на partition tolerance и делают CA системы, которые еще и ACID умеют.

Это почему?

Точнее так: если у вас синхронная репликация, то получается CA, этот случай уже рассмотрели.
Если асинхронная, то AP. То есть может быть так что произошла запись на сервер А, но он упал и запись пошла на Б и продали два билета.

Отнюдь. Операции в рамках системы не атомарны, и именно вся система целиком будет консистентна только в какой-то момент времени.

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

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

Не может, если сохранен порядок следования событий.

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

Аналогично, просто следите за последовательностью событий, и все будет хорошо.
За счет чего следить? В какой момент?
При асинхронной репликации и падении А, в момент продажи билета Б не знает о том, что была запись в А. Может и вообще не узнать, если A в итоге не включится.
За счет чего следить? В какой момент?

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

(самое простое решение — хорошо резервированная очередь, но система с ее участием не толерантна к падению самой очереди)
Гарантии нужны только на шаге 2.
Например так в монге можно забронировать билет: (для примера, в реальных системах по другому)
db.tickets.findAndModify({ query:{ _id:1, booked:false }, update:{ booked:true } })

И у вас не получиться забронировать билет дважды, п. 2 выполняется.
И это тоже неверно:
1) По умолчанию монга не гарантирует что пользователь прочитает то, что записал даже на одной ноде. В итоге две бронирования одного и того же билета могут выполнится «успешно» в одной и той же ноде.
2) В случае если запросы приходят на разную ноду, то все еще хуже.
В итоге две бронирования одного и того же билета могут выполнится «успешно» в одной и той же ноде.

Это вранье.
Хватит сферической теории, приведите скрипт в качестве доказательства которым «гарантия» ломается (я же привел код).

До того момента продолжать разговор нет смысла, т.к. вы приводите ложную на практике информацию.
Наверно вы правы, при записи в одну ноду такое поведение получить не удастся. Но в случае падении ноды после восстановления не гарантированно данные сохранятся, а билет уже продан. Именно такой косяк я видел на практике. Добавление реплик не спасает по причине того, что согласованность между репликами теряется.
Но в случае падении ноды после восстановления не гарантированно данные сохранятся, а билет уже продан.
Это уже другой вопрос, но и для этого есть решения, например write concern, это позволяет, при обновлении документа, указать (минимальное) кол-во нод, на которые «запишутся» изменения прежде чем документ будет считаться записанным.

Из доки: «Например, 'w: 2' показывает подтверждения от primary и по меньшей мере один secondary.», таким образом, если изменения не ушли на 2 ноды, то можно паниковать, откатывать транзакцию, и т.д.
Это не другой вопрос, а тот же самый. C в CAP требует сохранения порядка даже при падении отдельных звеньев.

например write concern, это позволяет, при обновлении документа, указать (минимальное) кол-во нод, на которые «запишутся» изменения прежде чем документ будет считаться записанным.


Если количество реплик N, а минимальное количество нод, на которые надо записать M, то при любом M<N можно продать два билета на одно место. Другая проблема, что теряется устойчивость к разделению — если при разделении сети нода, на которую пришла запись может достучаться до нод, общем количеством меньше M, то или теряем согласованность записи, или доступность (или крутимся в retry-цикле пока связь не восстановится).
Но в случае падении ноды после восстановления не гарантированно данные сохранятся, а билет уже продан
Для этого в монге есть журналирование, из доки: «MongoDB uses write ahead logging to an on-disk journal to guarantee write operation durability and to provide crash resiliency.»
И тут можно считать что вопрос закрыт — NoSQL данную задачу решает.

По поводу нескольких нод:
Если количество реплик N, а минимальное количество нод, на которые надо записать M, то при любом M<N можно продать два билета на одно место.
Если прикинуть что нода падает раз в год (хотя на моей практике, ещё реже), то шанс что 2 ноды упадут в один момент, стремиться к нулю, и этого достаточно (хотя кол-во нод можно поднять).

если при разделении сети нода, на которую пришла запись может достучаться до нод, общем количеством меньше M, то или теряем согласованность записи, или доступность
Если сеть «расколется», то будет работать только тот кусок где есть арбитр, остальные куски «встанут» и клиент получит фейл. Тут же можете манипулировать с M, N, т.е. есть варианты.

А что вы будете делать с *SQL и несколькими нодами?
MongoDB uses write ahead logging to an on-disk journal to guarantee write operation durability and to provide crash resiliency.
Это по умолчанию так работает? Помоему даже в текущей версии монга говорит что все ОК сразу после принятия команды и до записи в лог.

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

Если мы начинаем рассматривать вероятности, то оказывается что вероятность разделения сети равна нулю в локальных сетях.

Если сеть «расколется», то будет работать только тот кусок где есть арбитр, остальные куски «встанут» и клиент получит фейл. Тут же можете манипулировать с M, N, т.е. есть варианты.
Это называется кворум.

А что вы будете делать с *SQL и несколькими нодами?

Прекрасно, только дорого выходит.
Это по умолчанию так работает? Помоему даже в текущей версии монга говорит что все ОК сразу после принятия команды и до записи в лог.
Это регулируется с помощью «write concern», можете часть команд выполнить «до журнала», часть «после журнала», часть после «репликационной ноды».
То есть приложение должно разбираться на сколько нод нужно сохранить, чтобы хотя бы уменьшить вероятность продать два билета на одно место? Гарантировать то все равно не выйдет в случае M<N.

А как приложение должно узнать сколько нод сейчас живы?

А если записи будут приходить на разные ноды? Или все идет только в одну?
Помоему даже в текущей версии монга говорит что все ОК сразу после принятия команды и до записи в лог.
Подтверждаю.
А что вы будете делать с *SQL и несколькими нодами?

Обычно master-slave репликация. При падении мастера выбирается другой мастер.
То есть приложение должно разбираться на сколько нод нужно сохранить
можно настроить дефолтное поведение, а вообще это гибкость, например для логов и комментариев это не обязательно.

А если записи будут приходить на разные ноды? Или все идет только в одну?
Обычно master-slave репликация. При падении мастера выбирается другой мастер.
в монге реплика работает подобным образом.
можно настроить дефолтное поведение, а вообще это гибкость, например для логов и комментариев это не обязательно.
Отвечу цитатой своего комментария выше:
Ну и опять же, если начинать крутить настройки Монги, чтобы она стала сопоставима по надежности/доступности с чем-то из обычных реляционных БД, то ВНЕЗАПНО оказывается, что Монга начинает работать во много раз медленнее и эти самые традиционные реляционные БД её обгоняют.
Есть подозрение, что ребята демонизируют CAP теорему. Она нужна не для того, чтобы «что-то там решить а потом запилить универсальный всемогутор и вот». Она нужна для того, чтобы когда молодые, амбициозные и креативные тим лиды в команде уже вторую неделю пилят «универсальный фреймворк для обеспечения надежности нашей распределенной базы данных» им можно было сказать «хватит нарушать CAP теорему, идите работать». Без наличия сформулированной теоремы разъяснение им всех нюансов требует существенных затрат времени и маны. А тут уже все сфрмулировано — даешь им вечер на почитать после чего берешь тепленькими и отправляешь работать. Удобно.
Очень мало кто пилит системы, где разделения появляются достаточно часто, чтобы это стало проблемой.
И я о том же. Зато у очень многих стартапов молодые, амбициозные и креативные разработчики, которые хотят решать интересные задачи «на всякий случай» и «потому, что это интересно» :).
Если кому интересно более основательно углубиться в сабж, могу рекомендовать замечательную книжку Фаулера: "NoSQL Distilled"(здесь есть годная рецензия от SergeyT ). Книга содержит обстоятельное обсуждение CAP теоремы и выводов, которые из нее вытекают.
Разделение сети — крайне редкое явление в наше время. Гилберт и Личн прямо заявляют, что системы, работающие в локальной сети, можно считать не подверженными разделению.

Как писали Стругацкие, «Вы мне это прекратите!».

«Крайне редкое» — понятие очень растяжимое. 61 раз за 700 дней — это по вашему «крайне редкое»? А ведь такую статистику по одному проекту собрали в Google. Имхо, если случай возникает чаще двух раз в неделю, то распределенная программная система должна проектироваться с учетом такого случая.

Вот тут выжимка из целой коллекции исследований на тему: An informal survey of real-world communications failures

Если бы для каждого «факта» в вашей статье были какие-то свидетельства, его подтверждающие, то доверие вашей статье было бы куда больше. А так — вброс вбросом.

Я долго «не верил» в CAP-теорему, считая ее модным приемом технического маркетинга. А потом почитал доказательство и ряд других работ, которые пытались его опровергнуть или подвергнуть сомнению, а также работ, которые, наоборот, подтверждали правильность доказательства. Я склонен доверять научному методу познания окружающего мира, даже если из-за этого мне приходится перестать верить в некоторые чудеса.
Прочитайте исследование для начала. Network partitions — это когда отдельные звенья продолжают работать, но не могут обмениваться сообщениями.

Падение сервера — не является network partition. Падение коммутатора тоже не является, потому что сервер становится недоступен для любых клиентов и это эквивалентно падению сервера.
На практике я ни разу не видел разделения сети. А вы видели?

Набор фактов составлен из того же исследования Гилберта и Линч, почитайте сами.
На практике я ни разу не видел разделения сети. А вы видели?

Кластер из RabbitMQ в двух ЦОДах, связанных двумя магистральными оптами, получил «split brain» 4 раза за месяц, пока его не разобрали. Да, руки кривые. В результате — переделали на 2 независимых подсистемы. Но не надо о том, что разделения сети не бывает.
Повторю. Речь о разделении сети в локальных сетях.
Мне казалось, что CAP справедлива в любых сетях :) От того что сеть не локальная она только чаще ведёт себя как asynchronous network.
Почитайте исследование. Сами исследователи подмечают, что в локальных сетях можно считать, что partitions не случаются.
Возможно, бывают ситуации, когда маршрут между дата-центрами проседает и скорость обмена между узлами не удовлетворяет лимиту по времени генерации ответа пользователю. Может звенья и «могут» обмениваться сообщениями, но если они это делают раз в полчаса — это, видимо, говорит о том, что критерии разделения сети размыты.
Если узлы обмениваются раз в полчаса, то это убьёт или consistency, или availability. Хотя с таким определением availability его потеря не столь страшна.
Ребята уже упоминали про связь между датацентрами. Но у меня подобная ситуация возникала в AWS внутри одной availabilty zone. Конечно, никто не знает, какая именно там топология сети, но факт есть факт.
Серверы не видели друг друга, но были доступны извне?
Да, именно вариант «split brain» — от примерно сотни машин с одинаковой конфигурацией отвалились 8. Проблему обнаружили, когда начал кидать ошибки сторонний сервис, куда и основная часть, и отщепенцы одновременно писали противоречивые метрики. Все дело продлилось минут 40.

Но если честно, кто его знает, как там у Амазона сетка организована. Может, тоже иерархия свитчей какая-то, невидимая с точки зрения виртуалок.

Было явно понятно, что какой-то из ряда вон выходящий случай, и мы так и не смогли решить, как данные объединить. Решили просто похерить все, что те 8 серверов насоздавали.

Я еще думаю, что раз все эти ребята — и Google, и Facebook, и Bashoo, и другие вендоры — так упирают на этот случай, значит, действительно актуальная для них проблема. Вопрос в том, актуальна ли она для «простых смертных». Мы тогда забивали, но было неприятно потом баланс сводить и рефандить недовольных клиентов.
а у вас не было кворумов и подобной фигни?

Availability zone, насколько я понимаю, гарантирует как раз то, что два сервера в одной az одновременно не будут отключены. Для этого их размещают как минимум в разных стойках.

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

Вопрос в том, актуальна ли она для «простых смертных». Мы тогда забивали, но было неприятно потом баланс сводить и рефандить недовольных клиентов.
то есть у вас была ap система. если не секрет, то что использовалось?
На практике если в сети 5к машин и роутеры выстроены в иерархию — как нефиг делать. Например когда вылетает верхнеуровневый коммутатор образуются несколько островов где 1) есть связь внутри каждого осторова 2) есть интернет потому, что он через другую сеть.
В теории да, а на практике какой смысл размещать систему в разных сегментах, если сеть локальная? Кроме того пользователи ходят через те же коммутаторы, поэтому чаще всего отказ коммутатора приводит к недоступности серверов.
Чтобы 5к машин не простаивали из за сбоя одной железки? Потому что для некоторых задач хорошо подходят всякие хитрые топологии (fat-tree)? В больших кластерах типично может быть 3-4 сети: 1) интернет через ethernet (если он нужен на каждом узле), 2) infiniband/10g ethernet для обмена данными 3) одна или несколько служебных сетей ehternet
Имхо с CAP можно побороться за ACID, если выйти за плоскость только софтверных решений. См например research.google.com/archive/spanner.html
Не надо бороться с CAP за ACID, Spanner это каноничная CP-система. Аппаратное решение там уменьшает время простоя, но система будет работать корректно и без него.
кто-нибудь обязательно вспомнит о CAP-«теореме»
Если это вы про мой комментарий в теме про MongoDB, то я-то как раз имел ввиду изначальную формулировку, которая, конечно же, никакая не теорема, а гипотеза, основанная на общих соображениях.

С исследованием ознакомился, спасибо. Мне кажется, вместо уточнения формулировок там подгон под решение — специально выбраны такие формулировки, чтобы получилось что-то формально доказать. Ну, то есть, они доказали что-то другое :)
Если говорить о терминологии, то для гипотезы имеющей экспериментальное и теоретическое обоснование, больше подходит аналог физического принципа или постулата.
В начале написано, что формулировки не из воздуха появились, а после общения с Брюером.
>> AP системы в чистом виде бесполезны.
Да, ладно. Мемкеш на нескольких нодах при включенном failover`е более полезен, чем его отсутствие. Ну бедет чуть другой кеш иногда показываться, это не всегда страшно.
Мемкеш все таки имеет delayed consistency, это раз.
Он работает в локальной сети, где вероятность partitions крайне мала.
>> Мемкеш все таки имеет delayed consistency, это раз.
Как настроите.
>> Отложенная согласованность или согласованность в конечном счете может быть достигнута, только если не происходит записи на интервале достижения согласованности.
Она как раз при failover=1 в клиенте может происходить.

>> Он работает в локальной сети, где вероятность partitions крайне мала
А что вы имеете ввиду под чистым AP? Два инстанса MySQL с MASTER-MASTER репликацией на разных континентах? Тогда да, бесполезно.
Всё-таки подумал и понял, что вы правы. Рано или поздно Delayed consistency произойдёт (или ключи устареют или перезапустят memcache).
Тогда не понятно, что же такое AP система в чистом виде.
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Изменить настройки темы

Истории