'JTA'에 해당되는 글 2건

  1. 2013.08.27 Atomikos 3.7 - Spring3.1 - Tomcat7 Integration
  2. 2013.08.07 [번역] JTA와 XA, 그리고 Atomikos

이번 포스트에서는 오픈소스 JTA 구현체인 Atomikos를 스프링 웹 어플리케이션 및 Tomcat과 연동하여 사용하는 방법에 대해 다뤄 보겠습니다. 기본적인 내용들은 Atomikos 홈페이지에서 다루고 있기는 하지만, 그대로 따라해보니 몇 가지 부족한 부분이 있더군요. 이 포스트에서는 원문을 보지 않고도 최대한 간단히, 그리고 빠르게 적용할 수 있도록 설명해 보도록 하겠습니다.

Atomikos 홈페이지에서 소개하고 있는 Tomcat Integration 정보는 [여기]에서 확인하실 수 있습니다. 이 페이지에서 자신이 사용하는 버전에 맞는 항목을 참고하시면 됩니다. 이 포스트에서는 Tomcat 7.x와 연동하는 방법에 대해 살펴보도록 하겠습니다.


이 포스트의 내용을 진행하기 위한 사전 준비사항은 다음과 같습니다.

  1. 설치 및 설정 완료된 Apache Tomcat 7.x
  2. 사용하는 DB에 대한 JDBC Driver JAR 파일
  3. Tomcat에서 실행할 스프링 웹 어플리케이션
  4. Atomikos에서 제공하는 JAR 파일 
    1. atomikos-integration-extension-3.7.1-20120529.jar


