Стратегии для Java ORM с ненадежной сетью и низкой пропускной способностью

#java #hibernate #caching #ehcache #unreliable-connection

#java #переход в спящий режим #кэширование #ehcache #ненадежное соединение

Вопрос:

Я рассматриваю Hibernate для системы, которая должна работать в ненадежной сети. Существует единая центральная база данных, к которой нам нужен доступ для чтения и записи, но она доступна через довольно неоднородную сеть Wi-fi. Кроме того, могут быть потери мощности, которые не приводят к чистому завершению работы приложения, поэтому любое решение должно иметь постоянный кэш, который может выдерживать циклы питания. Наконец, это встроенная система с небольшим объемом памяти и дискового пространства, поэтому, например, выполнение полномасштабной репликации базы данных не является осуществимой стратегией.

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

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

Ищу некоторый опыт или возможные альтернативы.

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

1. Обратите внимание, когда я сказал «скромная» память, я имел в виду около 256 Мб, и есть виртуальная память. Так что это неплохо, просто не так громоздко, как рабочий стол / сервер.

Ответ №1:

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

У вас уже есть решение в вашей голове с помощью кэша 2-го уровня гибернации. Но вы не сказали, каковы реальные требования. У вас нереализуемая сеть. Все в порядке, у вас нереализуемый источник питания. Это тоже нормально. Теперь, какого уровня обслуживания вы хотите достичь? Что приемлемо или нет?

Допустима ли потеря данных? Сколько вы могли бы принять? Какой риск вы принимаете?

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

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

Итак, вы устанавливаете RAID и добавляете источник бесперебойного питания. Это приятно. Вы обнаруживаете событие сбоя питания в операционной системе. Завершите текущую транзакцию и корректно завершите работу. Ваш RAID защищает вас от сбоя диска.

Хорошо, но что произойдет, если весь компьютер перестанет функционировать? Что происходит в случае пожара? Или повреждение водой? Весь диск будет управляться, данные невозможно восстановить, а то, что не синхронизировано с центральной базой данных, будет потеряно. Это приемлемо или нет?

Даже когда Wi-Fi включен, источник питания работает отлично… Какова надежность центральной базы данных в любом случае? У вас есть регулярные резервные копии? Или решение для кластеризации? Вы уверены, что ваша центральная база данных в любом случае надежна?

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

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

Это функциональная проблема. Что делать, когда несколько изменений происходят в автономном режиме и вам приходится объединять? Что приемлемо? Чего нет. Возможно, при повторном подключении применяется самое последнее изменение, более старые изменения отбрасываются. Обнаруживаются конфликты или ptential и пользователю предлагается разобраться с ними. Вы можете попробовать применить изменения в очереди и применить их все…

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

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

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

Ответ №2:

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

Я рекомендую вам определить набор высокоуровневых атомарных операций, а затем определить набор (например) restful services для них. Или, если хотите, вы можете использовать soap и изучить параметры WS-* для надежного обмена сообщениями, чтобы позаботиться о повторных попытках и всех других неприятных деталях.

Или вы могли бы исследовать, будет ли что-то вроде cassandra по ссылке работать лучше, чем SQL, или что-то еще, что сильно влияет на репликацию.

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

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

Ответ №3:

Как насчет постановки операций с БД в очередь долговременных сообщений, и пусть какое-нибудь промежуточное программное обеспечение для обмена сообщениями решает проблему с сетью?

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

Я бы не решался использовать EhCache и т.д. Они не были предназначены для этого, и, следовательно, вам, возможно, придется «растянуть» фреймворк. Очереди сообщений, с другой стороны, имеют решения, которые были разработаны для таких сценариев.

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

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

2. @Nicolas: Постоянное хранилище, которое будет использовать «периферийная» очередь сообщений, должно будет использовать локальное хранилище устройства. Если для этого используется сетевой ресурс, это действительно не будет иметь никакого смысла.. В принципе, операции должны храниться (ставиться в очередь) в локальном хранилище устройства, и системе обмена сообщениями необходимо повторять операцию, пока она не завершится успешно. Надежность центральной базы данных — это другой вопрос.

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

Ответ №4:

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

Возможно, вы можете хранить журнал транзакций в сжатом виде.

Ответ №5:

Спящий режим (и кэш второго уровня) на самом деле не предназначены для этого. Я предполагаю, что вам, вероятно, лучше всего использовать маломасштабную встроенную Java СУБД (например, H2 или HSQLDB) в качестве локальной временной очереди (в наиболее долговременном доступном режиме), а затем выполнить синхронизацию с фоновым потоком. Затем вы могли бы предоставить пользовательский интерфейс sync spinner, подключенный к этому фоновому потоку, чтобы обеспечить некоторую степень обратной связи для пользователя.

Кстати, Hibernate немного жирноват для выгрузки во встроенную среду. Возможно, вы захотите вместо этого рассмотреть MyBatis.

Ответ №6:

Репликатор Daffodil (http://enterprise.replicator.daffodilsw.com/index.html ) позволяет выполнять репликацию между источниками JDBC. Он поддерживает двунаправленные обновления, слияние и разрешение конфликтов, а также частичные реплики.

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