우분투 11.10에 JDK설치하는 방법으로, 아래 내용은 http://blog.sudobits.com/2011/09/14/how-to-install-jdk-on-ubuntu-11-10/ 에서 더 자세하게 보실 수 있습니다.

* OpenJDK 설치..
sudo apt-get install openjdk-7-jdk
* Sun JDK 설치..
sudo add-apt-repository ppa:ferramroberto/java sudo apt-get update sudo apt-get install sun-java6-jdk sun-java6-plugin
저작자 표시
Tag // Java SDK, JDK, ubuntu

Updater/Launcher using jnlp

from Java 2011/07/18 19:53
예전에 자바로 개발해본 업데이터/런처입니다.. 
jar 파일의 다운로드는 jnlp를 이용하고 있습니다.. 당근 파샬(partial) 업데이트 불가입니다.. ^^;;
설명은 없고, 코드만 있습니다.. ㅋㅋ

 
저작자 표시
LRU는 Least Recently Used의 약자로, 간단하게 최근에 사용된 넘을 캐시에 유지한다는 것이 LRUCache 입니다..
간단하게 아래와 같이 만들 수 있습니다.

1. 코드 속에서 간단하게 만들기..
final int MAX_ENTRIES = 100;
Map cache = new LinkedHashMap(MAX_ENTRIES+1, .75F, true) {
    // This method is called just after a new entry has been added
    public boolean removeEldestEntry(Map.Entry eldest) {
        return size() > MAX_ENTRIES;
    }
};

2. LinkedHashMap을 이용해서 만들기..

public class LRUCache<K,V> extends LinkedHashMap<K,V> {
    private int lruSize;

    public LRUCache(int size) {
        lruSize = size;
    }

    @Override
    protected boolean removeEldestEntry(Map.Entry eldest) {
        return size() > lruSize;
    }
}

보통 위에처럼 하게 되면 그냥 됩니다..
그러다가 점점 메모리 릭이 납니다.. ^^;;

그래서 해결책을 찾아보니, https://code.google.com/p/reflection-dsl/source/browse/trunk/ReflectionDsl/src/br/com/bit/ideias/reflection/cache/LRUCache.java?spec=svn204&r=204 에서는 Value에 해당하는 객체를 SoftReference로 래핑해서 땜빵(?)하고 있네요.. ^^;;

그래서 저같은 경우에는 명시적으로 객체를 삭제하는 코드를 입력해서 사용하고 있습니다.
아래의 코드를 통해서 잠재적으로 발생할 수 있는 메모리릭을 없애 주세요.. ^^
    protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
        boolean isRemove = size() > maxsize;
       
        if (isRemove) {
            Object obj = this.get(eldest.getKey()); 
            if(obj instanceof BufferedWriter) { // V가 BufferedWriter 인스턴스임..
                try {
                    ((BufferedWriter)obj).close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            this.remove(eldest.getKey());
        }

        return isRemove;
    }







저작자 표시

java nio scatter/gater

from Java 2010/12/07 20:11
자바도 nio 패키지 내에서 channel을 통한 buffer의 scatter/gater를 지원하고 있습니다.
현재, 프로젝트의 프로토콜이 header + body의 구조를 띄고 있고, 매번 single buffer에 put, send 하고 있고, 받을 때도 역시, 똑같이 하고 있습니다. 그걸 아래의 튜토리얼에 있는 scatter/gater 방식을 통해서 코드를 깔끔하게 만들 수 있습니다.

* read

ByteBuffer header = ByteBuffer.allocate(128);
ByteBuffer body   = ByteBuffer.allocate(1024);
ByteBuffer[] bufferArray = { header, body };
channel.read(buffers);

* write

ByteBuffer header = ByteBuffer.allocate(128);
ByteBuffer body   = ByteBuffer.allocate(1024);
ByteBuffer[] bufferArray = { header, body };
channel.write(buffers);

위 예제와, 좀 더 자세한 내용 아래의 주소를 통해서 보실 수 있습니다. ^^
http://tutorials.jenkov.com/java-nio/scatter-gather.html
저작자 표시
Tag // gather, java, NIO, Scatter
SocketChannel의 read 메쏘드는 timeout이 존재하지 않습니다.
혹, SocketChannel 객체의 .socket() 메쏘드로  소켓객체의  타임아웃을 세팅해도 먹지 않죠.. ^^;;
그래서, non-blocking의 read 메쏘드에 대한 timeout은 busy waiting하는 형태로 타임아웃을 줄 수 있겠습니다..

                // 20초               
                long timeout = 20 * 1000;  
                long stime = new Date().getTime();
                long rtime = 0L;
               
                int rvalue =0;
                int rvalues = 0;
                while (rtime < timeout ) {
                    rtime = System.currentTimeMillis() - stime;
                    rvalue = channel.read(rbuffer);
                    if(rvalue == -1)
                        throw new Exception("connection closed");
                   
                    rvalues = rvalues + rvalue;
                    if(rtime > timeout)
                        throw new Exception("read timeout exception");

                    if(rvalues >= 4)
                        break;
                }

저작자 표시
non-blocking SocketChannel에서 끝까지 읽어오는 코드입니다.
개인적으로 헤더 8byte, 헤더의 앞의 4byte를 전체 패킷을 길이로 잡습니다.
그리고, 아래처럼 SocketChannel에서 packet handling variables와 같이 패킷을 끝까지 다 읽어 들입니다.
아래 내용은 non-block으로 대용량의 바이너리 데이타를 읽어들이기 위해서 꼭 필요한 내용일 듯 합니다.

* read() 내용

    //// packet handling variables
    private int fullsize = 0;
    private int readedsize =0;
    private int minsize = 8;
   
    @Override
    public void read() {       
        try {
            // 읽기
            int rbytes = this.channel.read(rbuffer);
                   
            // 연결종료
            if (rbytes == -1) {
                ((ChannelListener)this.listener).disconnected(this);
                this.close();
                return;
            }
   
            // 버퍼에 내용이 없는 경우
            if (rbytes == 0) {
                this.channel.configureBlocking(false);
                this.handle();
                return;
            }
           
            // 읽은 바이트 갯수를 증감시킨다.
            readedsize += rbytes;   
            rbufferList.add(this.copy(this.rbuffer, rbytes));
           
            // 최소 패킷의 길이에서 패킷을 전체 길이를 리턴한다.
            if(readedsize >= minsize && this.fullsize == 0) {
                this.fullsize = this.createResultBuffer().getInt();
                for(int i=0; i< this.rbufferList.size(); i++) {
                    this.rbufferList.get(i).position(0);
                }
            }
           
            // 패킷을 다 읽어 들였다.
            if(fullsize == readedsize) {
                ((ChannelListener)this.listener).arrived(this,this.createResultBuffer());
            }
           
            this.channel.configureBlocking(false);
            this.handle();
        } catch(Exception e) { // disconnected
            try {
                this.close();
            } catch(IOException ie) {
                new CallbackExceptionHandler().handle(ie);
            }
           
            ((ChannelListener)this.listener).disconnected(this);
        }
    }

저작자 표시
2004년도에 작성한 자료네요.. 이런 테스트 결과가 논문으로 게제가 되는건지 살짝 의아함이 드네요.. 물론 저도 할말은 없지만.. ^^;;

情報通信 論文紙 第 8 輯 (2004)

Journal of Telecommunications and Information, Vol. 8, 2004.

Socket, RMI및 JMS를 이용한 통신 프로그램의 성능 비교

강 동 현*, 김 화 종**

Performance Comparison between

 Network Program Using Socket, RMI, JMS

Dong-Hyun Kang*, Hwa-Jong Kim**

 

Abstract

This paper compares the performances among network programs using Socket, RMI(Remote Method Invocation) and JMS(Java Message Service). Socket is used for data transmission and RMI is used in distributed computing environment by invoking method running on remote computer. JMS  supports message-based middleware. Even if there are basic different between the methods, this paper presents guidline for programmers to select  appropriate method to implement proper network program.

    <Keywords : JMS, Socket, RMI>

I. 서 론1)

