카테고리 없음2010. 10. 29. 21:46
웹서버에서 이미지 파일 다운로드 받기
new File("downloadedimg.jpg").withOutputStream { os -> new URL("http://server/img_uri.jpg").withInputStream { is -> os << is } } 
Posted by jintopark
카테고리 없음2010. 1. 1. 17:55
몽고디비(MongoDB)로 마음이 쏠렸었는데, 너무 겉핥기로만 지나쳤다는 미안함이 있어, CouchDB도 테스트 해봤습니다.

드라이버
--------
그루비쪽에서 보면, 몽고나 카우치나 거기서 거기더군요. 테스트에는 jcouchdb를 드라이버로 사용했습니다. 그루비에 내장된 REST 로 시도해보았는데, jcouchdb에 비해 너무 느리더군요. groovyx.net.http.RESTClient 는 구현이 제대로 안된 것 같습니다.

jcouchdb는 자바용 드라이버이지만, 그루비에서도 이런 식으로 사용할 수 있었습니다.
[code groovy]
def db = new org.jcouchdb.db.Database("xxx.xxx.xxx.xx", 5987, "dbname");
def doc = [name:'박제권' ....]
db.createDocument(doc);
[/code]

테스트
------
테스트는 게시문 20만건, 사용자디비 6만건, 댓글 100만건 정도를 INSERT 해보았습니다.
서버는 몇군데서 돌아가면서 해봤는데, 체감결과는 비슷했습니다. 메모리가 많으면 더 잘도는 것 같긴합니다만, 워낙 느려서...

다음은 기록해둘만한 사항들입니다.



버전
----
데비안에서 couchdb의 안정버전은 아직도 0.8 입니다.  문제는 0.10 버전이 조금 빨라지기도 했고, VIEW 쪽 접근 URL도 다르다는  점입니다. (view 의 url 이 달라지니까... 나중에 0.10 이 안정버전이 되면 어플리케이션 코드를 손대야 하는...)

데비안4 나 5 모두 couchdb 0.10 을 설치하려면 testing으로 올려야합니다.
ubuntu 9.10 / fedora 11 에서는 문제없이 0.10을 설치해줬습니다.

컴파일하는 것도 한가지 방법인데... erlang, openssl 까지 의존 목록에 들어있더군요. 따라서....귀찮습니다.

(저는 안정버전에 집착하는 편인데, 좀 문제네요.)


벌크 인서트
----------
처음에 며칠동안은 테스트 데이터 한 건식 루프를 돌면서 insert 해보았는데요. 최장 8시간까지 걸리더군요. 댓글의 경우는 그나마 데이터가 적어서인지 빨리되는데, 게시물같은 경우는 초당 10개가 안되기도 합니다.

상황에 따라 정확한 시간은 달라질 수 있습니다만, 동일 환경에서 mongodb에서는 13분 걸리더군요. 그냥 두 DB가 성격이 다른 거니까, 속도를 비교하는 것은 무리인 듯 합니다.

더 조사해보니, 벌크인서트(bulk insert)라는 것이 있어서 이걸 써봤습니다.

[code groovy]
def array = [];
rawdata.each {r->
   def doc = [name:r->name, ....]
   array.add(doc);
   if((i%500) != 0) {
     db.buldCreateDocuments(array);
     array = [];
   }
}
[/code]
와 같은 방식으로 사용할 수 있습니다.

이 API를 이용하니까, 전체 데이터 로딩속도가 엄청나게 빨라졌습니다. (30분정도)


뷰 == 미리 정의해야 하나
-----------------------
다음 문제는 뷰(View)였습니다. 카우치에서 가장 독특해보이는 녀석이 자바스크립트로 만들어진 뷰인데요. 여기에 map/reduce라는 개념까지 들어가면 공부하기 힘들어보입니다.

저는 테스트 데이터를 입력하면서 회원/게시물/댓글 에 대해서 doc_type 이라는 필드를 만들고, 각각 member/article/comment 라는 값을 주었습니다.

[code groovy]
articles_data.each { r->
  def doc = [doc_type :'article', name:r->name, ....]
  db.createDocument(doc);
}
comments_data.each { r->
  def doc = [doc_type :'comment', name:r->name, ....]
  db.createDocument(doc);
}
[/code]
그리고, 각 타입의 문서가 몇개나 있는지 세어보는 view를 만들었습니다. 앞의 함수가 map 이고, 뒤의 함수가 reduce 입니다.