아래 내용에서 사용되는 환경변수들은 다음과 같습니다.

  • $CATALINA_HOME : 톰캣 설치 디렉토리.
  • $CATALINA_LIB : $CATALINA_HOME/lib - 톰캣이 사용할 라이브러리가 위치하는 디렉토리
  • $CATALINA_CONF : $CATALINA_HOME/conf - 톰캣에 대한 환경설정 파일 이 위치한 디렉토리
  • $WEB_CONTEXT_ROOT : 웹 어플리케이션이 설치된 디렉토리


  1. 먼저 Tomcat에 대한 설정을 진행합니다. (2~7)

  2. 사용하는 DB에 대한 JDBC 드라이버 JAR 파일을 $CATALINA_LIB 디렉토리에 복사해 넣습니다.
    (저의 경우에는 Oracle10g를 위한 ojdbc6.jar 파일을 넣었습니다.)

  3. atomikos-integration-extension-3.7.1-20120529.jar 파일을 $CATALINA_LIB 디렉토리에 복사해 넣습니다.

  4. 그 외 JTA와 Spring 연동을 위한 갖가지 라이브러리들을 $CATALINA_LIB 디렉토리에 복사해 넣습니다.
    (atomikos-integration-extension-3.7.1-20120529.jar 파일은 2번에서 이미 넣은 것이니 여기서는 생략해도 됩니다.)


    이 파일들은 [JAR Finder]에서 검색하여 다운로드 받으실 수 있습니다. (이 파일들이 없으면 Tomcat 기동 시 수많은 오류를 보게 될 것입니다.)

  5. $CATALINA_CONF/server.xml 파일에 다음 내용을 입력합니다.
    <Listener className="com.atomikos.tomcat.AtomikosLifecycleListener" />
    


  6. $CATALINA_CONF/context.xml 파일에 다음 내용을 입력합니다. 이 정보는 context.xml 파일에 등록되어 있는 <WatchedResource> 태그 이후에 입력합니다.
        <Transaction factory="com.atomikos.icatch.jta.UserTransactionFactory" />
    	<!-- Also register Atomikos TransactionManager as java:comp/env/TransactionManager -->
        <Resource name="TransactionManager"
                auth="Container"
                type="com.atomikos.icatch.jta.UserTransactionManager"
                factory="org.apache.naming.factory.BeanFactory" />
    
        <!-- Spring LoadTimeWeaver Support for the Tomcat server. -->
        <Loader loaderClass="org.springframework.instrument.classloading.tomcat.TomcatInstrumentableClassLoader"
              useSystemClassLoaderAsParent="false"/>
        <Resource
    			name="defaultDatasource"
    			auth="Container"
    			type="com.atomikos.jdbc.AtomikosDataSourceBean"
    			factory="com.atomikos.tomcat.EnhancedTomcatAtomikosBeanFactory"
    			uniqueResourceName="defaultDatasource"
    			xaDataSourceClassName="oracle.jdbc.xa.client.OracleXADataSource"
    			
    			xaProperties.serverName="xxx.xxx.xxx.xxx" 
    			xaProperties.portNumber="xxxx"  
    			xaProperties.user="xxxx"
    			xaProperties.password="xxxx"
    			xaProperties.databaseName="xxxx"
    			xaProperties.URL="jdbc:oracle:thin:@xxx.xxx.xxx.xxx:xxxx:xxxx"
    			
    			maxPoolSize="10"
    			minPoolSize="1"
    	/>      
    


  7. 여기까지 하면 일단 Tomcat에 대한 설정은 마무리된 것입니다. 이제 웹 어플리케이션에 대한 설정을 진행합니다.

  8. $WEB_CONTEXT_ROOT/WEB-INF/web.xml 파일에 다음과 같이 resource-ref 정보를 입력합니다. 8에서 입력했던 Datasource 정보를 이용합니다.
    	<resource-ref>
    		<res-ref-name>defaultDatasource</res-ref-name>
    		<res-type>com.atomikos.jdbc.AtomikosDataSourceBean</res-type>
    		<res-auth>Container</res-auth>
    		<res-sharing-scope>Unshareable</res-sharing-scope>
    	</resource-ref>
    


  9. 스프링 웹 어플리케이션에서 사용할 데이터소스 정보와 트랜잭션 매니저 정보를 다음과 같이 스프링 컨텍스트 파일에 입력합니다. 이 예제에서는 MyBatis를 같이 이용하고 있습니다.
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    	xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context"
    	xmlns:tx="http://www.springframework.org/schema/tx" xmlns:jee="http://www.springframework.org/schema/jee"
    	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    		http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
    		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
    		http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
    		http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.0.xsd">
    
    	<tx:annotation-driven transaction-manager="transactionManager" />
    
    	<jee:jndi-lookup id="defaultDataSource" jndi-name="defaultDatasource" />
    
    	<!-- Construct Atomikos UserTransactionManager, needed to configure Spring -->
    	<bean id="AtomikosTransactionManager" class="com.atomikos.icatch.jta.UserTransactionManager" init-method="init"
    		destroy-method="close">
    
    		<!-- when close is called, should we force transactions to terminate or not? -->
    		<property name="forceShutdown" value="false" />
    	</bean>
    
    	<!-- Also use Atomikos UserTransactionImp, needed to configure Spring -->
    	<bean id="AtomikosUserTransaction" class="com.atomikos.icatch.jta.UserTransactionImp">
    
    		<property name="transactionTimeout" value="300" />
    	</bean>
    
    	<!-- Configure the Spring framework to use JTA transactions from Atomikos -->
    	<bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager">
    		<property name="transactionManager" ref="AtomikosTransactionManager" />
    		<property name="userTransaction" ref="AtomikosUserTransaction" />
    	</bean>
    
    
    	<bean id="oracleSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    		<property name="dataSource" ref="defaultDataSource" />
    		<property name="configLocation" value="classpath:mybatis/oracle-configuration.xml" />
    	</bean>
    
    	<bean id="oracleSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate">
    		<constructor-arg ref="oracleSessionFactory" />
    	</bean>
    
    	<bean id="myBatisMapperScanner" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
    		<property name="basePackage" value="com.bory.app.dao" />
    		<property name="annotationClass" value="org.springframework.stereotype.Repository" />
    	</bean>
    
    </beans>
    
    


  10. $WEB_CONTEXT_ROOT/WEB-INF/classes 디렉토리에 jta.properties 파일을 생성하고 그 내용을 적절히 수정합니다. jta.properties 파일에 대한 내용은 [여기]에서 확인하실 수 있습니다.


이제 모든 작업이 완료되었습니다. Tomcat을 재기동하면 Atomikos에 의해 트랜잭션 처리가 수행되는 웹 어플리케이션을 이용할 수 있게 됩니다.

신고
Posted by Layered 트랙백 0 : 댓글 0

댓글을 달아 주세요

이 글은 Atomikos라고 하는 오픈소스 JTA 라이브러리 사이트에서 제공하는 JTA와 XA에 대한 설명을 번역한 것입니다. 

사내 교육용으로 번역했었는데, 교육 효과는 개뿔, 읽어본 아이들이 손에 꼽을 정도내요. 이대로 사장(?)되는 것이 아쉬워 올려봅니다. 원문 주소는, http://www.atomikos.com/Documentation/GettingStarted 입니다. 

Atomikos는 스프링 프레임워크가 더 이상 JOTM(Java Open Transaction Manager)를 정식으로 지원하지 않으면서 더욱 각광을 받고 있는 듯 합니다. 나중에 기회가 되면 [Atomikos를 이용한 Spring 분산 Transaction처리]와 [Tomcat/Glassfish에 Atomikos 적용하기] 등을 다뤄볼까 합니다.


What is JTA

