2012년 3월 22일

경량 데이터 동기화 모듈 구현하기 : Part 1



데이터 동기화

데이터 동기화란 여러 애플리케이션, 데이터베이스 또는 시스템에 포함된 데이터의 일관성을 유지하는 것이다.

대부분의 경우는 데이터가 여러 애플리케이션이나 데이터베이스에 의해 별도로 관리되는 정보시스템에 존재하면서도 시스템간에 일관성이 유지되어야한다. 데이터 동기화에 대한 필요성은 (데이터 마이그레이션을 위한) 임시 또는 (시스템 간의 데이터 동기화) 영구가 될 수 있다. 데이터 동기화 단일방향 또는 양방향 중 하나가 될 수 있다.

웹 기반 응용 프로그램에서 요구하는 데이터 동기화는 서로 다른 데이터베이스 간의 데이터를 동기화다. 이런 이유에서 많은 웹 기반 어플리케이션 프로젝트에서는 동기화를 위하여 EAI 와 같은 통합 솔루션을 사용하지 않고 상황에 맞는 JDBC 프로그래밍을 통하여 구현하고 있다.


그림1. 데이터베이스간의 데이터 동기화 구성도



데이터 동기화 구현

효율적이고 신뢰할 수있는 데이터 동기화 프로세스 구현에는 많은 어려움이 있을 것으로 예상되지만 (비기능, 기능)품질 수준을 최소화 한다면 어려운 것만은 아니다. 또한 웹 어플리케이션에서 요구하는 최소 수준의 데이터 동기화 구현은 웹 어플리케이션 개발에 있어 생산성에 많은 기어를 할 것으로 생각한다.

보다 손쉬운 접근을 위하여 데이터 동기화 구현을 위하여 자바 기반의 EAI(Enterprise Application Integration) 소프트웨어 openadaptor 의 소프트웨어 아키텍처 와 네이밍 규칙을 차용하였다. (개념수준이며 실 구현은 전혀 다르다)

먼저 데이터 동기화 구현는 커넥터(Connector), 프로세서(Processor)들로 구성된 하나의 어댑터(Adaptor)로 구성된다.


그림2. 데이터 동기화를 위한 어텝터 구성도

이들은 아래의 그림 3. 스퀀스 다이어그램이 보여주는 방식으로 동기화 작업을 수행한다.


그림3. 시퀀스 다이어그램


커넥터(Connector)
커넥터(Connector) 는 읽기를 수행하는 ReadConnector 와 쓰기를 수행하는 WriteConnector 로 구성된다.



Connector.java
package architecture.common.adaptor;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public interface Connector {

 public static final Log LOG = LogFactory.getLog(Connector.class);
 
}
ReadConnector.java
package architecture.common.adaptor;

public interface ReadConnector extends Connector{

 public abstract Object pull(Context context);
 
}
WriteConnector.java
package architecture.common.adaptor;

public interface WriteConnector extends Connector {
 
 public abstract Object deliver(Context context);

}


프로세서(Processor)
프로세서(Processor)는 커넥터(Connector)를 사용하여 데이터를 읽기/쓰기 작업 만을 수행한다.


프로세서는 동작 방법에 따라 READ, WRITE, MERGE 3가지 형태로 분류할 수 있으며 연속적으로 프로세스를 사용하여 원하는 데이터 동기화 작업을 수행하게 된다.

  • READ 프로세서 : READ 커넥터(Connector)를 사용하여 데이터에 대한 읽기 작업을 수행한다.
  • WRITE 프로세서 : WRITE 커넥터(Connector)를 사용하여 READ 프로세서에서 처리된 데이터에 대한 쓰기 작업을 수행한다.

아래의 그림은 READ > MERGE > WRITE 프로세서를 단일 프로세서 그룹으로 정의하여 데이터를 복사하는 구조를 보여준다. (MERGE 은 Adaptor 가 하나 이상의 프로세스들을 연속으로 사용하여 데이터를 처리한다.)




DataProcessor.java
package architecture.common.adaptor;

public interface DataProcessor {

 public abstract Context getContext();
 
 public Object process(Object... args);
 
}

DataSyncProcessor.java
package architecture.common.adaptor.processor;

import architecture.common.adaptor.Context;
import architecture.common.adaptor.DataProcessor;
import architecture.common.adaptor.ReadConnector;
import architecture.common.adaptor.WriteConnector;

public class DataSyncProcessor implements DataProcessor {
 
 private ReadConnector readConnector;
 
 private WriteConnector writeConnector;
 
 /**
 * 
 */
 public Object process(Object... args) {

 Context context = getContext(); 
 
 Object data = getReadConnector().pull(context); 
 
 context.setObject("data", data); 
 
 return getWriteConnector().deliver(context);
 }

 public Context getContext() {
 return null;
 }

 public ReadConnector getReadConnector() {
 return readConnector;
 }

 public void setReadConnector(ReadConnector readConnector) {
 this.readConnector = readConnector;
 }

 public WriteConnector getWriteConnector() {
 return writeConnector;
 }

 public void setWriteConnector(WriteConnector writeConnector) {
 this.writeConnector = writeConnector;
 }
 
}

어댑터 (Adaptor)
어댑터(Adaptor)는 프로세스 매핑에 따라 커낵터를 통하여 읽기/쓰기 작업을 수행한다. 어뎁터는
  1. 커넥터를 정의하는 connectors
  2. 프로세서 동작을 정의하는 processMapping
  3. 프로세서 그룹을 정의하는 pipelineMapping
로 구성되어 있다. Adaptor 인터페이스 클래스는 어떤 클래스가 어댑터인가를 구분하는 목적으로 사용될 뿐  어댑터가 어떻게 구현되어야하는 가는 정의하고 있지 않는다. 보다 구체적으로 어댑터를 정의하는 클래스는 Adaptor 인터페이스을 상속하여 목적에 맞도록 설계할 수 있도록 하였다. 여기에서는  DataSyncClient  인터페이스 클래스가 어댑터에 대한 상세한 기능을 정의하고 있는 인터페이스 클래스에 해당한다.




DataSyncClient.java
package architecture.ext.sync.client;

import java.util.List;
import java.util.Map;

import architecture.common.adaptor.Adaptor;
import architecture.common.adaptor.processor.ProcessCallback;


public interface DataSyncClient extends Adaptor {
 
 public abstract List> read (String processName);
 
 public abstract List> read (String processName, Object[] args);
 
 public Object write(String processName, Map input);
 
 public Object write(String processName, List> input);
 
 public abstract T process ( String processName, Object[] args, ProcessCallback action);
 
 public abstract Object process (String processName);
 
 public abstract Object process (String processName, Object[] args);
 
}


DataSyncException.java
package architecture.ext.sync.client;

import org.apache.commons.lang.exception.NestableRuntimeException;

public class DataSyncException extends NestableRuntimeException {

 private static final long serialVersionUID = 6202766507431175181L;

 public DataSyncException() {
 super();
 }

 public DataSyncException(String msg, Throwable cause) {
 super(msg, cause);
 }

 public DataSyncException(String msg) {
 super(msg);
 }

 public DataSyncException(Throwable cause) {
 super(cause);
 }

}

댓글 없음:

댓글 쓰기