2013년 12월 19일 목요일

HP 커널 파라메터 확인

ndd -get /dev/udp '?'
ndd -get /dev/tcp  '?'

ndd -get /dev/udp udp_status 하면 udp_status 설정값을 알수 있음


출처 : http://blog.naver.com/PostView.nhn?blogId=leekh8412&logNo=100157984266

네트워크 bandwidth 측정툴

Coherence * Web 을 사용하기로 했는데 자꾸 캐시서버와 WAS 간 성능 저하가 발생해서, 벤더사에서 제공하는 datagram-test.sh 구동 결과 0.5 (50%) success rate 발생!

네트워크 담당자는 네트워크에는 이상이 없다고 하고 , 특정 OS 에서만 발생하는 등 여러가지 복합적 문제가 발생중이다.

답답해서 오픈소스 네트워크 bandwidth 측정툴 검색


 iPerf (Win. Solaris, Linux.. )
   * http://blog.pages.kr/991
   * http://sourceforge.net/project/iperf
   * iperf3 : http://code.google.com/p/iperf/

 netperf (HP-UX)
   * http://hpux.connect.org.uk/hppd/hpux/Networking/Admin/netperf-2.6.0/

현재 환경에서는....네트워크 측정을 한다고 해도..이게 서버의 네트워크 파라메터 관련인지, 정말 bandwidth 가 부족한건지 알길이 없을듯 ......


2013년 11월 21일 목요일

[펌] OOME 정리

OOME 정리가 깔끔하게 되어있는 사이트 발견
---
원글 : http://ukja.tistory.com/61

OOME 개요

JVM이 일정한 크기의 메모리를 할당하는데 실패하면 Out Of Memory Error, 이른바 OOME가 발생한다.
OOME의 발생 원인은 매우 다양하며, 이는 JVM이 사용하는 메모리 공간의 다양성에 기인한다. 대부분의 JVM은그 사용 용도에 따라 메모리를 몇가지 종류로 구분해서 사용한다. 가령 Sun HotSpot JVM은 다음과 같은 세 가지 종류의메모리 공간을 사용한다.((참고) 통상적으로 Permanent Space는 Java Heap의 하위 영역으로 설명된다. 하지만 본 문서에서는 Java Heap = Young Generation + Old Generation으로 간주한다)

  1. Java Heap: 사용자가 생성하는 Java Object들이 거주하는 공간이다. -Xms와 -Xmx Option에 의해 크기가 결정된다.
  2. Permanent Space: Class에 대한 메타 정보를 저장하는 공간이다. -XX:PermSize=와 -XX:MaxPermSize= Option에 의해 크기가 결정된다.
  3. Native Heap: Java Object가 아닌 Native Object들이 거주하는 공간이다. Native Heap의 크기는 JVM Option으로 지정할 수 없으며, OS 차원에서 결정된다.

각 메모리 공간의 용도와 사용 방식이 틀리기 때문에 OOME또한 매우 다양한 상황에서 발생하게 된다. OOME가 발생하는 정확한 원인을 분석하려면 각 메모리 공간의 특성을 이해하고 그에 맞는 해결책을 모색해야 한다.
(주의) 비록 Java 언어와 JVM이 자동화된 메모리 관리 기능을 제공하지만, 이것이개발자나 관리자가 메모리 관리에 대해 무신경해도 된다는 것을 의미하지 않는다는 사실을 명심하자. Java에서도 잘못된 메모리관리는 여전히 많은 문제를 일으키며, Garbage Collection에 의한 성능저하나 OOME에 의한 Applictaion정지나 System Crash등이 대표적인 예이다.

Java Heap에서의 OOME

Java Heap에서 OOME가 발생하는 경우에는 다음과 같은 에러 메시지가 출력된다.
Exception in thread "main": java.lang.OutOfMemoryError: Java heap space 또는
Exception in thread main: java.lang.OutOfMemoryError: Requested array size exceeds VM limit
전자의 메시지는 Java Heap Space의 부족으로 Object를 생성하지 못하는 경우에 발생한다. 후자의메시지는 Java Heap의 최대 크기보다 큰 Array가 요청되는 경우에 발생한다. 가령 Java Heap의 최대 크기가256M인 상황에서 300M 크기의 Array를 생성하는 경우가 이에 해당한다.
Java Heap에서 OOME가 발생하는 이유는 다음과 같다.
  • Java Heap의 크기가 작은 경우
  • Memory Leak이 발생하는 경우
    • Application Logic에 의한 Memory Leak
    • JDK Bug나 WAS Bug에 의한 Memory Leak
  • finalize 메소드에 의한 Collection 지연

Java Heap의 크기와 OOME

Java Heap의 최대 크기가 Application의 메모리 요구량에 비해 작게 설정된 경우에 OOME가 발생한다.Memory Leak이 발생하지 않는데도 OOME가 발생한다면 Java Heap의 크기가 부족하다고 판단할 수 있다.-Xmx 옵션을 이용해서 Java Heap의 최대 크기를 키워주어야 한다.

Memory Leak과 OOME

Memory Leak이발생하는 경우에는 Java Heap의 크기와 무관하게 OOME가 발생할 수 있다. 아무리 Java Heap의 크기를 크게하더라도 결국 Memory Leak에 의해 Collection되지 않는 Garbage 객체들이 메모리를 다 소진하기 때문이다.Memory Leak은 대부분 잘못된 Application 로직에 의해 발생한다. Object에 대한 참조(Reference)관계가 복잡한 경우 조그마한 실수로 인해 사용되지 않은 Object를 계속해서 참조하게 된다. 이러한 Object들은 비록Application에서는 사용되지 않지만 Garbage Collection에 의해 메모리 해제가 이루어지지 않기 때문에OOME를 유발하게 된다.
JDK Bug나 WAS Bug에 의해서도 Memory Leak이 발생할 수 있다. JDK가 제공하는 라이브러리나WAS가 제공하는 라이브러리에서 로직 오류로 인한 Memory Leak 가능성이 있기 때문이다. ApplicationLogic에서 Memory Leak이 검출되지 않는 경우에는 JDK나 WAS의 Bug를 의심해볼 필요가 있으며 각 Vendor가제공하는 Bug Database를 통해 검색 가능하다.

finalize 메소드에 의한 Collection 지연과 OOME

특정 Class에 finalize 메소드가 정의되어 있는 경우, 이 Class Type의 Object는 GarbageCollection 발생시 즉각적으로 Collection 되지 않는다. 대신 Finalization Queue에 들어간 후Finalizer에 의해 정리가 된다. Finalizer는 Object의 finalize 메소드를 실행한 후 메모리 정리 작업을수행한다. 만일 finalize 메소드를 수행하는데 오랜 시간이 걸린다면 그 만큼 객체가 오랫동안 메모리를 점유하게 된다. 이로인해 OOME가 발생할 확률이 높아진다. 이런 이유 때문에 finalize 메소드는 되도록 사용하지 말아야 한다.

Object Allocation Profiling

Java Heap의 메모리 부족 문제를 정확하게 분석하려면 Object Allocation Profiling을 수행해야한다. 즉, 어떤 Object가 어느 개수만큼 생성되었으며 얼마나 많은 메모리를 차지하는지 분석할 필요가 있다. HProf는 모든 JVM이 표준으로 제공하는 Profiler로, 간단한 Object Allocation Profiling 기능을 제공한다.
 java -Xrunhprof:heap=sites [Main Class] 
또는 다음과 같이 doe(dump on exit) Option을 비활성화해서 시간순으로 Profiling을 수행할 수도 있다.
 java -Xrunhprof:heap=sites,doe=n [Main Class]
 ...
 Control+Break (혹은 다른 Console에서 kill -3 [pid])
Java Process에서 Signal을 보내서 Dump를 생성하는 방법은 Thread Dump를 참조한다.
아래에 HProf를 이용한 Object Allocation Profiling 결과의 간단한 Sample이 있다. 아래 Sample에서는 byte[] 유형의 객체가 20%의 Heap 공간을 사용하는 것을 알 수 있다.
        percent          live          alloc'ed  stack class