일 반적인 네트워크 통신은 다른 모든 기술의 기반이 되는 네임드 파이프나 TCP/IP 소켓 등이 사용된다. 이러한 로우 레벨 기술을 사용하여 애플리케이션 간의 통신을 수행하기 위해서 개발자는 상대방 네트워크의 상태를 관리하고, 메시지를 처리하는 최선의 방법을 결정하기 위해 많은 노력을 기울여야 한다.

본 논문에서는 엔터프라이즈 메시징 환경을 구축하기 위한 방법으로 자바의 Socket, RMI 및 JMS로 구현할때 각 방식이 제공하고 있는 기본적인 특성 및 고유 기능에는 차이가 있으나 이들을 이용하는 클라이언트-서버 통신 프로그램의 수용 용량, 서비스 처리시간 등의 성능 비교함으로써 엔터프라이즈 환경을 구축할 때 어떤 방식이 유리할지를 선택하는 기준을 제공하고자 한다.

본 논문의 구성은 2장에서는 성능측정을 위한 전반적인 기술을 소개하고, 3장에서는 성능 측정 및 분석 방법으로 성능 측정 방법을 설명하고 4장에서는  성능 비교를 통한 실제 결과값을 보인다. 5장에서는 성능에 따른 문제점과 보안점을 제시한다.

II. 관련기술

2.1 엔터프라이즈 시스템 구조

엔터프라이즈 메시징에서 통신하는 애플리케이션이 많아질수록 애플리케이션간의 연결이 많아질 것이다. 그림 1 은 복잡한 애플리케이션 간의 상관관계를 보여준다. 각 화살표는 각 애플리케이션의 목적지의 집합을 나타낸다.

그림 1. 엔터프라이즈 애플리케이션 구성도

엔 터프라이즈 메시징 애플리케이션은 각각의 애플리케이션과 연결을 생성해야 한다. 새로운 애플리케이션을 생성하면, 새로 생성된 애플리케이션과 통신 하기위해 기존의 애플리케이션을 변경해야 하는 문제점이 있다. 이러한 문제점을 해결할 수 있는 방법으로 Hub ans Spoke 구조를 사용할 수 있다. 이 구조에서는 메시지 브로커(Message Mboker) 또는 메시지 서버(Message Server) 라고 불리는 중계 애플리케이션을 정의한다. 메시지 브로커는 모든 애플리케이션의 목적지가 되고 메시지 내의 정보를 사용하여 해당하는 대상 애플리케이션들에게 메시지를 라우트한다. 그림 2 는 메시지 브로커의 구성도를 보여주고 있다.

그림 2. 메시지 브로커 구성도

2.2 Socket

 소 켓은 소프트웨어로 작성된 통신 접속점이라고 할 수 있는데 네트워크 응용 프로그램은 소켓을 통하여 통신망으로 IP 패킷을 송수신하게 된다[1]. 자바에서도 유닉스 소켓(socket) 또는 윈도우 소켓(Winsock)과 같은 소켓 프로그래밍 인터페이스를 지원한다. 소켓 관련 클래스는 java.net 패키지가 제공하는데 연결형 서비스(TCP)를 위하여 Socket과 ServerSocket 클래스가 있으며, 비연결형 서비스(UDP)를 위하여 DatagramSocket과 DatagramPacket이 정의되어 있다.

2.3 RMI(Remote Method Invocation)

네 트워크에서 분산 작업을 처리하기 위해  RPC(Rtmote Procedure Call)가 널리 사용된다. RMI 프로그램에서는 서버는 원격 객체에 잘 알려진 부팅 레지스트리와 함께 스텁을 등록하게 되고 클라이언트는 잘 알려진 부팅 레지스트리를 통해서 서버 객체(스텁)의 첫 참조를 얻는다. 클라이언트는 이제 스텁을 통해서 서버와 통신할 수 있다. 통신이 되면 레지스트리는 더 이상 필요하지 않다.

 그림 3 RMI가 동작하는 전체 흐름을 보여주고 있다

그림 3. RMI 프로그램 동작 다이어그램

2.4 JMS

JMS(Java MessageService)는 자바로 개발된 MOM(Message-Oriented Middleware) 벤더와 DB개발 업체 그리고 인터넷 관련 업체가 메시징 기반 제품을 사용하는데 접근하기 위한 공통의 자바 API를 제공하기 위해 만들어 졌다. MOM(Message Oriented Middleware)이란 메시지 기반 미들웨어로서 메시징시스템을 비즈니시 시스템에 적용했을때 엔터프라이즈 메시지 시스템 또는 메시지 기반 미들웨어라고 한다.

메 시징 제품은 Point-to-Point(이하 PTP) 또는 Publish/Subscribe(이하 pub/sub)으로 구분하며 PTP는 메시지 큐(Queue)에 관한 개념이며 각각의 메시지가 큐로 전달하면 메시지를 수신하는 클라이언트가  큐로부터 메시지를 수신하는 동작원리를 가지고 있다. Pub/Sub는 다수의 메시지 생성자가 토픽(Topic)으로 전달하여 다수의 메시지 소비자에게 메시지를 전달하는 메시지 모델이다.

JMS 는 인터페이스를 구현하고 관리와 제어 기능을 제공하는 메시징 시스템을 JMS 제공자(Provider)라고 한다. 메시지 클라이언트는 JMS 클라이언트와 비 JMS 클라이언트로 나눌수 있다. JMS 클라이언트는 자바 언어로 작성하고, JMS API를 사용하여 메시지를 보내고 받는 프로그램이다. 프로그래밍 언어에 상관없이 다른 프로그램은 비-JMS 클라이언트이다. 두 종류의 클라이언트는 서로 통신할 수 있다.

JMS 가 사용하고 있는 관리객체와 인터페이스 개발순서를 보면 관리객체는 시스템 관리자가 생성하는 객체로서 JMS Configuration Information을 포함하는 객체를 말하고 이 객체는 클라이언트가 사용하는데 관리자는 이 객체를 네이밍 서비스의 네임스페이스(JNDI1))내에 둔다.

III. 성능 측정 및 분석

 이 장에서는 엔터프라이즈 환경을 구성하는 시스템 구조와 엔터프라이즈 메시징 환경에서의 애플리케이션들 사이의 통신을 수행하는 방법인 보통 네트워크, RPC 및 MOM을 사용하는 방식에서 클라이언트-서버의 환경의 최대 수용용량, 클라이언트 수에 따른 서비스 처리시간, 메시지 크기에 따른 서비스 처리시간을 한 클라이언트가 다른 전체 클라이언트에게 전체 발송하는 Broadcast 방식과 클라이언트와 서버가 통신하는 Echo 방식으로 나누어 테스트하였다.

3.1 서버의 최대 수용 용량

소켓, RMI 및 JMS의 클라이언트-서버 모델로 구성하여 서버가 받아 들일 수 있는 최대 수용용량을 측정 하였다. 최대 수용 용량 측정시 클라이언트가 다른 클라이언트에게 메시지를 보내는 boradcast 방식으로 측정하였다.

3.2 메시지 변동량에 따른 성능 비교

클 라이언트와 서버 사이의 통신 성능 측정에서 클라이언트 연결 수와 전송할 메시지의 수를 증가시켜 가면서 통신 성능 상태를 측정하였다. 소켓, RMI 및 JMS는 같은 방법으로 프로그램되었으며 Broadcast 방식과 Echo 방식으로 나누어 테스트하였다.

