2017년 8월 8일 화요일

ETL 솔루션 환경

ETL 솔루션 환경
하둡은 대용량 데이터를 값싸고 빠르게 분석할 수 있는 길을 만들어줬다.
통계분석 엔진인 “R”역시 하둡 못지 않게 관심을 받고 있다.

빅데이터 역시 데이터라는 점을 볼때 분산처리와 분석 그 이전에 데이터 품질 등 데이터 거버넌스가 이뤄지지 않고서는 제대로 된 결과물을 얻기는 힘들다.

ETL은 그런 점에서 주목받지 못하지만 정보시스템 상에서 앞단 작업에 선봉에 있는 ETL 빅데이터 시대 숨은 공로자와 같다.

생존을 위해 경쟁력을 갖추기 위한 노력
IT 투자 및 운영에 “효율”이라는 과제를 던지게 됐으며, 성능이 아닌 TCO(Total Cost of Ownership)에 맞춰 기업 내 정보시스템을 구축,운영하려는 노력을 하고 있다.

기업의 정확한 비즈니스 의사결정을 위해 사용하는 데이터 접근, 수집, 보관, 분석 등의 애플리케이션과 기술의 집합인 비즈니스 인테리전스(BI) 역시 변화가 감지되고 있다.

기업은 로그데이터, 페이스북, 트위터 상에서 생성되는 SNS 데이터까지 분석 해 경쟁력 강화를 위한 해답을 얻기 위한 방법을 고민하고 있다.

또한 그동안 과거 데이터를 분석했다면 이제는 현재와 미래를 파악하고 예측하기 위해 실시간 데이터에 접근  또는 분석을 통해 기업의 발 빠른 대응을 하기 위한 정보시스템 구축에도 나서고 있다.


ETL은 기업 시스템 내에 축적된 데이터 중 A 시스템에 데이터를 추출, 데이터웨어하우스 등에서 이용하기 쉬운 형태로 변환해, 대상이 되는 B 시스템에 적재하는 용도로 쓰인다. 이렇게 처리된 데이터는 시각화 작업을 통해 기업 의사결정권자들을 위한 비즈니스 리포트로 만들어진다.  통계 데이터 생성이 주업무인 정보계 시스템내 데이터를 추출해 DW에 적재하는 용도로 사용된다.

ETL 툴에는 그래픽 사용자인터페이스를 가용해 데이터의 흐름을 가시화하고 데이터 형식의 변환 기능, 부정 데이터를 배제한 일정 형식으로 데이터를 수정하는 데이터 클렌징 기능 등이 탑재된다. 실제 ETL 작업이 전체 작업의 반절 이상을 차지 할 만큼 BI 시스템에서 중요한 역할을 했지만 전통적인 데이터 처리 과정에서 봤을 때 ETL은 금융과 대규모 정형 데이터를 처리하는 기업에서만 찾는 제한적인 기능이었다. 데이터 규모가 크지 않는 기업들은 수작업을 통해 데이터를 코딩했기 때문에 ETL 툴 같은 상용 제품을 굳이 구매할 이유는 없었다.

그러나 데이터의 폭발적 증가와 함께 구조화·반구조화 데이터 뿐만 아니라 기존에 다루지 않았던 비구조화 데이터까지 처리해야 하는 상황에서 일일이 수많은 데이터를 기업 데이터 포맷으로 코딩해야하는 상황은 더 이상 쉬운 일이 아니게 됐다. 이에 직접 코딩하지 않아도 되는 ETL 툴이 적극적으로 도입되기 시작했다.

BI 시스템 흐름 상 ETL은 시작을 담당하는 전초부대와 같다. 데이터의 추출·변환·적재가 이뤄져야 분석이 이뤄지기 때문이다. 빅데이터 분석 역시 구조화 및 비구조 데이터가 구조화 데이터로 변환·적재가 이뤄져야 분석이 가능하다.

이터의 품질이 좋아야 제대로 된 분석 결과를 얻을 수 있다는 점에서 구조화 데이터 외 비구조화 데이터 역시 품질이 확보돼야 정확한 분석 결과를 얻을 수 있다. 이런 흐름에 맞춰단순 추출·변환·적재 기능뿐만 아니라 메타데이터와 데이터 품질까지 포함해 데이터를 거버넌스 하는 식으로 시장의 요구 상황에 맞춰 ETL 툴 보유 기업이 이런 전략을 취하고 있다.