rank   self  accum     bytes objs     bytes  objs trace name
   1 20.36% 20.36%    190060   16    190060    16 300000 byte[]
   2 14.92% 35.28%    139260 1059    139260  1059 300000 char[]
   3  5.27% 40.56%     49192   15     49192    15 300055 byte[]
   4  5.26% 45.82%     49112   14     49112    14 300066 byte[]
   5  4.32% 50.14%     40308 1226     40308  1226 300000 java.lang.String
   6  1.62% 51.75%     15092  438     15092   438 300000 java.util.HashMap$Entry
   7  0.79% 52.55%      7392   14      7392    14 300065 byte[]
   8  0.47% 53.01%      4360   16      4360    16 300016 char[]
   9  0.47% 53.48%      4352   34      4352    34 300032 char[]
  10  0.43% 53.90%      3968   32      3968    32 300028 char[]
  11  0.40% 54.30%      3716    8      3716     8 300000 java.util.HashMap$Entry[]
  12  0.40% 54.70%      3708   11      3708    11 300000 int[]

Permanent Space에서의 OOME

Permanent Space에서 OOME가 발생하면 다음과 같은 에러 메시지가 출력된다
Exception in thread "main": java.lang.OutOfMemoryError: Perm Gen space'
Permanent Space는 Class의 메타 정보를 저장하는 공간이다. 따라서 많은 수의 Class를 로딩하는Application의 경우 Permanent Space의 크기가 작으면 OOME가 발생할 수 있다. 다음과 같은 유형의Application들에서는 Permanent Space의 크기를 키워줄 필요가 있다.
  • 매우 많은 수의 JSP 파일을 로딩하는 Web Application. JSP 파일은 Servlet으로 변환된다.하나의 Servlet은 하나의 Java Class에 해당한다. 따라서 이 경우 매우 많은 수의 Class가 로딩된다.
  • ReflectionMechanism을 사용해 동적으로 Class를 로딩하는 Framework. Spring과 같은 현대적인 Framework들은Reflection Meachanism을 통해 동적으로 Class를 생성한다. 이 경우 개발자가 의도하지 않은 많은 수의Class들이 로딩될 수 있다.
이런 문제는 대부분의 Permanent Space의 크기를 키워주면 해결된다.-XX:PermSize=, -XX:MaxPermSize= Option을 이용해Permanent Space의 최소 크기와 최대 크기를 지정할 수 있다.

Class Loading 모니터링

Permanent Space에 Loading되는 Class의 목록을 모니터링함으로써 OOME가 발생하는 원인을 간접적으로 분석할 수 있다. 다음과 같은 방법을 통해 Class Loading을 모니터링할 수 있다.
  • -verbose:gc: Loading되는 Class들을 Standard Out을 통해 출력해준다.
  • Platform MBean: JMX 표준을 통해 제공되는 ClassLoadingMXBean API를 이용하면 프로그래밍적으로 Class Loading 정보를 얻을 수 있다.
  • JConsole: JConsole을 이용하면 Class Loading 정보를 조회할 수 있다. JConsole은 JMX 클라이언트의 표준 샘플로 Platform MBean과 통신해서 Class Loading 정보를 얻는다.
아래에 -verbose:class 옵션에 의한 Class Loading 모니터링의 간단한 Sample이 있다. Open된 jar 파일과 Loading된 Class 목록을 확인할 수 있다.
[Opened c:bea10jdk150_06jrelibrt.jar]
[Opened c:bea10jdk150_06jrelibjsse.jar]
[Opened c:bea10jdk150_06jrelibjce.jar]
[Opened c:bea10jdk150_06jrelibcharsets.jar]
[Loaded java.lang.Object from c:bea10jdk150_06jrelibrt.jar]
[Loaded java.io.Serializable from c:bea10jdk150_06jrelibrt.jar]
[Loaded java.lang.Comparable from c:bea10jdk150_06jrelibrt.jar]
[Loaded java.lang.CharSequence from c:bea10jdk150_06jrelibrt.jar]
[Loaded java.lang.String from c:bea10jdk150_06jrelibrt.jar]
[Loaded java.lang.reflect.GenericDeclaration from c:bea10jdk150_06jrelibrt.jar]
...
(참조) IBM JVM에서는 Thread Dump에서도 Class Loading 정보를 제공한다.

Class Reloading과 OOME

현대적인 대부분의 WAS가 Class Reloading 기능을 제공한다. Class Reloading이란 Runtime에Class가 재생성되면 이를 JVM을 Reboot하지 않고 Reloading하는 기능을 의미한다. 일부 WAS의 경우Class가 Reloading될 때 이전 버전의 Class를 해제하지 않는 경우가 있다. 따라서 Class Reloading이자주 발생하면 Permanent Space가 금방 꽉차게 되고 OOME가 발생하게 된다. 이와 같은 경우에는 WAS가 제공하는버그 패치를 적용하거나 WAS를 주기적으로 Restart해야 한다.

Native Heap에서의 OOME

Java Heap과 Permanent Space가 Java와 관련된 Object들이 거주하는 공간인 반면, NativeHeap은 OS 레벨의 Native Object나 JNI Library 레벨의 Native Object이 거주하는 공간이다.
Native Heap에서 OOME가 발생하면 다음과 같은 에러 메시지가 출력된다.
java.lang.OutOfMemoryError: request bytes for . Out of swap space? 또는
java.lang.OutOfMemoryError: (Native method)' 또는 java.lang.OutOfMemoryError: unable to create new native thread

첫번째 메시지는 VM code 레벨에서 메모리 부족 현상이 발견된 경우이다. 두번째 메시지는 JNI나 Native Method에서 메모리 부족 현상이 발견된 경우에 해당한다. 세번째 메시지는 Thread를 생성할 수 없을 때 발생한다. Thread는Native Heap 공간의 메모리를 필요로 하기 때문에 Native Heap 공간의 메모리가 부족하면 Thread 생성시OOME가 발생한다.
Native Heap에서 메모리 부족이 발생하는 이유는 매우 다양하다.
  • Thread Stack Space가 부족한 경우
  • Virtual Space Address가 소진된 경우
  • Swap Space가 모자란 경우
  • JNI Library에서 Memory Leak이 발생하는 경우

Thread Stack Space와 OOME

Java Thread는 Native Heap 공간에 Stack Trace를 저장할 공간을 필요로 한다. ThreadStack Space의 크기는 -Xss 옵션을 통해 지정된다. -Xss 옵션을 통해지정되는 공간은 개별 Thread가 사용하는 공간이다. 만일 N개의 Thread가 활성화되면 N* 만큼의메모리 공간이 필요하다.
대부분의 OS에서 Thread Stack Size는 512K ~ 1M 사이다. 따라서 많은 수의 Thread가 활성화되면 Thread Stack Space만으로도 큰 크기의 Native Heap 메모리 공간을 소모한다.
Thread Stack Space 문제에 의한 OOME를 해소하는 방법은 다음과 같다.
  • Thread의 수를 줄인다. 동시에 수십개 이상의 Thread를 사용하는 것은 메모리의 문제 뿐만 아니라 지나친 Context Switching으로 인해 성능을 저하시키는 요인이 된다. Thread Pool 기법을 사용해서 동시 Thread의 수를 줄인다. 대부분의 WAS들이 Thread Pool 기법을 사용하고 있다.
  • Thread Stack Size를 줄인다. 대부분의 OS에서 Thread Stack Size는512K ~ 1M이다. 만일 많은 수의 Thread가 필요한 Application이라면 Thread Stack Size를줄임으로써 OOME를 방지할 수 있다. 많은 경우 -Xss128k 정도나 -Xss256k 정도의 크기에서도 문제없이 작동한다.단, Stack Size가 줄어든 만큼 Stack Overflow Error가 발생할 확률은 높아진다.
  • Java Heap 크기를 줄인다. 32bit Process가 사용 가능한 메모리 공간은 OS에따라 2G ~ 4G로 제한된다. 하나의 Java Process가 사용 가능한 공간은 [Java Heap+PermanentSpace+Native Heap]으로 이루어진다. 따라서 Java Heap이 지나치게 큰 공간을 사용하는 경우 NativeHeap에서 사용 가능한 공간이 줄어들게 된다. 따라서 Java Heap 크기를 줄이면 Native Heap의 메모리 부족에의한 OOME 문제를 해결 할 수 있다. 하지마 Java Heap 크기를 지나치게 줄이면 Java Heap 부족에 의한 OOME현상이 발생할 수 있으므로 유의해야 한다. Java Heap 크기를 줄이는 방법은 Thread Stack Space의 부족 문제뿐 아니라 Native Heap 부족에 의한 OOME 문제를 줄이는 공통적인 해결 방법이다.
  • 64bit JVM을 사용한다. 64bit JVM에서는 32bit JVM Process가 가지는2G ~ 4G의 제한이 없다. 따라서 Native Heap의 메모리 부족 문제가 줄어든다. 이 방법 또한 Native heap부족에 의한 OOME 문제를 줄이는 공통적인 해결 방안이다.
