2007-11-18

Russian edition for "2K ill | NOT 2K ill (on the essence of KeepAlive)"

Убивать - не убивать (мёртвые сеансы и KeepAlive)

У меня завалялась неопубликованная статья (которую я готовил как MetaLink Note году так в 2001-2002. Были там этакие правила для центров тех.поддержки). Несмотря на преклонный возраст, статья бывает периодически востребована для решения проблем наших (ЦТП {Центр Технической Поддержки} ЗАО "РДТЕХ") заказчиков.

Обычно эти проблемы связаны с неудовлетворительным качеством сети (удаленный доступ с клиентских рабочих мест по "шумящим каналам")

Либо с непродуманной (как минимум) организацией промежуточного (middle tier/multi-tier, серверы приложений) программного обеспечения. Особенно когда промежуточное ПО не использует опции типа connection pooling, а вместо этого реализует stateless connection (т.е. статус соединения не отслеживается). Типично для "кривых" реализаций WEB-интерфейсов к БД. На каждый "клик" в броузере октрывается соединение к БД, выполняется пара-тройка команд... И о соединении забывают (т.е. не закрывают его корректно). Решения тут понятны и прозрачны... Однако... что делать DBA, столкнувшемуся с данной проблемой, пока разработчики системы "прочухаются"?

Один из способов: использование свойства протокола TCP/IP - KeepAlive

Ниже - перевод той самой давней статьи на тему.

---------
Целевая аудитория

Статья может быть полезна опытным DBA, когда клиенты подсоединены к основной БД по сети неудовлетворительного качества, когда соединения с клиента с сервером могут неожиданно прерываться (по различным, вне сферы ответственности DBA причинам)

Введение

В подавляющем большинстве случаев серверный процесс/диспетчер вовремя обнаруживает факт утраты соединения с клиентом. Обнаружив сей прискорбный факт, серверный процесс аварийно завершается, позволяя фоновому процессу PMON выполнить свою работу. Обсуждаемая проблема касается тех случаев, когда до PMON'а дело не доходит. Т.е. серверный процесс жив, но клиент о нём забыл.

Типичная ситуация:

a) по какой либо причине соединение на стороне клиента аварийной прервано (пользователь нажал кнопку "RESET" или "POWER OFF" на своей персоналке, или случился кратковременный перебой в обеспечении WAN-соединения, или вмешался firewall/router/switch со своими тайм-аутами и т.п.). В этом случае серверный процесс может "выжить", в то время как клиентская программа уже забыла о его существовании или вообще аварийно завершилась.

b) пользователь переустановил соединение (создал новый сеанс со своим серверным процессом)

c) "старый" сеанс был в неактивном состоянии ('INACTIVE') в момент аварийного завершения соединения на стороне пользователя (в случае 'ACTIVE' рано или поздно серверный процесс попытался обменяться сообщениями с клиентом, обнаружил бы сбой соединения и благополучно завершился)

d) этот "старый" сеанс никогда не завершится (или завершится через весьма продолжительный период времени)

e) DBA хочет завершить данный сеанс, поскольку PMON никаких действий не предпринимает, а сеанс мешает другим пользователям (например, в процессе выполнения транзакции удерживает блокировки)

f) удаление сеанса средствами Oracle не помогает, status='KILLED', process='PSEUDO'
ALTER SYSTEM KILL SESSION '<sid>,<serial#>',;
ALTER SYSTEM DISCONNECT SESSION '<sid>,<serial#>' IMMEDIATE;


Надо отметить, что вторая команда (DISCONNECT) срабатывает чаще

g) поиск процесса для удаления его средствами ОС
SELECT p.spid FROM v$session s, v$process p
WHERE s.paddr=p.addr
AND s.sid=<sid>;


не возвращает строк. Конечно, процесс можно найти методом исключения (в V$PROCESS он всё еще присутствует).

