BLOG ARTICLE Java Ping | 1 ARTICLE FOUND

  1. 2009/04/15 BMT 단골 등장 메뉴 - 랜선 뽑기 및 해결책 (3)

저 같은 경우 role이 pre-sales였기 때문에 지금까지 정말 많은 BMT(Bench Mark Test)를 진행했습니다. 처음일 때는 모듈을 담당하는 엔지니어로 참여를 시작했었고, 시간이 흐르면서 전체 BMT를 코디네이션하는 BMT PM까지 세기도 힘들 정도로 BMT에 참여를 많이 했습니다.

국내의 경우 외국처럼 돈을 주고 BMT를 한다거나 하는 경우는 거의 없습니다.
"개선되어야 할 BMT 문화"에도 글을 적었지만 엔지니어를 고용한다는 것은 비싼 비용을 치르게 되는 원인이 되니 기업들은 어떻게든 벤더를 꼬득여서 공짜 BMT를 치르려고만 합니다. 말을 시작하면 한도 끝도 없겠지요.

부하 테스트는 애플리케이션을 초짜처럼 짜지 않는 이상은 Web Application Server는 별 무리없이 돌아가는 것이 일반적입니다. Memory leak이 난다거나 CPU 점유율이 높고 hang이 걸린다거나 하는 것들은 금새 찾아낼 수 있습니다. 실제 운영기에서 저러한 문제가 발생을 했다면 사전에 면밀한 검증, 테스트도 안하고 운영한 고객도 일부 원인 제공자가 될 수 있습니다.

위의 케이스도 장애의 한 종류이다보니 BMT를 하게 되었을 때 장애테스트를 상당히 중요시합니다. 갑자기 전원이 끊겼다던지, 네트워크 장애가 발생했다던지 했을 경우에 대처하는 방법에 대한 것입니다.

다음과 같은 것들이 단골 메뉴입니다.
1. 부하 도중 DB Shutdown
2. DB reboot 후 장애 복구 및 응답속도 회복에 걸리는 시간
3. RAC로 구성된 DB중 하나의 랜선을 뽑기
4. 1억건의 데이터 중 몇 건의 오류 데이터를 걸러내기
5. 클러스터된 WAS 노드를 하나씩 shutdown 시킨 후 재기동 했을 때 TPS 원상 복구 여부 확인

위의 것들 말고도 아주 지랄(?)같은 요건들이 많이 있습니다. 지금 논의할 사항은 DB의 랜선을 뽑았을 경우 어떻게 대처할 수 있느냐입니다. 데이터베이스 풀을 만들어 연결을 250개 만들고 부하를 주는 상태에서 랜선을 뽑게 되면 어떤 일이 일어날까요? 누구는 뭐 그런 일이 일어나겠어라고 생각하겠지만 살다보면 별별 사건이 있으니 안 일어난다는 보장도 없겠지요.

실제 결과를 살펴보면 랜선을 뽑았을 경우 양쪽의 상태를 netstat로 봤을 때 250의 TCP 세션이 "ESTABLISHED" 상태로 5일을 가게 되어 있습니다(Linux default 설정). 다시 꽂으면 통신이 또 잘됩니다. 자바 애플리케이션에서 소켓풀을 사용하여 위의 짓거리(?)를 하게 되면 Exception발생이 안되어 데몬 프로그램을 바보로 만드니 그 프로그램을 만든 여러분은 당황하실게 분명합니다.

WebLogic이나 JBoss 같은 경우 "Test on reserved connection"과 ValidConnectionChecker같은 클래스를 제공하고 있지만 이는 드라이버 내에서 연결된 커넥션에 DB 인스턴스로 ping을 날리니 역시 랜선을 뽑아도 감지 못할게 분명합니다.

Connection이 valid한지 검사하는 방법은 현재의 pool에 있는 connection을 얻어와 다음과 같은 코드를 통해 이루어지는 데 앞서 말씀드린 것처럼 아무런 응답도 못받게 되는 현상이 발생합니다.

public SQLException isValidConnection(Connection c)
   {
      //if there is a ping method then use it, otherwise just use a 'SELECT 1' statement
      if (driverHasPingMethod)
      {
         try
         {
            ping.invoke(c, params);
         }
         catch (Exception e)
         {
            if (e instanceof SQLException)
            {
               return (SQLException) e;
            }
            else
            {
               log.warn("Unexpected error in ping", e);
               return new SQLException("ping failed: " + e.toString());
            }
         }
      }


기존의 무식한 방법은 Socket을 열고 address, port를 준뒤 connect 메소드에 timeout을 주는 방법을 택해야만 했습니다. 이런 방식으로 만약 mysql같이 3306번 port로 요청을 날리면 mysql은 왜 접속해놓고 데이터를 안주냐며 auto_flush 모드를 세팅하라고 성질을 냅니다.

이를 극복하기 위해서는 소위 ping(ICMP protocol)을 주기적으로 체크하는 방법이 필요합니다. JDK1.5부터 이러한 요구사항을 받아들여 JNI를 이용한 ICMP packet을 보내 대상 서버의 상태를 체크하도록 합니다.
 

int timeOut = 500; // I recommend 3 seconds at least
  boolean status = false;
  try {
   status = InetAddress.getByName(host).isReachable(timeOut);
   if( !status ) {
    throw new SocketException("Can' connect to " + host);
   }
   return status;
  } catch (UnknownHostException e) {
   throw new SocketException(e.getMessage());
  } catch (IOException e) {
   throw new SocketException(e.getMessage());
  }


위의 코드를 ThreadExecutor로 background 실행시켜 서버측의 문제점을 확인하고 만약 문제가 발생하면 필요한 데몬 작업을 수행하도록 함으로써 서버측의 장애에 한 단계 더 대비하도록 설계할 수 있습니다.

크리에이티브 커먼즈 라이센스
Creative Commons License
2009/04/15 09:52 2009/04/15 09:52