понедельник, 10 июня 2013 г.

Коммуникация в кластере серверов приложений Oracle WebLogic

В данной заметке мы рассмотрим довольно важный для понимания настройки и поддержки серверов приложений Oracle WebLogic вопрос - вопрос коммуникации в кластере.

Общие положения


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

  • IP-сокеты - для коммуникации вида точка-точка между участниками кластера;

  • IP unicast и multicast для распространения информации о доступности серверов и их состоянии, а так же для построения кластерного JNDI-дерева.

При создании кластера с помощью Configuration Wizard по умолчанию устанавливается режим обмена unicast, а при создании кластера с помощью WLST - multicast. Если есть проблемы с распространением JNDI-дерева на кластер с помощью unicast, то может помочь использование нового свойства - ClusterMBean.MessageOrderingEnabled. По умолчанию данное свойство не включено. Чтобы его включить нужно добавить следующую строчку в config.xml:

<message-ordering-enabled>true</message-ordering-enabled>.

Если данная настройка не решает проблему, то нужно перейти на использование multicast режима.



IP multicast


Простая технология для массовой рассылки пакетов (для broadcast), позволяет нескольким приложениям "подписаться" на заданный IP-адрес и номер порта для получения сообщений.

У приложения есть локальный буфер для multicast сообщений. Если данный буфер полон, то новые сообщения не будут в него записываться, но приложение в свою очередь не будет уведомлять источник сообщений об этом. Сообщения будут теряться, т.е. гарантированная доставка сообщений не обеспечивается.

multicast-адрес - это IP-адрес из диапазона от 224.0.0.0 до 239.255.255.255, значение по умолчанию для сервера приложений WebLogic - 239.192.0.0. Не рекомендуется использовать адреса в диапазоне x.0.0.1.

WebLogic использует multicast для обмена между серверами в кластере вида "один-ко-многим". Данный обмен включает в себя:
  • Обновления кластерного (cluster-wide) JNDI - каждый сервер рассылает уведомления об обновлении своего JNDI-дерева, другие сервера в кластере подписываются на данные уведомления с целью синхронизации информации о чужих JNDI-деревьях.

  • Рассылки сообщений о доступности сервера. Экземпляры кластера так же мониторят IP-сокеты для обнаружения сбоев.

  • Кластер, элементы которого размещены на нескольких узлах, использует multicast для обмена между узлами.

Определение недоступных серверов и распространение JNDI-дерева - критические функции multicast-обмена внутри кластера.

Проблемы и советы

Если кластер развернут на нескольких подсетях в WAN, то сеть должна обеспечивать:

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

  • Низкую латентность. Большинство multicast пакетов должны доходить до получателя за 200 - 300 мс.

Multicast Time-to-Leave для кластера необходимо выставить таким образом, чтобы роутеры не отвергали пакеты до того, как те достигнут получателей.

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

Брендмауэры могут не пропускать multicast-трафик. Тунелирование multicast-трафика через фаерволы не рекомендуется для кластера WebLogic. Следует рассматривать каждый кластер WebLogic как одно целое и не распределять участников кластера по разным зонам безопасности. Кроме того, любые технологии, вносящие задержки в распространение IP-трафика, могут приводить к ложному срабатыванию детектора сбоев (т.е. сервера будут думать, что сервер А упал, хотя на самом деле с ним все в порядке, просто от него не дошли сообщения).

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

Необходимо помнить о такой вещи, как Multicast-шторм. Если сервер не успевает обработать сообщения, то по сети генерируется дополнительный трафик - Negative Acknowledgement (NAK) сообщения и heartbeat re-transmissions. Т.е. если участник кластера не принял пакет, то он посылает NAK. Источник принимает NAK, соответственно повторно отправляет пакет. Нагрузка на сеть растет, пакеты не успевают доставляться, возникает положительная обратная связь. Повторяющаяся передача multicast-пакетов по сети называется multicast-штормом и может вести к лавинному росту нагрузки на сеть и на подключенные станции, что в свою очередь ведет к падению сети. Помочь может увеличение multicast-буфера.

Обмен с использованием Unicast


Unicast проще чем Multicast, т.к. не требует дополнительной настройки сети. Так же unicast уменьшает количество сбоев в сети, вызванных конфликтом адресов multicast.

Настройка unicast

Настройка осуществляется путем выставления в нужное значения свойства ClusterMBean.isUnicastBasedClusterMessagingEnabled(). По умолчанию значение равно false. Изменения данного свойства нединамические и требуют перезагрузки кластера.