Еще комментарий - если для unix-подобных систем команда ОС kill -KILL решает проблему почти всегда (главное не ошибиться с выбором удаляемого процесса :-)), то в MS Windows в некоторых версиях, например, не освобождается PGA. Если версия, к тому же, 32-битная, то следует ожидать TNS-12560... Гхмм... А кто знает, как удалить сеанс на zOS/MVS?

Oracle Net (NET8, SQL*NET v2) предоставляет механизм DCD (Dead Connection Detection) для разрешения подобных ситуаций. Чтобы задействовать его, следует в sqlnet.ora на сервере установить параметр SQLNET.EXPIRE_TIME (значение в минутах). Достоинство этого метода - в независимости от сетевого протокола (хотя нынче выжил единственный протокол - TCP/IP). К сожалению, реализация его до версии 10g оставляла желать лучшего. В частности, при задании параметра на стороне клиента некоторые операции по экспорту или, скажем, вызову долго выполняющихся ( > SQLNET.EXPIRE_TIME ) процедур PL/SQL|Java могли неожиданно быть прерваны задействованным механизмом. Вы можете спросить - но ведь sqlnet.ora надо править на сервере? Да. Но вспомним о dblink... Один из серверов становится клиентом другого(-их).


Свойство "Keep Alive" протокола TCP/IP

Протокол TCP/IP является фактически единственным стандартным протоколом, используемым в современных сетях в Oracle Net.

Сетевой протокол Oracle (Oracle Net/NET8/SQL*Net) использует возможности стандартных протоколов (в частности TCP/IP).

Адаптер сетевого протокола Oracle может использовать общие возможности нижележащего протокола, в частности, обсуждаемый в этой статье механизм "Keep Alive".

ВАЖНОЕ ЗАМЕЧАНИЕ: в случае, когда сообщение "keep alive" не получает ответа, серверный процесс благополучно завершается (так как не содержит соответствующего обработчика исключительной ситуации), позволяя процессу PMON выполнить "зачистку".

Механизм Keep Alive

достаточно прост - две стороны соединения (клиент и сервер) периодически (по умолчанию интервал равен двум часам) посылают друг другу "пустые" или "пробные" пакеты TCP/IP, которые предназначены исключительно для проверки факта, что партнер в состоянии ответить. Если партнер не ответил на "пробник", посылавшая "пробник" сторона посылает еще несколько пакетов (но уже с другой частотой, отличной от 2-х часов по умолчанию). В конце концов, если ни на один "пробник" ответа не получено, соединение помечается как сбойное (драйвером TCP/IP) и процессу посылается TRAP от драйвера на уровне ОС.

Поскольку обработчика прерывания в серверном процессе Oracle не предусмотрено (или же он не является последним в цепочке обработчиков), то процесс (серверный) аварийно завершается. Аварийное завершение серверного процесса обнаруживается PMON, что и требовалось.

Механизм DCD (Dead Connection Detection)

несколько отличается, хотя общие черты, естественно, имеются. PMON (если не ошибаюсь) периодически пересылает IPC (Inter-Process Communication) сообщение серверным процессам средствами Oracle (постановка сообщения в очередь сообщений процессу и, в зависимости от платформы, взведение семафора, задействование post-wait драйвера и т.п.). И ждет ответа. Предполагается, что каждый серверный процесс периодически проверяет свою очередь входных сообщений*), посылает "пробник" партнеру, и, в случае успеха, ответчает на них PMON'у. Вопрос в том, как часто происходит такая проверка. Что, если исполняется "долгоиграющая" процедура? Или долго выполняющаяся команда? И предусмотрен ли механизм асинхронной проверки очередей сообщений (т.е. вне стандартного потока действий по обработке команды)? По тестам видно, в Oracle10g проверки проводятся асинхронно. Поэтому начиная с версии 10g можно полагаться на DCD. Но не в предыдущих версиях.

Как задействовать Keep Alive на разных платформах

Предполагается, нашей целью является
a) включение этой возможности
b) регулирование частоты проверок (два часа могут быть слегка завышенной цифрой)