[code groovy]
function(doc) {
  emit(doc.doc_type, 1);
}

function(key, values) {
    return sum(values);
}
[/code]
아래는 결과입니다.

[code groovy]
"article"    : 245328
"member"  : 68076
"comments":1157777
[/code]

이 녀석이 카우치 디비에서 가장 감동적인 장면인 것 같아서 캡쳐해봤습니다. (테스트 도중이라 값이 다른 부분이 있습니다)


맵/리듀스를 이리저리 쓰다보면 기존의 SQL과는 또다른 재미있는 데이터 인출기법이란 점이, 꽤 ... 재미있습니다. 하지만, 문제는 저 함수가 호출될 때마다, 인덱스가 수정된다는 점이었습니다.

카우치는 데이터와 인덱스를 분리해서 관리합니다. 데이터를 저장할 때는 인덱스 처리를 하지 않습니다. 대신 VIEW 엔진이 동작할 때, 관련된 인덱스를 수정하게 됩니다.

이게 묘한 부작용을 일으키는데요.

update나 insert 가 많이 이루어진 후에 view를 호출하면 인덱스하는데 시간이 너무 오래걸린다는 점입니다. 테스트를 포기할 정도로 오래걸린 경우도 많았습니다.


나중에 찾아낸 해결책은 벌크-인서트를 수행하면서, 중간 중간에 view 엔진을 호출해주는 겁니다. 그렇게 하면 어느정도 참고 기다릴만합니다. 하지만 좀.. 뻘짓하는 느낌이었습니다.

인덱스 수정이 완료된 이후에는 VIEW를 수행하는데 걸리는 시간이 굉장히 짧아집니다. 그리고, 테스트에서 처럼 몇만개씩이 아닌, 천개정도의 데이터를 추가하고, VIEW를 돌려봤는데요. 응답을 얻기까지 얼마 안걸리더군요. 1~4초 내외인데, 오래걸린다는 느낌은 없었습니다.


유니크 키
---------
이건 좀 문젠데요. 카우치는 유니크키(unique key)를 지원하지 않습니다. (몽고는 지원) 편법은 있는 것 같지만, 어쨌든, 시스템이 자동생성하는 키( 필드명 : _id ) 를 제외하고는 유니크 키를 지원하지 않습니다.

즉, 회원 아이디라던가, 하는 것을 유니크 키로 지정해서, 동일한 아이디의 회원이 만들어지지 않도록 디비를 설정하는 것이 안됩니다.

요기 맨아래에 설명이 있는데... 노드가 하나일 때는 _id 필드에 원하는 필드를 넣으면 되긴하는데, multi-master 환경에서는 충돌할 수도 있다, 라고 적혀있습니다.



데이터 사이즈
------------
MySQL : 1.9G
MongoDB: 2.1G
CouchDB non-bulk: 18G
CouchDB bulk: 3.5G

데이터의 형태에 따라 차이가 날 것 같습니다만, 비율은 저정도 인것 같습니다. 특이한 점은 카우치는 MVCC때문인 것 같습니다만, 벌크일때와 아닐때 차이가 납니다. (compact db 라는 명령이 따로 있습니다.)



결론
----
몽고디비랑 카우치디비를 일대일로 비교하기는 힘듭니다. 초당 insert 가 너무 느리긴 합니다만, 카우치는 원래 컴퓨터를 추가하고 연결만 하면 자동으로 클라우드로 동작하는 것이 목표인 데이터베이스입니다. 느리면 서버를 추가하면 되죠.

몽고디비는 처음부터 속도를 중시하는 쪽이구요. (몽고도.. master-master 지원하지만 fail-over를 위한 것이라고 하네요. 그래도 그냥 잘 쓴다는 사람도 있긴합니다만..)

카우치디비는 일단 재미삼아 공부하기 적당하구요. 서비스 환경에 적용한 케이스도 꽤 있고, 그리 나쁜 선택은 아닌 것 같습니다. 하지만, 문제를 공부를 해야한다는 점입니다.

몽고디비는 지금 돌아보니 mysql 의 document-db 버전인 것 같다는 인상입니다. sql을 알던 사람이 적응하기 쉽고, 드라이버나 예제들도 따라하기 좋습니다. 공부하는데 드는 시간이 비교적 짧습니다.