이런 ETL의 진화가 국내에서는 다소 더디게 흘러가고 있다. ETL의 툴이 선보인지 20년이 지났지만 그동안 ETL 툴은 BI 시스템 기본 요소로 시장 규모 자체가 커지긴 했지만 국내 사정을 감안했을 때 성숙되어 있다고 보기는 힘들다.

2017년 7월 27일 목요일

Using Docker Tools on Windows 10 with Hyper-V

Hyper-V 는 Windows 10 pro 이상의 버전에서만 설치 할수 있습니다.  Hyper-V는 Windows 설치시에 기본적으로 비활성화 되어 있습니다. 반드시 Windows 기능 켜기/끄기에서 Hyper-V를 활성하해야 합니다.

Docker Toolbox을 Hyper-V에 설치하기 위해서는 다음 절차대로 진행하면 됩니다.

  1. Hyper-V 관리자를 실하여 "가상 스위치 관리자"를 실행한다.
  2. 새 가강 네트워크 스위치를 만든다. 이때 "외부"를 선택하고, 이름은 "External Virtual Switch"로 지정한다. 이름은 다른걸 사용해도 상관없다.
  3. "https://www.docker.com/products/docker-toolbox"에서 docker-toolbox를 다운로드 받아서 설치한다.
  4. 설치가 끝나면 관리자 권한의 명령 프롬프트를 열어 "c:\Program Files\Docker Toolbox"로 이동한다.
  5. "docker-machine.exe create --driver hyperv --hyperv-virtual-switch "External Virtual Switch" --hyperv-cpu-count "1" --hyperv-memory "1024" --hyperv-disk-size "20000" mydockervm" 이명령어를 입력한다. 2번에서 다른 이름을 지정하였다면 지정한 이름으로 바꿔서 입력한다.
  6. boot2docker.iso 이미지를 설치한다. 설치가 끝나면 Hyper-V 관리자에서 "mydockervm"이 설치되어 있음을 확인할수 있다.
  7. 관리자 권한의 명령프롬프트에서 "docker-machine ssh mydockervm"를 입력하면 Docker에 접속할수 있다.
  8. 이제 Docker를 사용하면된다.

Hyper-V에서 Docker를 사용해본 결론은 불편하다 그리고 뭐가 더 좋은건지 모르겠다., 그냥 Virtual-Box를 사용하자. 





2017년 7월 4일 화요일

Redis 자료구조

Redis는
  • BSD 라이선스 기반의 Key-value 캐시 & Store 소프트웨어.
  • String, hash, lists, sets, sorted set, bitmap, hyperloglogs 등 다양한 데이터 구조를 저장.
  • In memory 데이터베이스, NoSQL 데이터베이스로 분류

Redis의 장정
  • Redis는 데이터 저장소로 가장 I/O 속도가 빠른 장치인 메모리를 사용함.
  • 단순한 구조의 데이터 모델인 Key/Value방식으로 빠른 속도를 보장함
  • 캐시 및 데이터 스토어에 유리함
  • 다양한 API 지원

Redis 자료 구조

Strings
  • 키에 대한 값으로 문자열을 저장한다.
  • 가장 단순한 타입, redis를 사용한다면 가장 먼저 고려해볼 타입
  • JSON, XML 등 문자열로 된 데이터를 저장
  • 웹서비스에 최적
  • HTML문서의 전체 혹은 일부분을 캐시하여 사용할수 있다.
  • String이라고 해서 문자열만 저장하는게 아니고, 바이너리 데이터도 저장 가능
  • 최대 512M까지 저장이 가능
  • APPEND 명령어를 이용해서 문자열을 추가로 붙일수 있음
  • GETRANGE와 SETRANGE를 이용해서 해당 범위의 문자열을 리턴
lists
  • string의 형태로 되어 있으며, 삽입순서에 따라 정렬
  • 주요특징으로는 수백만건의 삽입과 삭제가 head와 tail에 일어나더라도 일정한 시간복잡도를 제공한다. head와 tail 근처의 요소에는 매우 빠르게 접근되지만 매우 큰 list의 중간 지점을 접근하면 느림.
  • 소셜 미디어의 타임라인 경우, LPUSH로 새로운 요소를 입력하고, LRANGE를 이용하여 최근 입력된 요소를 가져올수 있다.
Blocking operation on lists
  • list 데이터 타입에 대해서 Blocking operation을 지원
  • BRPOP, BLPOP명령은 호출하면, 데이터가 없을 경우 데이터가 준비될 때까지 block된다.

