'CAPS'에 해당되는 글 4건

  1. 2007.03.29 아이디어 노트 - 도움말
  2. 2007.02.22 데이터 마이그레이션 수행속도 높이기 (8)
  3. 2006.11.29 체육대회 (4)
  4. 2006.11.22 프로젝트 얘기를 시작합니다. (4)

담당자의 잦은 교체로 업무 지식이 전달되지 않는다. 지식관리 시스템이 별도로 존재하지 않는다. 메뉴별 도움말 작성 기능을 "지식나눔" 이란 이름으로 타이틀 영역 옆에 추가해도 좋을 듯 하다. 

신고
Creative Commons License
이 저작물은 크리에이티브 커먼즈 코리아 저작자표시-비영리-변경금지 2.0 대한민국 라이선스에 따라 이용하실 수 있습니다.
TAG CAPS

현재 수업 모듈의 개발이 진행 중인데요, 정치적 상황으로 논리 모델 자체가 와장창 바뀌는 경우가 많아 데이터 마이그레이션을 자주 실행하게 되었습니다. 처음 개발한 마이그레이션 프로그램이 최적화를 많이 고민하지 않아서 17 시간이 걸렸는데요, 자주 수행하기 위해 최적화 작업을 수행했습니다. 최적화 작업 이후 100만건 수준의 데이터를 마이그레이션하는 시간이 20분으로 줄어들었습니다. 거의 1/50로 수행시간이 줄어들었네요. 최적화에 사용한 기본원리는 한계는 없다는 믿음과 굳어있는 머리를 깨는 것. ^^* 마이그레이션은 특정 시간에 작업을 멈추고 진행하기 때문에 메모리 옵션을 최대한 주고 실행한다는 점에 착안해서 캐쉬를 적극 활용하는 방법을 사용한 것입니다.

수강신청 데이터 마이그레이션을 샘플로 살펴보겠습니다. 마이그레이션 로직은 2단계로 나누어집니다. 우선 Legacy DB에서 수강신청이력 데이터를 모두 읽어온 다음, 각각의 수강신청 이력 데이터별로 변경된 스키마에 맞춰 값을 입력하고 마이그레이션이 끝난 개설강의, 학생, 코드(학기, 수강신청유형, 등등)의 정보를 찾아와 관계를 재설정하여 입력합니다. 그런 다음 수강신청이력 중 패턴을 분석해서 수강신청 데이터로 남아야 할 것을 찾아낸 다음 그것을 다시 수강신청 데이터로 변환하여 관계를 재 설정한 후 입력합니다.


사용자 삽입 이미지


수행되는 쿼리들을 분석해보면 처음에 Legacy에서 읽어올 때 select 문은 1번밖에 실행되지 않습니다. 그러나 각 데이터 별로 관계 설정을 위해 특정 조건에 맞는 개설강의, 학생, 코드를 찾아와서 연결해주는 쿼리가 반복적으로 호출되고 있음을 확인할 수 있습니다. 모두 5개의 코드 값을 참고 하기 때문에 패턴검사를 통과한 수강신청 데이터가 20만개라고 볼때 실행되는 쿼리는 select 1 + 100만 * (select 7 + insert 1) + 20만 * (select 7 + insert 1) 개가 됩니다. 즉, 840만건의 select 문과 120만건의 insert 문이 실행되는 거죠.

여기서 가장 문제가 되는 것이 840만건에 이르는 select 문입니다. Legacy에서 읽어오는 단 1개의 select 문이나, 개발DB로 실제로 데이터를 넣어주는 insert 문은 생략할 수 있는 부분이 아니기 때문에 그 select 문이 튜닝 대상이 됩니다. DB I/O 자체를 줄이는게 목적인거죠.

