Oracle*NET DCD(DEAD CONNECTION DETECTION) 과 O/S KEEP ALIVE 의 관계


Client PC의 process가 사라지고 난 후 server에서 접속이 close가 안 되었을 경우 문제가 발생할 수 있다. 전형적인 예로는 Oracle에 접속되어 있는 상황에서
사용자가 기계를 reboot 하거나 전원을 끊거나 할 경우 client process는 정확히 종료되었을 지 모르나 서버상의 background process는 client가 아직까지 접속
되어 있는것으로 생각하고 처리를 계속 수행하고 있으므로 이 결과로 인하여 서버 상에서는 많은 자원을 낭비할 수 있다.

이는 Oracle의 문제가 아니며 TCP/IP의 제한에 따른 것이다.

Dead Conection을 발견하여 보다 빠르게 close시키고 server상에서 사용하고  있는resource를 보다 빠르게 free시키기 위해서는 keepalive를 정확하게 설정
하여야 한다.

Problem Description
——————-

** KEEPALIVE **

TCP/IP접속을 하고 있는 양측에서 접속을 하고 있는 동안 정해진 시간내에  다른 반대편으로 부터 아무런 데이터를 받지 못했음을 감지하는 경우
그것으로 인하여 transparent layer에서 “dummy(test)” packet을 application layer로 보내고 응답(acknowledgement)가 올 때가지 다른 한쪽에서는 기다리게 된다.
만일 접속된 process에서 응답(acknowledgement)를 기다리는 중에 timeout이 되는 경우 TCP/IP에서는 접속을 포기하기전에 보내진 “dummy(test)” packet에 대한
응답(acknowledgement)를 기다리는 일련의 일들을 몇번이고 재시도 할 수 있도록 구현되어 있다.

즉 keepalive가 설정되어 있을 경우에는 client process들이 실제로 connection을 유지하고 있는 지 확인하기 위해 모든 비활성 TCP/IP 접속을 주기적으로 조사
(Polling)한다. 접속이 되어 있는 process들은 정해진 비활성 주기 이후에 서버의 TCP/IP s/w에 의해 “dummy(test)”을 보내기 시작하며 반대편으로 부터 반드시
응답(acknowledgement)을 받아야 한다. 만일 보낸 시도 packet들이 client에서 무시되어 버린다면 서버는 접속이 최악의 상태인것으로 간주하고 접속을
close한다. 그런 다음 ORACLE에서는 connection과 관련된 shadow process를 안전 하게 제거한다.

SQL*NET의 TCP/IP level에서는 listener가 startup될때 setsockopt()라는 함수를 호출함으로서 listener에서는 keepalive가 구현되어 있다.

* Dead mans Handle *

일반적으로 네트워크를 이용하여 양쪽에 도달하기까지에 대한 algorithm의 이름이며 keepalive와 매우 동일하고 이는 TCP/IP에서 사용하는 전문용어는  아니다.
SQL*NET에서 사용하는 용어로서 SQL*NET v2.1이상에 포함되어 있는 dead man’shandle에 근간을 둔 algorithm으로 모든 platforms들과 protocol들에서 일반적
으로 사용하고 있으며 이를 DCD(DEAD CONNECTION DECTION)라고도 부른다. SQL*NET V2.1.3 이상 (RDBMS V7.1.3이상)에서 사용할 수 있다.

* Timeout *

Timeout은 orasrv의 기능으로 client가 connection handhake (client가 요청한 break-mode, buffersize, SID에 관한 정보를 어디로 전달할 것이지를 찾는
일련의 작업)를 하는 동안 응답이 올때까지 계속 기다리는 것을 방지하기 위해 orasrv에 추가된 기능이다.
이 기능은 SQL*NET V1.2.7.2.3이상에서 가능하며 다음의 명령어를 수행하여 사용할 수 있다. (Default = 0)

$ tcpctl timeout 5

만일 사용자가 application에서 정상적으로 종료하지 않고 전원을 끄는 경우 process들은 “Clean-up”되지 않고 이러한 shadow process들은 고아(oraphaned)
process가 될것이다.
만일 수많은 사용자들이 이렇게 비정상 종료를 할 경우 서버에서는 이러한 defunct process들로 인하여 과부하가 걸리게 될 것이며 이때 이들 process들은 parent
process id (PPID)를 1로 갖는 daemon 또는 init 소유의 process들이다.

이러한 상황을 해결하기 위해, 사용자는 TCP/IP level에서 KEEPALIVE option을 설정할 수 있으며 이 parameter는 /usr/include/netinet디렉토리내의 tcp_timer.h
참조 할 수 있다.

일반적으로 Keepalive는 다음에서 보는 parameters에 의해 제어 할 수 있으며 물론 system마다 parameters이름은 약간의 차이가 있을 수 있다.

