욱'S 노트

Spring XD - Modules 본문

Programming/Spring XD

Spring XD - Modules

devsun 2015. 3. 4. 10:49

소개


Spring XD는 stream을 정의하여 데이터를 획득하는 것을 지원한다. Stream은 module로 구성된다. Module은 캡슐화된 작업 단위를 재활용가능한 컴포넌트로 만든 것이다. Spring XD의 job 또한 모듈로서 구현되어야 한다.


모듈은 타입에 따라 분류될 수 있다. 타입은 일반적으로 모듈의 역할과 기능을 나타낸다. 현재 Spring XD 모듈의 타입은 source, sink, processor 그리고 job이다. 타입은 스트림에서 모듈이 어떻게 조합될지 혹은 배치 작업으로 디플로이 될 떄 사용될 지 여부를 결정한다.


  • Source는 외부 리소스로 또는 이벤트로 부터 트리거되어 output을 제공한다. stream의 첫번째 모듈은 반드시 source여야 한다.
  • Processor는 입력 메시지를 사용하여 어떤 작업을 수행한 후 새로운 메시지를 생성한다. 그래서 입력과 출력이 모두 요구된다.
  • Sink는 입력 메시지를 소비하여 외부 리소스에 데이터를 출력한다. 그리고 stream을 종료시킨다.
  • Job은 Spring XD에서 사용가능한 Spring Batch 작업이다.


Spring XD에서는 stream으로 조합할 수 있는 빌트인 모듈을 제공한다. File, HDFS, Spark, Kafka, http, syslog, GemFire 등등. 또한 사용자는 복잡한 빅데이터 어플리케이션을 이러한 모듈들을 자바코드 없이 조합해 만들 수 있다. Spring XD의 모듈을 생성하기 위해서는 Spring, Spring Integration 또는 Spring Batch에 대한 지식은 필수적이다. 다음 내용들은 이러한 주제들에 대해 이미 알고 있다고 가정한다.


Creating a module

Source, processor 그리고 sink는 Spring Integration을 이용하여 생성되고, stream에서 쉽게 재활용할 수 있는 개별 task로 수행된다. 커스텀 모듈은 레거시 서비스와의 연계와 같은 특별한 기능을 수행한다,

  • Source는 poller나 trigger가 설정된 inbound adapter로부터 데이터를 제공받는 output으로 명명된 direct channel을 포함한 유효한 메시지 플로우이다. 
  • Processor는 input으로 명명된 direct channel과 output으로 명명된 subscribable channel(direct or publish subsrcibe)을 포함한 유효한 메시지 플로우 이다. 일반적으로 입력 메시지를 기반으로 새로운 메시지를 생성하는 transformation을 수행ㅎ나다.
  • Sink는 input channel과 외부 리소스에 메시지를 전달하기 위한 outbound adapter 또는 service activator를 포함한 유효한 메시지 플로우이다. 

예를들면, file source는 file inbound adapter를 이용하여 디렉토리로부터 파일을 획득한다. 그리고, file sink는 입력된 message payload를 덧붙여 file outbound adapter를 사용해 파일을 생성한다. 이러한 컴포넌트들은 틀별할 것이 없다. 단지 일반적인 Spring XML 빈 설정이다.

그러나 모듈을 생성할때는 중요한 규칙이 있다. Input과 output channel의 이름은 항상 input과 output이어야 한다. Spring XD 런타임은 이렇게 명명된 channel들을 이용하여 메시지를 전송한다.

모듈은 Spring application context를 생성하기 위해 사용되는 artifact를 포함한 패키지 컴포넌트이다. 일반적으로 모듈은 런타임 환경에 대해 알 필요가 없다. 각 모듈의 application context는 분산 처리를 지원하기 위해 플러그인을 통해 설정되고 연결된다. 모듈은 다른 stream 처리에 사용될 수 있다. Spring XD에서는 특정한 모듈 타입을 정의하고 있다. 모듈 타입은 마이크로 서비스 아키텍처의 핵심 컴포넌트로서 동작하도록 설계되었다.