Hash
  • field&value의 쌍으로 이루어진 테이블을 저장할 수 있는 데이터 타입
  • 객체를 표현할때 최고의 데이터 타입

Set
  • 정렬되지 않은 String의 집합
  • 맴버의 추가와 제거가 가능하며 set안의 맴버들의 존재여부를 호가인 가능
  • set은 중복된 이름을 허용하지 않는다.
  • set의 흥미로운 점은 서버사이드에서 set과 set사이에 집합연산이 가능하다.
  • 데이터 타입을 통해 유니크한 값을 수집할 수 있다.

Sorted Set
  • set과 hash를 섞은 데이터 타입.
  • set과 마찬가지로 키는 유니트하며, 키로 정렬

Operation on range
Sorted set은 범위 검색을 위한 몇 가지 툴을 제공

Bitmaps
  • 바이너리 데이터에 대한 bit연산 기능
  • 가장 큰 장점은 0과 1의 상태를 가지는 아이템들을 대단히 효율적으로 저장하고, 읽을 수 있다.

HyperLogLogs
  • 어떤 데이터셋의 집합에서 유일한 원소의 개수를 검사하기 위해서 사용하는 알고리즘


2017년 6월 30일 금요일

Redis와 전자정부프레임워크 연동

Redis와 전자정부프레임워크 연동

Spring과 Redis을 사용하기 위해서는 “spring-data-redis”와 “jedis”(Java redis Client)의 현재 버전은 1.8.4와 2.9.0 이 버전을 사용하기 위해서는  Spring 4.3.9이상이 필요합니다.
현재 전자정부 프레임워크 3.6 버전에 포함된 Spring은 4.1.2이기 때문에 이를 지원하는  1.5.2, 2.6.2 버전으로 설정하였습니다.

Redis 설치
  1. Ubuntu인경우 “sudo apt-get install redis-server” 명령어로 간단하게 설치가능
  2. Windows인경우 “https://github.com/MSOpenTech/redis/releases”에서 설치파일을 다운로드 받아 설치한다.

추천하는 방식은 1, 2, 3도 아닌 Docker 이미지로 설치하는 방식이다.
“docker pull redis”
“docker run --name my-redis -d -p 46379:6379 redis” → 이런식으로

Redis Desktop Manager 설치
RDM이라고 줄여 말하기도 하는데 Windows, Linux, MacOS에서 Redis 서버를 관리할수 있는 오픈소스 GUI 관리도구 이다. 설치하면 알겠지만 정말 딱 필요한 기능만 있습니다.

전자정부 프레임워크에 설정하기
개인적으로 Object Configuration 방식이 아닌 XML Configuration 방식을 선호하기에 XML 방식으로 설명하겠습니다.

  • pom.xml에 Dependency 추가
<!-- for Redis -->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-redis</artifactId>
<version>1.5.2.RELEASE</version>
</dependency>
  
<dependency>
   <groupId>redis.clients</groupId>
   <artifactId>jedis</artifactId>
   <version>2.6.2</version>
</dependency>

  • redis 관련 Context 추가
resource/egovframework/context-redis.xml 파일을 만들어 아래내용을 추가
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
       http://www.springframework.org/schema/beans     
       http://www.springframework.org/schema/beans/spring-beans-4.1.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context-4.1.xsd">

<context:property-placeholder location="classpath:config/redis.properties" />
<!-- Redis -->
<bean id="connectionFactory"
class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"
p:use-pool="true"
p:host-name="localhost"
p:port="46379" />

<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate"
p:connection-factory-ref="connectionFactory" />

<!-- end of Redis -->

</beans>

이렇게 하면 전자정부 프레임워크에서 Redis을 사용하기 위한 준비는 끝입니다. 정말 간단하죠.

Spring에서는 Redis을  DAO Layer로 구분짓습니다. 그러니 Redis는 Service Layer에서 호출 되거나 다른 DAO에서 호출되어야 합니다. 기존에 구축되어 있는 프로젝트에 Redis을 추가하는 경우 Service Layer을 수정하는 것보다는 DAO Level을 수정하는 방식이 Side impact를 최소화할 수 있습니다. 여기서는 전자정부프레임워크에 포함된 Sample 프로젝트에 Redis을 추가하는 방식으로 진행해보겠습니다.

  • RedisTemplateSupport.java
전자정부프레임워크의 “EgovAbstractMapper”와 비슷한 일을 하는 객체를 만들어줍니다.
별것 없는 코드지만 이것을 만들어주는 것은 코드일 관성을 유지하기위한 조치라고 생각하면 되겠습니다.

