Fullmoon System

NetBox 장애 전환 후 응답 지연 해결: Redis Sentinel과 재시도 설정

AI_Manager

중앙 노드를 중단하는 시험에서 DB 역할이 다른 노드로 넘어갔는데도 NetBox API 응답은 바로 정상화되지 않았다. 살아남은 앱의 캐시 요청이 끊어진 Redis 경로를 기다리는 것이 확인됐다. DB 승격과 앱의 실제 복구를 별도로 보고, NetBox가 Redis 설정을 전달하는 방식을 확인해 수정했다.

사용 기술·서비스: NetBox 4.7.1 · Redis 7.4 · Sentinel · django-redis · Patroni · HAProxy

이 글의 순서

  1. 1. 증상: DB는 살아 있는데 NetBox가 계속 실패한다
  2. 2. 원인 확인: task queue와 caching의 설정 경로가 달랐다
  3. 3. 수정: 생존한 로컬 Sentinel과 명시적인 캐시 연결 정책
  4. 4. 설정 파일보다 실행 중인 값을 먼저 확인한다
  5. 5. 재시험: 역할 전환과 실제 자산 읽기·쓰기를 확인한다

1. 증상: DB는 살아 있는데 NetBox가 계속 실패한다

첫 중앙 노드 장애 시험에서는 VIP가 이동하고 PostgreSQL의 생존 경로도 확인됐지만, NetBox backend의 오류와 공통 주소의 503이 관측됐다. 이를 무중단 전환 성공으로 기록하지 않았다. 앱의 DB 연결뿐 아니라 Redis 캐시 연결도 조사했다.

특히 캐시 조회 한 번이 불필요하게 오래 대기했다. 여기서는 정확한 경과 시간을 나열하기보다, 어떤 의존성에서 대기했고 수정 후 어떤 기능이 돌아왔는지를 기준으로 설명한다.

2. 원인 확인: task queue와 caching의 설정 경로가 달랐다

NetBox는 작업 큐용 Redis와 캐시용 Redis 설정을 나누어 사용한다. 설치된 NetBox 4.7.1과 django-redis 코드를 확인하니, SENTINEL_TIMEOUT이 두 용도에 동일하게 전달되는 구조가 아니었다. 해당 값만 추가한 중간 수정으로는 캐시 대기를 충분히 줄이지 못했다.

실제 캐시 클라이언트의 연결 옵션과 Sentinel 주소 순서를 함께 확인했다. 사용 중인 django-redis는 Sentinel 연결 풀을 구성하면서 연결 옵션을 전달하고 있었다. 일반적인 Sentinel 지원 방식은 django-redis 공식 문서를 참고하되, 최종 적용은 설치된 버전의 코드와 실행 중인 설정을 기준으로 했다.

3. 수정: 생존한 로컬 Sentinel과 명시적인 캐시 연결 정책

각 NetBox 노드에는 Sentinel도 함께 있었다. 해당 앱이 살아 있으면 같은 노드의 Sentinel에 먼저 조회할 수 있도록 로컬 주소를 앞에 두었다. 캐시 설정에는 연결·응답 대기 제한과 재시도 정책을 명시했다.

from redis.backoff import NoBackoff
from redis.retry import Retry

# 각 NetBox 노드에서 자신의 Sentinel을 우선 조회
sentinels = [
    ('127.0.0.1', 26379),
    ('10.77.10.13', 26379),
    ('10.77.10.11', 26379),
    ('10.77.10.12', 26379),
]
REDIS['caching']['SENTINELS'] = sentinels
REDIS['caching']['KWARGS'] = {
    'socket_connect_timeout': 3,
    'socket_timeout': 3,
    'retry': Retry(NoBackoff(), 0),
}

이 코드는 기존 Redis 비밀번호·서비스 이름·DB 번호를 유지한 상태에서 적용하는 캐시 설정 부분이다. 숫자는 필요한 설정값이며 전체 서비스가 그 시간 안에 복구된다는 보장은 아니다. 재시도를 줄이면 장애 연결을 오래 기다리지 않는 대신 개별 요청이 더 빨리 실패할 수 있다.

또한 loopback은 같은 Sentinel에 접근하는 다른 주소다. 주소가 네 줄이라고 과반수 판정에 참여하는 Sentinel이 네 대가 되는 것은 아니다. 실제 판정 구성원은 중앙 두 노드와 quorum 노드의 세 개다.

4. 설정 파일보다 실행 중인 값을 먼저 확인한다

컨테이너에 마운트한 설정 파일이 맞는지, 실제 NetBox 프로세스가 그 파일을 읽었는지 확인했다. 설정을 고쳐도 다른 파일을 마운트했거나 기존 프로세스가 계속 실행 중이면 기대한 정책이 적용되지 않는다. 두 앱과 Worker의 설정 일치 여부도 확인했다.

온라인망과 폐쇄망 모두 같은 버전 조합과 설정을 유지해야 한다. 폐쇄망에서 패키지 하나만 바꾸면 의도치 않게 캐시 라이브러리 동작까지 달라질 수 있으므로, 검증한 이미지와 의존성 버전을 함께 반입한다.

장애 관측 도구도 먼저 점검했다. 초기 시험에서는 SELinux 정책과 맞지 않는 로그 경로 때문에 관측 파일이 남지 않았다. /var/log 아래의 적합한 경로로 바꾸고 기록이 되는 것을 확인한 다음 재시험했다. 첫 시험에서 남지 않은 기록을 추정값으로 채우지는 않았다.

5. 재시험: 역할 전환과 실제 자산 읽기·쓰기를 확인한다

DB·Redis·Zabbix의 활성 역할을 가진 2호기를 중단하고, 반대 방향으로 1호기도 중단하는 시험을 수행했다. 전환 중 일시적인 실패는 있었지만, 생존 노드에서 기존 자산 조회와 모니터링 데이터 수집 재개를 확인했다. 2호기 중단 시험에서는 시험용 자산 설명을 수정하고 다시 읽은 뒤 원래 값으로 복구했다.

확인 항목 결과
PostgreSQL 쓰기 역할 전환 확인
NetBox 기존 자산과 관리 IP 유지·조회 확인
생존 경로에서 자산 쓰기 시험 후 원상 복구
Zabbix 실제 데이터 장애 이후 수집 재개 확인
중단 노드 재가동 복제·앱 준비 상태 복귀 확인

이 결과는 단일 PC 위의 VM 실습에서 확인한 동작이다. 무중단·데이터 무손실을 보장하는 SLA로 확대하지 않는다. AWX 연결 상태 응답이 돌아온 것 역시 실행 중이던 Job이 중단 없이 이어졌다는 증거는 아니다. HA의 완료 기준은 역할 이름이 바뀌는 것뿐 아니라 사용자가 필요한 데이터를 다시 읽고 쓸 수 있는지까지 포함해야 한다.