У меня есть следующая (испорченная) распределенная архитектура, в которой есть условия гонки. Я знаю, что у некоторых из вас, вероятно, есть решения этой классической «проблемы распространения распределенного состояния» — и я хотел бы их услышать. Если вы меня потерпите, вот архитектура:
Допустим, у вас есть два сервера приложений golang, S1 и S2.
Также есть два узла базы данных Cassandra, DB1 и DB2.
S1 и S2 подключены как к DB1, так и к DB2.
Пользователь делает две вещи примерно в одно и то же время в двух браузерах:
- Он открывает клиентский браузер C1, который подключается к S1 через веб-сокеты и отправляет запросы на получение состояния либо из DB1, либо из DB2. Сообщение M1 содержит состояние и отправляется от S1 к C1.
- Он открывает клиентский браузер 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; обрабатывает распространение состояния для меня; и позволяет легко инициировать поведение при изменении состояния. Я не знаю ничего подобного.
Какие инструменты или архитектуры вам известны, которые удовлетворяли бы этим ограничениям:
- нет условий гонки
- высокодоступный, устойчивый к разделам (в конечном итоге непротиворечивый)
- обрабатывает немонотонные изменения состояния