package kr.co.keytech.framework.redis;

import javax.annotation.Resource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.ListOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.SetOperations;

public class RedisTemplateSupport {

@Autowired
protected RedisTemplate template;
@Resource(name = "redisTemplate")
protected ListOperations listOps;

@Resource(name = "redisTemplate")
protected HashOperations hashOps;

@Resource(name = "redisTemplate")
protected SetOperations setOps;
}

  • SampleRedisDAO.java
전자정부 프레임워크 Sample프로젝트 을 보면 SampleDAO가 있습니다. 이와 똑같은 API가 있는 SampleRedisDAO을 만들어줍니다. RedisDAO가 하는 일은 다음과 같습니다.
  1. 요청에 대해서 Redis에 Cache가 있으면 그정도를 전달합니다.
  2. 없다면 DAO에 요청을 하고 Cache에 넣은 다음에 전달, 다음에 똑같은 요청이 있다면 Cache에가 전달될것입니다.
  3. 갱신요청이나 생성요청 삭제요청도 Cache도 작업해주고 DAO작업해줍니다.

package kr.co.keytech.egov.sample.dao;

import java.util.List;

import javax.annotation.Resource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Repository;

import kr.co.keytech.egov.sample.vo.SampleDefaultVO;
import kr.co.keytech.egov.sample.vo.SampleVO;
import kr.co.keytech.framework.redis.RedisTemplateSupport;

@Repository
public class SampleRedisDAO extends RedisTemplateSupport {

private static final Logger LOGGER = LoggerFactory.getLogger(SampleRedisDAO.class);
private static final String KEY = "SAMPLE";
@Resource(name="sampleDAO")
private SampleDAO sampleDAO;
/**
* 글을 등록한다.
* @param vo - 등록할 정보가 담긴 SampleVO
* @return 등록 결과
* @exception Exception
*/

public void insertSample(SampleVO vo) throws Exception {
sampleDAO.insertSample(vo);
LOGGER.debug("#####################################");
LOGGER.debug("A sampleVO insert to Redis, ID="+vo.getId());
try {
hashOps.put(KEY, vo.getId(), vo);
} catch (Exception e) {
LOGGER.info(e.getMessage());
}
}
/**
* 글을 수정한다.
* @param vo - 수정할 정보가 담긴 SampleVO
* @return void형
* @exception Exception
*/
public void updateSample(SampleVO vo) throws Exception {
sampleDAO.updateSample(vo);
LOGGER.debug("#####################################");
LOGGER.debug("A sampleVO update to Redis, ID="+vo.getId());
try {
hashOps.put(KEY, vo.getId(), vo);
} catch (Exception e) {
LOGGER.info(e.getMessage());
}
}

/**
* 글을 삭제한다.
* @param vo - 삭제할 정보가 담긴 SampleVO
* @return void형
* @exception Exception
*/
public void deleteSample(SampleVO vo) throws Exception {
sampleDAO.deleteSample(vo);
LOGGER.debug("#####################################");
LOGGER.debug("A sampleVO delete at Redis, ID="+vo.getId());
try {
hashOps.delete(KEY, vo.getId());
} catch (Exception e) {
LOGGER.info(e.getMessage());
}
}

/**
* 글을 조회한다.
* @param vo - 조회할 정보가 담긴 SampleVO
* @return 조회한 글
* @exception Exception
*/
public SampleVO selectSample(SampleVO vo) throws Exception {
SampleVO sampleVO =  (SampleVO)hashOps.get(KEY, vo.getId());
if(sampleVO != null) {
LOGGER.debug("#####################################");
LOGGER.debug("Finded a SampleVO at Redis, ID="+vo.getId());
} else {
sampleVO = sampleDAO.selectSample(vo);
}
try {
hashOps.put(KEY, vo.getId(), sampleVO);
} catch (Exception e) {
LOGGER.info(e.getMessage());
}
return sampleVO;
}

/**
* 글 목록을 조회한다.
* @param searchVO - 조회할 정보가 담긴 VO
* @return 글 목록
* @exception Exception
*/
public List<SampleVO> selectSampleList(SampleDefaultVO searchVO) throws Exception {
return sampleDAO.selectSampleList(searchVO);
}

/**
* 글 총 갯수를 조회한다.
* @param searchVO - 조회할 정보가 담긴 VO
* @return 글 총 갯수
* @exception
*/
public int selectSampleListTotCnt(SampleDefaultVO searchVO) throws Exception {
return sampleDAO.selectSampleListTotCnt(searchVO);
}

}

  • EgovSampleServiceImpl.java 수정