아마도, 테스트 과제 따위에서는 카우치, 당장 서비스 할 것에는 몽고, 가 어떨까 합니다. 저는 한동안 두가지 모두 병행해서 사용해보려고 합니다. 카우치쪽이 다음버전에서 어떤 점이 좋아질지 궁금하기 때문입니다. (어쩌면 속도?)

이상입니다.
Posted by jintopark
카테고리 없음2009. 4. 8. 18:06

기욤 아저씨의 블로그에 "구글 앱 엔진에서 그루비를 써보아요!"라는 글이 올라왔다. 처음 든 생각은, 이거, 며칠 늦은 만우절 농담이네. 헌데, 설마.. 하며 링크들을 살포시 눌러보니...

구글 블로그 : "앱 엔진에서 자바를 쓸 수 있다." : 어, 진짜?

스프링쪽에도 글이 올라와있다. : "write your Google App Engine applications in Groovy!"  (이 쪽에는 간단한 튜토리얼도 있네?)

오옷!, 엔제인가 앱엔진에서 그루비 쓰게 해달라고 전세계 찌질이 그루비빠들이 구글에 졸라댈 때 나도 함께 졸랐었는데, 그때 졸라대면서도 속으로는 '설마 안될꺼야,' 라고 생각했었다. 우짜둥둥 경사로다. ^^


----

P.S. 사실 JVM을 열어준거니까, JRuby, Scala, Jython도 모두 쓸 수 있다. ^^

Posted by jintopark
카테고리 없음2009. 3. 28. 20:43
자바와 그루비를 비교해 볼 수 있는 좋은 글이 있어서 소개합니다.


다음은 자바로 만든 Hello World 프로그램이다.

[code java]public class HelloWorld {
private String name;

public void setName(String name) {
this.name = name;
}

public String getName() {
return name;
}

public String greet() {
return "Hello " + name;
}

public static void main(String[] args) {
HelloWorld helloWorld = new HelloWorld();
helloWorld.setName("Groovy");
System.out.println( helloWorld.greet() );
}
}[/code]

평범한 자바 소스다. 이 소스 파일을 그대로 그루비에서 groovyc 로 컴파일하거나, groovy 로 실행해보면, 한줄도 수정하지 않은 상태에서, 잘 실행해준다. 그루비 문법은 자바 문법을 대부분 수용한다.



이제 이 소스를 그루비답게 단계별로 고쳐보자...


우선 그루비에서는 세미콜론(;)과 public을 생략할 수 있다. 한줄에 명령문이 하나라면 세미콜론을 생략할 수 있고, public은 디폴트라서 생략할 수 있다. 또, 리턴(return)도 생략하자. 메서드의 마지막 문장이 return이면 생략할 수 있다.


[code groovy]
class HelloWorld {
    private String name

    void setName(String name) {
        this.name = name
    }

    String getName() { name }

    String greet() { "Hello "+name }
   
    static void main(String[] args) {
        HelloWorld helloWorld = new HelloWorld()
        helloWorld.setName("Groovy")
        System.out.println( helloWorld.greet() )
    }
}[/code]

이번에는 getName()에서 GString을 써보자.


[code groovy]
String greet() {
    return "Hello ${name}"
}
[/code]
${name} 부분에서 GString의 문자열 치환기능을 사용했다. 파이썬이나 다른 언어에서 본 적이 있을 것이다. 저걸 사용하면 문자열 다루기가 훨씬 수월해진다.

프로퍼티 자동 생성 기능도 사용해보자.


그루비에서는 setName, getName 따위의 메서드를 따로 만들 필요가 없다. 변수를 public으로 정의하면 그루비가 자동으로 getXXX(), setXXX()를 만들어준다.

[code groovy]
class HelloWorld {
    String name

    String greet() { "Hello ${name}" }
   
    static void main(String[] args) {
        HelloWorld helloWorld = new HelloWorld()
        helloWorld.name = "Groovy"
        System.out.println( helloWorld.greet() )
    }
}

[/code]

이번에는 괄호도 생략하고, 동적 자료형도 써보자. 그루비도 오리형(duck type)을 지원한다.

[code groovy]
class HelloWorld {
    def name

