본문으로 건너뛰기

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

· 약 2분

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

스트림 보관 기간(max_age)은 소비자가 메시지를 가져가는 주기보다 넉넉히 길게 잡습니다. 이 값이 짧으면 소비자가 오기 전에 메시지가 만료되어 사라집니다.

분명히 발행했는데 소비 쪽에는 아무것도 도착하지 않는 사고가 대개 여기서 납니다.

JetStream 스트림과 보관 정책(retention policy)​

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 를 소비 주기보다 짧게 잡으면​

  • 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를 함께 두면 가장 먼저 도달한 한도가 적용됩니다.

참고자료​