수술전
for (Map<String, Object> 리거시수강신청이력데이터 : 리거시수강신청이력데이터들) {
    수강신청이력 saHist = new 수강신청이력();
    saHist.set학생(학생Dao.get학생By학번(리거시수강신청이력데이터.get("학번"))
}

위에 색깔이 표시된 학생Dao 사용에 의해 for 문에 입력된 데이터의 갯수만큼 발생하는 select 문을 어떤 방법으로 없앨 수 있을까요? 아래와 같이 전체 학생 정보를 한번에 읽어와서 Map에 담아두고 이용하면 됩니다.

private void initStudentMap() {
  studentMap = new HashMap<Integer, Student>();
  List<Student> students = studentDao.getAll();
  for (Student student : students) {
   Student fakeStudent = new Student();
   fakeStudent.setStudId(student.getStudId());
   studentMap.put(student.getStudNo(), fakeStudent);
  }
 }

이제 앞의 문제코드는 for 문 밖에서 전체 학생정보를 읽어오는 1번의 쿼리만 DB에 날아가고, for 문 내부에서는 Map을 이용해서 메모리에 있는 학생 정보를 적당한 키 값으로 가져오는 방식으로 변경되었습니다.

수술후
initStudentMap();
for (Map<String, Object> 리거시수강신청이력데이터 : 리거시수강신청이력데이터들) {
    수강신청이력 saHist = new 수강신청이력();
    saHist.set학생(studentMap.get(리거시수강신청이력데이터.get("학번"))
}

같은 원리로 ehCache와 같은 라이브러리를 쓰는 방법도 있습니다. 사용방법은 초기화하는 부분을 빼면 Map과 별 차이가 없습니다.

또 하나의 팁은 하이버네이트를 이용하기 때문에 발생하는 문제를 해결하는 것인데요, DAO를 적정한 주기로 flush하고 clear 해줘야 합니다.

public static final int STEP=20;
public void migration() {
 initLegacyMap();
 int cnt = 0;
 List<Map<String, Object>> mapForStud = new ArrayList<Map<String,Object>>();
 for (Map<String, Object> map : maps) {
  cnt++;
  // do migration
  if (cnt%STEP == 0) studyApplyDao.flushAndClear();
 }
}

예전에 for 문을 잘못 사용하는 방법을 예로 들며 동일한 배정문이 for 문 안에 있을 때 그것 밖으로 빼내서 1번만 수행하도록 하는 코드 샘플을 본 기억이 나네요. 불필요한 Select 문을 Map이나 Cache를 이용해서 제거하는 원리는 그것과 다르지 않습니다.

사용자 삽입 이미지
불필요한 Select 문을 없애서 DB I/O 비용을 줄이는 것과, 적절한 주기로 하이버네이트 세션을 flush & Clear 해주는 이 단순한 조작만으로도 마이그레이션 수행 시간이 1/50로 줄어든다는 사실이 놀랍네요. 덕분에 저와 동료분들의 소중한 작업 시간이 조금 더 확보되었습니다. :)

이제 migration_all 태스크만 실행하면 저희 시스템에서 사용하는 모든 리거시 데이터가 개발자 PC의 PostgreSQL이나, 개발 서버의 Sybase로 자동으로 1시간 내에 마이그레이션 되니까요.

물론 아직도 개선할 여지가 어딘가에 남아 있을 거라는 사실은 잘 알고 있습니다. 히딩크처럼 늘 배고파 하며 살아야 하는 개발자의 숙명이기도 하죠. 하지만 이정도 속도면 처음의 불편함을 해소하는데 충분하기 때문에, 추가적인 성능 향상에 대한 필요성이 제기되면 그 때 다시 고민해보도록 하죠.
신고
Creative Commons License
이 저작물은 크리에이티브 커먼즈 코리아 저작자표시-비영리-변경금지 2.0 대한민국 라이선스에 따라 이용하실 수 있습니다.

체육대회

이전글/2006 2006.11.29 19:29
현재 프로젝트를 진행하고 있는 곳에서는 매달 마지막 주 수요일이 공식적인 체육행사가 있는 날입니다. 한달에 하루, 오후 시간만이긴 하지만. 전체 팀원이 함께 무엇인가를 함께 할 수 있는 소중한 시간이 보장되는 셈이죠. 보통은 영화를 보거나, 맛집을 찾아 다니며 맛있는 것을 먹고 사무실로 돌아와 체육관에서 간단히 체육행사를 합니다. 오늘은 PM 누님이 몇 일전 입원했던 것에 대한 보험금이 나왔다며 오리 고기로 한턱 냈답니다. 수통골이라는 곳에 있는 맛집이였는데 훈제 오리의 맛이 정말 일품이더군요. 함께 곁들인 흑수제비 맛도 감탄을 연발할 지경이였죠. 모처럼 아주 뱃속이 든든해 졌습니다.

사무실로 돌아와 2시간 정도 일을 한 뒤에는 배드민턴과 탁구를 즐겼습니다. 아쉽게도 2가지 운동 모두 제가 팀에서 제일 실력이 쳐지는 편이라 쉽게 이기진 못하지만, 다 함께 땀을 한번 흘리고 나면 하루동안 쌓여있던 찌뿌둥한 기분까지 함께 날아가 버리는 것 같은 기분이 듭니다. 요즘 팀의 막내가 1년간의 타지 생활에 쌓였던 외로움 때문에 많이 힘들어했는데, 오늘은 조금 기분이 풀린 것 같더군요. 덕분에 저까지 유쾌해졌습니다. 다들 오늘처럼 즐겁게 프로젝트를 함께 마무리하길 기도해봅니다. :) 사진은 프로젝트 초기에 기념으로 만든 포스터예요.. ^^*