- для включения механизма Keep Alive следует воспользоваться настройками на стороне клиента. В определение сетевого имени службы (оно же alias, описатель соединения... кратко говоря - то, что содержится в tnsnames.ora) следует включить "кляузу" (ENABLE=BROKEN). Пример:

xxx.domain.com = (DESCRIPTION=(ENABLE=BROKEN)(ADDRESS= ....)... )

подробности в MetaLink Note:39357.1

- ниже приведен (неполный) перечень действий по изменению интервала передачи "пробных пакетов" Keep Alive на разных платформах.

a) Windows: Изменить установки в реестре. Подробности на сайте поддержки Microsoft 120642

HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Services/Tcpip/Parameters
Edit - Add value : KeepAliveTime (REG_DWORD)
Decimal -> 180000 (3 minutes, for example)

b) Solaris/HP-UX

/usr/sbin/ndd –set /dev/tcp tcp_keepalive_interval 180000
(интервал 3 минуты)

c) Linux

/sbin/sysctl -w net.ipv4.tcp_keepalive_time=1800 ?
(интервал 3 минуты)

d) Tru64

/usr/sbin/netconfig tcp_keepidle 360
(интервал 3 минуты)
ЗАМЕЧАНИЕ: время указывается в единицах 1/2 секунды

e) AIX

/usr/sbin/no -o tcp_keepidle=360
(интервал 3 минуты)

ЗАМЕЧАНИЕ: время указывается в единицах 1/2 секунды

2007-11-17

2K ill | NOT 2K ill (on the essence of KeepAlive)

I have one article, intended for publishing as a MetaLink note quite long ago (2001-2002?). Inspite of of its quite venerable age, I use it quite often as the recommendation for the customers, who experience the problems with the dead sessions.

Usually this is due to unsophisticated (to say the least) quality of the middle-tier in use (stateless WEB connection, repeated logins for a couple of statements and forgetting to close the connection to DB - i.e. not using proper connection pooling), the other cases may raise due to bad quality of the network. Anyway, the DBA should find some method to deal with that situation.

One of the many ways is to utilize the KeepAlive feature of TCP/IP protocol.

So, the article is here. Your comments/corrections are very welcome.

---------

Adressee's

This short article may be usefull for of those advanced DBA's, whose client's PCs are connected to the Oracle Server via slow/noisy channels, i.e. where temporary breaks in the network (using TCP/IP) connections occur quite often.

Preface

In most cases the Oracle foreground/server/shadow process detects that a communication channel to the client is broken in a timely fashion, so the rest of connection failure processing is successfully performed by PMON background process. However, this is not always the case.

Typical situation:

a) for some reason (for example, a user have pressed RESET or POWER-OFF/ON button on his/her PC, or there was a short break in the WAN network, or there are any time-outs specified on the firewall/router/switch) the client part of the connection terminated abnormally. Which means, that server processs "sirvived" while client program was terminated or detected a network failure.

b) the user had re-established connection to the server (i.e. created the new session)

c) the "old" session was in 'INACTIVE' state during the abnormal disconnect (otherwise - status 'ACTIVE' - the broken connection would be detected when the server process will try to return the result or status of the current command to the client)

d) this "old" session never dies (or will die too late)

e) DBA wants to "cleanup" the instance, because PMON does nothing on the "old" session and this session holds the resources like locks, which bother the other sessions.

f) an attept to kill the old session via Oracle doesn't help: status='KILLED', process='PSEUDO'

alter system kill session '<sid>,<serial#>';
alter system disconnect session '<sid>,
<serial#>' immediate;


g) an attept to kill the session after f) also causes some difficulties
select
p.spid from v$session s, v$process p
where s.paddr=p.addr
and s.sid=<sid>;

returns nothing. Of course, there are methods to find the runaway process as it is still present in V$PROCESS.

One more comment: though in unix-like systems the kill -KILL usually solves the problem (when the right process was killed :-)), this is not the case with Oracle 32-bit on the 32-bit Windows and versions <9i.

