Как изолировать пользовательские сессии в Java EE? - PullRequest
8 голосов
/ 09 марта 2011

Мы рассматриваем разработку критически важного приложения в Java EE, и одна вещь, которая по-настоящему меня впечатлила, это отсутствие изоляции сессии в платформе. Позвольте мне объяснить сценарий.

У нас есть собственное приложение Windows (полное ERP-решение), которое получает около 2 тыс. LoC и 50 исправлений ошибок в месяц от редких участников. Он также поддерживает сценарии, поэтому заказчик может добавить свою собственную логику, и мы понятия не имеем, что делает такая логика. Вместо использования пула потоков у каждого узла сервера есть посредник и пул процессов. Посредник получает запрос клиента, ставит его в очередь до освобождения пулированного экземпляра, отправляет запрос этому экземпляру, доставляет ответ клиенту и освобождает экземпляр обратно в пул процессов.

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

Теперь, учитывая переход на Java EE, я не смог найти ничего похожего на спецификации или популярных серверах приложений, таких как Glassfish и JBoss. Да, я знаю, что большинство кластерных реализаций осуществляют прозрачное переключение при сбое с репликацией сеанса, но у нас есть небольшие компании, которые используют нашу систему на простом 2-узловом кластере (и у нас также есть искатели приключений, которые используют систему на 1-узловом сервере) , С пулом потоков я понимаю, что поток с ошибками может привести к остановке всего узла, потому что сервер не может его обнаружить и безопасно уничтожить. Вырубить весь узел гораздо хуже, чем убить один процесс - у нас есть развертывания, где на каждом узле около 100 экземпляров пула процессов.

Я знаю, что IBM и SAP знают об этой проблеме, основываясь на

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

Теперь идут вопросы!

  1. Если у вас есть похожий сценарий и использовать Java EE, как вы решили?

  2. Знаете ли вы о предстоящем продукт с открытым исходным кодом или изменения в Спецификация Java EE, которая может решить эту проблему вопрос

  3. Есть ли у .NET такая же проблема? Можно Вы объясняете или цитируете ссылки?

  4. Знаете ли вы о некоторых современных и открытая платформа, которая может решить эту проблему вопрос и стоит делать задачу ERP бизнес логика?

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

Спасибо за внимание!

Ответы [ 3 ]

6 голосов
/ 09 марта 2011

То, на что вы наткнулись, является фундаментальной проблемой, касающейся использования Java и "враждебных" приложений.

Это фундаментальная проблема не только на уровне Java EE, но и на уровне ядра JVM. Типичные доступные JVM имеют все виды проблем с загрузкой «небезопасного кода». Типичная JVM из-за утечек памяти, утечек из-за загрузчиков классов, исчерпания ресурсов и неочищенных потоков приводит к тому, что типичная JVM просто недостаточно надежна, чтобы хорошо обрабатывать плохо работающий код в общей среде.

Простой пример - исчерпание памяти кучи Java. Как правило, NOBODY (и никем, я специально имею в виду базовую библиотеку Java и почти все остальные сторонние библиотеки) ловит исключения OutOfMemory. Есть редкие, которые делают, но даже они мало что могут с этим поделать. Типичный код обрабатывает исключения, которые они «ожидают» обработать, но позволяют другим провалиться. Исключения времени выполнения (одним из которых является OOM) будут счастливо подниматься в стеке вызовов вплоть до самого верха, оставляя за собой обломки непроверенного кода критического пути, оставляя все виды вещей в неизвестном состоянии.

Такие вещи, как конструкторы или статические инициализаторы, которые «не могут потерпеть неудачу», оставляя после себя неинициализированные члены класса, которые «никогда не равны нулю». Эти поврежденные классы просто не знают, что они повреждены. Никто не знает, что они повреждены, и нет способа их почистить. Куча, попадающая в OOM, представляет собой небезопасный образ, и в значительной степени ее необходимо перезапустить (если, конечно, вы сами не написали или проверили ВСЕ код, чего, естественно, не будете - кто будет?).

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

Итак, это не обязательно проблема Java EE, это проблема JVM.

Хостинг враждебного кода в JVM - плохая идея. Единственный способ, которым это практично, - это если вы размещаете язык сценариев, и этот язык сценариев реализует некоторый вид управления ресурсами. Это можно сделать, и вы можете вначале настроить существующие (JavaScript, Groovy, JPython, JRuby). Тот факт, что эти языки предоставляют пользователям прямой доступ к библиотекам Java, делает их потенциально опасными, поэтому вам, возможно, придется ограничить это только аспектами, заключенными в обработчики сценариев. Однако в этот момент возникает вопрос «зачем вообще использовать Java».

Вы заметите, что Google App Engine не выполняет ничего из этого. Он создает отдельную JVM для каждого запускаемого приложения, но даже в этом случае он значительно ограничивает то, что может быть сделано в этих JVM, особенно с помощью существующей модели безопасности Java. Различие здесь в том, что эти экземпляры имеют тенденцию быть «долгоживущими», чтобы не переносить затраты на обработку при запуске и завершении работы. Я должен сказать, что они ДОЛЖНЫ быть долгоживущими, а те, кто этого не делают, несут эти расходы.

Вы можете сделать несколько экземпляров JVM самостоятельно, предоставить им немного инфраструктуры для обработки запросов на логику, предоставить им собственную логику загрузчика классов, чтобы попытаться защитить от утечек загрузчика классов, и минимально позволить убить экземпляры (они просто процесс) если хочешь. Это может сработать и, вероятно, сработает «хорошо» в зависимости от степени детализации вызовов и времени «запуска» для вашей логики. Время запуска будет минимально загружать классы для логики от запуска к запуску, что само по себе может сделать это плохой идеей. И это, конечно, не будет "Java EE". Java EE не настроен на подобные вещи. Но вам не ясно, какие функции Java EE вы просматриваете.

По сути, это то, что делает Apache и "mod_php". Несколько экземпляров, таких как процессы, индивидуально обрабатывающие запросы, с плохим поведением, когда их убивают по мере необходимости. Вот почему PHP распространен в бизнесе виртуального хостинга. В этой структуре это в основном "безопасно".

0 голосов
/ 23 ноября 2011

У нас был похожий - хотя и не такой серьезный - порт действительно огромного Perl-сайта на Java. Получив HTTP-запрос, мы создаем экземпляр класса и вызываем его метод processRequest. в окружении пробной ловли и измерения времени. Добавление таймера и потока было бы достаточно, чтобы иметь возможность убить поток. Этого, вероятно, достаточно в реальной жизни.

Сервер Java EE, такой как glassfish, является контейнером OSGi, который может иметь больше изолирующих средств.

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

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

0 голосов
/ 09 марта 2011

Я полагаю, что ваш сценарий очень нетипичен, поэтому маловероятно, что существует готовый фреймворк / платформа для решения этой проблемы.В Java EE предполагается, что код обработки запросов написан той же командой, что и остальная часть приложения, поэтому его не нужно часто изолировать, просматривать и сбрасывать, а исправления ошибок будут обрабатываться одинаково во всех частяхсистема.Это предположение значительно упрощает разработку, развертывание, тестирование и т. Д. Для большинства проектов, не заставляя их платить за то, что им не нужно, и да, это не подходит для всех.Если вы хотите что-то принципиально другое, вам, вероятно, нужно самостоятельно реализовать достаточное количество логики отработки отказа.Java EE обеспечивает фундаментальные строительные блоки для этого.

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

...