tcp_keepidle : time before keepalive probes begin
tcp_keepintvl : time between keepalive probes
tcp_maxidle : time to drop (after probes)
tcp_ttl : time to live for TCP segs
PR_SLOWHZ : usually 2 times per second

KEEPALIVE의 기존 interval은 다음과 같이 정의 되어 있다.

#define TCPTV_KEEP_IDLE (120*60*PR_SLOWHZ) /* dflt time before probing */

여기서 PR_SLOWHZ을 1초로 정의되어 있다고 가정하면 (120*60*PR_SLOWHZ)은 2시간을 나타내는 것이다. KEEPALIVE가 시작되면 “dummy” packet을 connection
들에 보내어 만일 connection이 active상태라면 KEEPALIVE가 작동하지 않을 것이고 만일 더 이상 active상태가 아니라면 KEEPALIVE에 의해 connection이
close될것 이다. 그런 다음Dedicated server process(shadow process)는 kill signal을 받는 것과 동시에 종료될 것이다.

주의 : KEEPALIVE의 특징을 모든 TCP/IP Verdor에서 제공하는 것은 아니며,이는 TCP/IP level에서 설정하는 것으로 Oracle의 기능은 아니다.
이 기능은 vendor마다 다를 수 있으므로 만일 값을 설정하려면 TCP/IP vendor로 문의하기 바란다.
이 기능은 문제를 피해갈 수 있는 하나의 방법일뿐 문제해결을 위한 해결책이 아니므로 이로 인해 생기는 문제에 대해 는 보장하지 않는다.

SQL*NET V2.1이상의 서버와 SQL*NET V2.0.14이상의 client에서 제공하는 DCD(Dead Connection Detection) 기능은 TCP/IP의 KEEPALIVE 특징처럼 동일한
기능을 수행한다.

DCD는 서버의 $ORACLE_HOME/network/admin/sqlnet.ora파일내에 있는 parameter인
sqlnet.expire_time에 정의할 수 있으며 단위는 분이며 1 ~ 무한대까지 가능하다.

만일 sqlnet.ora에 정의되어 있지 않았다면 DCD의 기능은 사용되지 않는 다.이 parameter는 client와 server사이에서 connection을 통하여 연속되는 시도
packet들을 전달하는 시간 주기를 결졍한다.

Workaround
———–

지금까지 설명한 keepalive에 대한 기능을 각 H/W에서는 어떻게 설정하는 지 알아 보도록 한다. (일반적으로 만이 사용하는 H/W를 기준)
그리고 다음의 OS parameter를 수정시에는 반드시 OS engineer와 상의는 하는 것이 바람직 하겠다.

<< Windows NT >>

1. Regedt32를 수행한다.

2. HKEY_LOCAL_MACHINE -> SYSTEM -> CurrentControlSet -> Services ->

Tcpip -> Parameters으로 간다.

3. 편집메뉴 -> 값추가를 선택하면 값추가 윈도우가 나타난다.

4. 값이름을 KeepAliveTime으로 넣고 데이타 형식을 REG_DWORD로 선택한후 확인버튼을 누르게 되면 DWORD편집기 윈도우가 나타나며 여기서 기수
(이진, 십진, 16진)를 선택하는 데 십진을 선택하고 난후 데이타 값을180000 (3분) 설정한 후 확인 버튼을 누른다.

<< Netware >>

Netware에서는 DCD기능이 적용 안됨

<< SunOS, Sun Solaris >>

# ndd /dev/tcp \? —–> parameter 확인하는 방법
# ndd /dev/tcp tcp_keepalive_interval —–> 설정된 값 확인
7200000                         (기본값 : 7200000 ms)
# ndd /dev/tcp
tcp_keepalive_interval 10000
# ndd /dev/tcp tcp_keepalive_interval
10000

<< Digital Unix >>

# dbx -k /vmunix

(dbx) p tcp_maxidle
1200
(dbx) p tcp_keepidle ——> print value
14400                    ——> 설정된 값 확인
(dbx) assign tcp_keepidle = 1200 ——> new value assign
1200
(dbx) assign tcp_maxidle = 600     ——> new value assign
600
(dbx) quit

두 parameter의 단위는 0.5초 입니다. tcp_keepidle의 기본값은 2시간이며 tcp_maxidle의 기본값은 20분입니다.
tcp_keepidle은 keepalive code가 적용되기 전까지의 시간이며, tcp_maxidle은 connection이 drop될때까지 keepalive가 적용되는 시간과의 사이를 정해놓은
시간입니다.
즉 예를 들자면 tcp_keepidle을 10분으로, tcp_maxidle을 5분으로 설정하여 놓았다면 defaunct connection들은 15분후애 종료됩니다.

