클러스터링 환경에서는 프로세스가 두 개가 뜨기 때문에 종료 스크립트가 있는 것이 편리합니다. 그렇지 않고 JBoss 에서 제공되는 종료 스크립트를 이용할 경우 바로 프로세스가 떨어지지 않아 사용자의 요청이 종료 중이 프로세스로 갈 수도 있습니다. 바로 프로세스를 죽이는 것이 운영 중에는 좋습니다.
# Status worker for managing load balancer
worker.status.type=status
각 서버의 Apache HTTP Server 설정을 위와 같이 바꾸어주면 자신의 서버에 올려져 있는 인스턴스 뿐만 아니라 다른 서버의 인스턴스까지 요청이 가능하게 됩니다.
단, 이러한 구성의 경우 세션 복제로 인한 오버헤드가 발생할 수 있습니다. buddy-replication 설정을 통해 근접한 인스턴스에게만 세션 복제를 할 수 있게 설정할 수 있습니다.
node1 -> node2, node2 -> node3, node3 -> node4, node4 -> node1 이런 방식으로 buddy-replication 을 설정하면 하나의 노드가 죽더라도 buddy 노드가 해당 세션을 복제 받을 수 있을 것 입니다. 하지만 이러한 경우 sticky-session 설정이 되어야 할 것으로 생각되네요...
쉬울지 알고 접근했던 JBoss 클러스터링인데, 역시 뭐든지 실제로 해보고 느껴봐야 할 것 같습니다.
안해봤으면 말을 하지 마요~ 어후...
configuration 을 설정하는 것 입니다. all 을 통해 복사한 node1, node2 를 각 인스턴스별로 설정합니다.
-g
클러스터 이름을 설정합니다. (그냥 자기가 좋아하는 이름을 지정하면 될 것 같습니다.)
-u
내부 클러스터 통신을 위한 멀티캐스트 주소를 설정합니다.
-b
소켓에 바운딩될 아이피 주소를 설정합니다.
System properties
jboss.messaging.ServerPeerID
각 노드마다 지정되는 유니크한 정수 값 입니다. 1부터 순차적으로 증가하면 될 것 같습니다.
jboss.service.binding.set
ServiceBindingManager 를 통해 포트 설정을 위한 프로퍼티입니다. 시스템별 첫번째 인스턴스에는 ports-default 로 설정하고 그 다음 인스턴스부터는 ports-01, ports-02 ... 과 같이 설정을 합니다. 기본적으로 JBoss 의 포트가 8080 이고 AJP 1.3 포트가 8009 라면 ports-default 는 8080, 8009 로 바인딩 되고, ports-01 은 8180, 8109 로 바인딩 됩니다.
나중에 나오겠지만 mod_jk 설정을 위해 미리 jvmRoute 를 설정합니다. <JBOSS_HOME>/server/"node1|node2"/deploy/jbossweb.sar/server.xml
각 인스턴스 별로 <Engine> element 의 attribute 로 jvmRoute 를 설정합니다.
웹 어플리케이션을 어떤 방식으로 배포하냐에 따라서 설정이 달라지게 됩니다.
두 인스턴스의 deploy 경로에 각각 배포를 하는 방식이 있고, 한 곳에 배포하여 공유하여 사용하는 방식이 있습니다.
한 곳의 배포하는 방식 중에 한가지는 farm 을 이용하는 것 입니다.
<JBOSS_HOME>/server/node1/farm 에 배포를 하게 되면 각 인스턴스들이 공유하여 사용할 수 있습니다.
(해보지는 않았습니다... 어디선가 본 자료입니다.)
다른 방법으로는 같은 배포 경로를 각 인스턴스에 설정을 하는 것 입니다. <JBOSS_HOME>/server/"node1|node2"/conf/bootstrap/profile.xml
<deployment>
...
<!--
The profile configuration
This contains required properties:
The uri to jboss-service.xml.
The uri to the deployers folder.
A list of uris to deploy folders. -->
<bean class="org.jboss.system.server.profileservice.repository.StaticProfileFactory" name="BootstrapProfileFactory">
<property name="bindingsURI">${jboss.server.home.url}conf/bindingservice.beans</property>
<property name="bootstrapURI">${jboss.server.home.url}conf/jboss-service.xml</property>
<property name="deployersURI">${jboss.server.home.url}deployers</property>
<property name="applicationURIs">
<list elementclass="java.net.URI">
<value>${jboss.server.home.url}deploy</value> <value>file:/home/webapps</value>
</list>
</property>
<property name="attachmentStoreRoot">${jboss.server.data.dir}/attachments</property>
<property name="profileFactory"><inject bean="ProfileFactory"></inject></property>
</bean>
...
</deployment>
저의 경우에는 /home/webapps 에 war 를 배포할 예정이므로 위와 같이 설정을 하였습니다.
# Mount your applications JkMount /test-jboss/* loadbalancer
# You can use external file for mount points.
# It will be checked for updates each 60 seconds.
# The format of the file is: /url=worker
# /examples/*=loadbalancer
JkMountFile conf/uriworkermap.properties
# Add shared memory.
# This directive is present with 1.2.10 and
# later versions of mod_jk, and is needed for
# for load balancing to work properly
JkShmFile logs/jk.shm
# Add jkstatus for managing runtime data
<Location /jkstatus/>
JkMount status
Order deny,allow
Deny from all
Allow from 127.0.0.1
</Location>
웹 어플리케이션의 context-root 가 /text-jboss 이기 때문에 JkMount 에 설정하였습니다.
<APACHE_HOME>/conf/uriworkermap.properties
# Simple worker configuration file
# Mount the Servlet context to the ajp13 worker
/jmx-console=loadbalancer
/jmx-console/*=loadbalancer
/web-console=loadbalancer
/web-console/*=loadbalancer
/test-jboss=loadbalancer
/test-jboss/*=loadbalancer
웹 어플리케이션의 context-root 로 마운트 포인트를 설정합니다.
<APACHE_HOME>/conf/workers.properties
# Define list of workers that will be used
# for mapping requests
worker.list=loadbalancer,status
ERROR [SOAPFaultExceptionHelper] SOAP request exception java.lang.UnsupportedOperationException: setProperty must be overridden by all subclasses of SOAPMessage
회사에서 개발하는 솔루션이 spring framework 기반이라 웹서비스도 spring webservices 로 구축을 하였는데, JBoss 에 올리려고 하니 여러 오류가 생겨 재 작년부터 고민하고 여러가지 시도를 하였으나 실패를 하였습니다.
우연히 다른 것을 검색하다가 발견한 것에서 아이디어가 떠올라서 여러가지 실험을 해본 결과 JBoss 용 웹 서비스를 publish 하는 데 성공하였습니다.
기존의 Spring WebServices Class
별 다른 작업 없이 DI 를 이용하여 service 객체를 이용하여 웹 서비스를 제공하였습니다.
JBossWS 에서 Spring Bean 사용하는 WebService Class
JBossWS 에서는 @Resource 라는 어노테이션을 이용하여 ThreadLocal 한 WebServiceContext 객체를 설정할 수 있습니다.
메소드에 어노테이션 설정하여 WebServiceContext 객체가 웹 서비스 객체에 설정이 될 때 Spring Bean 을 WebApplicationContext 를 이용하여 가지고 오는 방법을 사용하였습니다.
이렇게 구성된 웹 서비스를 JBoss 에 publish 하는 방법은 단순합니다.
web.xml 에 servlet 과 servlet-mapping 에 웹 서비스 클래스를 등록하는 것이 전부입니다.
Spring WebService 로 publish 할 경우 별도의 포트로 binding 해야 하지만 JBossWS 는 JBoss 포트로 서비스가 가능합니다.
22:52:20,485 INFO [JMXKernel] Legacy JMX core initialized 22:52:21,235 ERROR [AbstractKernelController] Error installing to Instantiated: name=AttachmentStore state=Described java.lang.IllegalArgumentException: Wrong arguments. new for target java.lang.reflect.Constructor expected=[java.net.URI] actual=[java.io.File] at org.jboss.reflect.plugins.introspection.ReflectionUtils.handleErrors(ReflectionUtils.java:395) at org.jboss.reflect.plugins.introspection.ReflectionUtils.newInstance(ReflectionUtils.java:153) at org.jboss.reflect.plugins.introspection.ReflectConstructorInfoImpl.newInstance(ReflectConstructorInfoImpl.java:106)
13:06:51,379 ERROR [[jsp]] Servlet.service() for servlet jsp threw exception javax.servlet.ServletException: OncePerRequestFilter just supports HTTP requests at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:62) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)