SQL Server 이야기

SQL Server 클러스터 리소스의 상태 체크(LooksAlive/IsAlive Check) 방식

늘푸르른나 2010. 5. 5. 15:58

SQL Server 클러스터를 구성하는 이유는 SQL Server에 발생할 수 있는 장애 현상을 자동으로 감지하여 빠른 시간 안에 서비스를 정상화함으로써 가용성을 높이는 데 있습니다. 윈도우즈 클러스터에서는 클러스터 리소스의 상태를 체크하기 위해 LooksAlive와 IsAlive의 두 가지 체크 방식을 사용합니다. 기본적으로 LooksAlive 체크는 5초마다 수행되고 IsAlive 체크는 60초 마다 수행되는데 대부분의 클러스터 리소스는 LooksAlive 체크와 IsAlive 체크가 동일한 방식으로 수행되기 때문에 차이가 없습니다.

 

SQL Server 리소스는 윈도우즈의 서비스로 동작하는 SQL Server 프로세스(sqlservr.exe)에 대응되는 개체입니다. SQL Server는 DBMS의 동작 특성상 서비스가 온라인인지(SQL Server 프로세스가 실행중인지) 여부도 중요하지만 실제 접속이 가능한 상태인지 여부와 쿼리문 실행 결과가 일정 시간 안에 반환되는지 여부도 중요합니다. 따라서, SQL Server 리소스에 대한 상태 체크는 기타 클러스터 리소스에 비해서 정교하게 구현되어야 하며 LooksAlive 체크와 IsAlive 체크 방식이 다르게 구현되어 있습니다.

 

Windows Server 2008 클러스터에서 리소스의 상태를 체크하는 작업은 리소스 호스트 서브시스템(Resource Host Subsystem) 프로세스(rhs.exe)에 의해 처리됩니다(Windows Server 2003 클러스터에서는 리소스 모니터 프로세스(resrcmon.exe)에 의해 처리됨). 기본적인 클러스터 리소스인 IP 주소, 네트워크 이름, 실제 디스크 등에 대해서는 리소스 호스트 서브시스템에서 직접 리스스의 상태를 체크하지만 SQL Server와 같은 복잡한 리소스에 대해서는 해당 응용프로그램에서 별도로 제공되는 Resource DLL을 추가적으로 로드하여 Resource DLL에서 제공되는 함수를 호출하는 방식으로 상태 체크 작업이 수행됩니다. SQL Server 리소스의 상태 체크를 위해 사용되는 Resource DLL은 sqsrvres.dll(SQL Server Cluster Resource DLL)이며 이 Resource DLL 내에 LooksAlive와 IsAlive 체크 함수가 정의되어 있습니다.

 

SQL Server 리스소에 대한 LooksAlive 체크는 SQL Server 서비스가 온라인 상태인지 여부에 대한 간단한(피상적인) 검사 작업만을 수행하며 QueryServiceStatus Windows API 함수를 호출하는 방식으로 이루어집니다. 기본적으로 LooksAlive 체크는 5초마다 수행되며 LooksAlive가 실패할 경우 IsAlive 체크 작업이 곧바로 수행됩니다. LooksAlive 체크 작업이 실패한다고 해서 SQL Server 리소스가 실패 상태에 있는 것으로 판단되는 것은 아니며 IsAlive 체크 작업이 실패했을 때에만 비로소 SQL Server 리소스가 실패한 것으로 간주됩니다.

 

SQL Server 리소스 실패 여부의 판단 기준이 되는 IsAlive 체크는 실제로 SQL Server에 ODBC 연결을 맺은 다음 간단한 쿼리문(select @@servername)을 실행해 보는 테스트를 수행하여 SQL Server가 정상적으로 동작하고 있는지 여부를 정밀하게 검사합니다. 기본적으로 IsAlive 체크는 60초마다 한번씩 수행되는데 세부적으로는 쿼리문을 실행해 보고 그 결과를 전역변수에 설정하는 작업과 설정된 전역변수 값을 검사해 보는 작업이 독립적으로 수행됩니다. 쿼리문을 실행해 보는 작업은 60초마다 수행되는데 이는 IsAlive 체크 간격(IsAlive Polling Interval)과는 다르게 고정적인 값으로 변경할 수 없습니다. 반면에 IsAlive 체크 간격은 기본 값으로 60초가 사용되지만 필요에 따라서 변경할 수 있습니다.

 

다음은 IsAlive 체크 로직을 개략적으로 정리한 것입니다. 핵심적인 사항은 SQL Server에 대해서 60초마다 쿼리문(select @@servername)을 실행하는 작업은 별도의 스레드에서 지속적으로 수행되고 있으며 IsAlive Polling Interval(Default 값은 60초)마다 수행되는 IsAlive 체크는 전역변수에 저장되어 있는 State 값을 검사해 보는 작업만을 수행한다는 것입니다. 쿼리문 실행시 Query Timeout 속성을 60초로 설정해서 실행되기 때문에 SQL Server에 문제가 있을 경우 IsAlive 체크를 통해 SQL Server 리소스가 실패한 것으로 처리되는 데에는 최대 120초가 소요될 수 있습니다(쿼리문 실행 직전에 IsAlive 체크가 실행되었을 경우를 가정해 보면 다음 번 IsAlive 체크가 실행되었을 때에는 아직 쿼리문이 Timeout 오류와 함께 실패하지 않았기 때문에 IsAlive 체크가 한번 더 수행되어야만 SQL Server 리소스가 실패한 것으로 처리될 것입니다).

 

 