JTA(Java Transaction API)은 플랫폼마다 상이한 트랜잭션 매니저들과 어플리케이션들이 상호작용할 수 있는 인터페이스를 정의하고 있다. Java에서 제공되는 대부분의 API와 마찬가지로, JTA는 실제 구현은 다르지만 어플리케이션이 공통적으로 사용할 수 있는 하나의 인터페이스를 제공한다. 이 말은 트랜잭션 처리가 필요한 어플리케이션이 (API의 사용 방식 그대로만 사용한다면) 특정 벤더의 트랜잭션 매니저에 의존할 필요가 없음을 의미한다. Atomikos와 같이 JTA 구현체들을 오픈소스로 제공하는 벤더들도 있고, IBM 같이 JTA 구현체를 어플리케이션 서버의 한 부분으로 제공하는 벤더들도 있다.

JTA의 구현체를 사용할 때에는 주의를 기울여야 한다: 자세히 들여다 보면 뭔가 잘 못 되어 있는 것처럼 보이기 때문이다. 믿기 어렵겠지만, J2EE 호환됨이라고 검증을 받은 어플리케이션 서버들도 트랜잭션 관리를 제대로 지원하지 않거나 가상적으로만 지원할 수도 있다.

 

What is XA

XA(eXtended Architecture)는 동일한 전역 트랜잭션(Global Transaction) 내에서 몇 개의 백엔드 데이터 저장소에 접근하기 위한 X/Open 그룹 표준의 하나이다. XA 표준 규격은 하나의 트랜잭션 매니저가 어떤 트랜잭션의 한 부분으로 어떤 작업이 수행되고 있는지를 데이터베이스에 통보하는 방식과, 각 트랜잭션이 완료될 때 2단계 커밋(2 Phase Commit)을 수행되는 방식을 관장한다. 또 데이터 저장소에서 지연되고 있는 트랜잭션을 회복시키는 방법도 포함하고 있다.

XA의 장점

XA 역시 하나의 표준이기 때문에, 모든 호환되는 데이터 저장소(혹은 드라이버)들이 전역 (분산) 트랜잭션의 부분으로서의 트랜잭션 매니저와 연동할 수 있다. 다른 말로, 2단계 커밋이 고려되어야 하는 상황이라면 XA는 트랜잭션 매니저와 데이터 저장소를 연결해 주는 역할 담당한다는 말이다. 이것이 Atomikos와 같은 솔루션들이 Oracle이나 Sybase와 같은 데이터베이스와 연동하여 커밋과 롤백 등의 모든 작업을 수행할 수 있는 이유이다.

 

When to use JTA / XA

JTA XA는 데이터가 오염되는 것(그리고 그로 인한 사업상의 손실)을 막아주는 일종의 보험 시스템 같은 것이다. 가장 흔한 경우는 다음과 같다.

l  (Queue)로부터 JMS 메시지를 받아 처리한 뒤 그 결과를 데이터베이스에 저장하는 경우: 데이터베이스에 대한 저장이 실패한 경우에도 JMS 메시지가 유실되어서는 안 된다.

l  두 개 이상의 레거시 백엔드 시스템에 대해 동일 트랜잭션으로 업데이트 해야 하는 경우

일반적으로 하나 이상의 백엔드 시스템에 대해 동일 트랜잭션으로 여러 작업을 수행해야 하는 경우에 JTA/XA의 사용을 강하게 권고한다. 그렇지 않으면 데이터의 유실이나 오염의 위험이 매우 커질 수 있다. (그리고 그것을 확인할 방법이 없을 수도 있다.)

많은 프로그래머들이 JTA/XA의 오버헤드를 피하기 위해 어플리케이션에 특정 복구 코드를 프로그래밍 하기도 한다. (예를 들어, 중복 요청 처리라던가, 데이터베이스에 부가 상태 정보를 저장하는 것과 같은) 그러나 이 방법들은 모두 (재사용 불가능하고, 어플리케이션에 종속적이고 테스트하기 어렵기 때문에) 불완전하다. 결과적으로, 모두가 예측할 수 있는 JTA/XA의 오버헤드가 같은 작업을 하지만 버그를 내포하고 있는 어플리케이션 레벨의 오버헤드로 대체된 것과 같다.

간단한 계산으로 JTA/XA의 이점을 보여줄 수 있다: 은행이 하나 있고, 일반적으로 하루에 백만 트랜잭션을 처리하며 평균적으로 트랜잭션 당 100$가 처리된다고 가정해 보자. 즉 하루에 총 100,000,000$가 처리되는 것이다. 만약 시스템에 문제가 발생하여 1%의 데이터가 유실된다면, 한 번의 문제로 전체 1,000,000$의 손실을 입게 되는 것이다. JTA/XA는 명백하게 이런 문제를 미연에 방지해준다.

 

When NOT to use JTA / XA

