Артём Данилов обратил моё внимание на неверное толкование понятия "partition tolerance" в старом посте про CAP-теорему. За это я ему очень благодарен, потому что сам долго осознавал, что не понимаю этой части теоремы, но стеснялся признаться :-).
Артём написал про это свой пост на Хабре, в котором всё хорошо объяснено, но главное, там есть ссылка на ещё более другой пост — You Can't Sacrifice Partition Tolerance, который лично мне хорошо всё расставил в голове на места.
Хочу теперь ещё раз написать всё это здесь своими словами для закрепления пройденного.
Путаница у меня в голове идёт из-за того, что "partition tolerance" обычно переводится, как "устойчивость к сбою узлов". Однако на самом деле оно означает возможность работы при наличии сбоев передачи по сети. А эту возможность обязана учитывать любая распределённая система, иначе она не будет работать. Словами Коды Хейла:
Не требовать partition tolerance для распределённой системы означает работу в сети, гарантирующей никогда не терять (или даже задерживать) сообщения, и чьи узлы гарантированно никогда не падают. Вы и я не работаем с такими системами, потому что их не существует.
Другими словами, требование partition tolerance для распределённой системы — это не выбор инженера, а просто практическая данность, и выбирать остаётся только между consistency и availability. Даже если инженер упрямо решит построить систему с расчётом на 100% надёжность сети, то при следующем сбое она либо потеряет данные и станет неконсистентной, или не сможет вернуть ответ на запрос, и будет недоступной.
Интересно, что в моём изначальном посте в качестве примера CA-системы, не учитывающей partition tolerance, я сначала привёл вырожденный случай системы из одного узла. Но, как мне подсказали в комментариях, такая система уже не является распределённой. Поэтому я тогда поменял пример на неверный по сути :-). Сейчас вернул обратно с разъяснением.
Комментарии: 4
Greg Young в своих докладах по CQRS очень часто говорит, что CQRS позволяет обойти CAP-теорему благодаря разделение приложения на 2 части: Command и Query. Боюсь сейчас ошибиться, но вроде бы Command при этом поддерживает C и P, а Query - A и P. Между самими же частями системы при этом присутствует т.н. Eventual Consistency, но только Eventual подразумевает здесь не рассогласованность данных, а просто временную задержку, пока данные из основного Command-хранилища не попадут в Query-хранилище: http://codebetter.com/gregyoung/2010/04/14/quick-thoughts-on-eventual-consistency/
Если показать это на примере, то Command-часть отвечает за хранение данных и операции их изменения и является полностью consistent, а сразу после попадания данных в основное хранилище они ставятся в очередь на добавление в Query-хранилища. Query-хранилищем может быть база данных, NOSQL хранилище или что-нибудь еще, более того, Query-часть системы может быть распределена как угодно - на нее идут лишь операции чтения, поэтому consistency между нодами для записи сохранять не нужно.
Ну и последний пример (от того же Грега): Facebook (да наверняка и другие высоконагруженные системы) тоже являются Eventual Consistent. Пользователи Facebook в обычном режиме работают со своими локальными серверами, куда перенаправляются запросы. При обновлении данных (например, изменении статуса) меняются в первую очередь центральные хранилища, а сам пользователь перебрасывается на некоторое время на них, чтобы видеть свои изменения. Остальные пользователи этого региона их не увидят, пока данные не реплицируются в регион. После этого пользователь перебрасывается назад на свой локальный сервер. Заметно это иногда, когда изменения вдруг на время "теряются", а потом появляются, не успев вовремя реплицироваться, хотя пользователь уже вернулся назад.
Спасибо и вам, и Артему за дальнейшее обсуждение и комментарии по этой теме.
http://mantonov.blogspot.com/2012/01/cap.html -вот тут я попробовал собрать свои мысли воедино, максимально просто и с примерами. Раньше я тоже понимал теорему несколько по другому.
Хотелось бы прокомментировать Вашу цитаты слов Коды на счет связи между Partition Tolerace и паденеем нод. Он вроде в апдейтах написал, что был не прав на счет этого, и что не нужно падение нод приплетать к partition tolerance, на что ему указали Брюрер и Стоунбрейкер.
Да, я читал этот апдейт, но в итоге решил цитату не править, потому что смысла это не меняет. Опять же, несмотря на формальное определение, по которому отказ узлов не входит в P, на практике он проявляется именно так. Я думаю, потому он сначала так и написал.