Как удаленно обновлять приложения Java?

У нас есть серверное приложение Java, которое работает на ряде компьютеров, все подключены к интернету, некоторые брандмауэры. Нам нужно удаленно обновлять файлы JAR и сценарии запуска с центрального сайта без заметного прерывания самого приложения.

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

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

кто-нибудь уже нашел хорошее решение для этого? Есть идеи или предложения?

просто чтобы уточнить: это приложение является сервером, но не для веб-приложений (здесь нет контейнеров webapp или файлов WAR). Это просто автономная Java-программа.

8 ответов


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

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

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

  1. рассмотрите возможность загрузки.файл jar, который способен чтение файла jnlp и загрузка необходимых/обновленных банок перед запуском приложения.

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

  3. даже если можно перезаписать банки, вы можете рассмотреть подход пинг-понга для своего пути lib (если у вас еще нет запуска приложений, настроенного на автоматическое чтение всех файлов jar в папке lib и автоматическое добавление их в путь класса, то это то, что вы действительно хотите сделать). Вот как работает пинг-понг:

App запускает и смотрит на lib-ping\версия.свойства и lib-pong\версия.свойства и определяет, что новее. Допустим, у lib-ping есть более поздняя версия. Пусковая установка ищет lib-ping*.jar и добавляет эти файлы в CP во время запуска. Когда вы делаете обновление, вы загружаете файлы jar в lib-pong (или копируете файлы jar из lib-ping, если вы хотите сохранить пропускную способность, и JAR фактически не изменился - это редко стоит усилий!). Как только вы скопируете все банки в lib-pong, самое последнее вы создаете версию.файл свойств (таким образом, прерывистое обновление, которое приводит к частичной папке lib, может быть обнаружено и очищено). Наконец, вы повторно запускаете приложение, и bootstrap подхватывает, что lib-pong-это желаемый путь к классам.

  1. пинг-понг, как описано выше, позволяет за откат. Если вы спроектируете его правильно, у вас может быть одна часть вашего приложения, которую вы тестируете, а затем никогда не меняете, чтобы проверить, должен ли он откатить данный версия. Таким образом, если вы испортите и развернете что-то, что сломает приложение, вы можете аннулировать версию. Эта часть приложения просто удалить версию.файл свойств из папки bad lib -*, затем повторный запуск. Важно держать эту часть грязи просто потому, что это ваш безотказный.

  2. У вас может быть более 2 папок (вместо ping/pong, просто есть lib-yyyymmdd и очистить все, кроме новейших 5, например). Это позволяет более продвинутым (но сложнее!) откат банок.


вы обязательно должны взглянуть на OSGi, он был создан только для этих случаев (особенно для встроенных продуктов) и используется большим количеством компаний. Вы можете обновлять jar "bundles", добавлять и удалять их, пока приложение работает. Я не использовал его сам, поэтому я не знаю о качестве фреймворков/серверов с открытым исходным кодом, но вот куча полезных ссылок, чтобы получить вас начал:

http://www.osgi.org/Main/HomePage
http://www.aqute.biz/Code/Bnd
http://blog.springsource.com/2008/02/18/creating-osgi-bundles/
http://blog.springsource.com/
http://www.knopflerfish.org/
http://felix.apache.org/site/index.html


Я бы рекомендовал Capistrano для многосерверного развертывания. Хотя он построен для развертывания приложений Rails, я видел, что он успешно используется для развертывания приложений Java.

ссылка: Capistrano 2.0 не только для рельсов


банки не могут быть изменены, пока JVM работает поверх него и приведет к ошибкам. Я пробовал подобные задачи, и лучшее, что я придумал, - это сделать копию обновленной банки и перейти к сценарию запуска, чтобы посмотреть на эту банку. Как только у вас есть обновленная Банка, запустите ее и дождитесь окончания старой банки после подачи сигнала. К сожалению, это означает потерю GUI и т. д. на секунду, но сериализация большинства структур в java проста, и текущий GUI может быть передано в обновленное приложение до фактического закрытия (некоторые вещи могут быть не сериализуемыми, хотя!).


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

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

далее, дублируйте установку. Теперь у вас есть "работающая" версия а у вас есть "новая" версия.

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

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

когда вы довольны новой установкой, в исходном запущенном экземпляре переименуйте исходный каталог (MV application application_old), переименуйте новый каталог (mv application_new application) и запустите его обратно.

ваше время простоя сокращается до завершения работы сервера и времени запуска (так как переименование "бесплатно").

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

другая хорошая вещь заключается в том, что ваша инфраструктура услуг статична (например, ваши rc-скрипты, задания cron и т. д.), поскольку они указывают на каталог" приложение", и он не меняется.

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

но метод прост, и около доказательства пули если ваше применение сотрудничает.

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


Я считаю, что вы можете развернуть файлы JAR, если используете сервер приложений на основе OSGi, например сервер SpringSource dm. Я никогда не использовал его сам, но, зная общее качество весеннего портфеля, я уверен, что стоит посмотреть.


мы используем Eclipse, который система обновления OSGi, и наш опыт очень хорош.

рекомендуем!


последняя версия Java Web Start позволяет вводить приложение в локальный кэш без фактического вызова программы, и она может быть помечена как "offline". Поскольку кэш используется для вызова программы, он будет обновлен только для следующего запуска. Для этого вам, скорее всего, понадобятся банки с номерами версий в их названии (например, наша-библиотека-2009-06-01 - ... сосуд.)