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

У меня есть следующая (испорченная) распределенная архитектура, в которой есть условия гонки. Я знаю, что у некоторых из вас, вероятно, есть решения этой классической «проблемы распространения распределенного состояния» — и я хотел бы их услышать. Если вы меня потерпите, вот архитектура:

Допустим, у вас есть два сервера приложений golang, S1 и S2.

Также есть два узла базы данных Cassandra, DB1 и DB2.

S1 и S2 подключены как к DB1, так и к DB2.

Пользователь делает две вещи примерно в одно и то же время в двух браузерах:

  1. Он открывает клиентский браузер C1, который подключается к S1 через веб-сокеты и отправляет запросы на получение состояния либо из DB1, либо из DB2. Сообщение M1 содержит состояние и отправляется от S1 к C1.
  2. Он открывает клиентский браузер C2, который подключается к S2 для переключения некоторого состояния. S2 обновит это состояние либо в DB1, либо в DB2. После этого DB1 и DB2 будут синхронизироваться друг с другом. S2 также должен сообщить C1 о новом состоянии и отправляет это сообщение об обновлении состояния с помощью NSQ (или вашей любимой очереди сообщений) на S1, который затем отправляет сообщение M2 с изменением состояния на C1.

Теперь между (1) и (2) есть условия жесткой гонки. На C1, что прибывает раньше, M1 или M2? M1 может включать обновление состояния, содержащееся в M2, или нет, в зависимости от времени распространения Cassandra относительно запроса C1.

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

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

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

Эту проблему можно решить, если иметь перехватчики/обратные вызовы базы данных, где сервер приложений может прослушивать изменения в определенном состоянии и получать уведомления, когда распространение состояния достигает этого узла базы данных. Я знаю, что такие ловушки существуют в некоторых согласованных базах данных, таких как Rethinkdb, но (насколько мне известно) их нет в Cassandra или любой другой высокодоступной (HA), устойчивой к разделам (PT) базе данных.

Я обнаружил, что жажду абстракции состояния на уровне приложения, которая: кросс-платформенная; интегрируется с распределенным постоянным хранилищем HA/PT; обрабатывает распространение состояния для меня; и позволяет легко инициировать поведение при изменении состояния. Я не знаю ничего подобного.

Какие инструменты или архитектуры вам известны, которые удовлетворяли бы этим ограничениям:

  • нет условий гонки
  • высокодоступный, устойчивый к разделам (в конечном итоге непротиворечивый)
  • обрабатывает немонотонные изменения состояния

person Rusty Fieldstone    schedule 02.07.2015    source источник


Ответы (2)


Я думаю, что Cassandra имеет очень своеобразные функции, но не может управлять транзакциями так, как вам нужно, даже если бы вы использовали один узел. Я не знаю, почему вы используете Cassandra, может быть, у вас есть причины быть прошитым к ней, но для ваших нужд я бы использовал кластер SQL db в конфигурации HA: Oracle или SQL Server уже решили эти проблемы. Конечно, они могут быть дорогими

person cristian v    schedule 03.07.2015

Попробуйте использовать один из ваших серверов Cassandra, например. DB1 в качестве сервера блокировки. Это гарантирует атомарность всех ваших операций, поэтому в вашем случае операции не будут мешать друг другу.

person Dennis Anikin    schedule 11.07.2015
comment
Это интересная идея, но не создает ли она единой точки отказа? - person Rusty Fieldstone; 13.07.2015
comment
Не совсем. Если сервер блокировки не работает, вы просто делаете то, что делаете сейчас. Я имею в виду, что если вам повезло, и сервер блокировки работает, то у вас есть согласованность. Если вам не повезло, и он упал, то вы этого не сделаете. Но разве это не лучше, чем не иметь постоянной последовательности? - person Dennis Anikin; 13.07.2015
comment
Ненадежная блокировка - это интересно. блокируйте/разблокируйте, когда можете (в большинстве случаев), но не позволяйте этому остановить операцию. - person Rusty Fieldstone; 15.07.2015
comment
В яблочко. Но вы сможете сделать все более гладко, если избежите распределенных блокировок и распределенных транзакций. Старайтесь иметь на одном сервере все данные, которые вам нужны, за одну транзакцию. Возможно ли это в вашем случае? - person Dennis Anikin; 15.07.2015