3.3 메시지 크기에 따른 성능 비교

클 라이언트-서버 사이에 주고 받는 메시지 크기를 변동하여 그에 따른 클라이언트수와 메시지 변동량 사이의 송수신 시간을 측정 하였다. 메시지 크기에 따른 송수신 시간을 측정하는 것은 소켓, RMI및 JMS에서 Boadcast 방식과 Echo 방식으로 테스트하였다.

IV. 통신 프로그램의 성능 비교

소켓, RMI 및 JMS를 클라이언트-서버로 구성하여 최대 클라이언트 수용용량, 서비스 처리시간, 메시지에 따른 서비스 처리 시간을 brocast 방식과 echo 방식으로 성능 비교를 하였다.

4.1 데이터 전송 속도

소 켓, RMI 및 JMS를 서버와 클라이언트로 구성하여 메시지를 서버에 보내고 다시 그 데이터를 받는 작업을 반복해서 실행하고 반복횟수를 증가시키며 전송시간을 측정한다. 표 5 는 전송 속도 측정 결과 이다. 그림 4에서 보듯 데이터를 전송하는 방식에서는 Socket방식이 데이터를 전송하는데 가장 좋은 성능을 나타냄을 알 수 있다.


표 5. 데이터 전송 속도 측정 결과

횟수

100

200

300

400

500

600

700

800

900

소켓

(sec)

0.031

0.032

0.047

0.062

0.063

0.078

0.078

0.094

0.109

RMI

(sec)

0.22

0.422

0.614

0.846

1.00

1.14

1.338

1.594

1.719

JMS

(sec)

0.843

1.203

1.472

1.905

2.243

2.515

2.853

3.343

3.625


그림 4. 데이터 전송 속도 비교

데 이터 전송 측정 시간결과 소켓이 가장 좋은 성능을 보이고 있음을 알 수 있다. RMI는 내부적으로 TCP/IP 상에서 소켓을 이용하는 분산 시스템이다[4].  RMI와 JMS의 차이점은 RMI에서 객체는 임의의 장소에 상주하고 가상머신의 범주내에 있다. 반면 JMS 에서의 메시지(객체)는 네트워크를 통해서 물리적으로 한 JVM에서 다른 JVM으로 비동기적으로 돌아 다닌다.

4.2 최대 클라이언트 수용용량

소 켓, RMI 및 JMS를 서버와 클라이언트로 구성하여 하나의 서버가 수용할 수 있는 최대 수용용량을 측정하기 위해 클라이언트의 수를 증가시켜 최대 클라이언트를 수를 측정하였으며, 각 클라이언트는 전체 메시지 발송을 하게 하여 클라이언트 증가에 따른 메시지 전송 속도도 함께 측정하였다.

표 6. 최대 클라이언트 수용용량

방식/횟수

100

300

500

700

900

 Socket Client(sec)

0.594

3.235

9.110

17.125

29.891

 RMI Client(sec)

4.62

30.672

80.734

160.953

160.953

 JMS Client(sec)

9.484

69.672

197.797

417.625

697.767


그림 5. 최대 연결수에 따른 연결 시간

표 6 과 그림 5의 측정 결과는 한계를 900 까지 정해 놓고 동일한 조건상의 시간을 나타낸 것이다.  최대 수용용량에 관한 테스트 결과 최대 연결부분에서는 소켓이 1250개의 연결을 지원하고 있으며 서버와 클라이언트의 송수신에 걸리는 차이는 네트웍상의 속도에 따라 미묘한 차이가 있다.

RMI는 최대 연결부분에서는 1300까지 측정하였으나 그 이상의 측정은 하지 않았다. RMI는 원격 메소드를 호출하는 구조로서 스레드의 사용이 없고 메모리 사용량이 적어 다른 방식에 비해 많은 연결을 지원하고 있다.

JMS 는 최대 900개의 연결을 할 수 있으나 테스트에 사용된 웹 로직 6.0이 j2sdk1.4와의 버그로 생기는 메모리 누수로 인해 그 이상의 연결시도나 메시지 전송시 서버가 다운되었다.  JMS의 경우 클라이언트의 메시지를 서버가 다시 채널에 등록하는 시간은 다른 방식보다 좋다. 하지만 클라이언트의 수신시간은 한

PC 상에서 많은 클라이언트를 동작시키기 위해 Thread를 사용하였고 웹 로직에 접근하는 수신 대기 시간이 길어져 많은 차이가 발생하였다.

4.3 클라이언트의 수와 메시지 전송량

소 켓, RMI 및 JMS를 서버와 클라이언트로 구성하여 클라이언트 수와 메시지의 수를 증가시켜 전송량에 따른 서비스 시간을 측정하였다. 전송량에 따른 성능비교는 broadcast 방식과 Echo 방식 두가지로 나누어 하였다. 표 7은 Broadcast 방식에서의 클라이언트수와 메시지 전송량에 대한 성능 비교이고,  표 8 은 Echo 방식에서의 클라이언트수와 메시지 전송량에 대한 성능 비교 표이다.


표 7. broadcast방식의 연결수와 메시지 전송량의 성능비교

Socket

클라이언트수

메시지수

시간(sec)

100

10

3.39

 

100

35.718

 

300

104.203

300

10

29.938

 

100

305.734

 

300

961.86

500

10

86.046

 

100

866.688

 

300

2587.656

RMI

클라이언트수

메시지수

시간(sec)

100

10

36.031

 

100

336.734

 

300

1056.766

300

10

305.671

 

100

3042.032

 

300

9086.485

500

10

836.922

 

100

8963.516

 

300

25455.72

JMS

클라이언트수

메시지수

시간(sec)

100

10

8.828

 

100

915.859

 

300

3147.577

300

10

978.500

 

100

에러 

 

300

에러

500

10

에러

 

100

에러

 

300

에러

 

클 라이언트 수와 메시지 전송량에 대한 비교로 보았을때 broadcast 방식은 적은 수의 클라이언트가 많은 양의 전송량을 보내는 것이 유리하고  Echo 방식에서는 또한 적은 수의 클라이언트가 많은 양의 전송량을 보내는 것이 조금더 성능이 좋아 지는 것을 보였다. 표에는 작성되지 않았지만 broadcast 방식에서나 Echo 방식에서의 소켓은 서버가 보내는 시간이나 클라이언트들중 처음 보내는 클라이언트나 마지막으로 메시지를 보내는 클라이언트나 속도 차이는 없다. 하지만 RMI 경우 Echo 방식에서는 차이가 없었으나 broadcast 방식에서는 클라이언트들중 처음 보내는 클라이언트가 가장 오랜시간 동안 대기하여 메시지를 전송받고 마지막으로 보낸 클라이언트가 가장 짦은 수신 시간을 얻었다. 이것은 소켓은 tm레드를 통한 평균적인 수신시간을 얻지만 RMI의 경우 서버의 객체가 동작을 완료할 때까지 대기 해야 되는 문제점이 발생하게  된다.

4.4  메시지 크기에 따른 성능 비교

소 켓, RMI 및 JMS를 서버와 클라이언트로 구성하여 클라이언트 수와 메시지의 크기를 증가시켜 전송량에 따른 서비스 시간을 Echo 방식으로 측정하였다.  표 9 는 각 방식에서 하나의 클라이언트가 서버에게 1000개의 메세지 송수신 하는데 각 메시지의 크기를 1000byte씩 증가시켜 각각에 걸리는 시간을 측정한 표이다.

표 9 . 메시지 크기에 따른 성능 비교

크기

1000

2000

3000

4000

5000

socket

400

520

640

760

890

RMI

1920

2040

2400

2530

2954

JMS

3750

4109

4640

5047

6062

크기

6000

7000

8000

9000

10000

Socket

1016

1125

1250

1359

1485

RMI

3078

3350

3530

4047

4203

JMS

6375

6468

6938

8437

8853

 그 림 6 은 메시지 크기에 따른 성능 비교를 나타내고 있다. 서버에게 하나의 클라이언트가 1000개의 메시지를 전송시 각 메시지를 1000byte씩 증가 시키는데에 따른 각 방식의 시간을(ms) 비교한 그림이다. 메시지의 크기에 따른 전송 성능 역시 소켓이 가장 뛰어남을 볼 수 있다.

그림 6. 메시지 크기에 따른 성능 비교

V. 결 론

본 논문에서는 엔터프라이즈 메시징 환경을 구축하기 위한 방법으로 자바의 Socket, RMI 및 JMS를 각각 사용할 때 클라이언트-서버 통신 프로그램의 수용 용량, 서비스 처리시간 등의 성능 비교함으로써 엔터프라이즈 환경을 구축할 때 어떤 방식이 유리할지를 선택하는 기준을 제공하였다.

각 프로그램 방식의 장점과 단점을 보고 성능을 비교하므로써 엔터프라이즈 환경을 구축시에 서버와 클라이언트의 연결 수와 메시지의 전송량에 따른 성능을 보기 위해 본 논문을 작성 하였다.

서 비스 처리시간에서는 Socket이 가장 우수 하였다.RMI와 JMS방식은 내부적으로 TCP/IP의 소켓을 사용하고 있으므로 Broadcast나 Echo로 테스트한 클라이언트의 증가량에 따른 메시지 처리시간, 클라이언트와 메시지의 증가량에 대한 처리시간 메시지의 크기에 대한 처리시간 모두 소켓보다 낮은 성능을 내고 있다.

각 방식으로 엔터프라이즈 환경을 구축할 때 프로그램의 편리성과 좀더 유동적인 환경에서는 RMI와 JMS가 소켓자체를 작성하지 않기 때문에 편리하고 좀더 유동적인 환경과 상대적으로 쉬운 유지보수를 할 수 있다. 본 논문에서는 성능만을 측정하였으나 실제 엔터프라이즈 환경을 구축할시 고려해야 할 중요한 부분이다. 

MOM 의 호환성 문제를 해결하기 위해 JMS를 측정한 결과에서 서비스 처리시간, 수용용량 모두 낮은 성능을 나타내고 있다. 이것은 J2SDK1.4  버전과 웹 로직 6.0의 버그로 인한 문제점으로 밝혀져 웹 로직7.0과 서비스 팩을 확장하였으나 높은 CPU사용과 메모리 점유율로 인해 서버의 기능을 제대로 하지 못하였다. 웹 어플리케이션 서버의 장점인 다양한 미들웨어 제품에 대한 서비스처리를 할 수 있는 장점에 비해 JMS처럼 특정 부분에 대한 서비스 처리는 낮은 것으로 나왔다.

앞으로의 연구과제는 웹로직의 문제점을 해결하기 위해  JMS의 최신 스펙을 지원하고 안정된 서비스를 지원하는 SwiftMQ, SpirtWave, SonicMQ등의 제품을 사용하여 JMS에 대한 성능을 정확히 측정하는 것이다.

참고 문헌

[1] 김화종 저, “컴퓨터 네트워크 프로그래밍”, 홍릉과학출판사, 2000

[2] Chad Darby, "Beginning Java Networking", wrox, 2002

[3] Subrahmany Allamaraju, "ProFessional Java Server Programming J2EE 1.3 Edition" wrox, 2002

[4] 박천구, 문창수 저, “Enterprise Java Beans EJB & WebLogic" 가메 출판사, 2001

[5] Ken Arnold, James Gosling, David Holmes, "The Java(TM) Programming Language(3rd Edition)", Addison-Wesley, June 2002

[6] McGraw-hill, "Java(TM)2 NetWorking", couch, 2001

[7] JStrom 박지훈 저, "Enterprise JavaBeans", 대청, 2001[]]

[8] David A, "Java Message Service", o'reilly , 2000

[9] IBM Developer Home, http://www-903.ibm.com/

[10] The Source for Java Technology

,

* 출처 : http://blog.naver.com/an5asis/60022142872
저작자 표시
Tag // java, jms, RMI, socket
문서를 정리하다가 전에 정리된 문서에서 아래와 같은 내용이 있어서 포스팅 합니다..
단, 출처는 생각이 안 나네요. ^^;;

The following set of command line options are recommended for running high performance server applications:

-XX:+AggressiveOpts
-XX:+AggressiveHeap
-XX:ParallelGCThreads=2
-XX:InterpreterProfilePercentage=10
-XX:CompileThreshold=35000
-XX:OnStackReplacePercentage=80
-XX:PermSize=256m
-XX:MaxPermSize=256m
-XX:AllocatePrefetchStepSize=128
-XX:AllocatePrefetchStyle=2
-XX:AllocatePrefetchDistance=1024
-XX:+UseCompressedOops if heap size is less than 32GB
-Xmx, -Xms, -Xmn should have sufficiently large values.
(For example, -Xms6600m -Xmn5000m -Xmx6600m or -Xms20000m -Xmn18000m -Xmx20000m.)

저작자 표시

1. 다운로드 : http://java.sun.com/javase/downloads/index.jsp

Java SE Development Kit 6u21
* jdk-6u21-linux-i586.bin

2. 파일 퍼미션 변경 : chmod 700 jdk-6u21-linux-i586.bin

./jdk-6u21-linux-i586.bin 실행

jdk1.6.0_21

3. 풀린파일 복사 : sudo cp -r jdk1.6.0_21 /usr/local

4. 링크 : sudo ln -s /usr/local/jdk1.6.0_21/ /usr/local/java

5. 환경설정
/etc/profile 에 아래와 같이 기술을 하고 저장을 한다. 
JAVA_HOME=/usr/local/java
PATH=$PATH:$JAVA_HOME/bin
CLASSPATH=$CLASSPATH:$JAVA_HOME/lib

6. 설정확인
source /etc/profile 을 통해서 환경설정을 확인한다.

7. 확인
java -version

저작자 표시

java signal handling

from Java 2010/07/16 11:03
java에서 처리할 수 있는 signal과 그 내용입니다.
아래의 reference를 통해서 java에서 signal을 어떻게 처리하고, 새로운 signal을 등록할 수 있는 예제를 확인하실 수 있습니다.. 좋네요.. ^^

아래는 자바에서 지원되는 시그널과 내용입니다..

Signal Name

Description

SIGSEGV

Incorrect access to memory (write to inaccessible memory)

SIGILL

Illegal instruction (attempt to invoke a unknown machine instruction)

SIGFPE

Floating point exception (divide by zero)

SIGBUS

Bus error (attempt to address nonexistent memory location)

SIGSYS

Bad system call issued

SIGXCPU

CPU time limit exceeded (you've been running too long!)

SIGXFSZ

File size limit exceeded

SIGEMT

EMT instruction (AIX specific)

SIGABRT

Abnormal termination. The JVM raises this signal whenever it detects a JVM fault.

SIGINT

Interactive attention (CTRL-C). JVM will exit normally.

SIGTERM

Termination request. JVM will exit normally.

SIGHUP

Hang up. JVM will exit normally.

SIGUSR1

User defined. Used by some JVMs for internal control purposes.

SIGUSR2

User defined. Used by some JVMs for internal control purposes.

SIGQUIT

A quit signal for a terminal. JVM uses this for taking Java core dumps.

SIGBREAK

A break signal from a terminal. JVM uses this for taking Java core dumps.

SIGTRAP

Internal for use by dbx or ptrace. Used by some JVMs for internal control purposes.

SIGPIPE

A write to a pipe that is not being read. JVM ignores this.

No Name (40)

An AIX reserved signal. Used by the AIX JVM for internal control purposes.



OS별 지원되는 signal에 대한 내용입니다.

E.g. for Unix/Linux based platform the signals are SEGV, ILL, FPE, BUS, SYS, CPU, FSZ, ABRT, INT, TERM, HUP, USR1, QUIT, BREAK, TRAP, PIPE.

For Windows based platform, the signals are SEGV, ILL, FPE, ABRT, INT, TERM, BREAK.


reference
* http://www.ibm.com/developerworks/ibm/library/i-signalhandling/
* http://twit88.com/blog/2008/02/06/java-signal-handling/
* http://mimul.com/pebble/default/2009/07/19/1248007080000.html

저작자 표시

JDBC Type 별 내용

from Java 2010/06/25 15:01
JDBC 1,2,3,4의 타입별 드라이버의 동작 방식과 설명입니다.
개인적으로는 가능한 JDBC4 타입으로 사용하는 것이 좋을듯 합니다.
아래내용은 http://www.precisejava.com/javaperf/j2ee/JDBC.htm#JDBC102 에서 참고를 하였습니다.

 Type
 Tier  Driver mechanism  Description
 1  Two  JDBC-ODBC  This driver converts JDBC calls to ODBC calls through JDBC-ODBC Bridge driver which in turn converts to database calls. Client requires ODBC libraries.
 2  Two  Native API - Partly - Java driver  This driver converts JDBC calls to database specific native calls. Client requires database specific libraries.
 3  Three  JDBC - Net -All Java driver  This driver passes calls to proxy server through network protocol which in turn converts to database calls and passes through database specific protocol. Client doesn't require any driver.
 4  Two  Native protocol - All - Java driver  This driver directly calls database. Client doesn't require any driver.

저작자 표시

'Java' 카테고리의 다른 글

ubuntu(linux) server에서 java 설치하기  (2) 2010/07/20
java signal handling  (0) 2010/07/16
JDBC Type 별 내용  (0) 2010/06/25
외부 API를 JDK에서 내포한 경우, 최신의 외부 API 사용하기..  (0) 2010/06/22
#ifdef #ifndef in Java  (0) 2010/06/15
Tag // java, jdbc, jdbc type
외부 API들이 JDK에 많이 포함이 되어 있습니다.
http://java.sun.com/javase/6/docs/api/ 문서의 package들을 보시면, javax나 org로 시작하는 외부(?) API들을 보실 수가 있는데요.. JDK에서는 rt.jar에 포함되어 잇지만, 아래의 내용처럼, http://aploit.egloos.com/4806304 님의 블로그에 포스팅된 내용을 보시면, 최신의 외부 API를 사용하기 위해서 java.endorsed.dirs 옵션을 사용해서 해결하는 내용을 보실 수가 있습니다.
java로 작업을 하다보면 가끔씩 endorsed라는 디렉토리 명이 보였다. 사전을 찾아보면 배서하다, 추천하다, 양도하다 정도의 뜻이고, 사전적 의미가 아닌 java쪽에서는 어떤 의미로 사용되는지 몰랐다.

그냥 몰라도 별 문제는 없었고 해서 그냥 넘어갔었다.

그런데 의미를 확실히 알게 되었다. 

jdk1.4에는 JAXP1.2의 라이브러리들이 포함되어 있다. 대표적으로 org.w3c.dom의 패키지와 javax.xml의 패키지가 그것이다.

그런데 JAXP1.3, 1.4가 나왔고, jdk1.4의 환경에서 이들을 사용하고자 할 경우에 문제가 된다.
(참고로 JAXP1.3은 JDK5.0에 JAXP1.4는 JDK6.0에 포함되었다. 따라서 JDK5.0에서는 JAXP1.3 라이브러리를 따로 설치할 필요가 없다.) jdk는 1.4이고 어플리케이션에서 JAXP1.3을 설치했다고 하면(구체적인 jar 파일은 jaxp-api.jar와 jaxp-ri.jar이다) 같은 패키지 이름까지 같은 클래스가 2개 존재하게된다. 예를 들면 org.w3c.dom.Document이다. 하나는 rt.jar에 있는 것이고(버전은 JAXP1.2) 하나는 jaxp-api.jar에 있는 것이다(요 버전은 JAXP1.3). 원했던 것은 rt.jar의 것이 아닌 jaxp-api.jar의 것이 로딩되는것이였는데, 그렇게 동작하지 않는다. 설치한 라이브러리들 간의 로딩 순서는 classpath에 설정한 순서로 조절할 수 있지만, rt.jar는 설정 순서로 조절할 수 없다.

JDK 자체에 포함된 것이 아닌 설치한 라이브러리의 것을 로딩할때 사용하는 매커니즘이 바로 endorsed이다. "java.endorsed.dirs"라는 시스템 파라매터를 설정하면 된다. 다음과 같이 java를 실행할 때 jaxp-api.jar가 있는 디렉토리를 설정해 주면 된다.
java -Djava.endorsed.dirs=/path/where/jar/is ......
여기서 /path/where/jar/is 디렉토리는 jaxp-api.jar가 있는 곳이다.

TOMCAT의 경우 endorsed 매카니즘을 사용하고 있다. tomcat 4.1.39의 bin/setclasspath.bat에서 set JAVA_ENDORSED_DIRS=%BASEDIR%\common\endorsed 으로 endorsed 디렉토리를 설정하고 catalina.bat에서 다음과 같이 java 실행 시에 시스템 파라매터로 설정해 주고 있다.
%_EXECJAVA% ... -Djava.endorsed.dirs="%JAVA_ENDORSED_DIRS%"

TOMCAT_HOME/common /endorsed에 가보면 xercesImpl.jar, xml-apis.jar가 있는데 이들은 JAXP 1.3의 것이다.


참 고로 클래스로딩의 매카니즘에서 "java." 로 시작하는 패키지의 클래스는 endorsed가 적용되지 않는다.


JAXP 에 대한 기타.
JAXP1.4가 설치되어 있다면 apache xalan의 다음과 같은 라이브러리들을 따로 설치할 필요 없다. JAXP안에 포함되어 있기 때문이다. 설치할 필요가 없는 것 보다는 쫑나는 상황을 피하기 위하여 설치해서는 안된다.
  serializer.jar
  xalan.jar
  xercesImpl.jar
  xml-apis.jar
  xsltc.jar

jaxp 는 sun의 glassfish 프로젝트에서 관리하고 있다.
저작자 표시

'Java' 카테고리의 다른 글

java signal handling  (0) 2010/07/16
JDBC Type 별 내용  (0) 2010/06/25
외부 API를 JDK에서 내포한 경우, 최신의 외부 API 사용하기..  (0) 2010/06/22
#ifdef #ifndef in Java  (0) 2010/06/15
멀티쓰레드 프로그램 평가기준  (0) 2010/06/01

#ifdef #ifndef in Java

from Java 2010/06/15 17:30
C구문의 전처리 구문인 #ifdef나 #ifndef같은 넘을 자바에서 사용하는 기본적인 내용입니다.
아래처럼 println이 DEF가 정의되었냐 혹은 DEBUG모드냐에 따라 달라지는 형태로 되어 있는 구문인 경우
public class IFDef{
public IFDef(){
 int i = 100;
 #ifdef DEF
  System.out.println("DEF");
 #else
  System.out.println("not DEF");
 #endif  
 }
}

아래처럼, 바꿔주면 됩니다.
private static final boolean def = false;

if (def) {
System.out.println("DEF");
} else {
System.out.println("not DEF");
}

Tag // ifdef, ifndef, java
유명한 Doug Lea 교수님의 멀티 쓰레드 프로그램의 평가기준에 대한 내용입니다.
"Java 언어로 배우는 디자인 패턴 입문 멀티 쓰레드편, Yuki Hiroshi" 의 Introduction 2 챕터에 나오는 내용입니다. 아래 내용의 출처는 http://ethdemor.springnote.com/pages/4349969 입니다.

아래의 기준들은 Doug Lea 분류를 기준으로 한 것이며, 이런 류의 평가 기준은 대개 상반(trade-off)되는 경우가 있습니다.

필 수
안전성 (safety) - 객체를 망가트리지 않을 것
 - "망가 진다"는 것은 비유적 표현으로 객체의 필드가 예상 외의 값을 취하는 것을 의미합니다.
 - 복수의 스레드가 이용해도 안전성이 유지되는 클래스를 스레드 세이프(thread-safe)한 클래스라고 하며 자바 API에는 명시되어 있습니다.
생존성 (liveness) - 필요한 처리가 이뤄질 것

옵 션
재사용성 (resuability) - 클래스를 다시 사용할 수 있는 것
 - 멀티 스레드 프로그램에서는 스레드 배타제어, 구조, 방침을 캡슐화 하는 것이 관건이며 Java SE 5.0의 java.util.concurrent 패키지에서 이를 잘 실현하고 있습니다.
 - 수행 능력(performance) - 고속 / 대량으로 처리할 수 있을 것
   - throughput - 단위 시간 당 처리 수
   - 응답성 (responsiveness) - 요청을 한 뒤 반응이 나타날 때까지 걸리는 시간
      - GUI 프로그램에서는 요청의 완료까지 걸리는 시간보다 처리 시작까지의 시간을 중요하게 생각하기도 합니다. 여기서 완료는 요청 -> 처리 -> 응답 까지의 시간이며 처 리 시작은 완료까지의 시간은 좀 더 걸리더라도 클라이언트에게 먼저 응답(~을 처리 중입니다 등)을 보내는 것을 말합니다.
      - 응답성이 높은 프로그램은 대기 시간(latency)이 짧다고 표현합니다.
   - 용량 (capacity) - 동시에 처리할 수 있는 수
   - 그 밖에 효율(efficiency), 확장성(scalability), 저하(degradation) 등이 있습니다.

평가기준 정리
멀티 스레드 시스템에서 안전성과 생존성이 지켜지지 않으면 제대로된 프로그램이라고 할 수 없습니다.
따라서 이 필수 조건을 만족한 상태에서 재사용성과 수행 능력을 어떻게 높이느냐가 관건이 되겠습니다.




'Java' 카테고리의 다른 글

외부 API를 JDK에서 내포한 경우, 최신의 외부 API 사용하기..  (0) 2010/06/22
#ifdef #ifndef in Java  (0) 2010/06/15
멀티쓰레드 프로그램 평가기준  (0) 2010/06/01
간단한 SOAP 메시지 콜  (0) 2010/05/26
garbage collector  (0) 2010/04/29

간단한 SOAP 메시지 콜

from Java 2010/05/26 15:34

아래처럼 SAAJ를 이용해서 SOAP 1.1 버전의 메소드를 호출해서 사용할 수 있다..
흠.. soap 보다는 json with rest 방식으로.. ^^;;

import java.io.ByteArrayInputStream;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.soap.MessageFactory;
import javax.xml.soap.SOAPBody;
import javax.xml.soap.SOAPConnection;
import javax.xml.soap.SOAPConnectionFactory;
import javax.xml.soap.SOAPElement;
import javax.xml.soap.SOAPMessage;
import javax.xml.soap.SOAPHeader;
import javax.xml.soap.SOAPHeaderElement;
import javax.xml.transform.dom.DOMSource;

import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

public class SoapClient implements IClient  {
 
 public static String soapActionUrl = "http://localhost/soap_http/test.asmx?op=GetPurchaseListWBC";
 
 private SoapClient(){};
 
 public static SoapClient newInstance() {
  return new SoapClient();
 }
 
 public static String getRequestMessage(int serviceCode, int uuid) {
  String query = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
   + "<soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" "
   +  "xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" "
   +  "xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" >\n"
   //+  "xmlns:SOAP-ENC=\"http://schemas.xmlsoap.org/soap/encoding/\">\n"
   + " <soap:Body>\n"
   + "  <GetPurchaseListWBC xmlns=\"http://tempuri.org/\">\n"
      + "   <serviceCode>"+String.valueOf(serviceCode)+"</serviceCode>\n"
      + "    <uuid>"+ String.valueOf(uuid) +"</uuid>\n"
      + "   </GetPurchaseListWBC>\n"
   + " </soap:Body>\n"
   + "</soap:Envelope>";  
  return query;
 } 

 public SOAPMessage request(String soapActionUrl) throws Exception {
  Document doc = null;
  DocumentBuilder docBuilder = null;
  DOMSource domSource = null;
  SOAPConnection connection = null;
  
  SOAPMessage resultMessage = null;
  
  try {
   docBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
   doc = docBuilder.parse(new ByteArrayInputStream(getRequestMessage(1,2).getBytes()));
   domSource = new DOMSource(doc);
   
   SOAPMessage message = MessageFactory.newInstance().createMessage();  
   message.setProperty(SOAPMessage.CHARACTER_SET_ENCODING, "utf-8");
   message.setProperty(SOAPMessage.WRITE_XML_DECLARATION, "true");
   message.getSOAPPart().setContent(domSource);
   message.getMimeHeaders().addHeader("SOAPAction", "http://tempuri.org/GetPurchaseListWBC");

   //String url = "http://localhost:1351/test.asmx?op=GetPurchaseListWBC";
   connection = SOAPConnectionFactory.newInstance().createConnection();
   resultMessage = connection.call(message, soapActionUrl);
   
   NodeList nodes = resultMessage.getSOAPBody().getChildNodes();
   
   for (int i = 0; i < nodes.getLength() ; i++) {
    Node node  = nodes.item(i);
    this.traverse(node);
   }

  } finally {
   connection.close();
  }
  
  return resultMessage;
 }
 
 public void traverse (Node node) {
  String nodeName = node.getNodeName();
     String nodeValue = node.getNodeValue();
    
     if(!"#text".equals(nodeName))
      System.out.println("<" + nodeName +">");

     if (node.hasChildNodes()) {
      NodeList nodes= node.getChildNodes();
      for (int i=0; i<nodes.getLength(); i++) {
       traverse (nodes.item(i));
      }
     } else {
      System.out.println(nodeValue);
     }
    
     if(!"#text".equals(nodeName))
      System.out.println ("</" + nodeName +">");
 } 
 
}

 

'Java' 카테고리의 다른 글

#ifdef #ifndef in Java  (0) 2010/06/15
멀티쓰레드 프로그램 평가기준  (0) 2010/06/01
간단한 SOAP 메시지 콜  (0) 2010/05/26
garbage collector  (0) 2010/04/29
Circular Dependency Problem  (0) 2010/03/26
Tag // json, Rest, saaj, SOAP

garbage collector

from Java 2010/04/29 13:51
자바의 Garbage Collector 이슈는 성능과 더불어 자원 해제라는 막중한 역할을 하기 때문에 중요하게 파악을 해 둬야 되는 내용입니다. 아래는 자바에서 지원하고 있는 Garbage Collector의 영역별 내용과 형태에 대한 내용입니다.

 - serial collector : young, old 영역, java 1.4 버전까지 default collector, single cpu만 사용
 - parallel collector : young 영역, java 5 버전부터 CPU 2, MEM 2G 이상(Hot Spot VM)일 경우 자동선택
 - parallel compacting collector : old 영역, option으로 지정해야 선택됨
 - cms(concurrent mark-sweep) collector : old 영역, option으로 지정해야 선택됨.
 -
G1 collector : young, old 영역,  1.6.0_14(NUMA 구조 지원, 1.6.0_18 버전에 성능에 대한 언급) 부터 사용이 가능합니다. option으로 지정해야 선택됨. “early access software”, 자바 비즈니스 라이선스를 구매하지 않은 고객은 사용을 하지 않는 것이 좋다고 합니다. Java 7버전을 타켓으로 하고 있다고 합니다.

Circular Dependency Problem

from Java 2010/03/26 10:55
Circular Dependency의 해악은 개발을 하다보면 자연스럽게 알게 된다..
회사에서 개발하는 시스템중에 처음에는 그러하지 않았을 것인데, 아키텍처링을 할 수 없는 지금의 조직에서 자연스럽게 Circular Dependency를 걸어버렸다.. 일정이라는 최고의 명제 아래 말이다..
결국, 의존과 버전에 묶여서 뗄레야 뗄루 없는 커플처럼 되어 버린 기존의 시스템은 또다시 거대한 레거시로의 한발한발 다가서고 있다.. 정말로 뗄 수 없을 정도로 말이다..
누군가는 나서서 해결을 해야 겠지만, 누가 하겠는가.. 일정에 맞춰서 들어온 일 처리해야쥐..
결국 시스템의 모습은 직책자들의 마인드와 의지가 만들어 내는 우리의 현실이며, 이 모습은 좋은 개발팀 혹은 좋은 개발실은 아니라는 느낌을 지울 수 없다..

아래 Building속성에서의 Circular dependencies는 Warning이 아니라 Error 상황이 되어야 된다.
그래서, 위의 상황을 미연에 방지를 해야된다.. 단순한, 일정에 맞춰야 되서 Warning이 Default가 되어서는 안될 것이다.. ^^;;




'Java' 카테고리의 다른 글

간단한 SOAP 메시지 콜  (0) 2010/05/26
garbage collector  (0) 2010/04/29
Circular Dependency Problem  (0) 2010/03/26
String의 공백은 trim()을 두번 호출해야 된다는 얘기에 대해서..  (0) 2010/03/04
소켓 연결 확인하기..  (0) 2010/03/03
어느 윗분께서 String의 trim()을 사용하면, 한번더 호출해야 정확하게 trim()이 된다고 말씀을 하셔서.. String 클래스의 trim()메쏘드를 살펴보니 아래와 같이 코딩이 되어 있네요..

    public String trim() {
        int len = count;
        int st = 0;
        int off = offset; /* avoid getfield opcode */
        char[] val = value; /* avoid getfield opcode */
     
        while ((st < len) && (val[off + st] <= ' ')) {
            st++;
        }
       
        while ((st < len) && (val[off + len - 1] <= ' ')) {
            len--;
        }
       
        return ((st > 0) || (len < count)) ? substring(st, len) : this;
    }

위 코드를 살펴보면, char[]의 ' ' <-- 공백을 앞쪽에서는 st를 뒤로 밀고, 뒤쪽에서는 len을 앞쪽으로 땅기면서 substring을 하게 되어 있네요..

위 코드를 보면 분명히 한번만 trim()하면 공백이 날라가네요.. ^^


소켓 연결 확인하기..

from Java 2010/03/03 12:19
소켓을 기반으로 풀링을 하는 라이브러리를 개발할 시에 보통 소켓 클래스의 isconnected 라는 상태변수를 통해서 소켓의 연결상태를 확인할 수 있으나, 정확한 정보는 아니죠.. isconnected라는 변수는, 마지막 네트웍 이벤트를 처리한 소켓의 연결 상태이기 때문이죠.. 그래서 확실하게 풀을 관리하기 위해서는 네트웍 이벤트를 발생시켜 보는것이 Java에서는 해결책이라고 봐야 될듯 합니다. 
아래코드는 SocketChannel이 non-block인 상태를 기준으로, read 메쏘드를 호출했을 경우, 리턴값을 보고 상태를 확인하는 코드입니다.

int  readbytes = socketChannel.read(buf);

// 연결이 되어 있음..
if(readbytes == 0)
// 끊어졌네요.
if (readbytes == -1)
// 리시브된 데이타가 있네요..
if(readbytes >0)

소켓 풀링을 관리하는 매니저 클래스가 풀에 들어있는 소켓의 read 이벤트를 주기적으로 호출해보면, socket의 연결상태를 잘 유지할 수 있을 것입니다. ^^
보통 객체에 대한 고유값으로 hashCode() 메쏘드를 많이 사용하는데요.....
hashCode()는 Override가 가능하기 때문에, 고유값이 아닐경우가 잠재적으로 존재하게 됩니다.
그런 문제상황(?)을 해결할 수 있도록 System.identityHashCode(Object x)라는 메쏘드가 존재하고 있네요..

기존의 아래와 같은 방식을..
System.out.println(aa.hashCode());


이렇게 바꿔야 겠네요.. ^^
  System.out.println(System.identityHashCode(aa));
     System.out.println(System.identityHashCode(null)); <-- null일경우는 0이네요.. ^^

     

자바 메모리 구조

from Java 2010/01/27 18:04

MemoryUsage 클래스를 통해서 메모리에 대한 정보를 모니터링 해보면 아래의 결과를 볼수 있습니다.

USAGE(Code Cache) init = 163840(160K) used = 535168(522K) committed = 557056(544K) max = 33554432(32768K)
USAGE(Eden Space) init = 917504(896K) used = 807560(788K) committed = 917504(896K) max = 4194304(4096K)
USAGE(Survivor Space) init = 65536(64K) used = 0(0K) committed = 65536(64K) max = 458752(448K)
USAGE(Tenured Gen) init = 4194304(4096K) used = 0(0K) committed = 4194304(4096K) max = 61997056(60544K)
USAGE(Perm Gen) init = 12582912(12288K) used = 699408(683K) committed = 12582912(12288K) max = 67108864(65536K)
USAGE(Perm Gen [shared-ro]) init = 8388608(8192K) used = 5344032(5218K) committed = 8388608(8192K) max = 8388608(8192K)
USAGE(Perm Gen [shared-rw]) init = 12582912(12288K) used = 6771000(6612K) committed = 12582912(12288K) max = 12582912(12288K)



위 내용을 보면, 대략 7개의 메모리 영역이 있네요.. 메모리 영역에 대해서 찾아보니... 어느 성능관련 엔지니어님의 블로그에 아래와 같은 설명이 있네요. ^^ 

Code Cache: contains memory used for compilation and storage of native code
Eden Space: pool from which memory is initially allocated for most objects
Survivor Space: pool containing objects that have survived Eden space garbage collection
Tenured Gen: pool containing long-lived objects
Perm Gen: contains reflective data of the JVM itself, including class and memory objects
Perm Gen [shared-ro]: read-only reflective data
Perm Gen [shared-rw]: read-write reflective data



 

// second
long second = TimeUnit.SECONDS.convert(nanoSeconds, TimeUnit.NANOSECONDS);
// millisecond
long second = TimeUnit.MILLISECONDS.convert(nanoSeconds, TimeUnit.NANOSECONDS);

며칠전에 사석에서 상사분이 Tomcat은 IIS에 비해서 connection을 적게 받고, 그로 인해서 성능이 떨어진다고 말씀을 하시네요.. ^^;; 서비스의 전체적인 성능 문제가 Java 및 Tomcat에 기인을 하고 있다고 생각을 하는것 같아서.. 같은 개발자 입장에서 타 분야에 대한 경험으로 얘기하는게 아니라 말 그대로 선입견(Overlapped I/O의 성능만 말씀하시네 ^^;;)으로 얘기를 하는 듯한 느낌이었습니다.
 
서비스의 성능저하는 Tomcat이나 IIS보다는 그 위에 올라가는 어플이 더 성능에 영향을 미칠텐데 말입니다. ^^;;
그래서 IIS 기반의 ASP.NET 서비스들이 주로 사용하는 DataSet에 대해서 Serialize 데이타에 대해서 살펴보았습니다. 비교는 단순하게 Java , C# Object, C# DataSet으로 10개의 리스트를 가지는 모델을 가지고 하였습니다.

아래의 코드로 Java에서의 Object Array, C#에서의 Object Array, C#에서의 DataSet의 Serialize된 객체의 사이즈를 알수 있겠습니다. 단순하게 Serialize하는 속도 및 Deserialize하는 속도는 같다고 가정을 합니다.

* Java
SerializeModel.java

import java.util.ArrayList;
import java.io.Serializable;

public class SerializeModel implements Serializable {
 private static final long serialVersionUID = -7168303693593724718L;
 private int count = 0;
 private String name = null;
 private String address = null;
 private ArrayList<SerializeModel> models = new ArrayList<SerializeModel>();
 
 public SerializeModel(int count, String name, String address) {
  this.count = count;
  this.name = name;
  this.address = address;
 }

 public void addModel(SerializeModel model) {
  this.models.add(model);
 }
}



SerializeTest.java

import java.io.FileOutputStream;
import java.io.ObjectOutputStream;

public class SerializeTest {
 
 public static void main(String[] args) throws Exception {
  ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("java.ser"));
  
  SerializeModel model = new SerializeModel(0, "a", "b");
  
  for(int i=0; i<10; i++) {
   model.addModel(new SerializeModel(i, i +" name", i +" address"));
  }
  
  out.writeObject(model);
  out.flush();
  out.close();
 }
}



* C#

SerializeModel.cs

using System;
using System.IO;
using System.Runtime.Serialization;
using System.Collections;
using System.Collections.Generic;

namespace SerialzieTest
{
    [Serializable()]
    class SerializeModel
    {
     private int count = 0;
     private String name = null;
     private String address = null;
     private ArrayList models = new ArrayList();
     
     public SerializeModel(int count, String name, String address) {
      this.count = count;
      this.name = name;
      this.address = address;
     }

     public void AddModel(SerializeModel model) {
      this.models.Add(model);
     }
    }
}



SerializeModelDataSet.cs

using System;
using System.Data;
using System.Collections.Generic;
using System.Text;

namespace SerialzieTest
{
    [Serializable]
    class SerializeModelDataSet
    {
        private DataSet dataSet = new DataSet();
        public void AddDataTable(DataTable table) {
            this.dataSet.Tables.Add(table);
        }

        public DataSet GetDataSet()
        {
            return this.dataSet;
        }
    }
}



Program.cs

using System;
using System.Data;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;

namespace SerialzieTest
{
    class Program
    {
        static void SerializeObjectArray()
        {
            Stream stream = File.Open("csharp.ser", FileMode.Create);
            BinaryFormatter bformat = new BinaryFormatter();

            SerializeModel model = new SerializeModel(0, "a", "b");
            for (int i = 0; i < 10; i++)
            {
                model.AddModel(new SerializeModel(i, i + " name", i + " address"));
            }
            bformat.Serialize(stream, model);
            stream.Flush();
            stream.Close();
        }

        static void SerializeDataSet()
        {
            Stream stream = File.Open("csharp_dataset.ser", FileMode.Create);
            BinaryFormatter bformat = new BinaryFormatter();
            SerializeModelDataSet model = new SerializeModelDataSet();

            DataTable table = new DataTable();
            DataColumn itemCount = new DataColumn("count", Type.GetType("System.Int32"));
            DataColumn itemName = new DataColumn("name", Type.GetType("System.String"));
            DataColumn itemAddress = new DataColumn("address", Type.GetType("System.String"));

            table.Columns.Add(itemCount);
            table.Columns.Add(itemName);
            table.Columns.Add(itemAddress);

            DataRow row;

            for (int i = 0; i < 10; i++)
            {
                row = table.NewRow();
                row["count"] = i;
                row["name"] = i + " name";
                row["address"] = i + " address";
                table.Rows.Add(row);
            }
            model.AddDataTable(table);
            bformat.Serialize(stream, model);
            stream.Flush();
            stream.Close();
        }

        static void Main(string[] args)
        {
            SerializeObjectArray();
            SerializeDataSet();
        }
    }
}




위의 코드를 통해서 저장한 Object의 사이즈는 아래와 같습니다.

Java(Object ArrayList) : 665 byte
C#(Object ArrayList) : 1035 byte
C#(DataSet) : 3000 byte