물리적으로 모듈은 Servlet container에 war 파일과 어딘가 모르게 유사하다. Spring XD container는 module이 배포되었을 때 설정되고 모듈을 시작한다.  Spring XD에서 모듈 배포한 처리를 위한 instance를 활성화하는 것을 의미한다. War와 유사하게 자신의 리소스를 로드하기 위해 제공된 class loader를가진다.특히 자신의 설정과 라이브러리 디렉토리를 가진다. War파일과 또 다른 공통점은 설정된 위치에 설치되어야 하며 표준 레이아웃을 준수해야 한다는 것이다. Artifact는 정해진 위치에 설치되어야 한다. Spring XD 모듈은 동일한 방식으로 동작한다. Spring XD 모듈 레이아웃은 개별 모듈 개발을 지원하기 위해 새로운 기능이 추가 되었다. 이러한 발전은 일반적으로 개별 모듈을 활용한 더 유연한 아키텍처로 이끌 것이다. 그러나 모듈 패키징 구조는 잘 정의되어야 한다.

<module_name>
    ### <local class files and resources, e.g. com/acme/....>
    ### config
    #   ### <any-name>.properties
    #   ### <any-name>.[xml | groovy] (optional)
    ### lib
    #   ### <dependent libraries not already in Spring XD class path (xd/lib)>
    #

하위 호환성을 위해 Spring XD에 기배포된 모든 모듈은 XML 빈 설정 파일(<module-name>.xml)과 프로퍼티 파일(<module-name>.properties)를 사용하여 공통적으로 설정되어 있다. 모듈은 일반적으로 다음과 같은 사항을 포함한다.

  • 어플리케이션 컨텍스트 설정 : application context 설정을 위한 xml이나 groovy파일이 있어야 한다. 만약 설정클래스를 사용한다면 설정 파일에 표현되어야 한다.
  • 모듈 프로퍼티 파일 : 모듈이 어떤 옵션을 제공해야 한다면 프로퍼티 파일을 사용할 수 있다. 프로퍼티 파일은 Module Options Metadata 클래스의 fully qualified 클래스명을 포함한 option_class프로퍼티를 제공한다. 또한 프로퍼티 파일은 in-line module option descriptor를 제공할 수도 있다.