64bit JVM을 사용하는 경우, 다음과 같은 사실에 유의해야 한다.
  1. 일반적으로 32bit Application의 성능이 64bit Application에 비해 더 나은 성능을보이는 경우가 많다. 따라서 64bit JVM을 사용하는 경우 약간의 성능 저하가 발생할 수 있다는 사실에 유의해야 한다.
  2. 과도한 Virutal Memory의 사용은 Application의 성능을 저하시키는 주요인이다. JavaApplication의 성능은 모든 Object들이 Physical Memory에 머물러 있을때 가장 뛰어나다. 만일Physical Memory를 초과하는 크기의 Virtual Memory를 사용하면 Physical Memory의 일부를Disk에 저장하는 Paging In/Out이 발생한다. Paging In/Out은 Memory Operation에 비해 매우느리며 그만큼 Application의 성능도 저하된다.

Virtual Address Space와 OOME

32bit JVM에서 사용가능한 Virtual Address Space의 최대 크기는 OS에 따라 2G ~ 4G로제한된다. Java Process의 경우 Java Heap과 Permanent Space를 제외한 나머지 공간만을 NativeHeap이 사용할 수 있다. 가령 2G의 Virtual Address Space만이 사용가능하다고 가정하자. 이 때 JavaHeap이 1G, Permanent Space가 200M를 사용한다면 Native Heap이 사용 가능한 최대 크기는 800M에불과하다. 800M 중에는 OS가 Process 관리를 위해 사용하는 기본 메모리가 포함되기 때문에 실제로 JavaApplication이 사용 가능한 Native Heap의 크기는 훨씬 줄어든다. 따라서 이 경우 Native Heap 공간부족에 의한 OOME가 발생할 확률이 높아진다.
Virtual Address Space 부족에 의한 OOME를 해결하는 방법은 Thread Stack Space에의한 OOME 해결방안과 일맥상통한다. Java Heap 크기를 줄이거나 64bit JVM를 사용한다. Thread 수를줄이거나 Thread Stack Size를 줄임으로써 Native Heap 공간을 확보하는 것도 방법이 될 수 있다.

Swap Sapce와 OOME

Physical Memory를 초과하는 Virtual Memory 요청이 발생하면 Paging In/Out을 통해 필요한 메모리를 확보한다. Paging In/Out을 위한 공간이 Swap 공간이다. 따라서 Swap Space가 부족하면 Paging In/Out에 실패하고 이로 인해 OOME가 발생한다.
여러 개의 Process가 Swap Space를 사용하는 경우 Swap Space 부족에 의한 OOME가 발생할확률이 높아진다. OS가 제공하는 툴들을 통해 Swap Space와 Paging In/Out을 모니터링해야 하며, SwapSpace가 부족한 경우에는 크기를 키워주어야 한다.

OOME와 Fatal Error Log

Native Heap에서 OOME가 발생하면 JVM은 심각한 상황이라고 판단하고 Fatal Error Log를 남긴다. 아래에 OOME가 발생한 상황에서의 Fatal Error Log의 Header 정보에 대한 간단한 Sample이 있다.

#
# An unexpected error has been detected by Java Runtime Environment:
#
# java.lang.OutOfMemoryError: requested 20971520 bytes for GrET in C:BUILD_AREA
jdk6_02hotspotsrcsharevmutilitiesgrowableArray.cpp. Out of swap space?
#
# Internal Error (414C4C4F434154494F4E0E494E4C494E450E4850500017), pid=5840, ti
d=5540
#
# Java VM: Java HotSpot(TM) Client VM (1.6.0_02-b06 mixed mode)
# An error report file with more information is saved as hs_err_pid5840.log
#
# If you would like to submit a bug report, please visit:
# http://java.sun.com/webapps/bugreport/crash.jsp
#

2013년 11월 8일 금요일

IIS 6.0 - 최초 접속시 성능 지연

사이트에서 이상한일이 발생했다.
아침마다 처음 페이지 접속하는 사람이 3~5분동안 hang 상태인것 처럼 페이지가 안열리다가, 그사람이 접속된 이후로 다른사람은 접속이 잘된다는 것이다.

간혹 WAS를 최초 재기동 한 후에 jsp precomplie 설정이 되어 있지 않으면 읽은 jsp 를 처음 컴파일 하느라 느린 현상은 봤었는데, 이 현상은 WAS 를 재기동 하지 않아도 발생했다.

WAS 쪽에는 특이사항이 없어서, 웹서버 aceess 로그를 살펴봤다.

그중 발견한 사항이... 성능 저하가 발생하는 시점에는 access 로그에 다음과 같이 로그 헤더가 생성되는 것이다.


  ---------------------------------------------------------
  #Software: Microsoft Internet Information Services 6.0
  #Version: 1.0
  #Date : ...
  #Field : date time ...
  ----------------------------------------------------------

해당 현상으로 구글링을 해본 결과.....

http://www.microsoft.com/technet/prodtechnol/WindowsServer2003/Library/IIS/23ec8be2-649a-47b7-8d75-ffd937f16fe8.mspx?mfr=true

Logging Headers
In the past, the logging headers that were written to a log file typically indicated the restarting of the Web service. In IIS 6.0 this is not the case. After waiting for 15 minutes for a given site, HTTP.sys stops logging. When the next request for that site arrives, HTTP.sys restarts logging and writes a new set of headers to the log file.

"즉, 요청이 지속적으로 없는 경우 15분마다 HTTP.sys 가 restart 된다."

결과 확인을 위해 웹서버를 재기동 했더니 현상이 재현되었다.
이 사이트는 유저가 몇명 안되서 15분 이상 서버에 request 가 없는 경우 HTTP.sys (뭐하는건진 찾아보시라..) 가 재시작 되면서 성능 저하가 일어나는 것으로 추정된다.

MS 에 문의를 좀 해봐야겠다..

-- 출처 : 본인 작성

2013년 10월 29일 화요일

[펌] The mysterious ORA-03111 error

또 펌글이다..
WAS-DB 간 ora-03111 발생 관련

결론은...
statement 를 DB client 에서 보낸 후 설정된 타임아웃을 초과한경우, Client 에서 DB 로 cancel 요청을 보내는데 (URG TCP msg) 이에따라 ora-01013 이 리턴되지만, 경우에 따라 fetching 된 resultset 이 client 로 전송 중일때는 ora-03111 에러를 발생시킨다.


------------------------------------------------------------------------
http://royontechnology.blogspot.kr/2009/06/mysterious-ora-03111-error.html

The mysterious ORA-03111 error

Recently one of the applications that I developed started throwing exceptions, that had the following message:
SQL state [72000]; error code [1013]; ORA-03111: break received on communication channel
When I googled around, I couldn't come across anything useful. Sadly enough most of the sites just showed the documentation for that error, without any explanation from anyone experiencing that issues. So here you go, with the best possible explanation that I could come up with.

My application sets two things on the connection that is throwing this exception:
  • It sets the fetchSize to be 2500 rows
  • It sets the query timeout to be 10 seconds
The database server and the application are separated over a long latency network (actually there is a NetEm box that emulates the long latency between these two boxes) which has a latency characteristic of 50+/-5 milliseconds. This is the whole setup.

It is important to understand how the timeout is handled by the Oracle client (in my case JDBC client). Once the query is successfully submitted, the client starts a clock for the timeout. Once the timeout is reached, the client sends an URG message to the Oracle server. The moment Oracle server receives this message, it knows that the client wants to cancel the operation that it was carrying on, no matter what stage the operation is in.

So take a couple of cases. Assume the operation is a SELECT query that will result in 10000 rows. If the Oracle server hasn't even started fetching the results, most likely the client's request would be responded immediately with an error code ORA-01013, which has a description like:
SQL state [72000]; error code [1013]; ORA-01013: user requested cancel of current operation
But imagine the server has fetched the rows and in the process of pumping the resultset back to the client. If the client requests the Oracle server to cancel the operation while still there is pending data in the socket to be delivered, it just adds the ORA-03111 packet at the end of the pending packets and lets the client knows that the operation has been cancelled while there is pending data to be delivered.

