Объяснение Теоремы Cap

Статья " Непонимание теоремы CAP «И комментарии к нему свидетельствуют о том, что действительно имеется недопонимание.

И связано это не только с неправильной трактовкой термина «разделение», но и с мысленными ошибками на других уровнях.

Я попробую уточнить.



Конвенции
Для начала давайте договоримся об уровне абстракции.

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

С таким же успехом можно сказать, что такое свойство, как «доступность», в принципе недостижимо, поскольку любая система перестанет быть доступной, если выйдет из строя достаточное количество узлов (например, если выйдут все ее узлы).

Поэтому давайте договоримся, что мы все-таки говорим о модели и в ней сделаны некоторые предположения.

Будем считать, что вероятность выхода из строя критического количества узлов системы незначительна — это даст нам возможность говорить о том, что гарантировать доступность еще можно.

Мы не будем рассматривать строение узлов и характер связи между ними — для теоремы это не важно.

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

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

Как именно это достигается, не важно.

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

Дело в том, что это можно сделать, если кто-то этого действительно захочет. Они делают компьютеры, в которых 4 процессора считают одно и то же, просто чтобы перепроверить друг друга.

Такую же осторожность следует проявлять и в отношении гарантий связи.



Смерть слаще
Важно понимать, что смерть узла системы и потеря связи с ним не равнозначны .

Разница проста — мертвый узел не может совершать действия, которые «по незнанию» будут разрушительными по отношению к остальной системе.

Всегда можно устроить ему смерть навсегда, либо когда он придет в себя, то первым делом посоветуется с остальной системой, чтобы ненароком ничего не сломать.

Когда связь разрывается, все становится печальнее.

Узел не может позволить себе умереть, потому что только он может поддерживать его работу (без связи с другими узлами невозможно узнать, жив ли еще кто-нибудь).

Он не может синхронизировать свою работу с другими - нет связи.

Вам остается только действовать вслепую, на свой страх и риск.



Давайте посмотрим, что происходит, на конкретном примере.

Допустим, в нашей системе ровно 2 полностью одинаковых узла — A и B. Каждый из них хранит копию данных второго и может самостоятельно обрабатывать запросы извне.

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

Вариант 1: Узел А умирает. Система продолжает работать как ни в чем не бывало — B продолжает обрабатывать запросы.

Когда А придет в себя, он сначала синхронизируется с Б и они вдвоем продолжат работать дальше.

Ни доступность, ни согласованность не затрагиваются.

Вариант 2: А и Б живы, но связь между ними прервана.

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

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

Эту ситуацию часто называют «сплит-мозгом» — мозг разделен на два полушария, каждое из которых считает себя единоличным хозяином ситуации.

Система стала шизофренической.

Если в этот момент запрос на удаление определенной записи R обрабатывался в A, а запрос на изменение той же записи обрабатывался в B, то данные становились противоречивыми.

Когда соединение между А и Б восстановится, при синхронизации возникнет конфликт – удалить R или оставить модифицированную версию? Здесь можно выйти из ситуации разными стратегиями разрешения конфликтов, но мы уже потеряли последовательность .

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

В этом случае последовательность не будет нарушена, но будет доступность потеряна .



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

Но то же самое верно, если мы учтем, что A и B — не два отдельных узла, а два набора узлов.

При этом мы считаем, что связь между любыми двумя узлами внутри A и внутри B остается возможной, но узлы из A не могут взаимодействовать с узлами из B. При этом оба множества продолжают получать и обрабатывать запросы извне.

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

Сплит-мозг надежно обеспечивает систему при шизофрении даже в таком простом случае.

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



Возвращаясь к теореме
Теорема утверждает, что CA достигается только за счет потери устойчивости к сбоям связи между узлами .

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

Теорему не волнует, как мы этого достигнем.

Не надо ссылаться на «реальный мир», чтобы показать, что чуваки чего-то не догнали.

Теорема существует в рамках модели.

Так же, как это верно сейчас, это будет верно и послезавтра, когда, наконец, будет изобретен гравитонный передатчик.

Но даже без гравитонного передатчика все не так уж и плохо.

Потеря связи между дата-центрами – не частое явление.

В пределах одного дата-центра — еще реже.

Да, если произойдет раскол, конфликты придется решать.

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

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

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

Ну а если в вашем проекте вы считаете вероятность раскола достаточно высокой, то можно переформулировать теорему так: когда происходит раскол, остается только выбрать — А или С.



Лирическое отступление
Существуют методы смягчения теоремы CAP в различных особых случаях.

Человеку не обязательно нужна система, которая работает идеально.

Часто этого достаточно, чтобы он работал достаточно хорошо, по крайней мере, в большинстве случаев.

Эти методы включают в себя как попытки автоматического восстановления целостности после того, как произошло что-то ужасное, так и попытки предотвратить потерю целостности, не скатываясь к полному отрицанию доступности.

Самый простой пример: каждая нода автоматически прекращает обработку запросов извне, если видит меньше половины остальных нод. Это гарантирует, что если система будет разделена на две неравные части, то одна из них продолжит работать, а другая автоматически совершит харакири, чтобы не наделать глупостей.

Другое дело, что если оставить половину мощности, система, скорее всего, полностью упадет под нагрузкой.

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

Для систем с интенсивным чтением это вполне оправданный шаг.

Правда, предоставленные данные не всегда будут актуальными, но зачастую это лучше, чем ничего.

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

Хотя можно придумать что-нибудь похитрее.

Как бы вы ни старались, в общем-то теорему CAP не обойти.

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

ПС специалист по Java , спасибо за повод написать эту статью.

Теги: #NoSQL #Распределенные системы #разделение мозга #теорема о шапке #теорема о кепке

Вместе с данным постом часто просматривают: