본문 바로가기

코딩 내공 Project/IO&NIO 네트워크

[NIO] 향상된 서버 부분 정리



1. 버퍼를 사용할 때
: 버퍼를 null로 만들어서 카비지 커렉션 대상으로 하는것은 느려지는 원인
그러므로 ByteBufferPoll을 사용하여 메모리를 재사용하고 매번 ByteBuffer 객체를 생성, 해제에 따른 가비지 생성 부담이 줄어든다

2. 비효율적인 데이터 전송
: 클라이언트가 100byte를 보냈는데 그중 1byte만 먼저 서버에 도착했을때,
ⓐ 읽기 준비가 되었다고 셀렉션키의 레디키에 표시
ⓑ select()가 호출되고 isAcceptable(), isReadable() 이 호출
ⓒ read로 1byte를 읽고 다시 1번부터 반복한다.
: 읽기의 경우 무조건 read() 메소드를 두번 호출
 //데이터의 일부만 전송되었을 수도 있으므로 두번 read 한다.
   for (int i = 0; i < 2; i++) {
    sc.read(buffer);
   }

  쓰기의 경우 compact()또는 hasRemaining() 사용하여 아직 버퍼의 내용을 다 보내지 못한경우 곧바로 다시 전송
 Iterator iter = ChattingRoom.getInstance().iterator();
   while (iter.hasNext()) {
    SocketChannel member = (SocketChannel) iter.next();
    if (member != null && member.isConnected()) {
     //데이터 전송이 일부만 되었을 수 있으므로 버퍼를 확인해서 모두 보낸다
     while (buffer.hasRemaining()) {
      member.write(buffer);
     }
     //position 초기화
     buffer.rewind();
    }
   }

3. 동시성을 이용한 성능 극대화
  서버의 효율적인 측면을 강화하기 위해서는 쓰레드를 어떻게 활용하느냐가 중요하다
ⓐ Accept, Process 분리
- accept()는 상당히 느린 작업이다. 한명과의 접속이 0.01초라면 동시에 만명이 접속했을때 마지막사람은 1분30초가 걸린다
- accept 에 해당하는 부분은 별도의 스레드로 셀렉터로 분리시켜서 클라이언트의 접속을 전담하게 한다
- 나머지 이벤트 Connect, Read, Write 도 각각 별도의 처리 로직으로 분리하는 것이 대용량 서버에 유리하다

ⓑ SelectorPool 사용
- 셀렉터 하나에 동시접속자가 만 명일때, 관리할 채널이 너무 많아 비효율 적이다
- Read 를 수행하는 셀렉터 n개로 만들어서 사용하는 것이 효과적이다

ⓒ ThreadPool 사용
- Accept를 처리하는 것과 Processe를 처리하는 것으로 나눠서 별도의 독립적인 쓰레드풀로 운영하는것이 좋다
- 병목지점을 파악했을때 그쪽의 스레드 개수를 늘려주면 된다

'코딩 내공 Project > IO&NIO 네트워크' 카테고리의 다른 글

IO 클래스  (0) 2011.08.09
[NIO] 셀렉터 부분 정리  (0) 2011.05.08
[NIO] Chanel 부분 정리  (0) 2011.05.07
[NIO] Buffer 부분 정리  (0) 2011.05.05
생성자 - 소비자  (0) 2011.03.16