/인프라/Elasticsearch FORBIDDEN/12 index read-only 에러 5분 복구 가이드
인프라ElasticsearchOpenSearch

Elasticsearch FORBIDDEN/12 index read-only 에러 5분 복구 가이드

Elasticsearch/OpenSearch에서 FORBIDDEN/12 index read-only, cluster_block_exception으로 쓰기가 막혔다면 디스크 워터마크(flood_stage 95%) 초과가 원인입니다. 복붙용 curl·Kibana 명령으로 5분 만에 진단·복구하세요.

Elasticsearch FORBIDDEN/12 index read-only 에러 5분 복구 가이드

Elasticsearch FORBIDDEN/12 index read-only 에러 5분 복구 가이드

새벽에 알림이 울립니다. 애플리케이션 로그에는 이런 메시지가 도배되고 있습니다.

CODE
ClusterBlockException[index [logs-2026.06.14] blocked by:
[TOO_MANY_REQUESTS/12/disk usage exceeded flood-stage watermark,
index has read-only-allow-delete block];]

또는 클라이언트 측에서는 이렇게 보일 겁니다.

CODE
FORBIDDEN/12/index read-only / allow delete (api)

색인(인덱싱)이 전부 막혔고, 검색은 되는데 쓰기만 죽었습니다. 결론부터 말하면 열에 아홉은 디스크 워터마크 flood_stage(95%) 초과가 범인입니다. 이 글은 "지금 장애 중인 운영자"를 기준으로, 상단에 응급 복구 명령을 배치하고 아래에서 근본 원인 제거까지 다룹니다.

응급 흐름도: 지금 당장 뭐부터?

CODE
[쓰기 막힘] 
   │
   ├─ 1. 디스크 사용률 확인 (GET _cat/allocation?v)
   │       └─ 95% 넘었나? → 거의 확정: flood_stage 자동 차단
   │
   ├─ 2. 디스크 먼저 확보 (오래된 인덱스 삭제 / 볼륨 증설)
   │
   ├─ 3. read_only_allow_delete 블록 해제
   │
   └─ 4. 모니터링·알림·ILM 설정으로 재발 방지

⚠️ 순서가 핵심입니다. 디스크를 확보하지 않고 블록만 풀면 워터마크 체크 주기(기본 30초)에 곧바로 다시 차단됩니다. 아래에서 다시 강조하겠습니다.

5분 진단: 에러 원문 → 원인 분류표

에러 코드의 숫자가 원인을 알려줍니다. 먼저 이 표로 어떤 종류의 차단인지 분류하세요.

에러 원문트리거해제 키비고
FORBIDDEN/12 index read-only / allow delete (api)디스크 자동 (flood_stage 초과)index.blocks.read_only_allow_delete가장 흔함. 삭제는 허용
FORBIDDEN/8 index write (api)수동/스냅샷 복구 등 쓰기 차단index.blocks.write쓰기만 막힘
FORBIDDEN/5 index read-only (api)수동 읽기전용 설정index.blocks.read_only운영자가 직접 건 경우
cluster_block_exception ... no master클러스터 레벨 블록마스터/노드 상태 복구디스크 외 원인일 수 있음

진단 명령은 curl과 Kibana DevTools 양쪽으로 제공합니다.

curl 버전

Bash
# 노드별 디스크 사용률 (가장 중요)
curl -s "localhost:9200/_cat/allocation?v"

# 클러스터 상태
curl -s "localhost:9200/_cluster/health?pretty"

# 어떤 인덱스에 read_only 블록이 걸렸는지 확인
curl -s "localhost:9200/_all/_settings?flat_settings=true&filter_path=**.read_only*&pretty"

Kibana DevTools 버전

CODE
GET _cat/allocation?v
GET _cluster/health
GET _all/_settings?flat_settings=true&filter_path=**.read_only*

_cat/allocationdisk.percent 컬럼이 95를 넘었다면 진단 끝입니다. flood_stage 자동 차단입니다.

디스크 워터마크 3단계, 이렇게 동작한다

Elasticsearch/OpenSearch는 노드 디스크 사용률을 3단계로 감시합니다.

단계기본값동작
low85%새 샤드를 이 노드에 할당하지 않음
high90%기존 샤드를 다른 노드로 이동 시도
flood_stage95%해당 노드의 모든 인덱스에 read_only_allow_delete 자동 적용

핵심은 flood_stage입니다. 95%를 넘는 순간 데이터 손실(디스크 풀로 인한 인덱스 깨짐)을 막기 위해 ES가 스스로 쓰기를 차단합니다. 이름 그대로 읽기와 삭제는 되지만 새 문서 색인은 막힙니다. 즉 이건 버그가 아니라 보호 장치입니다.

즉시 복구: 쓰기 차단 해제

다시 강조합니다. 반드시 디스크를 먼저 확보한 뒤 아래 명령을 실행하세요.

curl 버전

Bash
curl -X PUT "localhost:9200/_all/_settings" \
  -H 'Content-Type: application/json' -d '
{
  "index.blocks.read_only_allow_delete": null
}'

Kibana DevTools 버전

CODE
PUT _all/_settings
{
  "index.blocks.read_only_allow_delete": null
}