Look at the tcpdump output below:
23:13:08.613007 IP jdbc_client.48681 > orcle_server.1521: P 2543:3174(631) ack 2342 win 11908
....
23:13:18.635068 IP jdbc_client.48681 > orcle_server.1521: P 3174:3175(1) ack 265693 win 65535 urg 1
....
23:13:20.472561 IP orcle_server.1521 > jdbc_client.48681: P 398520:398615(95) ack 3186 win 65535
0x0000: 0015 c5ec 12a8 0021 1c1d c0c3 0800 4500 .......!......E.
0x0010: 0087 5023 0000 3406 bad6 c0a8 fd9a c0a8 ..P#..4.........
0x0020: fc8b 05f1 be29 a792 459f a091 06cc 5018 .....)..E.....P.
0x0030: ffff 67c2 0000 005f 0000 0600 0000 0000 ..g...._........
0x0040: 0402 04e3 0203 f500 0001 0300 0300 0000 ................
0x0050: 0000 0000 0000 0000 0000 0001 0100 0000 ................
0x0060: 0033 4f52 412d 3033 3131 313a 2062 7265 .3ORA-03111:.bre
0x0070: 616b 2072 6563 6569 7665 6420 6f6e 2063 ak.received.on.c
0x0080: 6f6d 6d75 6e69 6361 7469 6f6e 2063 6861 ommunication.cha
0x0090: 6e6e 656c 0a nnel.

Pay special attention to the times when the SELECT query was sent (21:13:08) and when the cancel request as an URG packet was sent (21:13:18), and when the Oracle sends the last TNS packet that has the error code ORA-03111 (21:13:20).

The cancel request as an URG packet was sent after 10 seconds because as I mentioned earlier my query timeout is 10 seconds.

So now the million dollar question: What should I do if I am facing this issue in my application?

Follow these simple steps:
  • First make sure that your query can be completed within the timeout that you have specified. If you consistently face this exception, try increasing your timeout.
  • That might help to get rid of the exception, but not the root cause. The root cause usually is a database that is not optimized for the query that you are executing or a bad network.
  • To find out if its the database that is the issue, try executing the same query in a host closer to the network. Or try executing the same query hitting the database from a different network. If you are convinced the database is the issue, try to tune it.
  • To find if it is the network that is having the issue, try to do a tcpdump and analyze if there are any out of order deliver of packets. Or dropped packets. If yes, then try to fix the network.
In my case, it turned out to be the bad configuration in the NetEm that was causing too many packets to be delivered out of order and too many duplicated packets. Remember I was introducing a variance of 10 ms (i.e. my packets could be delayed anywhere from 45 ms to 55 ms, as per my configuration). In real cases, at least in a well maintained production network, the variance will not be more than 1 ms.

Since I am not an expert in Oracle, I would be happy if anyone reading this blog entry has something to add on top of what I have told here. And I sincerely believe that this posting would help whoever is facing this issue.

[펌] JDBC Internal - 타임아웃의 이해

요새는 펌글만 싣는거 같다..
공부좀 하자 .ㅎ_ㅎ

네*버 helloworld 에는 유용한 글들이 많은거 같다.
운영하는 사이트에 JDBC timeout 이 자꾸 이슈가 되어 찾은 글중 좋은게 있어 퍼나름..

---------------
원글: http://helloworld.naver.com/helloworld/1321

JDBC Internal - 타임아웃의 이해 개발자Tip