    def greet() { "Hello ${name}" }
   
    static main(args) {
        def helloWorld = new HelloWorld()
        helloWorld.name = "Groovy"
        println helloWorld.greet()
    }
}[/code]

String이 def로 바뀌었다. def로 정의한 변수는 오리형 변수가 된다.


마지막으로 그루비는 클래스파일을 생성할 수도 있지만, 동시에 스크립트로 호출할 수 도 있으니까. main 함수를 스크립트처럼 바꿔보자..


[code groovy]
class HelloWorld {
    def name
    def greet() { "Hello ${name}" }
}   

def helloWorld = new HelloWorld()
helloWorld.name = "Groovy"
println helloWorld.greet()
[/code]

마지막 예제만 보면 자바프로그램처럼 보이지 않겠지만, JVM 상에서 동작한다. 컴파일하면 class 파일도 만들어준다.

다시한번 ... 이 모든 것이 자바 가상 기계에서 돌아간다.

---


원문은 여기(http://groovy.dzone.com/news/java-groovy-few-easy-steps)에 있습니다.

Posted by jintopark
카테고리 없음2009. 3. 16. 00:04
요즘 진행중인 프로젝트에서 서블릿을 만들 때 자바 대신 그루비를 사용한다. 헌데 코드가 조금 복잡해지면서
OutOfMemoryError: PermGen space

라는 오류가 자꾸 발생했다. 일단 저 오류가 뜨고나면 톰캣이 더이상 동작하지 않는 상태가 된다.

이 문제로 5일이나 삽질한 끝에 방금 전에 해결했다.

여러가지 해결 책이 있겠지만, 일단 가장 쉬운 방법은 WEB-INF/lib 에서 mysql*.jar 를 삭제하는 것이다. 더불어 commons-logging*.jar도 삭제하자. 그러면 문제도 해결되고 애플리케이션 속도도 빨라진다.

그래도 해결이 안되고 계속 문제가 발생하면, 톰캣 실행옵션에
-XX:+CMSClassUnloadingEnabled -XX:+CMSPermGenSweepingEnabled

을 줘보자. 또는 -XX:MaxPermSize=256m도 효과가 있다고 한다. 나는 일단 jar파일들 삭제까지만 해서 문제가 해결되었다.
Posted by jintopark
카테고리 없음2009. 1. 16. 23:34
그루비에서 SWT를 쓰는 방법 (먼저 자바1.4 또는 자바 5를 설치해주세요.)

0. 그루비를 설치한다. (요즘 안정버전은 1.5.7이다)

1. Eclipse-libs.ZIP을 다운로드 받는다.

2. 파일을 WORK/lib 에 푼다.  (WORK는 작업디렉토리)

3. WORK 디렉토리에 r.groovy 파일을 만들고 다음과 같이 적는다.
 def loader = this.class.classLoader.rootLoader
 def dir = new File('lib')
 dir.eachFileMatch(~/.*\.jar$/) {
     loader.addURL(it.toURL())
}
evaluate(new File('test.groovy'))


4. test.groovy 에는 다음과 같이 적는다

import org.eclipse.swt.SWT
import org.eclipse.swt.widgets.* 

def swt = new groovy.swt.SwtBuilder()
def shell = swt.shell(text:'Groovy / SWT Test') {
    rowLayout()
    label(style:"none", text:'Simple demo of Groovy and SWT')
    button(style:"push", text:'  Push Me  ') {
        onEvent(type:"Selection", closure:{ println "Hello" })
    }
}

shell.pack()
shell.open()
while (!shell.disposed) {
  if (!shell.display.readAndDispatch()) shell.display.sleep()
}


5. 이제, 프롬프트에서 다음 명령을 내리면 화면에 SWT로 만든 어플리케이션이 보인다.

C:\WORK\>groovy r.groovy


사용자 삽입 이미지

http://groovy.codehaus.org/GroovySWT 에서 베껴왔다.

Posted by jintopark
카테고리 없음2008. 5. 5. 12:16
그루비 1.6 베타 1 이 나왔는데, 속도개선이 가장 큰 이슈라고 주장하고 있다. "최고 460%까지 속도가 향상되었어요"라고 한다.

그럼, 그전에는 그렇게나 느렸어요? 라는 질문이 떠오르긴 하지만. ^^

이렇게 빨라진 가장 큰 이유는 call site cache기법때문이라고 한다. 루비나 그루비나 메서드호출을 동적으로 할 수 있다는 점이 언어의 강점인데, 동적호출은 비용이 많이 드는 일이다.

한번 호출하면 그 기록을 가지고 있다가 똑같은 호출이 발생하면 이런 저런 계산을 거치지 않고 기억해두었던 메서드를 다시 호출한다는 것이 call site cache 기법. JRuby에서는 이미 1년전부터 적용하고 있었단다.

그루비가 이제서야 JRuby랑 겨룰 수 있게 되었다. 하지만, 아래쪽에 있는 하이버네이트나 스프링덕분에 Grails의 속도는 그렇게 빨라지기는 힘들지 않을까.

어쨌든, 이 글이 이번 사건에 대해 가장 냉정한 분석인 것 같다.

Posted by jintopark
카테고리 없음2008. 4. 27. 02:13
그루비 1.5.6 이 나왔다.

1.5.5 에서 바뀐 것들을 보고있으면 어쩐지 그루비란 것이 아직은 쓸만하지 않은 건 아닌가, 의심이 들기도한다. 하지만 반대로 저렇게 열심히 버그를 잡고 있다는 것은 프로젝트가 살아있다는 뜻이기도 하겠다.

G2One and the Groovy development team is pleased to announce the release of Groovy 1.5.6, a bug fix release for the stable Groovy 1.5.x branch.

A regression introduced in 1.5.5 was fixed, and 35 bugs have been resolved (generics, MOP, and joint compiler issues, better line information for IDE support, etc)

As usual, you can download the latest Groovy dustribution and read the change log to know all the details. (from http://groovy.dzone.com/news/groovy-156-released)


Posted by jintopark
카테고리 없음2008. 4. 15. 13:49
그루비 컴파일러가 느리다는 생각은 안하고 있었는데, 개발팀에서는 열심히 컴파일 속도를 높이고 있었단다.

http://glaforge.free.fr/weblog/index.php?itemid=238

우짜둥둥 이번 릴리즈 (1.5.5)에서는 컴파일 속도가 3배에서 5배까지도 빨라졌다고 한다. 그루비로 만든 프로그램의 속도에 대한 이야기가 없는 걸로 봐선... 그쪽은 신경쓰기 힘든가보네..
Posted by jintopark
카테고리 없음2008. 3. 24. 00:54
레일즈(rails)랑 그레일즈(grails)를 대강 비교해봤다.

레일즈는 "ab -n 1000 -c 10"의 테스트에서 CPU 99% MEM 8% 까지 먹는다.
그레일즈는  "ab -n 100 -c 1" 만 줘도 CPU 99% MEM 80% 까지 간다. 대략 10배정도 힘들어한다. (메모리를 더주면 GC를 안할테니 비교해볼만할지도 모른다.)

초당 요청 처리는 그레일즈가 3개, 레일즈는 29개 정도. 한개를 처리하는 시간은 그레일즈 336ms, 레일즈 30ms. 어디를 봐도 10배정도 느리다. ab 를 쓰는 테스트는 너무 많이 부정확한 걸까?


대강 살펴본 것이고, 결정적으로 메모리가 별로 없는 서버라서 비교하기 힘들긴 하지만, 그래도 대강비교에서는 레일즈 승. Graeme씨가 테스트하기로는 그레일즈가 더 빠르다고 했는데, 어째 이런 결과가 나온 걸까? 흠...

레진(resin)과 아파치에 연결해서 테스트해본 결과, 아파치-레진-그레일즈의 조합보다는 레진-그레일즈의 조합이 더 안정적인 결과를 보여준다. 최고 초당 4개까지 처리한다. 흑. 어쨌든,그레일즈는 아직 도입불가.

사실... 스프링같은 것이 아래쪽에 들어있는 놈을 쓸 필요는 없겠지. 너무 크니까...

http://graemerocher.blogspot.com/2008/01/grails-making-java-developers-forget.html
을 읽어봐도 꼭 옮겨갈 필요는 없어보인다. 다만..

내가 뭘만들든지 이 녀석들은 참고할 필요가 있겠다.  이녀석들 : http://grails.org/Plugins

이상~

Posted by jintopark

 

 
«이전  1 2  다음»