네트웍을 통해서 전송되는 Data의 크기는 성능에 중요한 영향을 미치지요..
실제로 성능을 높이기 위해서 Socket Buffer의 사이즈를 적당히 줄이는 것도 팁으로 나와 있구요..

위 상황에서 C#의 DataSet은 더욱 멋진 모습을 보여줍니다.
아래의 화면처럼 말이죠.. 아래의 화면은 Hex Viewer로 본 화면입니다.


Object의 Serialize는 C#이 version, locale 및 가비지(?) 데이타로 인해서 좀 더 크게 나옵니다.
그리고, 중간의 DataSet은 Serialize된 내용에 xml의 형태로 저장을 하고 있네요.. 결국 DataSet이 데이타로 네트웍을 통해서 전송이 되면, 사이즈보다는 Serialize/Deserialize할때의 String연산(XML 데이타 리드)이 성능저하의 주범이 되지 않을까요? 결국, Tomcat, IIS가 중요한게 아니라 C#에서 널리 쓰이는 DataSet을 많이 사용하고 있는 IIS기반의 ASP.NET 어플들의 서비스가 더 성능이 안 좋을 거라는 생각이 드네요... ^^;;;;

Exception StackTrace to a String

from Java 2009/11/24 11:15

Exception이 발생하게 되면 Call Stack에 대한 내용을 저장을 해야 디버깅을 할 수 있다.. 

구글링을 하다보니, Save Exception StackTrace to a String 에서 Exception을 String으로 변환하는 쉬운 예를 보여주고 있네요. 

몇개의 예가 있긴 한데, 아래의 코드가 간결하고 좋네요.. ^^

public static String getException(Exception e )
{
StringWriter w = new StringWriter();
e.printStackTrace(new PrintWriter(w));
return w.toString();
}
Tag // exception, java
java.util.Timer를 Logging 라이브러리에서 사용을 하다보니, Logging라이브러리를 사용하고 있는 로깅서버에서 addShutdownHook() 메쏘드를 통해서 등록된 쓰레드가 실행이 안 된다.. ^^;;

Java API 문서를 보면, 아래와 같은 내용이 있습니다.
Timer 객체의 마지막 라이브 참조가 종료해, 미처리의 태스크가 모두 실행되면, 타이머의 태스크 실행 thread도 동시에 완료해, 가비지 컬렉트됩니다. 다만, 이것에는 한없고 긴 시간이 걸리는 경우가 있습니다. 디폴트에서는 태스크의 실행 thread는 「demon thread」로서는 실행되지 않기 때문에 어플리케이션이 종료하지 않게 할 수 있습니다. 타이머의 태스크 실행 thread를 즉시 완료시키는 경우, 호출측은 타이머의 cancel 메서드를 호출할 필요가 있습니다.
흠... 그렇군요.. 종료가 안되더군요... ^^;;
그래서, Timer() 대신 daemon으로 Timer객체를 생성하면, addShutdownHook() 메쏘드에 등록된 쓰레드의 run() 메쏘드가 잘 동작하더군요.. ^^;;

Timer ()
          새로운 타이머를 작성합니다.

Timer (boolean isDaemon)
          demon로서 실행되도록 지정할 수 있는 관련 thread를 가지는 새로운 타이머가 작성됩니다.