Service Layer에서 사용중인 DAO를 RedisDAO로 변경합니다.  기존 DAO와 똑같은 구조이기 때문에 아주간단하게 변경될것입니다.

@Resource(name="sampleDAO")
private SampleDAO sampleDAO;
이것을..

@Resource(name="sampleRedisDAO")
private SampleRedisDAO sampleDAO;
이렇게..

  • TestCase 작성
다들 아시는 일반적인 ServiceLayer 단위테스트 방식대로 TestCase을 작성합니다.(모르신다면 큰일입니다. 빨리 공부하셔야죠.)

package kr.co.keytech.egov.sample.service;

import java.util.Date;

import javax.annotation.Resource;

import org.junit.Test;
import org.springframework.test.annotation.Rollback;

import kr.co.keytech.egov.sample.vo.SampleVO;
import kr.co.keytech.framework.AbstractTestCase;

public class EgovSampleServiceTestCase extends AbstractTestCase{

/** EgovSampleService */
@Resource(name = "sampleService")
private EgovSampleService sampleService;
@Test
@Rollback(value = false)
public void testInsertSample() {
SampleVO vo = new SampleVO();
vo.setName("YunChang.Lee");
vo.setDescription("Insert TestCase="+new Date());
vo.setRegUser("KeyTech");
vo.setUseYn("Y");
try {
sampleService.insertSample(vo);
} catch (Exception e) {
e.printStackTrace();
}
}
@Test
@Rollback(value = false)
public void testUpdateSample() {
}
@Test
public void testDeleteSample() {
String id = "SAMPLE-00135";
SampleVO vo = new SampleVO();
vo.setId(id);
try {
sampleService.deleteSample(vo);
} catch (Exception e) {
e.printStackTrace();
}
}
@Test
public void testSelectSample() {
String id = "SAMPLE-00135";
SampleVO vo = new SampleVO();
vo.setId(id);
try {
vo = sampleService.selectSample(vo);
System.out.println(objectToString(vo));
} catch (Exception e) {
e.printStackTrace();
}
}
}


TestCase에 보시면 objectToSring이라는 메소드가 있는데 이것은 테스트을 위해서 Object을 Json으로 바꿔주는 API 입니다. 그외에도 몇개 더있는데 다음과 같습니다.

/**
* JSON 문자열을 Value Object 로 변환한다.
*
* @param str
* @param objType
* @return
*/
public static <T> T stringToObject(String str, Class<T> objType) {
if (str == null || str.length() == 0) {
return null;
}
ObjectMapper mapper = new ObjectMapper();
try {
return mapper.readValue(str, objType);
} catch (IOException e) {
e.printStackTrace(System.err);
return null;
}
}
/**
* Value Object 를 JSON 문자열로 변환한다.
*
* @param obj
* @return
*/
public static String objectToString(Object obj) {
if (obj == null) {
return null;
}
ObjectMapper mapper = new ObjectMapper();
try {
return mapper.writeValueAsString(obj);
} catch (IOException e) {
e.printStackTrace(System.err);
return null;
}
}
public static <T> T stringToJson(String json, Class<T> clazz) {
if (json == null || clazz == null) {
return null;
}
ObjectMapper mapper = new ObjectMapper();
T targetObject;
try {
targetObject = mapper.readValue(json, clazz);
} catch (JsonParseException e) {
e.printStackTrace(System.err);
return null;
} catch (JsonMappingException e) {
e.printStackTrace(System.err);
return null;
} catch (IOException e) {
e.printStackTrace(System.err);
return null;
}
return targetObject;
}

아주 간단하게 Redis와 전자정부 프레임워크를 연동해봤습니다. 이글에서는 Redis에 대한 기능설명을 하지 않았습니다. 왜냐면 간단하게 몇문장으로 Redis을 논하기 어렵기 때문입니다.

Redis에 대해서는 따로 자료를 정리해서 올리도록하겠습니다.

ETL 솔루션 환경

ETL 솔루션 환경 하둡은 대용량 데이터를 값싸고 빠르게 분석할 수 있는 길을 만들어줬다. 통계분석 엔진인 “R”역시 하둡 못지 않게 관심을 받고 있다. 빅데이터 역시 데이터라는 점을 볼때 분산처리와 분석 그 이전에 데이터 품질 등 데이...