아참, 물개는 두번이나 출연했답니다. 어디있을까요? ㅋㅋ
신고
Creative Commons License
이 저작물은 크리에이티브 커먼즈 코리아 저작자표시-비영리-변경금지 2.0 대한민국 라이선스에 따라 이용하실 수 있습니다.
TAG CAPS

오늘부터 블로그에 적는 글들은 높임말로 작성해보려 합니다. 글쓰기를 연습할 만한 시간을 따로 마련하기 힘들어서요.

CAPS 프로젝트라는 카테고리를 하나 추가했습니다. 다른 개발자 분들과 함께 얘기를 나누다보면 제게는 어떤 기술을 어떻게 적용하고 있는지에 대한 생생한 경험담을 듣는 것이 가장 흥미로웠습니다. 그런 이유로 현재 프로젝트에서 진행하고 있는 여러 기술들을 간단히 소개하는 글을 작성해보려 합니다. 어떤 특별한 목적이 있는 건 아닙니다. 오히려 괜한 창피를 자초하는 것이 아닌가 조심스럽습니다. 굳이 목적을 생각해보면 지금 프로젝트를 진행해나가면서 얻게 된 것들을 정리해 나가는 것이 가장 큰 이유이고.. 더불어 누군가에게는 작은 도움이 된다면 더 이상 바랄게 없다는 생각입니다.

현재 저는 모 대학의 학사관리시스템을 개발하고 있습니다. 개발인원은 9명입니다. 보고된 인력은 더 많지만 실제 개발에 참여하고 있는 분은 10명이 채 되지 않습니다. 여러 정치적인 이유로 초기에 약속되었던 개발 인력이 투입되지 못한 경우입니다. 그중 분석인력이 2명, 디자이너, 퍼블리셔가 각각 1명이니 순수 개발 인력은 5명이 되겠네요. 꽤 단촐한 구성이죠? 하지만 모두 즐거운 마음으로 참여하고 있습니다. 프로젝트는 반드시 성공한다, 그리고 그 기간이 끝나면 우리 스스로도 분명히 한단계 더 성장해 있을거라고 믿으면서 말이죠. 아참 저희팀은 놀랍게도 성비율이 5:4로 여자분이 더 많답니다. 재밌겠죠? 팀에 피해를 주지 않는 범위 내에서 조금은 특이한 저희 프로젝트의 에피소드들을 들려드릴께요. 기술적인 것들을 포함해서 ^^

신고
Creative Commons License
이 저작물은 크리에이티브 커먼즈 코리아 저작자표시-비영리-변경금지 2.0 대한민국 라이선스에 따라 이용하실 수 있습니다.
TAG CAPS
1 

글 보관함

카운터

Total : 226,198 / Today : 42 / Yesterday : 57
get rsstistory!

티스토리 툴바