본문으로 건너뛰기

NATS JetStream 스트림 보관 정책 이해하기

· 약 4분

NATS JetStream 스트림이 메시지를 언제까지 보관하고 언제 지우는지, 그리고 보관 기간을 잘못 잡으면 어떤 일이 생기는지 정리합니다.

결론부터 말하면, 스트림 보관 기간(max_age)은 소비자가 메시지를 가져가는 주기보다 넉넉히 길게 잡아야 합니다. 짧으면 소비하기도 전에 메시지가 지워집니다.

JetStream 스트림과 보관 정책이란

JetStream 스트림은 NATS가 메시지를 디스크에 저장해 두는 저장소입니다. 일반 NATS는 메시지를 흘려보내고 끝이지만, JetStream은 스트림에 쌓아 두고 소비자가 나중에 가져갈 수 있게 합니다.

보관 정책(retention policy)은 이 쌓인 메시지를 언제 지울지를 정하는 규칙입니다. 모든 메시지를 영원히 둘 수는 없으므로, 스트림마다 지우는 기준이 필요합니다.

보관 정책 세 가지

NATS JetStream 보관 정책 세 가지와 메시지가 지워지는 조건

NATS JetStream의 보관 정책은 세 가지입니다.

정책메시지를 지우는 시점쓰는 곳
Limits (기본)한도(개수·용량·기간)에 도달하면 오래된 것부터여러 소비자가 같은 메시지를 각자 읽는 경우
Interest관심 있는 모든 소비자가 ack하면구독자 모두 처리한 뒤 비워도 될 때
WorkQueue소비자 하나가 ack하면 즉시작업 큐(한 메시지를 한 번만 처리)

대부분은 Limits를 씁니다. 이때 "한도"를 어떻게 잡느냐가 핵심입니다.

메시지는 언제 지워지나 (Limits 정책)

Limits 정책에서는 다음 세 한도 중 하나라도 넘으면 오래된 메시지부터 지워집니다.

  • max_msgs: 최대 메시지 개수
  • max_bytes: 최대 용량
  • max_age: 최대 보관 기간(메시지의 수명)

여기서 가장 사고가 잦은 것이 max_age입니다. 소비자가 가져가는 주기보다 짧게 잡으면, 가져가기도 전에 메시지가 만료되어 사라집니다.

max_age가 소비 주기보다 짧으면 소비 전에 삭제되고, 길면 소비 후 만료되어 안전하다

스트림 설정 방법

스트림을 만들 때 StreamConfig에 정책과 한도를 지정합니다.

from nats.js.api import StreamConfig, RetentionPolicy

config = StreamConfig(
name="MY_STREAM",
subjects=["my-service.>"],
retention=RetentionPolicy.LIMITS, # 기본
max_age=14 * 24 * 60 * 60, # 14일 (초 단위), 소비 주기보다 길게
# max_msgs, max_bytes 도 함께 둘 수 있음
)
await js.add_stream(config)

max_age소비자가 메시지를 가져가는 주기보다 넉넉히 잡습니다. 하루 한 번 모아 가는 소비자가 있다면, 하루로 잡지 말고 며칠 이상 두는 식입니다.

흔한 함정

  • max_age를 소비 주기보다 짧게: 소비 전에 메시지가 삭제됩니다. 발행도 삭제도 정상 동작이라 오류 로그가 남지 않아 찾기 어렵습니다. (이 사고를 직접 겪은 이야기는 회고 글에 적었습니다.)
  • CLI로 임시 변경: nats stream edit로 바꿔도, 서비스가 코드의 StreamConfig로 스트림을 다시 갱신하면 코드값으로 되돌아갑니다. 영구 변경은 코드에서 합니다.
  • 스트림마다 제각각 보관 기간: 팀에서 1d/7d/30d를 임의로 섞으면 실수가 납니다. 공통 상수 하나로 고정하는 편이 안전합니다.

Q&A

  • max_age와 소비자(consumer)의 ack는 무슨 관계인가요?
    • Limits 정책에서는 무관합니다. 소비자가 ack하지 않아도 max_age가 지나면 지워집니다. ack 기반으로 지우려면 Interest나 WorkQueue 정책을 씁니다.
  • 메시지를 잃지 않으려면 어떻게 하나요?
    • 소비 주기보다 max_age를 길게 두고, 처리 실패분은 별도 DLQ(데드레터) 스트림으로 보냅니다. DLQ는 보통 보관 한도를 두지 않습니다.
  • 한도를 여러 개 동시에 걸 수 있나요?
    • 네. max_msgs, max_bytes, max_age를 함께 두면 가장 먼저 도달한 한도가 적용됩니다.

참고자료

  • NATS Docs: JetStream Streams / Retention Policies
  • NATS Docs: nats stream add / StreamConfig