Можно задать канал, который будет использоваться для коммуникации между кластерами, это делается с помощью вызова метода setNetworkChannelForUnicastMessaging(String NetworkChannelName) бина ClusterMBean. Если задано имя канала и включен режим обмена unicast, то сервера будут пытаться использовать канал с данным именем для коммуникации, иначе будет использоваться канал по умолчанию.

Если для коммуникации используется unicast и сервера кластера развернуты на разных машинах, то необходимо явно задать адреса данных машин или их DNS-имена.

Обмен в режиме точка-точка с использованием сокетов


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

  • доступа к некластеризованным объектам, развернутым на другом участнике кластера, находящимся на другой машине;

  • репликации состояния HTTP-сессий и сессионных бинов с сохранением состояния между основным и резервным серверами;

  • доступа к кластеризованному объекту, находящемуся на удаленном экземпляре сервера. Это происходит только
    в многослойной кластерной архитектуре (Multi-Tier Architecture).

Важно! Весь RMI-обмен осуществляется с использованием сокетов, например обмен между клиентским приложением, запрашивающим удаленный объект, и сервером.

Настройка обмена с помощью сокетов критически влияет на производительность кластера серверов приложений WebLogic. Два фактора определяют эффективность обмена:

  • использует ли система, на которой развернут WebLogic, нативные или Java-сокеты;

  • настроено ли достаточно потоков чтения для систем, использующих Java-сокеты.

Java и нативные реализации чтения сокетов

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

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



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

Апплеты не могут использовать нативные сокеты и, соответственно, имеют ограничения эффективности коммуникации
посредством сокетов.

Определение потенциального числа используемых сокетов

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

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

Если вы используете репликацию HTTP-сессии в памяти и разворачиваете объекты гомогенно, то каждый экземпляр сервера приложений может открыть максимум два сокета, по одному для каждого соседа: на один он передает свои сессии, на другой - принимает сессии от соседа. В данной ситуации достаточно настроек потоков по умолчанию.



Если используются "прикрепленные" (pinned) сервисы - сервисы, которые активны в каждый момент времени только на одном экземпляре сервера приложений, то число используемых сокетов увеличивается, поскольку экземпляры сервера должны открыть дополнительные соединения для доступа к прикрепленному сервису.



Пример: на одном из четырех серверов кластера размещен прикрепленный RMI-объект, в данном случае каждый экземпляр сервера приложений может открыть максимум 3 сокета - 2 для репликации HTTP-сессий и один для доступа к прикрепленному сервису.

Обмен с клиентом посредством сокетов

Клиент кластера использует Java-реализацию считывателей сокетов.

WebLogic позволяет настроить server affinity алгоритм балансировки нагрузки, который уменьшает количество открытых сокетов для клиентского Java-приложения. Клиент использует один сокет для получения доступа к нескольким объектам на экземпляре сервера. В случае сбоя клиент перебрасывается на другой сервер и должен открыть сокет для обмена с данным сервером. В предыдущих версиях WebLogic, без поддержки режима affinity, клиент был вынужден открывать соединения с каждым экземпляром сервера в кластере.

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

JNDI-сервис уровня кластера


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

Экземпляры серверов в кластере используют JNDI-дерево уровня кластера (кластерное дерево, cluster-wide JNDI). Данное дерево аналогично дереву сервера приложений, поскольку так же содержит список доступных сервисов, но в дополнение к дереву сервера, дерево уровня кластера хранит сервисы, предоставляемые кластеризованными объектами (EJB и RMI-классы), размещенными на других экземплярах WebLogic, входящих в кластер.

Очень важно! Не используйте кластерное JNDI-дерево как хранилище закэшированных объектов вашего приложения. Хотя WebLogic и реплицирует дерево по другим узлам кластера, элементы удаляются из кластерного дерева в случае недоступности оригинального экземпляра сервера. Так же сохранение тяжелых объектов в JNDI-дереве ведет к резкому увеличению multicast или unicast трафика и мешает нормальной работе кластера.

Построение кластерного JNDI-дерева

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

Когда вы запускаете управляемый сервер в кластере, экземпляр сервера находит другие запущенные экземпляры участников кластера для того, чтобы слушать информацию об их состоянии после некоторого времени, называемого временем прогрева (warm-up). Данное время определяется параметром MemberWarmupTimeoutSeconds бина ClusterMBean. Значение данного параметра по умолчанию равно 30 сек.

