2010년 10월 26일 화요일

금천구청 - 광명역 전동열차 시간표

간혹 KTX를 타기위해서 광명역에 가야할 때가 있습니다. 광명역을 대중교통으로 갈때는 1호선 금천구청역에서 광명행 셔틀 전동열차를 갈아타면 5분이면 도착합니다. 장점은 편리하다는거...단점은 셔틀 전동열차가 잘 다니지 않는 다는거....TT

짜증나서 시간표를 정리해 봅니다. 지가 기억하기 위해서^^

환승역: 금천구청, 작성일: 2010-10-26, 소요시간: 6분

출발시각KTX 광명역 출발 시간
05시18분
06시04분
07시01분, 44분
08시25분
09시06분, 55분
10시16분
11시05분, 31분, 58분
12시없음
13시00분, 55분
14시13분, 35분
15시34분
16시05분, 44분
17시34분
18시15분, 36분, 53분
19시34분, 57분
20시24분, 46분
21시20분, 44분
22시31분
23시1분

2010년 10월 21일 목요일

Jersey 라이센스

RESTFul를 구현할때 Jersey를 많이 사용합니다. 아무래도 JAX-RS 중에서 문서화나 프레임웍 완성도가 가장 높은것은 Jersey라고 생각합니다. (Grizzly 서버와 테스팅 통합 기능이 굉장하죠...)