null로 설정하면 명시적으로 걸린 블록이 제거됩니다(false보다 null을 권장 — 자동 관리 상태로 되돌립니다). 해제 후 다시 GET _cluster/health로 색인이 정상화됐는지 확인하세요.

💡 실무 팁: 저는 장애 대응 때 항상 _cat/allocation을 먼저 띄워놓고 디스크 % 가 90 아래로 떨어지는 걸 눈으로 확인한 다음 해제 명령을 칩니다. 디스크를 안 비우고 해제부터 하면, 명령은 성공 응답을 주는데 30초 뒤 또 막혀서 "왜 안 풀리지?"로 시간을 날리게 됩니다. 이게 가장 흔한 함정입니다.

근본 원인 제거 & 디스크 확보 실전

1) 무엇이 디스크를 먹고 있나

Bash
# 데이터 디렉터리에서 용량 큰 것부터
du -sh /var/lib/elasticsearch/* | sort -rh | head
df -h

2) 오래된 인덱스 삭제 (즉효약)

로그성 데이터라면 오래된 날짜 인덱스가 대부분 용량을 차지합니다.

CODE
# 와일드카드로 과거 인덱스 일괄 삭제
DELETE logs-2024.*

삭제 직후 디스크가 비워지고, 위 해제 명령을 실행하면 곧바로 쓰기가 복구됩니다.

3) ILM/롤오버로 자동화 (재발 방지)

수동 삭제는 임시방편입니다. ILM(Index Lifecycle Management) 정책으로 자동 삭제를 걸어두세요.

CODE
PUT _ilm/policy/logs-policy
{
  "policy": {
    "phases": {
      "hot": {
        "actions": { "rollover": { "max_size": "50gb", "max_age": "1d" } }
      },
      "delete": {
        "min_age": "30d",
        "actions": { "delete": {} }
      }
    }
  }
}

OpenSearch에서는 ILM 대신 ISM(Index State Management) 으로 동일한 롤오버/삭제 정책을 구성합니다.

4) 워터마크 임계값 조정 (신중하게)

디스크 증설 전 임시로 임계값을 올려야 할 때가 있습니다. 단, 근본 해결이 아니라는 점을 기억하세요.

CODE
PUT _cluster/settings
{
  "transient": {
    "cluster.routing.allocation.disk.watermark.low": "90%",
    "cluster.routing.allocation.disk.watermark.high": "95%",
    "cluster.routing.allocation.disk.watermark.flood_stage": "97%"
  }
}

작은 디스크에서는 % 대신 "50gb"처럼 절대값으로 지정하는 게 더 예측 가능합니다.

결론: 재발 방지 체크리스트

  • 디스크 사용률 알림을 워터마크보다 낮은 80%에 설정 (low 도달 전 인지)
  • ILM(ES) / ISM(OpenSearch)로 롤오버·자동 삭제 정책 적용
  • Data Tiers·Searchable Snapshot으로 콜드 데이터를 저비용 스토리지로 이전
  • 워터마크 설정값을 문서화하고 운영 환경별로 명시
  • 복구 순서(디스크 확보 → 해제 → 모니터링)를 런북에 기록

로그·관측성 데이터가 폭증하면서 디스크 포화는 ES/OpenSearch 운영자에게 가장 흔한 장애가 됐습니다. flood_stage는 적이 아니라 데이터를 지키는 마지막 방어선이라는 점, 그리고 "해제만으로는 안 풀린다"는 점만 기억하면 5분 안에 복구할 수 있습니다.

자주 묻는 질문 (FAQ)

Q. 읽기전용이라는데 디스크는 여유가 있습니다. 왜죠? A. 한 번 flood_stage를 넘으면 디스크가 다시 내려가도 블록이 자동으로 풀리지 않는 버전이 있습니다(특히 구버전 ES 7.x 이전). 디스크 확보 후 index.blocks.read_only_allow_delete: null 해제를 수동으로 실행해야 합니다. 또는 수동으로 read_only(FORBIDDEN/5)를 걸어둔 경우일 수도 있으니 settings를 확인하세요.

Q. 노드 일부만 차단된 것 같습니다. A. flood_stage는 노드 단위로 동작합니다. 특정 노드만 디스크가 꽉 차면 그 노드의 샤드를 가진 인덱스만 차단됩니다. _cat/allocation으로 노드별 사용률을 보고, 샤드 리밸런싱이나 해당 노드 디스크 정리를 진행하세요.

Q. AWS OpenSearch Service(매니지드)에서도 같나요? A. 동작 원리는 같지만 매니지드 환경에서는 SSH·df 접근이 막혀 있어 디스크를 직접 비울 수 없습니다. 콘솔의 스토리지 사용량을 확인하고, 인덱스 삭제 또는 노드 스토리지 증설(또는 인스턴스 확장)로 대응해야 합니다. UltraWarm·Cold Storage로 오래된 데이터를 옮기는 것이 근본 해결책입니다.

✦ ✦ ✦
편집 검토 · Editorial Review

이 글은 AI 에이전트가 1차 초안을 작성한 뒤, 사람 편집자가 사실관계·출처·톤과 맥락을 검토하여 발행했습니다. 오류나 부정확한 내용이 확인되면 24시간 이내에 정정합니다.

작성 · Content Reviewer·검토 · 사람 편집자·발행 · 2026년 6월 13일

댓글

불러오는 중...