Spring XD 1.1 모듈의 빈 설정 리소스나 프로퍼티 파일명은 임의로 지을 수 있다. 현재 top level config 디렉토리는 규칙이다. 이것은 config에 다른 비슷한 파일 타입 사용을 위한 제약이다. 다수의 xml, groovy 또는 properties 파일이 존재할 경우 예를들어 config/*xml 경우에는 exception이 발생한다. 다수의 resource로 부터 빈 정의를 조합하기를 원한다면 클래스패스의 어느 위치에 리소스를 놓고 import를 이용해라. 

만약 설정 파일이 없다면 Spring XD는 base_packages 프로퍼티의 컴마로 구분된 패키지 리스트를 찾는다. 그리고 모듈 범위로 Spring component로 스캔한다.

개별 코드 : 일반적으로 jar파일로 패키징 된다. root 레벨에는 @Configuration class가 포함될 수 있고, 모듈에 디펜던시 클래스들이 포함 될 수 있다.
디펜던시 jar files : Spring XD classpath ($XD_INSTALL_DIR/xd/lib)에서 제공되지 않는 모듈을 위해 사용되는 jar파일은 /lib 디렉토리에 위치 시킨다.

Spring XD 모듈은 directory tree로 풀어서 설치될 수 있고 archive로 설치될 수도 있다. 만약 모듈이 연관된 jar가 필요하다면 Spring Boot의 uberjar로 패키지할 수도 있다. 

Creating a module project

Spring XD 1.1.x 에서는 Maven이나 Gradle에서 모듈 테스트 및 패키지를 지원한다.

Maven의 경우 프로젝트의 pom.xml에 다음과 같이 parent 설정을 추가한다.
<parent> 
<groupId>org.springframework.xd</groupId> 
<artifactId>spring-xd-module-parent</artifactId> 
<version>1.1.0.RELEASE</version>
</parent>

Gradle의 경우 bulid script에 다음과 같은 내용을 추가하자.

buildscript {
    repositories {
... }
    // Add the path of the Spring XD Module plugin
    dependencies {
      classpath("org.springframework.xd:spring-xd-module-plugin:1.1.0.RELEASE") //or a later release ofthe plugin
} }
//The Spring XD version is required by the plugin to pull in order to configure dependent libraries that
 your module project will likely need.

ext {
  springXdVersion = '1.1.0.RELEASE' //or a later release of Spring XD
}

apply plugin: 'spring-xd-module'


Uber-jar로 모듈을 패키징 할때 컴파일 및 테스트를 위해 필요한 Spring XD 라이브러리를 제공하는 빌드 지원 툴은 각각의 지원툴은 Spring Boot Maven Plugin 또는 Spring Boot Gradle Plugin이다.


모듈은 Spring XD Container로 부터 제공되니 않는 디펜던시를 포함해야 한다. 이러한 사항들은 module이 디플로이 될 때 module class loader에 의해 로딩된다. 라이브러리 디렉토리에 포함되는 않는 jar는 ClassDefNotFoundException을 발생시킬 것이다. 게다가 모듈 Spring XD 클래스패스에 다른 버젼의 라이브러리가 존재한다면 confliect나 class loading 이슈가 발생할 수도 있을 것이다. 그러나 걱정할 필요는 없다.


  • Spring Boot 패키징 레이아웃은 uber-jar에 제공된 디펜던시가 포함되지 않는 것을 보장해준다. Spring XD 모듈 빌드는 제공된 디펜던시는 spring-xd-dirt로 정의하고 해당 클래스들을 모듈 개발시 제공한다.
  • 만약 Spring XD runtime 디펜던시를 포함한 uber-jar라면 해당 디펜던시를 제거해준다.


빌드 지원 툴은 spring-xd-dirt와 spring-xd-test를 정의된 디펜던시를 지원한다. spring-xd-test는 모듈 개발에 유용하다.


  • 자바로 정의된 Module Options Metadata
  • In-Container 모듈 테스팅 - 임베디드 싱글 노드 컨테이너를 구동, 모듈 배포 및 결과 검증


Testing a Module Project


자세한 테스트 예제는 각각 타입별 모듈 섹션에서 제공한다. 모듈을 빌드하기 위해서는 다음과 같은 커맨드를 수행한다.


$mvn clean package


$gradlew clean test bootRepackage



Registering a Module


Spring XD Module Registry에 모듈을 등록해보자. 모듈은 stream이나 job으로 배포되기 전에 등록되어야 한다. 모듈이 패키징 되었다면 쉘의 업로드 커맨드를 통해서 등록을 할 수 있다.


xd:>module upload --file [path-to]/mymodule-1.0.0.BUILD-SNAPSHOT.jar --name mymodule --type processor


모듈정의는 모듈을 유니크하게 식별하기 위해 다음과 같은 속성을 요구한다.


name - 컴포넌트명, 모듈의 목적을 나타내는 한 단어

type - 모듈 타입, source, sink, processor 그리고 job


모듈은 Spring XD에 modules 디렉토리에 위치한다. 그리고 Module Registry는 타입과 일치하는 서브 디렉토리에 따라 구성된다.


modules

      ### job

      ### processor

      ### sink

      ### source


Spring XD는 ModuleRegistry라는 전략 인터페이스를 제공한다. 현재 Spring XD ResourceModuleRegistry를 구현하여 제공한다. 


Custom 모듈은 독립 모듈과 분리해서 위치한다. Custom 모듈은 위치를 변경할 수도 있다. severs.yml의 xd.customModule.home의 위치를 수정하면 된다. 디폴트 위치는 ${xd.home}/custom-modules이다. 그러나 custom module이 production에서 사용된다면 네트워크 파일시스템으로 세팅해라. 두가지 이점이 있다. 첫번째, custom 모듈은 XD Admin을 포함한 모든 노드의 XD 컨테이너에서 접근가능해야 된다. 이러면 모든 컨테이너의 해당 모듈이 디플로이 될 수 있을 것이다. 두번째 Spring XD의 설치본에 등록되어 있다면 Spring XD 업그레이드시 사라질 것이다.


Module Class Loading


모듈은 독립된 클래스 로더를 사용하여 모듈의 라이브러리 디렉토리로부터 클래스를 로딩한다. 만약 해당 클래스를 찾을수 없다면 Spring XD에서 일반적으로 사용되는 parent 클래스 로더의 클래스를 로딩할 것이다. 그러나 두가지 사항에 유의하자.

  • Spring XD 클래스패스에서 제공된 jar 파일을 modules lib에 넣는것은 피하자. ClassCastException이나 class loading 이슈가 발생할 수 있다.
  • 메시지로의 payload 타입에 대한 참조를 가진 클래스는 xd/lib에 설치되어야 한다. 그래야 Producer 및 Consumer 모듈에서 접근이 가능하다.
Module Options

모듈 인스턴스는 Module Options Metadata를 통해 정의된 모듈 옵션 바인딩을 위한 property placeholder가 설정되어 있다. 옵션은 필수 혹은 선택적일 수 있으며 선택적일 경우 기본값을 제공해야 된다. Module Options Metadata는 모듈 프로퍼티 파일 혹은 모듈의 자바 클래스로 제공되어 진다. 추가적으로 모듈 옵션의 모듈의 어플리케이션 컨텍스트의 프로퍼티로 제공되며 Spring environment profile을 활성화시키기 위해 사용될 수도 있다.

<beans>
<bean class="org.springframework.integration.x.twitter.TwitterSearchChannelAdapter"> 
<constructor-arg ref="twitterTemplate"/>
<property name="readTimeout" value="${readTimeout}"/>
<property name="connectTimeout" value="${connectTimeout}"/>
<property name="autoStartup" value="false"/>
<property name="outputChannel" ref="output"/>
<property name="query" value="${query}" />
<property name="language" value="${language}" />
<property name="geocode" value="${geocode}" />
<property name="resultType" value="${resultType}"/> 
<property name="includeEntities" value="${includeEntities}"/>
</bean>
<bean id="twitterTemplate" class="org.springframework.social.twitter.api.impl.TwitterTemplate"> 
<constructor-arg value="${consumerKey}"/>
<constructor-arg value="${consumerSecret}"/>
</bean>

<int:channel id="output"/> 
</beans>


스프링 프로퍼티로 query, language, consumerKey 그리고 consumerSecret이 제공되고 있다. Spring XD는 이러한 프로퍼티들을 각 모듈 인스턴스에 옵션으로서 제공된다. 이러한 모듈의 노출된 옵션은 TwitterSearchOptionsMedataa.java에 정의되어 있다.


예를 들면 아래와 같이 옵션에 따른 두가지 다른 stream을 생성할 수 있다.


xd:> stream create --name tweettest --definition "twittersearch --query='java' | file"


xd:> stream create --name tweettest2 --definition "twittersearch --query='spring' --language=en --consumerKey='mykey' --consumerSecret='mysecret' | file"


추가적으로 옵션은 모듈에서 Spring Bean 찹조가 될 수 있다. 각 모듈 인스턴스는 빈의 다른 구현을 인젝션할 수 잇을 것이다. 이러한 기능을 통해 같은 모듈 정의를 다른 설정과 함께 자신의 어플리케이션 컨텍스트를 생성할 수 있게 된다. 이러한 유용한 기능의 결과로 input, output과 같은 단순한 프로퍼티 이름을 빈의 표준 아이디로 사용할 수 있게 되는 것이다.


위의 예에서 디폴트값을 사용한 것을 확인 할 수 있다. 때때로 디폴트는 stream명, module명 또는 runtime context로 대체될 수 있다. 예를들면 file source는 디렉토리를 필요로 한다. 적당한 방법은 공통의 input 패스를 디폴트로 정의하는 것이다. 그리고 Stream 정의에서 dir옵션을 통해 디렉토리를 변경하는 것이다. 이러한 사항들은 module info 커맨드를 통해 확인할 수 있다.




또한 Spring XD에서는 모든 모듈에 아래와 같은 공통적인 PlaceHolder를 제공한다.



모듈은 재활용가능한 Spring Integration 혹은 Spring Batch application context이다. 이들은 module options을 통해 동적으로 설정될 수 있다.

모듈 옵션은 stream이나 작업 정의로 부처 설정된 어떤값이다. 되도록이면 사용가능한 옵션을 metadata로서 제공해야 한다. 옵션값을 할당하는 우선순위는 다음과 같다.


1. stream정의에서 제공된 값

2. platform-wide 디폴트 값

3. 모듈의 메타 데이터에서 제공된 디폴트값


Platform-wide 디폴트는 다음과 같은 기준으로 할당된다.


1. <moduletype>.<modulename>.<optionname>로 명명된 system property

2. <moduletype>.<modulename>.<optionname>로 명명된 환경변수

3. <root>/<moduletype>/<modulename>/<modulename>.properties 프로퍼티 파일의 <optionname>이 key인 프로퍼티

4. <root>/ <module-config>.yml의 <moduletype>.<modulename>.<optionname>


Composing Modules


Stream은 모듈의 순서를 정의한 것이다. 때때로 stream는 공통 처리 chain을 공유하고 싶을때가 있다. Composite 모듈은 똑같은 정의 중복을 피하는 방법으로 사용될 수 있다. 그리고 더욱 중요한 것은 성능을 증가하는 방식으로 사용될 수 있다. Stream에 표현된 각 모듈은 디플로이의 단위가 된다. Singlenode 런타임에서는 모듈간 통신을 In-memory 채널을 이용하지만 분산환경에서는 메시징 미들웨어를 통한다. 많은 경우 stream는 미들웨어 전송 및 오브젝트 마샬링을 피하기 위해 함께 배포되는 것이 성능이 더 나을 수 있다. 


Composite 모듈을 생성하기 위한 간단한 커맨드를 보면 다음과 같다.


xd:> module compose foo --definition "filter --expression=payload.contains('foo') | file"


잘 생성이 되었는지 확인해보자.



Composite 모듈은 Sink로 나타난다. 이유는 이론적으로 sink로 동작하기 때문이다. 그리고 (c) prefix가 붙은 걸 확인할 수 있다.

다음은 두 개의 processor를 composite 해보자. 이런 경우에는 processor로 분류된다.


xd:> module compose myprocessor --definition "splitter | filter --expression=payload.contains('foo')"


다음은 source와 processor를 결합하자. 이것은 source로 분류된다.


xd:> module compose mysource --definition "http | filter --expression=payload.contains('foo')"


Composite 모듈의 logical 타입에 근거하여 stream에서 사용할 수 있다. 다음은 사용예이다.


xd:> stream create httpfoo --definition "http | foo" --deploy

xd:> stream create filefoo --definition "file --outputType=text/plain | foo"  --deploy


더 이상 composite 모듈을 사용하고 싶지 않다면, delete 커맨드로 삭제할 수 있다. 하지만 이 경우 모듈이 stream에서 사용중에 있다면 먼저 stream을 destroy한 다음 delete를 수행하여야 한다.


xd:> stream destroy --name filefoo

Destroyed stream 'filefoo'

xd:> stream destroy --name httpfoo

Destroyed stream 'httpfoo'

xd:> module delete --name sink:foo

Successfully destroyed module 'foo' with type sink


모듈을 생성하거나 삭제할 때 타입별로 똑같은 이름이 존재한다면 타입 필터를 사용할 수 있다. (<type>:<module_name>) 

'Programming > Spring XD' 카테고리의 다른 글

Spring XD - DIRT(Distributed Runtime) 시작하기  (0) 2015.03.12
Spring XD - Source Module 개발하기  (0) 2015.03.05
Spring XD - Streams  (0) 2015.03.03
Spring XD - Job Module 개발하기  (0) 2015.02.05
Spring XD - Batch Jobs  (0) 2015.02.02
Comments