그러나 약간 사용하기 애매했던 부분은 라이센스 였습니다. Jersey의 라이센스에 대해서는 Jersey 홈페이지(https://jersey.dev.java.net/)에 다음과 같이 명시하고 있습니다.

We also use the same two licenses - CDDL 1.1 and GPL 2 with CPE - so, you can pick which one suites your needs better.

처음에는 GPL 2와 CDDL 1.1을 라이센스로 하기 때문에 Jersey를 사용할 경우 소스코드를 모두 공개해야 한다고 생각했습니다. 아무래도 GPL이라는 단어가 나오면 무서워서요. 그럴경우 Jersey를 사용하기 어렵고 개발혹은 학습 용도로 사용할 수 밖에 없다고 생각했습니다.

그런데 위 라이센스를 잘 보시면 GPL2와 CDDL 1.1을 선택적으로 사용할 수 있다라고 되어 있습니다. GPL과 CDDL 라이센스 중에서 사용자가 원하는 라이센스를 선택하도록 되어 있습니다.

즉 Jersey는 독점점 제품 개발용도로 사용할 수 있습니다. 단 CDDL 라이센스라는 것은 명시만 한다면 문제는 없을 것 같습니다. CDDL에 대한 해석은 Sun Developer Network에서 근거를 찾아 볼 수 있습니다. http://blog.sdnkorea.com/blog/419의 포스팅에 다음과 같은 구절을 찾을 수 있습니다.

저의 독점적인 제품에 CDDL 하에 배포되는 코드를 사용한다면 제 소스 코드를 반드시 공유해야 합니까?

그렇습니다. CDDL 하에 라이센스된 어떠한 소스 파일들이나 이러한 파일들을 수정한 부분들을 전부 공유해야 합니다. 그러나 여러분의 독점적인 소스 파일들은 공유할 필요가 없습니다.

이런 상황을 조합해 보면 RESTFul 프레임웍으로 Jersey를 사용하는 것은 라이센스 측면에서 어떤 제약 조건도 없습니다. 심지어 Jersey가 상용 WAS의 REST 구현체로 들어갈 계획에 있다구 하더군요. Jersey는 GPL과 CDDL 라이센스의 선택권을 사용자에게 위임함으로서 개발조직을 보호하는 정책을 지원하는것 같습니다.

2010년 10월 13일 수요일

Blogspot에 Code Syntax Highlight 설정

아무래도 직업이 개발자이다 보니 블러그에서도 코드를 많이 다루게 됩니다. 블러그를 선정할때도 코드를 깔끔하게 편집할 수 있는 기능이나 설정을 가장 먼저 고려하게 됩니다.

Blogspot에 JavaScript를 기반으로하는 Code Syntax Highlight 기능을 추가할 수 있습니다.

http://code.google.com/p/syntaxhighlighter/ 에서 진행되고 있는 syntaxhighlighter 프로젝트는 구글 프로젝트로 시작된 오픈소스 프로젝트 입니다. 프로젝트 정보는 다음 URL에서 찾을 수 있습니다.

1.5 버전까지는 구글 프로젝트로 진행되었고 그 이후는 alexgorbatchev.com에서 진행되고 있습니다. 현재 개발 최신 버전은 3.0.83 이고 안전화 버전은 2.1.382입니다.

syntaxhighlighter의 최종 산출물은 자바스크립트 파일, CSS 파일, SWF 파일로 구성됩니다. 설치 절차는 크게 두 단계로 구성됩니다.

  1. syntaxhighlighter의 구성 파일을 호스팅 서버에 올리기
  2. blogspot의 템플릿 수정

syntaxhighlighter의 구성 파일을 호스팅 서버에 올리기

blogspot은 별도의 파일을 호스팅 서버에 올리는 것이 불가능 합니다. 그러나 syntaxhighlighter를 정상적으로 설치하기 위해서는 주요 구성 파일을 서버에 올리고 url로 접근가능 할 수 있어야 합니다. 주요 구성 파일을 서버에 올리기 어려울 경우를 대비해서 alexgorbatchev.com에서는 주요 구성 파일의 호스팅 서비스를 제공합니다. alexgorbatchev.com에서 서비스하는 버전 별 url은 다음과 같습니다.

http://alexgorbatchev.com/pub/sh/1.5.1/
http://alexgorbatchev.com/pub/sh/2.0.278/
http://alexgorbatchev.com/pub/sh/2.0.287/
http://alexgorbatchev.com/pub/sh/2.0.296/
http://alexgorbatchev.com/pub/sh/2.0.320/
http://alexgorbatchev.com/pub/sh/2.1.364/
http://alexgorbatchev.com/pub/sh/2.1.364/
http://alexgorbatchev.com/pub/sh/2.1.382/
http://alexgorbatchev.com/pub/sh/current/

각 버전은 다음과 같은 구성 파일을 서비스 합니다.

/styles
    /styles/shThemeRDark.css
    /styles/shThemeMidnight.css
    /styles/shThemeMDUltra.css
    /styles/shThemeFadeToGrey.css
    /styles/shThemeEmacs.css
    /styles/shThemeEclipse.css
    /styles/shThemeDjango.css
    /styles/shThemeDefault.css
    /styles/shCoreRDark.css
    /styles/shCoreMidnight.css
    /styles/shCoreMDUltra.css
    /styles/shCoreFadeToGrey.css
    /styles/shCoreEmacs.css
    /styles/shCoreEclipse.css
    /styles/shCoreDjango.css
    /styles/shCoreDefault.css
    /styles/shCore.css
  /scripts
    /scripts/shLegacy.js
    /scripts/shCore.js
    /scripts/shBrushXml.js
    /scripts/shBrushVb.js
    /scripts/shBrushSql.js
    /scripts/shBrushScala.js
    /scripts/shBrushSass.js
    /scripts/shBrushRuby.js
    /scripts/shBrushPython.js
    /scripts/shBrushPowerShell.js
    /scripts/shBrushPlain.js
    /scripts/shBrushPhp.js
    /scripts/shBrushPerl.js
    /scripts/shBrushJScript.js
    /scripts/shBrushJavaFX.js
    /scripts/shBrushJava.js
    /scripts/shBrushGroovy.js
    /scripts/shBrushErlang.js
    /scripts/shBrushDiff.js
    /scripts/shBrushDelphi.js
    /scripts/shBrushCss.js
    /scripts/shBrushCSharp.js
    /scripts/shBrushCpp.js
    /scripts/shBrushColdFusion.js
    /scripts/shBrushBash.js
    /scripts/shBrushAS3.js
    /scripts/shBrushAppleScript.js
    /scripts/shAutoloader.js

이렇게 호스팅 되는 파일을 이용하여 블러그 설정이 가능합니다.

blogspot의 템플릿 수정

위와 같이 alexgorbatchev.com에서 호스팅하는 파일을 사용하거나 혹은 특정 서버에 배포하여 URL로 모든 구성자원이 접근가능하다면 블러그 템플릿 설정이 가능합니다.

blogspot의 템플릿 수정은 </b:skin>와 </head>테그 사이에 다음을 추가하면 됩니다.

<link href="http://alexgorbatchev.com/pub/sh/2.1.382/styles/shCore.css" rel="stylesheet" type="text/css" />
<link href="http://alexgorbatchev.com/pub/sh/2.1.382/styles/shThemeEclipse.css" rel="stylesheet" type="text/css" />


















Code highlight의 CSS 테마와 관련해서는 아래 URL을 참조하기 바랍니다. CSS 테마는 css 파일로 관리되며 필요한 css Themes는 link 설정에서 변경하면 됩니다.

http://alexgorbatchev.com/SyntaxHighlighter/manual/themes/default.html

이제 모든 설정은 완료된 상태이며 이제 블러그 포스팅시 Code를 적어주는 방법을 살펴보겠습니다.

SyntaxHighlighter 문법

기본 문법은 다음과 같습니다.

...

기본 brush 메핑은 다음 페이지를 참조하시기 바랍니다.


대표적인 brush 설정 방법은 다음과 같습니다.
<pre class="brush:javascript"> ---- </pre>
<pre class="brush:jscript> ---- </pre>
<pre class="brush:js"> ---- </pre>
<pre class="brush:css"> ---- </pre>
<pre class="brush:html"> ---- </pre>

2010년 10월 12일 화요일

Log4J 로깅 비용 계산

  1. 2006년 4월 30일에 제가 쓴 포스팅 입니다. 이글루스에 있던건데 의미가 있는것 같아서 옮겨 놓습니다. 원문은 이글루스 블러그입니다.


Log4J 로깅 비용 계산

기존의 System.out.println() 으로 로깅 할 때 발생하는 문제의 대안으로 Log4J를 요즘 많이 사용한다.

Log4J를 사용하면 OutputStream시 발생하는 자원독점 문제 해결, logging 레벨 설정을 코드와 분리, 로깅 output target 설정 변경 등 다양한 잇점을 얻을 수 있다. 그러나 Log4J가 실행될 때 발행하는 비용을 계산해 보면 Log4J를 사용할 때 주의가 필요하다.

무작정 사용하는 것은 WAS 전체에 심각한 문제를 발생 시킬 수 있다. 모 사이트에서 JVM의 GC가 자주 발생하는 문제가 발생하여 시스템 전체에 심각한 문제가 발생한 사례가 있었다. 물론 Log4J가 문제의 핵심은 아니었지만 어느 정도 영향은 미쳤다고 생각된다.

지금 다룰 내용은 "Log4J The Complete Manual" 23 페이지에 나온 내용을 참조하였다.
이 내용을 메뉴얼을 읽을 때는 심각하게 받아 들이지 않았지만 실제 사례를 접하니 간과할 수만은 없는 문제인 듯 싶다.

문제 코드 분석

문제가 발생한 사이트는 Struts를 기반으로 하는 프레임웍 구조를 갖고 있었다. Session 정보를 추출하기 위하여 다음과 같은 코드가 공통 코드 레벨에서 수행되고 있었다.

while( i.hasNext()  ){
  Map.Entry e = (Map.Entry) i.next();
  logger.debug("TABLE KEY : " + e.getKey() );
  logger.debug( "SESSION ID : " + ((HttpSession) e.getValue()).getId() );
}      

특정 상황에서 이 코드는 246번의 반복을 수행하였고, 두 개의 debug()이 실행하면서 각각 8메가의 임시 객체를 생성하였다. 해당 while문이 수행되면서 16메가의 임시 객체를 생성하였다.

물론 문제의 while문이 구동할 때 Log4J는 DEBUG 모드로 운영중인 상태였다.

이 코드로 발생하는 문제는 Log4J를 DEBUG 모드로 운영 중이기 때문에 발생한 것이고 WARNING이나 ERROR 모드로 운영하면 문제가 발생하지 않는다고 생각할 수도 있다. 그러나 Log4J가 실행되는 비용을 계산해 보면 이러한 문제는 Log4J의 운영 모드를 변경해도 동일하게 발생한다는 것을 알수 있다.(물론 일정 부분 감소는 할 것이다.)

Log4J 로깅 메소드 비용 계산


logger.debug("Entry number: "+i+" is "+String.valueOf(entry[i]));

예제 코드와 같은 코드가 있다고 할 때 다음과 같은 순서로 실행된다.


  1. logging 문자열 생성
    1. String 문자열 1개 생성: "Entry number: "
    2. String 문자열 1개 생성 총 2개: "Entry number: " + i
    3. String 문자열 1개 신규 생성, + 결합 1개 생성, 총 4개: 신규 생성: " is ", 결합 문자열: "Entry number: " + +i+" is "
    4. String 문자열 1개 신규 생성, + 결합 1개 생성, 총 6개: 신규생성: String.valueOf(entry[i]), 결합문자열: "Entry number: "+i+" is "+String.valueOf(entry[i])
  2. logger의 logging 레벨 체크
    1. 현재 등록된 로거의 로깅 레벨을 체크
    2. 현재 logger의 로깅 레벨이 DEBUG이면 다음단계 진행
    3. 현재 logger의 로깅 레벨이 INFO 이상이면 정지
  3. logger의 appender에 등록된 output에 출력
    1. layout 적용
    2. 출력

위와 같은 순서로 실행된다.

Log4j 운영 모드에 따른 비용 계산


  • Debug 모드일 때
    1. 1번 로깅 문자열 생성 = 6개의 스트링 객체 생성, 1개만 사용, 5개의 스트링 객체는 GC 대상
    2. 2번 logger의 레벨 체크 실행
    3. 3번 로깅 실행 - layout 적용 후 output에 로깅 적용
  • non-Debug 모드일 때
    1. 1번 로깅 문자열 생성 = 6개의 스트링 객체 생성, 1개만 사용, 5개의 스트링 객체는 GC 대상
    2. 2번 logger의 레벨 체크 실행
    3. 3번 실행 없이 종료

로그의 모드에 따라서 Log4J에서 생략되는 부분은 3번에 국한된다. 즉 로깅 문자열 생성이나 로그 레벨 체크의 비용은 발생한다. 여기서 로그레벨 체크는 전체 로깅 비용의 1%이하이고 극히 적은 비용을 발생하기 때문에 2번은 큰 문제가 되지 않을 수 있다. 그러나 1번의 발생 비용은 경우에 따라서 매우 심각해 질 수도 있다.

1번의 로깅 문자열은 스트링을 "+"하는 방식이기 때문에 수백번의 loop안에서 발생하거나 로깅 로직이 빈번하게 발생하는 조건에서는 temporary object를 양산하는 로직이 될 가능성이 크다.

위의 Log4j 운영 모드에 따른 실행 순서에서 알수 있듯이 이것은 로깅 모드를 변경한다고 해서 발생하지 않는 부분은 아니다.

문제 해결 코드


if(logger.isDebugEnabled(){
  logger.debug("Entry number: "+i+" 
    is "+String.valueOf(entry[i]));
}

위와 같은 코드의 사용이 바람직 하다. 이러한 코드는 Log4J의 예제에서 나오는 isDebugEnabled() 메소드를 이용하는 방법이다. 실제 프로젝트에서 보변 isDebugEnabled 메소드의 사용을 간과 하는 경우가 많다.

이 코드를 사용하면 로깅 문자열을 생성하기 전에 로깅 레벨을 체크하는 isDebugEnabled 메소드를 실행하여 로깅을 실행할 것인가를 미리 체크하게 된다. 기본적인 코드이지만 이러한 코드를 사용하는 것은 매우 중요하다.


문제 해결 코드의 side-effect


이 코드는 DEBUG 모드일대 부가적인 문제를 발생 시킨다.

if(logger.isDebugEnabled() { 
  logger.debug("Entry number: "+i+" is "+String.valueOf(entry[i]));  
}

이 코드는 DEBUG 모드일 때 LOGGER의 실행 레벨 체크를 두번한다는 단점을 갖는다.

isDubugEnabled 메소드에서 한번 체크하고 debug 메소드에서 다시 체크한다. debug 모드에서 로깅 레벨 체크후 degub 상태이면 로깅을 한다.

이러한 실행 과정은 단일 로깅일 때는 문제가 되지 않지만(로깅 전체에서 체크의 실행 비용은 1% 이하이다.) debug 메소드가 loop 문 안에 있거나, 하나의 메소드에서 debug 메소드가 여러번 호출될 때는 문제가 될수 있다. 1%이하라도 반복적으로 실행된다면 문제가 될 것이다.

public void foo(Object[] a) {
  for(int i = 0; i < a.length; i++) {
    if(logger.isDebugEnabled()){
       logger.debug("Original value of entry number: "+i+" is "+a[i]);
    }
    
    a[i] = someTransformation(a[i]);

    if(logger.isDebugEnabled()){
       logger.debug("After transformation the value is "+a[i]); 
    }
  }
} 

위 와 같은 메소드가 있을 경우에는 반복문속에서 두번의 debug 메소드가 실행된다. debug 모드 운영 중이라고 가정할 때 반복문 속에서

  1. 로그레벨 체크
  2. 로그레벨 체크 후 로깅
  3. 로그레벨 체크
  4. 로그레벨 체크 후 로깅
의 순서로 실행된다. 반복문 자체도 문제지만 반복적인 로깅 체크 역시 문제이다. 이러한 코드는 다음과 같이 변경하는 것이 바람직하다.

public void foo(Object[] a) {
  boolean isLogging = logger.isDebugEnabled();
  for(int i = 0; i < a.length; i++) {
    if(isLogging ){
      logger.debug("Original value of entry number: "+i+" is "+a[i]);
    }

    a[i] = someTransformation(a[i]);

    if(isLogging ){
       logger.debug("After transformation the value is "+a[i]);
    }
  }
} 

작은 결론 debug 메소드 사용시 주의 사항

지금까지 debug 메소드에 대해서 알아 보았다. debug 메소드를 사용할 경우 다음과 같은 두가지 사항에 주의해야한다.
  1. isDebugEnabled 메소드를 사용하여 사전에 로그레벨 체크: 불필요한 로깅 문자열 생성 비용 절감
  2. 반복문에서는 isDebugEnabled 메소드를 반복문 외부에서 실행하여 결과 저장 및 반복문 안에서 재사용: 불필요한 로깅 레벨 중복 체크의 비용 절감

Log4J를 사용함으로써 예전에 로깅 문제의 만은 부분은 해결되고 있지만 Log4J에 대한 올바른 사용에 주의를 기울일 필요가 있다. 지금은 debug 메소드만을 다루었지만 debug 외의 info(), warning(), error(), fatal() 메소드 역시 동일한 문제를 내포하고 있다.

이러한 고민에 앞서 로깅 관련 코드를 작성할 때 로깅 문자열 생성에 대한 각별한 주의가 필요한 것 같다.

무심코 작성한 코드 한줄이 폭탄이 될수도 있다.....^

세팅은 여기까지 ....... (한것도 없구만 하하)

대략 이정도에서 만족하고 슬슬 시작해 볼까요?

와 넗다.

슬슬 즐겨 보죠......

2010년 10월 10일 일요일

새로운 정착지

안녕하세요. Devtainer 입니다.

여기 저기 떠돌며 살았는데 이제는 정착을 해야 할 시기가 정말 된것 같습니다.
결국은 Blogstop으로 오고야 말았네요.

오늘도 즐거운 하루 되세요