NHN Business Platform 웹플랫폼개발랩 강운덕
성능 문제나 장애가 발생할 때 중요하게 살펴보는 부분(tier)은 WAS(Web Application Server)와 DBMS입니다. 대부분의 경우에 WAS를 담당하는 조직과 DBMS를 담당하는 조직이 달라, 각자 담당 분야를 중심으로 상황을 파악하려 합니다. 이때 상대적으로 관심을 못 받는 사각지대가 생기는데, 바로 WAS와 DBMS 사이입니다. Java 애플리케이션을 기준으로 말하면 DBCP와 JDBC입니다. 이 글에서는 JDBC의 타임아웃 설정을 중심으로 장애에 대응하는 방법을 설명하겠습니다.
  • 어느 날 DDoS 공격, 그 뒤로 먹통이 된 WAS

    다음과 같은 사고가 일어났다고 가정해 보자.
    DDoS 공격으로 서비스 전체가 정상적으로 동작하지 않았다. L4가 정상으로 동작하지 않아 네트워크가 단절되었고, 이로 인해 WAS도 동작 불능 상태에 빠졌다. 이후 보안팀에서는 DDoS 공격을 전부 차단했고, 네트워크도 정상으로 복구되었다. 그러나 WAS는 여전히 동작 불능 상태이다.
    서비스팀에서는 WAS의 ThreadDump를 통해 JDBC의 API 호출 중에 WAS가 정지해 있음을 확인했다. 10분이 지나고 20분이 지나도 WAS는 여전히 정지 상태(WAITING)였고, 서비스는 정상으로 동작하지 않았다. 그런데 30분이 지날 무렵 갑자기 Exception을 발생시키면서 서비스가 복구되었다.
    QueryTimeout 값도 3초로 설정되어 있는데 왜 30분씩이나 WAS가 정지 상태에 있었으며, 30분이 지나니 왜 정상적으로 WAS가 동작했던 것일까?
    정답은 JDBC의 타임아웃 과정을 이해하면 알 수 있다.
  • 왜 JDBC 드라이버에 대해서 알아야 하는가?

    JDBC는 DBMS에 접근하기 위한 표준 API이다. Sun은 4가지 타입의 드라이브를 정의하는데, NHN에서 주로 사용하는 것은 Type4 형식이다. JDBC Type4 드라이버는 Java로만 작성되어 있으며(pure java), Java 애플리케이션에서 소켓을 이용해 DBMS와 통신한다.
    122111_0935_JDBCInterna1.png
    그림 1 JDBC Type4 드라이버의 DBMS 통신 구조
    Type4 드라이버는 소켓을 통해 바이트 스트림(byte stream)을 처리하기 때문에 HttpClient 같은 네트워크 라이브러리와 근본적으로 동작이 같다. 즉, 많은 CPU자원을 소모하고, ResponseTime의 손해가 있으며, 다른 네트워크 라이브러리가 가지고 있는 장애 포인트를 동일하게 가지고 있다. HttpClient를 사용한 경험이 있다면 타임아웃 값을 제대로 설정하지 않아 장애(hang)가 발생한 상황을 겪어 보았을 것이다. Type4 드라이버 역시 SocketTimeout 값을 제대로 설정하지 않으면 동일한 장애가 발생할 수 있다.
    JDBC 드라이버의 SocketTimeout 값을 어떻게 설정하면 좋을지, 그리고 무엇을 고려해야 히는지 알아보자.
  • WAS와 DBMS의 통신 시 타임아웃 계층

    그림 2는 WAS와 DBMS와 통신 시 타임아웃 계층을 단순화한 것이다.
    122111_0935_JDBCInterna2.png
    그림 2 타임아웃 계층
    상위 레벨의 타임아웃은 하위 레벨의 타임아웃에 의존성을 가지고 있다. 하위 레벨의 타임아웃이 정상으로 동작해야 상위 레벨의 타임아웃도 정상으로 동작한다. 예를 들어, JDBC Driver SocketTimeout이 정상으로 동작하지 않으면, 그보다 상위 레벨의 타임아웃인 StatementTimeout과 TransactionTimeout도 정상으로 동작하지 않는다.
    "StatementTimeout을 설정했는데도 네트워크 장애가 발생했을 때, StatementTimeout이 동작하지 않아 애플리케이션이 장애 상황에서 회복되지 않았어요"란 문의를 많이 받았다. StatementTimeout은 네트워크 연결 장애에 대한 타임아웃을 담당하는 것이 아니다. StatementTimeout은 Statement 한 개의 수행 시간을 제한하는 기능만 담당한다. 네트워크 장애에 대비하는 타임아웃은 JDBC Driver SoecketTimeout이 처리해야 한다.
    JDBC Driver SocketTimeout은 OS의 SocketTimeout 설정에 영향을 받는다. JDBC Driver SocketTimeout을 설정하지 않아도 네트워크 장애 발생 이후 30분이 지나면 JDBC Connection Hang이 복구되는 것은 OS의 SocketTimeout 설정때문이다.
    그림 2에서 DBCP Connection Pool이 타임아웃 계층과 분리되어 왼쪽에 있는 것을 볼 수 있다. DBCP는 Connection을 생성하고 관리하는 일을 하며, 타임아웃 처리에는 관여하지 않는다. DBCP 내부에서 Connection을 생성하거나 Connection 유효성을 확인하려 Validation Query를 보낼 때에는 SocketTimeout이 영향을 주지만 애플리케이션에 직접적인 영향을 주지는 않는다.
    단, 애플리케이션 로직에서 DBCP에 getConnection() 메서드를 호출할 때 Connection을 애플리케이션이 얻을 때까지의 타임아웃을 지정할 수 있다. 하지만 이것은 JDBC의 ConnectTimeout과는 무관하다.
    122111_0935_JDBCInterna3.png
    그림 3 각 레벨 별 타임아웃
  • TransactionTimeout이란?

    TransactionTimeout은 프레임워크(Spring, EJB Container)나 애플리케이션 레벨에서 유효한 타임아웃이다.
    TransactionTimeout은 생소한 개념일 수 있다. 간단히 설명하면 "StatementTimeout x N(Statement 수행 수) + α(가비지 컬렉션 및 기타)"라고 할 수 있다. 전체 Statement 수행 시간을 허용할 수 있는 최대 시간 이내로 제한하려 할 때 TransactionTimeout을 사용한다.
    가령 Statement 한 개를 수행할 때 0.1초가 필요하다면, 몇 개 안 되는 Statement를 수행할 때에는 문제가 없다. 그러나 Statement 10만 개를 수행할 때에는 일만 초(약 7시간)가 필요하다. TransactionTimeout은 이런 경우에 사용할 수 있다.
    실 구현체로 EJB CMT(Container Managed Transaction)가 가장 대표적인 예이다. EJB CMT는 제작사마다 구현 방식과 동작 과정이 다르다. NHN에서는 EJB Container를 사용하지 않으므로, 가장 익숙한 예는 Spring의 TransactionTimeout이 될 수 있겠다. Spring에서는 다음과 같이 XML을 이용하여 설정하거나, Java 코드에서 @Transactional을 이용하여 타임아웃을 설정할 수 있다.
    ?
    1
    2
    3
    <tx:attributes>
    <tx:method name="…" timeout="3">
    </tx:method></tx:attributes>
    Spring에서 제공하는 TransactionTimeout은 매우 단순하다. 해당 Transaction의 시작 시간과 경과 시간을 기록하면서, 특정 이벤트 발생 시 경과 시간을 확인하여 타임아웃 이상일 경우 예외(Exception)를 발생하도록 하고 있다.
    Spring에는 Transaction Synchronization방식이라고 하여 Connection을 ThreadLocal에저장해 두고 사용한다. ThreadLocal에 Connection 저장 시 Transaction의 시작 시간과 타임아웃 시간을 같이 기록하고, Proxy Connection을 사용하여 Statement를 생성하는 작업을 시도할 경우 경과 시간을 체크하여 예외를 발생시키도록 구현되어있다.
    EJB CMT 구현 방식 또한 크게 다르지 않다. 만약 TransactionTimeout이 매우 중요하고 사용하는 컨테이너나 프레임워크에서 이런 기능을 제공하지 않는다면 직접 구현해서 사용해도 별 무리가 없을 정도로 매우 단순한 구조이다. TransactionTimeout에 대한 표준 API는 없다.
    수행 시간이 200ms인 Statement가 5개 이하이고 기타 부수적인 비즈니스 로직 처리 시간이나 프레임워크 동작 시간이 100ms일 경우, TrasactionTimeout시간은 1100ms((200 x 5)+100) 이상으로 설정해야 한다.
  • StatementTimeout 이란?

    Statement 하나가 얼마나 오래 수행되어도 괜찮은지에 대한 한계 값이다. JDBC API인 Statement에 타임아웃 값을 설정하며, 이 값을 바탕으로 JDBC 드라이버가 StatementTimeout을 처리한다. JDBC API인 java.sql.Statement.setQueryTimeout(int timeout) 메서드로 설정한다.
    요즘 개발 환경에서는 개발자가 직접 StatementTimeout을 Java 코드로 설정하는 경우는 드물며, 프레임워크를 이용하여 해결하는 경우가 많다. iBatis를 예로 들어 설명하자면 "sql-map-config.xml" 파일의 sqlMapConfig/settings에 @defaultStatementTimeout 값으로 기본값을 설정할 수 있다. 또한 "sql-map.xml" 파일의 statement, select, insert, update 구문마다 @timeout 값으로 개별적으로 설정할 수 있다.
    StatementTimeout 시간은 애플리케이션 특성에 따라 지정하기 때문에 이에 대한 설정 권장 값은 없다.
  • JDBC 드라이버의 StatementTimeout 동작 방식

    StatementTimeout의 동작방식은 DBMS나 드라이버별로 다르다.
    Oracle과 Microsoft SQL Server의 동작 방식이 서로 비슷하고, MySQL과 CUBRID의 동작 방식이 서로 비슷하다.
  • Oracle JDBC Statement의 QueryTimeout

    122111_0935_JDBCInterna4.png
    그림 4 Oracle JDBC Statement의 QueryTimeout 동작 과정
    Oracle JDBC Statement의 QueryTimeout은 다음과 같은 과정으로 동작한다.
  • Connection.createStatement() 메서드를 호출하여 Statement를 생성한다.
  • Statement.executeQuery() 메서드를 호출한다.
  • Statement는 자신의 Connection을 사용하여 Oracle DBMS로 쿼리를 전송한다.
  • Statement는 타임아웃 처리를 위해 OracleTimeoutPollingThread(classloader별로 1개 존재)에 Statement를 등록한다.
  • 타임아웃이 발생한다.
  • OracleTimeoutPollingThread는 OracleStatement.cancel() 메서드를 호출한다.
  • Connection을 통해 취소(cancel) 메시지를 전송하여 수행중인 쿼리를 취소한다
  • jTDS(Microsoft SQL Server) Statement의 QueryTimeout

    122111_0935_JDBCInterna5.png
    그림 5 jTDS(Micsofot SQL Server) Statement의 QueryTimeout의 동작 과정
    jTDS(Microsoft SQL Server) Statement의 QueryTimeout은 다음과 같은 과정으로 동작한다.
  • Connection.createStatement() 메서드를 호출하여 Statement를 생성한다.
  • Statement.executeQuery() 메서드를 호출한다.
  • Statement는 내부 Connection을 사용하여 Microsoft SQL DBMS로 쿼리를 전송한다.
  • Statement는 타임아웃 처리를 위해 TimerThread에 Statement를 등록한다.
  • 타임아웃이 발생한다.
  • TimerThread는 JtdsStatement 객체 내부의 TdsCore.cancel() 메서드를 호출한다.
  • ConnectionJDBC을 통해 취소 메시지를 전송하여 수행중인 쿼리를 취소한다.
  • MySQL JDBC Statement의 QueryTimeout(5.0.8 버전)

    122111_0935_JDBCInterna6.png
    그림 6 MySQL JDBC Statement의 QueryTimeout의 동작 과정(5.0.8 버전)
    MySQL JDBC Statement(5.0.8 버전)의 QueryTimeout은 다음과 같은 과정으로 동작한다.
  • Connection.createStatement() 메서드를 호출하여 Statement를 생성한다.
  • Statement.executeQuery() 메서드를 호출한다.
  • Statement는 내부 Connection을 사용하여 MySQL DBMS로 쿼리를 전송한다.
  • Statement는 타임아웃 처리를 위해 새로운 타임아웃 처리용 스레드를 생성한다. 5.1.x 버전에서는 Connection에 한 개의 스레드가 할당되는 것으로 변경되었다.
  • 스레드에 타임아웃 처리를 등록한다.
  • 타임아웃이 발생한다.
  • 타임아웃 처리 스레드가 Statement와 동일한 설정의 Connection을 생성한다.
  • 생성된 Connection을 사용하여 취소 쿼리(KILL QUERY "connectionId")를 전송한다.
  • CUBRID JDBC Statement의 QueryTimeout

    122111_0935_JDBCInterna7.png
    그림 7 CUBRID JDBC Statement의 QueryTimeout의 동작 과정
    CUBRID JDBC Statement의 QueryTimeout은 다음과 같은 과정으로 동작한다.
  • Connection.createStatement() 메서드를 호출하여 Statement를 생성한다.
  • Statement.executeQuery() 메서드를 호출한다.
  • Statement는 내부 Connection을 사용하여 CUBRID DBMS로 쿼리를 전송한다.
  • Statement는 타임아웃 처리를 위해 새로운 타임아웃용 스레드를 생성한다.
  • 스레드에 타임아웃 처리를 등록한다.
  • 타임아웃이 발생한다.
  • 타임아웃 처리 스레드가 Statement와 동일한 설정의 Connection을 생성한다.
  • 생성된 Connection을 사용하여 취소 메시지를 전송한다.
  • JDBC 드라이버의 SocketTimeout 이란?

    JDBC Driver Type4는 소켓을 사용하여 DBMS에 연결하는 방식이고, 애플리케이션과 DBMS 사이의 ConnectTimeout 처리는 DBMS에서 하지 않는다.
    JDBC 드라이버의 SocketTimeout 값은 DBMS가 비정상으로 종료되었거나 네트워크 장애(기기 장애 등)가 발생했을 때 필요한 값이다. TCP/IP의 구조상 소켓에는 네트워크의 장애를 감지할 수 있는 방법이 없다. 그렇기 때문에 애플리케이션은 DBMS와의 연결 끊김을 알 수 없다. 이럴 때 SocketTimeout이 설정되어 있지 않다면 애플리케이션은 DBMS로부터의 결과를 무한정 기다릴 수도 있다(이러한 Connection을 Dead Connection이라고 부르기도 한다).
    이러한 상태를 방지하기 위해 소켓에 타임아웃을 설정해야 한다. SocketTimeout은 JDBC 드라이버에서 설정할 수 있다. SocketTimeout을 설정하면 네트워크 장애 발생 시 무한 대기 상황을 방지하여 장애 시간을 단축할 수 있다.
    단, SocketTimeout 값을 Statement의 수행 시간 제한을 위해 사용하는 것은 바람직하지 않다. 그러므로 SocketTimeout 값은 StatementTimeout 값보다는 크게 설정해야 한다. SocketTimeout값이 StatementTimeout보다 작으면, SocketTimeout이 먼저 동작하므로 StatementTimeout 값은 의미가 없게 되어 동작하지 않는다.
    SocketTimeout에는 아래 두 가지 옵션이 있고, 드라이버별로 설정 방법이 다르다.
    • Socket Connect 시 타임아웃(connectTimeout): Socket.connect(SocketAddress endpoint, int timeout) 메서드를 위한 제한 시간
    • Socket Read/Write의 타임아웃(socketTimeout): Socket.setSoTimeout(int timeout) 메서드를 위한 제한 시간
    CUBRID, MySQL, jTDS (Microsoft SQL Server), Oracle JDBC 소스를 모두 확인해 본 결과 네 개의 드라이버에서는 위의 두 가지 API를 사용함을 확인할 수 있었다. JDBC 드라이버별 SocketTimeout의 설정 방법은 아래와 같다. connectTimeout와 socketTimeout의 기본 값인 0은 타임아웃을 발생하지 않도록 하는 것이다.
    표 1 SocektTimeout 설정 방법
    JDBC 드라이버connectTimeout기본값단위적용 방법
    socketTimeout기본값단위
    MySQL DriverconnectTimeout0msDriverURL에 옵션 명시
    • 형식
    jdbc:mysql://[host:port],[host:port].../[database]
    [?propertyName1][=propertyValue1][&propertyName2][=propertyValue2]...
    jdbc:mysql://xxx.xx.xxx.xxx:3306/database?connectTimeout=60000&socketTimeout=60000
    socketTimeout0ms
    jTDS(MS-SQL Server) DriverloginTimeout0secDriverURL에 옵션명시
    • 형식
    jdbc:jtds:<server_type>://<server>[:<port>][/<database>][;<property>=<value>[;...]]
    jdbc:jtds:sqlserver://server:port/database;loginTimeout=60;socketTimeout=60
    socketTimeout0sec
    Oracle Thin Driveroracle.net.CONNECT_TIMEOUT0msDriverURL로 설정할 수 없고, OracleDatasource.setConnectionProperties() API를 통해 Properties 객체로 전달해야 한다.
    DBCP사용 시 다음 API를 사용한다.
    • BasicDatasource.setConnectionProperties()
    • BasicDatasource.addConnectionProperties()
    oracle.jdbc.ReadTimeout0ms
    Cubrid Thin Driver별도 설정 없음5,000msDriverURL로 설정할 수 없으며, 5초 후 타임아웃이 발생한다.
    • URL에 althost 옵션 지정으로 타입아웃 시 지정된 호스트로 연결 가능
    • C API로는 URL에 login_time 옵션을 ms단위로 명시 가능
    별도 설정 없음5,000msDriverURL로 설정할 수 없으며, 5초 후 타임아웃이 발생한다.
    • URL에 althost 옵션 지정으로 timeout 시 지정된 호스트로 연결 가능
    DBCP의 별도 API를 직접 사용하지 않고, Properties로 설정하는 방법도 있다. Properties 설정 시 키는 "connectionProperties", 값은 "[propertyName=property;]*" 형식의 문자열을 전달한다. 다음 예는 iBatis에서 XML을 통한 Properties 설정을 예로 들었다.
    ?
    1
    2
    3
    4
    5
    6
    <transactionmanager type="JDBC">
    <datasource type="com.nhncorp.lucy.db.DbcpDSFactory">
    ....
    <property name="connectionProperties" value="oracle.net.CONNECT_TIMEOUT=6000;oracle.jdbc.ReadTimeout=6000">
    </property></datasource>
    </transactionmanager>
  • OS 레벨 SocketTimeout 설정

    SocketTimeout이나 ConnectTimeout을 설정하지 않으면 네트워크 장애가 발생해도 애플리케이션이 대부분 이를 감지할 수 없다. 따라서 연결이 되거나 데이터를 읽을 수 있을 때까지 애플리케이션이 무한정 기다리게 된다. 그러나 서비스에서 발생한 실재 장애 상황에서는 30분 후에 애플리케이션(WAS)이 재연결을 시도하여 문제가 해결되는 경우가 많다. OS에서도 SocketTimeout 시간을 설정할 수 있기 때문이다.
    이 기사의 처음에 예로 든 리눅스 서버에서는 SocketTimeout을 30분으로 설정해 두고 있었다. 해당 설정 값을 통해 OS 레벨에서 네트워크 연결 끊김을 확인하는 것이다. 문제가 발생한 리눅스 서버의 KeepAlive 체크 수행 주기가 30분이므로 SocketTimeout 설정을 0으로 해도 네트워크 장애로 인한 DBMS 연결 장애 지속 시간이 30분을 넘지 않는 것이다. Linux 서버에서 KeepAlive 체크 수행 주기는 tcp_keepalive_time로 조정할 수 있다.
    네트워크 장애로 인해 애플리케이션이 대기 상태로 빠지는 경우는 대부분 애플리케이션이 Socket.read() 메서드를 호출하고 있을 때이다. 그러나 네트워크 구성이나 장애 유형에 따라 매우 드물게 Socket.write() 메서드를 실행하는 도중 대기 상태에 빠지는 경우가 있다.
    애플리케이션에서 Socket.write() 메서드를 호출하면 OS 커널 버퍼에 데이터를 기록한 후 바로 제어권을 애플리케이션에 반환한다. 즉 커널 버퍼에 값을 제대로만 기록하면 Socket.write() 메서드 실행은 언제나 성공한다. 그러나 특수한 네트워크 장애로 OS 커널 버퍼가 가득차면 Socket.write() 메서드도 대기 상황에 빠질 수 있다. 이 경우 OS는 일정 시간 동안 패킷 재전송을 시도하다고 한계 값에 도달하면 에러를 발생시킨다. 이 기사에서 예로 든 서버에서는 해당 값이 대략 15분으로 설정되어 있었다. 이 값은 Linux 서버의 tcp_retries2로 조절할 수 있다.
  • 마치며

    JDBC 내부의 동작 설명은 이것으로 마무리한다. 올바른 타임아웃 설정으로 장애를 줄이는 데 도움이 되었으면 하는 바람이다. 추가적인 문의나 JDBC에 관련한 좋은 정보가 있다면 개발자센터 블로그나 이 기사의 댓글로 글을 남겨 주기를 부탁한다.
    마지막으로 자주 문의가 들어온 내용을 정리해 보았다.
    • Q Statement.setQueryTimeout() 메서드로 QueryTimeout을 설정했는데도 네트워크 장애 발생 시 기대하는 대로 동작하지 않습니다.
      AQueryTimeout은 정상적으로 소켓 연결을 맺고 있을 때에만 유효합니다. 그렇기 때문에 네트워크 장애의 예외 상황을 처리할 수 없습니다. 네트워크 장애 상황을 대비하려면 JDBC 드라이버에 있는 SocketTimeout을 설정해야 합니다.
    • Q TransactionTimeout, StatementTimeout, JDBC 드라이버 SocketTimeout은 DBCP 설정 값과 어떤 관계가 있나요?
      A DBCP에서 Connection을 JDBC로부터 얻어올 때 DBCP의 waitTimeout 값만큼 대기할 수 있습니다. 그 외의 DBCP 설정 값은 DBCP 단독으로 동작합니다.
    • Q JDBC SocketTimeout을 설정하면 DBCP에서 유휴 상태(idle)로 오래 유지된 Connection이 닫히지 않나요?
      A 아니요, 닫히지 않습니다. Socket 옵션은 실제 데이터를 쓰거나 읽을 때 적용되기 때문에, DBCP 안에서 유휴 상태인 Connecton에 영향을 끼치지 않습니다. DBCP 내부에서 부족한 Connection 생성, 오래된 유휴 Connection 제거, Validation Check 시 영향을 줄 수 있지만 네트워크에 문제가 발생하지 않는 한 특이 사항은 일어나지 않습니다.
    • Q SocketTimeout시간은 얼마나 길게 설정해야 하나요?
      A 본문에서 말한 것처럼 StatementTimeout보다는 충분히 크게 잡아야 하며, 권장 값은 없습니다. JDBC 드라이버의 SocketTimeout 값이 영향을 주는 시점은 네트워크 장애가 발생한 이후입니다. 해당 값을 정밀하게 설정한다고 해서 장애가 발생하지 않는 것이 아니며, 경우에 따라(네트워크 장애가 곧 복구되었을 경우) 장애 시간을 줄일 수 있을 뿐입니다.

    강운덕_h.jpg
    NBP 웹플랫폼개발랩 강운덕
    웹플랫폼개발랩에서 사내 웹프레임워크인 Lucy를 담당하고 있습니다. 이외에도 사내에서 벌어지는 다양한 사건의 불을 끄러다니는 소방수일도 종종하고 있습니다. MS, Oracle처럼 제값을 받을 수 있는 소프트웨어를 개발해보고 싶은 개발자입니다.

    [펌] 트랜잭션 관련한 타임 아웃의 종류

    [펌] 트랜잭션 관련한 타임 아웃의 종류

    트랜잭션 관련한 타임 아웃의 종류
    ① 웹로직 콘솔의 Services – JTA로 설정하는 값의 의미
    • 흔히 생각하는 애플리케이션 트랜잭션 타임 아웃의 기능과 웹로직 서버 도메인 혹은 서버 레벨의 트랜잭션 타임 아웃 기능임.
    • 웹로직 서버나 도메인 레벨의 트랜잭션 타임아웃은 웹로직 내부적으로 콘솔 작업, 모니터링 혹은 로깅 작업 관련한 웹로직 자체 내부의 트랜잭션 처리를 말함.
    • 전역적인 변수로 생각하여도 무방(턱시도의 BLOCKTIME 유사)
    • Admin Console에서 JTA Timeout값을 변경 하면 restart 없이 변경 되는 것으로 나오지만,현재 activate되어 있는 resource에는 적용되지 않는다. 해당 EJB를 redeploy 해야만 변경된 Domain의 JTA timeout이 반영된다. 따라서 Domain의 JTA timeout 자체에 대한 값은 restart 없이 반영이 되지만, 이미 activate 되어 있는 관련 resource들은 reactivate를 필요로 하기 때문에 웹로직 서버를 재부팅하여야한다.
    ② EJB 디스크립터에 존재하는 trans-timeout-seconds
    • 특정 ejb 애플리케이션의 트랜잭션 타임 아웃
    ③ sql statement에 설정할 수 있는 Statement.setQueryTimeout(int sec)
    • 원래 java에는 타임 아웃으로 특정 코드를 중지시키는 api등이 존재하지 않는데,jdbc 쿼리에 대하여 타임 아웃을 설정하여 바로 중지 시킬 수 있는 기능이 있고,exception이 발생하므로 에러 코드값을 읽어올 수 있음.
    ④ XA데이터소스에서 설정하는 XA Transaction timeout
    • 각 리소스 즉 흔히 db로 가정하고 그에 대한 처리시 필요한 타임 아웃
    ⑤ 오라클 데이터베이스인 경우 ora-init파일에 존재하는 DISTRIBUTED_LOCK_TIMEOUT -
    • Lock 타임 아웃(default 60 sec)
    타임 아웃 관계

    :!: 위의 그림에서 잘못된 부분이 setQueryTimeout값(웹로직 콘솔에서는 Statement Timeout으로 설정 가능)은 JTA값보다 작게 주어야 한다. 그래야만 악성 쿼리가 돌 때 JTA타임아웃이 적용되기 전에 쿼리를 종료시켜서 추후 rollback으로 인한 T4Cconnection에 대한 lock을 미연에 방지할 수 있는 대안 마련이 된다. 만약 setQueryTimeout 값을 적용하지 않으면 악성 쿼리가 오라클 JDBC드라이버에서 T4Cconnection을 점유하고, Rollback스레드가 이 T4Cconnection이 종료되기를 기다리는 현상이 발생될 수 있으며, 특별한 경우에는 트랜잭션이 종료되지 않고 Rollback 스레드가 무한정 증가하여, 웹로직이 사용자 request조차 받지 못하고, 심지어 웹로직 콘솔도 못들어가는 경우가 발생할 수 있다.
    아울러 Statement timeout(setQueryTimeout)을 설정하는 경우 애플리케이션에서 SQLException을 throw하도록 만들어야 한다. 그렇지 않으면 Transaction Manager에서는 정상적으로 수행된 쿼리로 인식하고 commit까지 한다.

    • Oracle 데이터베이스의 경우 init 파일의 DISTRIBUTED_LOCK_TIMEOUT 매개변수(디폴트값: 60초)를 XA 트랜잭션 제한 시간 값보다 크게 설정하는 것이 좋다. 그렇게 하지 않으면 WebLogic Server JTA 또는 JDBC XA 트랜잭션 제한 시간에 따라 분산 트랜잭션 시간 초과 상황이 처리되기 전에 Oracle 측에서 테이블이 비정상적으로 잠길 수도 있다.
    • 트랜잭션 관련 기본 규칙은 JTA 타임 아웃이 가장 작아야 한다.
      • JTA 제한 시간 값이 전역적이거나 EJB에 해당하는 개별 트랜잭션과 적용되는 것과 관계 없이 트랜잭션에 참가하는 모든 Resource에 대해 설정된 제한 시간 보다 가장 짧게 설정되어야 한다. 만약 JTA가 가장 크게 되면 예기치 않은 트랜잭션 배치 결과가 나타날 수 있다. 즉 XAResource가 분산 트랜잭션 코디네이터인 WebLogic Server JTA보다 먼저 제한 시간을 초과하게 되면 XAResource는 WebLogic Server가 인식하기 전에 rollback 과정에 들어가게 된다. 그런데 뒤늦게 타임 아웃이 발생된 것을 알게된 WebLogic 트랜잭션 매니저가 분산 트랜잭션을 commit 혹은 rollback 처리 하려고 들어가게 되면 자칫 휴리스틱(판단을 할 수 없는 모호한 상태) 에러가 발생할 수 있는 것이다.
    • Statement.setQueryTimeout(int sec)
      • 웹로직에서는 Statement Timeout 파라미터로 default값은 -1로서 사용되지 않는 값
      • 초 단위로 타임아웃을 설정하실 수 있고, 이 경우 주어진 시간 내에 query(update 포함)가 종료되지 않을 경우에는 SQLException이 발생된다. (이 시간은 트랜잭션 타임아웃에는 포함되지 않으며, 위의 그림은 서로간의 관계를 표현한 그림이다.)
        (ORA-01013: 사용자가 현재 작업의 취소를 요청했습니다)
    • Container Transaction인 경우
      • weblogic-ejb-jar.xml 안에 <trans-timeout-seconds> 설정이 없는 경우 WebLogic의 JTA timeout을 기본으로 적용 받으며, 설정이 되어 있으면 JTA timeout보다 우선으로 적용.
    • Statement.setQueryTimeout(int sec)는 초 단위로 타임아웃을 설정하실 수 있고, 이 경우 주어진 시간 내에 query(update 포함)가 종료되지 않을 경우에는 SQLException이 발생.
    • JTA 타임아웃은 단순 looping이나 sleep은 적용되지 않는다.
    • UserTransaction 사용시 setTransactionTimeout 메소드로 적용 가능.

    2013년 5월 15일 수요일

    [쉘스크립트] 파일의 각 라인의 맨앞에 "#" 붙이기

    유닉스 쉘프로그래밍을 할때,
    때때로 전체 파일의 주석을 달아야할때가 생겼다.. (그냥 내용을 지우는거보다는 주석을 달고싶어서...)

    다음과 같이하면 org.sh 안의 모든 줄 앞에 "#" 이 붙은채로 test.sh 로 생성된다.
    (cronjob 같은걸 서버 작업 등으로 인해 주석 처리해야할때 나름 용이함..)

    #!/usr/bin/ksh
    
    while read line; do
        echo "#$line" >> test.sh
    done < org.sh
    
    
    출처 : 본인작성 

    2013년 5월 9일 목요일

    이미지 확장자가 내용과 다를 때, 렌더링 불가현상

    .png 파일을 .jpg 로 변경후 해당 파일을 그림판으로 오픈하는 경우 정상적으로 표시(렌더링) 해준다.

    자 이제 해당 파일을 웹서버 ( IIS7.5 환경에서 테스트됨) 에 올려놓고, client 에서 호출하면!
    해당 파일도 정상적으로 호출된다. ;-) ;;;


    그런데....
    여기서 웹서버에 X-Content-Type-Options nosniff 헤더 옵션을 주게되면.
    IE8 에서는 해당 파일이 엑박 표시된다...... (크롬에서는 잘 보임)


    이유는.. IE 의 기본 설정인 "파일 확장명이 아닌 파일 내용에 따라서 파일을 엽니다." 가 "사용"이였는데  X-Content-Type-Options nosniff 헤더를 주면 "사용 안함" 과 같은 효과라서
    내용과 확장자가 일치할때만 파일을 표시하게되기 때문..(상세 사항 하단 참고)

    #### X-Content-Type-Option nosniff ####
    IIS 의 보안 권고 설정으로 악의적인 사용자가 exe 등의 파일을 html 확장자로 업로드할때,
    브라우저의 "파일 내용에 따라 파일을 여는" 행동으로 인해 exe 파일로 실행될 수 있게되는데. 해당 설정을 확장자와 내용이 동일할때만 실행하도록 하는 HTTP 헤더 옵션.

    2013년 5월 3일 금요일

    WAS와 IIS 연동시 304가 아닌 200 상태코드만 나올때. ..

    Windows 2008 서버에서 ajp 프로토콜을 쓰는 WAS 와 IIS 를 연동하기 위해 "isapi_redirect.dll" 을 구성했다.

    해당 시스템에 성능 이슈가 있어서 확인 결과 , eTag 나 Last-modired 헤더가 정상적임에도 계속 200으로 받아와서 네트워크 트래픽을 발생시키고 있었다. (성능에도 악영향)

    (기본 설정의 경우 서버측에서 최초 요청시 200상태코드로 데이터를 송신 후,  서버에서 파일이 변경되지 않은 경우 304 Not modired 상태코드를 보내준 후 실제 데이터는 보내지않고 브라우저의 로컬 캐시를 로딩하도록 한다. )

     1. MS 문의 결과 : IIS 문제는 아니고 isapi 필터 문제로 추정
     2. isapi 테스트
        - isapi 를 제거하니 정상적으로 동작
        - isapi dll 을 다른버전으로 구성
          1) 32bit (1.2.37 버전) : 현상 해소 (정상동작
          2) 62bit (1.2.37 버전) : 문제 현상 유지


    isapi dll 파일이 64비트에서 상태코드를 200으로 내려주는 듯 하다.
    ----
    버그인지에 대해서는 추가 확인 예정

    IIS7 특정 jpg 파일이 엑박표시될 때 ...

    IIS 7.5 에서 특정 jpg 파일이 엑박표시되었다.
    전부다 그런건 아니고 해당 파일만 .... (멘탈붕괴) ...

     1) 해당 파일을 크롬으로 오픈하니 열린다.
     2) 해당 파일을 png 로 확장자를 바꾸니 열린다.

    -----
    문제는 보안설정때문에 걸어놓은 "X-Contentx-Type-Options=nosniff" 때문이였다.
    해당 설정은 확장자와 본문의 내용이 다를때, 실행하거나 랜더링 하지 않는다.

    2013년 4월 25일 목요일

    정리되지 않은 글...

    2013.04.25
    마구잡이식 글쓰기를 해보기로 했다.
    정말 정리 안되겠지만.

    생각을 글로 정리하다보면..생각도 정리가 되지 않을까?

    세계 10대 기업

    http://www.forbes.com/global2000/#page:1_sort:0_direction:asc_search:_filter:All%20industries_filter:All%20countries_filter:All%20states

    우연찮게 세계 1000대 기업자료를 보게되었다.
    그런데 우선 메인 페이지에 나오는 세계 10대 기업에

    중국이 4개, 미국이 4개, 영국 1개, 네덜란드 1개 이다...

     더 놀라운건,,, 애플 마이크로 소프트는 10위 밖이고 (애플 15위 , 마이크로 소프트 41위)
    삼성은 20위이다.


    역시 날고 뛰어봐야...인구수를 이기긴 힘든거같다..
    중국....역시 나는건가...

    2013년 4월 17일 수요일

    visualVM 모니터링을 위한 WAS jmx setting

     WAS 모니터링을 할 때 JAVA 에서 기본적으로 제공하는 jvisualVM 을 이용하여 실시간 모니터링이 가능하다.

    유닉스에서는 DISPLAY 환경변수 및  Xwindow 설정을 통해 내 PC 에서 띄워서 사용이 가능하다 (상세한 방법은 Xwindow 사용법을 참고)

     윈도우 에서는 jvisualVM 과 WAS 가 같은 계정으로 구동될 때는 로컬에서 jvisualVM 만 기동해도 ($JAVA_HOME\bin 하위에 존재) java 프로세스를 자동으로 인식하나, WAS 를 윈도우 서비스로 등록한 경우 WAS 계정이 "SYSTEM" 계정으로 구동되어 자동인식이 어려운 경우가 있다.

    이런 경우 WAS 에 다음과 같이 JMX 세팅을 구성한 후 원격이나 로컬에서 호출이 가능하다.
     

      << WAS JAVA Option setting >>
      -Dcom.sun.management.jmxremote
     -Dcom.sun.management.jmxremote.port=1403
     -Dcom.sun.management.jmxremote.ssl=false
     -Dcom.sun.management.jmxremote.authenticate=false (이 값을 false 로 주는 경우에는 아이피와 JMX 포트만 아는 경우에는 네트워크 접속이 가능한 누구라도 불법으로(?) 모니터링이 가능하므로 될수있으면 true 로 주고 아이디 패스워드를 주도록 한다. )

     *** 기타 설정 (optional)  ***
     -Djava.security.policy=<policy file>
    -Dcom.sun.management.jmxremote.local.only=false (true 로 주면 로컬에서만 접속 가능, 이것을 주는 경우 아이디 패스워드가 불필요할수도 있겠다..)
    -Djava.rmi.server.hostname=<your public hostname>
    -Dcom.sun.management.jmxremote.password.file=<password_file>




    2013년 4월 2일 화요일

    퀼트 관련 사이트

    http://cafe.naver.com/nona040/578

    유닉스 쉘 스크립트 작성시 sub 스크립트 호출 방식에 따른 차이

    - 출처  : 본인 작성

    유닉스 쉘 실행 방식에 따른 차이점

    ※ child1.sh
       echo "$A"
       echo "child1 exit"
       exit 0
       
       echo "passed exit" 
     
    ※ child2.sh
       echo "child2 called"

    TEST CASE1) 단순 호출 ※ multi_call_test.sh
        echo "Location : Mail shell"
        A=3
        ## CAll child shell
        child1.sh (또는 sh child1.sh 로 해도 동일 결과) 
        ## Call child2 shell
        child2.sh
        
        # end
        
    CASE1 결과)
        prompt> multi_call_test.sh
        Location : main shell
        
        child1 exit
        child2 called 
        

    TEST CASE2) . 호출 (호출 쉘 앞에 dot(점,.) 추가) ※ multi_call_test.sh
        echo "Location : Mail shell"
        A=3
        ## CAll child shell
        . child1.sh    
        ## Call child2 shell
        child2.sh
        
        # end
     
    CASE2 결과)
        prompt> multi_call_test.sh
        Location : main shell
        3
        child1 exit
     
     
    결론) 호출 후 메인 쉘의 동작과 별도로 동작하게 하려면 sh (쉘이름), 메인 쉘과 운명을 같이 하게 하려면 .을 주어 호출




    끝.