The Oracle Net (Net8/SQL*Net) product provides for a mechanism called Dead Connection Detection (DCD). This is configured via Client Profile (sqlnet.ora) using SQLNET.EXPIRE_TIME parameter on a server side. Such a behaviour is protocol independent. Unfortunately, the implementation of this DCD feature is not always satisfactory. Namely, while the setting is in effect, some long running PL/SQL procedures might be erroneously recognized as "DEAD". Or the long running export utility sessions also could be "killed". The most typical mistake here is when the DCD is configured on the client (and not server) side. However, when the dblink is used, then the server becomes a client for the other server. Here is the problem.

TCP/IP "Keep Alive" feature

The TCP/IP protocol is by the fact an industry standard.

Oracle networking products just rely on the features of ANY industry standard protocol.

Oracle TCP/IP adapter also could use a common feature of TCP/IP, which is a subject of this note, namely "Keep Alive".

IMPORTANT NOTE: If the KeepAlive message is not responded upon in a required time interval, than the shadow (server) process dies gracefully, allowing the PMON to do the clear "process failure cleanup".

The mechanism of the KeepAlive

is very straightforward - the two communicating parties (client and server) periodically (by default the time interval equals to 2 hours) are sending each other some "empty" or "probe" TCP/IP packets, which just confirm, that the partner of the connection is able to respond. If the partner doesn't respond, than the sending party resends the KeepAlive packets at more frequent intervals for some time. Finally, if there is still no response, the connection is marked as "faulted" and corresponding TRAP is sent to the connection "owner" on the OS level. Oracle server processes do not provide any handlers for the TRAP, so the process dies. The death of the server process allows the PMON to cleanup.

The mechanism of the DCD

is a little bit different. The PMON (IIRC) periodically enqueues some IPC (Inter-Process Communication) message in the SHARED POOL and "posts" this message (via OS semaphore, post-wait driver or similar). The it waits for the reply through ICP. It is assumed, that each server process will check its own incoming message queue, sends an Oracle Net "probe" packet and in case of cuccess will respond to PMON in timely fashion. The question then is - how often this incoming queue is checked? Is it checked while the call execution is going on (i.e. asynchronously with respect to the main processing)? In the tests on Oralce10g there is an evidence of such asynchronous processing for DCD messages. But not in the earlier versions.

TCP/IP "Keep Alive" feature - how to (employ)

To switch on the KeepAlive feature of the TCP/IP protocol, one should:

- specify in the "service specification" in his/her client's tnsnames.ora/Oracle Names config the following clause (an example):

xxx.domain.com = (DESCRIPTION=(ENABLE=BROKEN)(ADDRESS= ....)... )

Some details can be found in the MetaLink Note:39357.1

- decrease (if required) the interval between KeepAlive messages on the OS level. The later is platform-depenent. Find below some examples for a number of the platforms:

a) Windows: change the registry settings (see Microsoft support site for case 120642

HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Services/Tcpip/Parameters
Edit - Add value : KeepAliveTime (REG_DWORD)
Decimal -> 180000 (3 minutes, for example)

b) Solaris/HP-UX

/usr/sbin/ndd –set /dev/tcp tcp_keepalive_interval 180000
(sets 3 minutes interval)

c) Linux

/sbin/sysctl -w net.ipv4.tcp_keepalive_time=1800 ?
(sets 3 minutes interval)

d) Tru64

/usr/sbin/netconfig tcp_keepidle 360
(sets 3 minutes interval)

NOTE: time is specified in 1/2 second units

e) AIX

/usr/sbin/no -o tcp_keepidle=360
(sets 3 minutes interval)

NOTE: time is specified in 1/2 second units

Welcome message from YAB (Yet Another Blogger)

I'm glad to welcome any interesting person, who managed to reach this blog.

Hopefully, the future publications and comments will add the value for Oracle community.

Andrey Kriushin, YAB