После того, как экземпляр сервиса свяжет сервис с локальным JNDI-деревом, дополнительные действия производятся для кластеризованных объектов, использующих replica-aware заглушки. После помещения реализации кластеризованного объекта в локальное дерево, экземпляр сервера отправляет заглушку другим участникам кластера. Другие участники кластера мониторят multicast- или unicast-адрес для обнаружения того факта, что удаленные экземпляры сервера предлагают новый сервис.



После получения соответствующего уведомления экземпляры сервера встраивают новый сервис в свои локальные JNDI-деревья.

Обновление локального JNDI-дерева происходит одним из двух способов:

  • Если кластеризованный сервис не встроен в локальное JNDI-дерево, то экземпляр сервера помещает заглушку в свое локальное дерево, что свидетельствует о доступности объекта X на сервере A. Сервера B и D кластера поступают таким образом, т.к. кластеризованный объект не развернут на данных серверах. Т.е. если на сервере нет своей реализации кластеризованного объекта, то в локальное JNDI-дерево помещается заглушка, ссылающаяся на удаленные реализации. Данный механизм позволяет использовать данные реализации прозрачно, как будто они локальные, правда это ведет к увеличению трафика между серверами.

  • Если сервер уже имеет связывание (binding) для кластеризованного объекта (на сервере имеется своя локальная реализация данного объекта), то он обновляет свое локальное JNDI-дерево, с целью указать, что реплика сервиса так же доступна и на сервере А. Сервер C будет обновлять свое дерево таким же способом, поскольку он уже будет иметь связывание для кластеризованного объекта X.

Каждый экземпляр сервера в кластере создает собственную копию кластерного JNDI. Тот же самый процесс репликации JNDI будет выполнен, если сервер C анонсирует, что объект X связан с его локальным JNDI-деревом. После того как все широковещательные сообщения получены, каждый экземпляр сервера в кластере будет иметь идентичные локальные JNDI-деревья, которые отражают доступность объекта на серверах A и C.



(Интересно, что на каждом сервере есть объект X и указано, что он размещен на серверах A и C. Это указано даже на самих серверах А и С, предоставляющих этот объект, т.е. сервер А знает, что объект есть и на сервере С, а сервер С - что и на А).

Как возникают конфликты JNDI наименований

Простой конфликт имен JNDI возникает тогда, когда экземпляр сервера пытается связать некластеризованный сервис, который имеет то же самое имя, что и некластеризованный сервис, уже присутствующий в локальном JNDI-дереве. Конфликты в кластерном JNDI возникают, когда экземпляр сервера пытается связать кластеризованный объект, использующий наименование некластеризованного объекта, уже существующего в JNDI. Например, если вы разворачиваете прикрепленный RMI-объект на один экземпляр сервера в кластере, то вы не можете развернуть реплику этого же объекта на другом экземпляре сервера в кластере.

Если два экземпляра сервера в кластере пытаются связать разные кластеризованные объекты, использующие одно и то же имя, то оба объекта будут успешно связаны локально. Тем не менее каждый экземпляр сервера будет отказываться связать заглушки объектов других экземпляров серверов в JNDI-дерево, т.к. это вызовет конфликт имен. Данный конфликт будет существовать до тех пор, пока один из двух серверов не будет выключен или один из экземпляров не удалит кластеризованный объект. Такой же конфликт произойдет, если оба экземпляра сервера попытаются развернуть прикрепленный объект с одним и тем же именем.

Гомогенное разворачивание с целью избежать конфликтов в кластерном JNDI

Для того, чтобы избежать конфликтов в кластерном дереве JNDI, вы должны гомогенно развернуть объекты на всех экземплярах WebLogic, входящих в кластер. Наличие несбалансированного развертывания на экземпляры
сервера приложений увеличивает шансы возникновения конфликтов имен при старте или повторном развертывании. Так же это ведет к несбалансированному распределению нагрузки в кластере.

Если все же вам нужно прикрепить конкретный RMI-объект или EJB к конкретному экземпляру сервера, то
не реплицируйте данный объект на кластер.

Как WebLogic обновляет дерево JNDI

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

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

Взаимодействие клиента с кластерным JNDI-деревом

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

Ссылки на документацию



Понравилось сообщение - подпишитесь на блог и Twitter

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

Отправить комментарий

Любой Ваш комментарий важен для меня, однако, помните, что действует предмодерация. Давайте уважать друг друга!