아래 표는 JTA/XA를 사용하지 말아야 할 경우와 몇몇 기회비용들을 보여주고 있다. 이 외의 경우에서는 JTA/XA가 신뢰성과 간결함이라는 측면에서 엄청난 혜택을 줄 수 있다.

시나리오

JTA/XA 없이 실행

JTA/XA 혜택

최대 하나의 리소스에 접근

안전함.
(
시스템 락이 트랜잭션 지연을 유지할 수 있음)

락이 무한정 걸리는 것을 방지함

하나의 백엔드 시스템 내에서 여러 자원에 접근

각 접근에 대해 동일한 커넥션을 이용하면 안전함. 서로 다른 접근 간에 데이터를 공유해야 할 경우에는 공유 커넥션 처리를 위해 Thread-local 조작이 필요할 수 있으며, 커밋 처리가 매우 복잡해 짐

데이터 공유가 XA에 의해 처리됨

상이한 백엔드 시스템들에 대한 다중 쿼리

가능함, 하지만 정확성은 보장되지 않음

모든 경우에 있어 정확한 데이터를 읽을 수 있음

다중 백엔드 시스템

안전하지 않음. 시스템 장애로 인해 데이터 손실이 발생해도 상관 없는 경우에만 사용할 것

데이터 손실이나 오염이 발생하지 않음

 

Getting Started with TransactionsEssentials

배경

Atomikos는 모듈화를 감안하여 설계되었다. icatch라고 하는 독점적인 API를 제공하는 트랜잭션 커널이 있는데, 이것을 바탕으로 수많은 트랜잭션 서비스들이 만들어졌다. 그 중 하나가 JTA 구현체이다: icatch의 상위 계층으로 JTA API 구현체가 존재한다.

수많은 다른 서비스들이 있긴 하지만 Atomikos TransactionsEssentials 배포에서 사용할 수 있는 것은 JTA가 유일하다. Atomikos ExtremeTransactions RMI와 웹서비스 인터페이스들을 포함하고 있다.

Atomikos를 이용하여 JTA 프로그래밍

일반적으로는 icatch API는 신경 쓸 필요 없이 JTA 인터페이스만 사용하면 된다.

트랜잭션 매니저를 초기화하려면, com.atomikos.icatch.jta.UserTransactionManager 인스턴스를 생성하고 생성된 인스턴스의 init () 메소드를 호출하면 된다. 어플리케이션이 종료될 때 close() 메소드를 호출하는 것을 잊어서는 안 된다.

이 클래스는 javax.transaction.TransactionManager 인터페이스를 구현했는데, 이 인터페이스에는 JTA 트랜잭션을 제어하기 위한 모든 작업 begin(), commit() 그리고 rollback()과 같은 메소드들이 정의되어 있다.

초기화하는 과정에서 이 클래스는 클래스패스의 루트 디렉토리에 있는 jta.properties 파일을 읽는다. 이 파일에 대한 설정 방법은 JTA Properties를 참고하기 바란다.

간단한 JTA 예제

이제 JTA API를 이용하여 트랜잭션 매니저를 초기화하고 시작하고 커밋 한 뒤 적절하게 셧다운 하는 예제 코드를 확인해 보도록 하겠다. 간결하게 설명하기 위해 예외 처리는 생략하였다.

JDBC JMS 자원을 설정하고 사용하는 상세한 방법은 JDBC와 TransactionsEssentials 사용하기JMS와 TransactionsEssentials 사용하기를 참고하기 바란다. 온라인에서 제공되는 Atomikos ExtremeTransactions 인증 코스를 통해 JDBC JMS에 대해 학습할 수도 있다.

import com.atomikos.icatch.jta.UserTransactionManager; 
import com.atomikos.jdbc.AtomikosDataSourceBean; 
 
import javax.jta.TransactionManager; 
import javax.sql.DataSource; 
 
public class AtomikosExample { 
 
  // Atomikos implementations 
  private static UserTransactionManager utm; 
  private static AtomikosDataSourceBean adsb; 
 
  // Standard interfaces 
  private static TransactionManager tm; 
  private static DataSource ds; 
 
  // initialize resources 
  private static void init() { 
    UserTransactionManager utm = new UserTransactionManager(); 
    utm.init(); 
    tm = utm; 
 
    adsb = ...; // omitted for clarity 
    ds = adsb; 
  } 
 
  // release resources 
  private static void shutdown() { 
    adsb.close(); 
    utm.close(); 
  } 
 
  public static void main(String[] args) { 
    init(); 
 
    tm.begin(); 
 
    Connection c = ds.getConnection(); 
    // use connection to execute SQL 
    c.close(); 
 
    tm.commit(); 
 
    shutdown(); 
  } 
 
} 

 

신고
Posted by Layered 트랙백 0 : 댓글 0

댓글을 달아 주세요


티스토리 툴바