60초마다 실행되는 쿼리문(select @@servername)이 실패할 경우에는 곧바로 쿼리문이 다시 실행되며 계속 실패할 경우 여러 차례에 걸쳐서 반복적으로 쿼리문이 실행됩니다. 일시적으로 쿼리문 실행이 실패했다가 다시 실행했을 때 성공하게 되면 전역변수의 State 값이 짧은 시간 동안만 SQL Server에 문제가 있음을 나타내게 되며 IsAlive 체크에 의해서 감지되지 못할 수도 있습니다. 이는 일시적인 현상으로 인해서 SQL Server가 실패로 판정되고 재시작되는 문제점을 예방하는 효과를 갖기도 합니다.

 

IsAlive 체크 간격(IsAlive Polling Interval)은 다음과 같이 SQL Server 리소스의 속성 중 '고급 정책' 탭에서 확인 및 변경할 수 있습니다. '기본 리소스 상태 검사 간격'은 LooksAlive Polling Interval을 의미하고 '정밀 리소스 상태 검사 간격'은 IsAlive Polling Interval을 의미합니다. 다음의 화면과 같이 '리소스 종류에 대한 표준 기간 사용'이 선택되어 있는 것이 기본 설정인데 LooksAlive Polling Interval은 5초, IsAlive Polling Interval은 60초가 각각 표준 기간입니다. 

 

예를 들어, SQL Server 리소스의 IsAlive Polling Interval을 기본 값 대신에 30초로 설정하려면 다음과 같이 '정밀 리소스 상태 검사 간격' 항목에서 '이 기간 사용(mm:ss)'을 선택하고 30초를 설정해 주면 됩니다. 

 

앞에서 설명했듯이 IsAlive Polling Interval 설정과는 무관하게 SQL Server에 대해서 수행되는 쿼리문(select @@servername)은 60초마다 실행됩니다. SQL Server에 대해 Profiler Trace를 수집해 보면 다음과 같이 60초 간격으로 'select @@servername' 쿼리문이 실행되고 있음을 확인해 볼 수 있습니다. 

 

SQL Server에 대해 'select @@servername' 쿼리문 실행이 실패했을 때 응용 프로그램 이벤트 로그에는 다음과 같은 오류 메시지가 기록됩니다(보통 3개의 오류 메시지가 함께 기록됩니다). 다음과 같은 오류 메시지가 발생했다고 해서 반드시 SQL Server 리소스가 실패한 것으로 처리되어 SQL Server가 재시작되거나 그룹 이동되는 것은 아닙니다. 다음의 메시지는 IsAlive 체크가 실패하였음을 의미하는 것이 아니라 sqsrvres.dll(SQL Server Cluster Resource DLL)에서 독립적인 스레드에 의해 60초마다 실행되는 쿼리문이 실패하였음을 의미하는 것이기 때문입니다. 오류 메시지에 보면 '[sqsrvres]'라는 태그가 붙어 있는 특징을 발견할 수 있는데 이는 오류 메시지를 발생시킨 주체가 sqsrvres.dll임을 의미하는 것입니다.  

오류 2010-05-04 오후 5:40:16 MSSQLSERVER 19019 장애 조치(Failover) "[sqsrvres] CheckQueryProcessorAlive: sqlexecdirect failed"
오류 2010-05-04 오후 5:40:16 MSSQLSERVER 19019 장애 조치(Failover) "[sqsrvres] printODBCError: sqlstate = HYT00; native error = 0; message = [Microsoft][SQL Server Native Client 10.0]쿼리 제한 시간이 만료되었습니다."
오류 2010-05-04 오후 5:40:16 MSSQLSERVER 19019 장애 조치(Failover) "[sqsrvres] onlineThread: QP is not online."

 

IsAlive 체크가 실패하게 되면 클러스터 서비스는 SQL Server 리소스가 실패한 것으로 판단하여 필요한 조치를 취하게 되는데, 이때 무조건 Passive 노드로 그룹 이동이 수행되는 것은 아닙니다. SQL Server 리소스가 실패하면 우선 현재의 노드에서 한번(Windows Server 2008 클러스터 기본 값이며 Windows Server 2003 클러스터에서는 3번까지) 재시작 시도를 하게 됩니다. 현재의 노드에서 한번의 재시작 시도가 실패하게 되면 Passive 노드로 그룹 이동이 수행됩니다.

 

SQL Server 리소스 속성에서 '정책' 탭을 클릭하면 다음과 같이 SQL Server 리소스가 실패했을 때의 동작 방식에 대한 설정 값들을 확인 및 변경할 수 있습니다. 다음의 화면에서 '다시 시작 기간(mm:ss)'이 15분, '지정된 기간 내의 최대 다시 시작 횟수'가 1로 설정되어 있음을 볼 수 있는데 이 설정 값으로 인해 15분의 기간 동안 최대 한번의 재시작 시도를 우선적으로 수행하게 됩니다. 예를 들어, 한번의 재시작 시도로 인해 SQL Server 리소스가 온라인된 이후에 15분이 경과하지 않은 상태에서 또다시 SQL Server 리소스가 실패했을 때에는 현재의 노드에서 재시작을 시도하지 않고 곧바로 Passive Node로의 그룹 이동을 수행합니다. 다음의 화면에서 '다시 시작이 실패할 경우 이 서비스 또는 응용 프로그램의 모든 리소스를 장애 조치(failover)합니다' 항목이 체크되어 있음을 볼 수 있는데 이로 인해 현재 노드에서 재시작이 실패할 경우 Passive 노드로의 그룹 이동이 수행됩니다.