<< IBM AIX >>

# no -a           ——-> 설정된 값 확인
…..               (units of half seconds)
tcp_keepidle = 14400 (2 hours)
tcp_keepintvl = 150 (75 seconds)
…..
# no -o tcp_keepidle=1200
# no -o tcp_keepintvl=40

tcp_keepidle는 keepalive 메세지를 보내기 전에 활동하고 있지 않은 시간을 결정하는 parameter이고 tcp_keepintvl은 keepalive시도 메세지를 얼마나 자주
보내는지를 결정하는 parameter이다. 접속은 8회의 비응답 시도후에 broken이 고려된다.

이러한 parameter의 값을 설정하는 것은 어려운 부분으로 불필요한 traffic을 감소시키기 위해 적은 값으로 설정하는 게 일반적이다. 실제로 이러한
parameter들은 시스템에 상당히 의존적이다.
아무튼 IBM AIX에서 oracle을 사용하는 경우 1200(10분)과 400(20초)으로 설정하여 사용하기를 추천한다.

이 parameter의 값을 영구보존하기 위해서는 /etc/rc.tcpip에 두개의 명령어를 추가한다.

<< HP-UX HP9000 Ver 10.01 I70 series >>

조정 할 수 있는 parameter를 확인한다.

# nettune -h

조정 할 수 있는 TCP parameter의 이름들을 확인한다.

# nettune -h tcp | grep

tcp_localsubnets:
tcp_receive:
tcp_send:
tcp_defaultttl:
tcp_keepstart:
tcp_keepfreq:
tcp_keepstop:
tcp_maxretrans:
tcp_urgent_data_ptr:
tcp_pmtu:
tcp_random_seq:

TCP에서 keepalives의 전송을 시작하기 전에 idle time을 변경하기위해 tcp_keepstart를 설정한다
그리고 keepalives사이의 시간을 변경하기 위해 tcp_keepfreq를 설정한다.

# nettune tcp_keepfreq –> This shows the current value: 75.

# nettune -l tcp_keepfreq –> This shows the range of values.

tcp_keepfreq = 75 default = 75 min = 5 max = 2000 units = seconds

# nettune -s tcp_keepfreq 1000 –> set it to 1000

# nettune tcp_keepfreq –> verify it as 1000

keepalive를 수정하기 위하여

# adb -w /ph-ux /dev/kmem

0d10$d (Change to base 10)
tcp_keepidle?D (Display value of keepidle – 14400 = 2 hours)
tcp_keepidle?W 1200 (This command updates the HP-UX kernel on disk)
tcp_keepidle/W 1200 (This command updates the HP-UX kernel in
memory)
tcp_keepidle?D (This will display the value used for the next
boot)
tcp_keepidle/D (This will display the value used for future
connections)
^d (CRTL-D to exit adb)

Again, this will modify the HP-UX kernel on disk and in memory.

사용자의 시스템을 위해 PHNE_8420=Nettune Cumulative Patch 와 PHNE_11758=FDDI cumulative patch를 찾아보기 바란다.

<< HP-UX HP9000 Ver 10.10 K210 series >>

TCP에서 keepalives의 전송을 시작하기 전에 idle time을 변경하기위해 tcp_keepstart를 설정한다
그리고 keepalives사이의 시간을 변경하기 위해 tcp_keepfreq를 설정한다.

# nettune tcp_keepfreq # what’s the current value?
75

# nettune -l tcp_keepfreq # what are the range of values?
tcp_keepfreq = 75 default = 75 min = 5 max = 2000 units = seconds

# nettune -s tcp_keepfreq 1000 # set it to 1000

# nettune tcp_keepfreq # verify it
1000

변경할 수 있는 모든 값들은 help를 이용하여 얻을 수 있다.

# nettune -h # what can I tune?
# nettune -h tcp # what TCP variables can I tune?
# nettune -h tcp | grep : # what are the TCP tunables named?

# adb -w /ph-ux /dev/kmem
0d10$d (Change to base 10)
tcp_keepidle?D (Display value of keepidle – 14400 = 2 hours)
tcp_keepidle?W 1200 (This command updates the HP-UX kernel on disk)
tcp_keepidle/W 1200 (This command updates the HP-UX kernel in
memory)
tcp_keepidle?D (This will display the value used for the next
boot)
tcp_keepidle/D (This will display the value used for future
connections)
^d (CRTL-D to exit adb)

이외의 H/W에 대해서는 OS verdor로 문의하여 알아 보시기 바랍니다.


Comments

comments

haisins

오라클 DBA 박용석 입니다. haisins@gmail.com 으로 문의 주세요.

댓글 남기기

이메일은 공개되지 않습니다. 필수 입력창은 * 로 표시되어 있습니다