워터마크
고친 사람 github-actions[bot]
워터마크는 스트림 처리 엔진에게 「이 시각까지 일어난 일은 거의 다 도착했다」고 알려 줍니다. 엔진은 이 신호를 보고 시간 구간을 닫습니다. 그리고 그 구간의 결과를 냅니다. 늦게 오는 데이터를 언제까지 기다릴지 정하는 기준인 셈입니다. 메모리 관리나 이미지 보호에서도 같은 이름을 쓰지만 가리키는 것이 다릅니다.
쉽고 빠른 이해
무슨 일을 하나 — 엔진에게 「이 시각까지의 데이터는 거의 다 왔다」고 알려 줍니다. 10시부터 10시 5분까지의 주문 수를 세는 중이라면, 워터마크가 10시 5분에 닿는 순간 엔진이 그 구간을 닫고 숫자를 냅니다.
왜 이렇게 하나 — 데이터는 일어난 순서대로 오지 않습니다. 폰이 잠깐 끊겼다 붙으면 몇 분 전 일이 이제야 옵니다. 마냥 기다리면 결과를 영영 못 냅니다. 바로 닫으면 늦게 온 것이 빠집니다. 워터마크가 그 사이에 「이만하면 됐다」는 선을 긋습니다.
어떻게 도나
- 엔진이 지금까지 받은 데이터의 시각을 보고 워터마크를 정합니다
- 워터마크는 앞으로만 갑니다
- 구간의 끝에 워터마크가 닿으면 그 구간의 결과를 냅니다
- 그 뒤에 온 데이터는 버리거나, 정해 둔 동안만 받아 결과를 고칩니다
언제 쓰나 — 데이터를 일이 일어난 시각 기준으로 구간에 나눌 때만 필요합니다. 엔진이 데이터를 받은 시각 기준으로 나누거나, 데이터를 다 모은 뒤 한 번에 돌린다면 필요 없습니다.
대가 — 짐작이라 틀릴 수 있습니다. 선을 일찍 그으면 결과가 일찍 나오는 대신 빠지는 데이터가 늘어납니다. 늦게 그으면 숫자가 맞아지는 대신 결과가 늦습니다. 기다리는 동안 데이터를 메모리에 쥐고 있어야 하기도 합니다.
상세
이 절은 먼저 스트림 처리에서 시각이 두 가지로 갈린다는 것부터 봅니다. 그 차이에서 「구간을 언제 닫나」라는 물음이 생깁니다. 워터마크가 그 물음에 답합니다.
그다음 작은 코드로 워터마크가 어떻게 정해지는지 따라갑니다. 뒤에서는 늦게 온 데이터를 다루는 방법과 입력이 여럿일 때의 규칙을 봅니다. 끝에서 이름이 같은 다른 워터마크를 표 하나로 가릅니다.
출석부를 닫는 시각
담임 선생님이 9시에 출석을 부릅니다. 버스가 늦은 학생이 있을 수 있으니 바로 출석부를 닫지 않습니다. 9시 10분쯤 되면 「9시까지 올 학생은 다 왔다」고 보고 그때 닫습니다.
워터마크는 이 판단 속의 「9시」에 해당합니다. 「이 시각까지의 데이터는 다 왔다」고 엔진이 판단하는 시각이 워터마크입니다. 9시와 9시 10분 사이의 10분은 늦는 학생을 기다려 주는 여유입니다.
끝없이 들어오는 데이터
스트림 처리는 끝없이 들어오는 데이터를 들어오는 대로 처리하는 방식입니다. 클릭 기록, 결제 기록, 센서 값처럼 멈추지 않고 쌓이는 데이터가 대상입니다. 이 일을 맡는 프로그램을 스트림 처리 엔진이라고 합니다.
하루치를 모아 한 번에 돌리는 배치 처리는 데이터를 다 모은 뒤에야 결과를 냅니다. 스트림 처리는 몇 초나 몇 분 안에 결과를 냅니다.
데이터에 끝이 없으니 「전체 합계」는 낼 수 없습니다. 그래서 시간을 구간으로 잘라 구간마다 결과를 냅니다. 이 구간을 윈도라고 부릅니다. 「10시부터 10시 5분까지의 주문 수」가 윈도 하나의 결과입니다.
윈도 안의 데이터를 세거나 더해 숫자 하나로 줄이는 일을 집계라고 부릅니다. 이 항목의 예는 전부 주문 수를 세는 집계입니다.
이벤트 시간과 처리 시간
데이터 한 건에는 시각이 둘 붙습니다. 일이 일어난 시각이 이벤트 시간입니다. 엔진이 그 데이터를 받아 처리한 시각이 처리 시간입니다. 처리 시간은 엔진의 시계로 잽니다.
두 시각은 자주 어긋납니다. 사용자가 지하철에서 10시 1분에 주문 버튼을 눌렀다고 합시다. 폰이 터널을 지나느라 10시 4분에야 기록을 보냈습니다. 그러면 이벤트 시간은 10시 1분, 처리 시간은 10시 4분입니다.
네트워크가 막히거나, 보내다 실패해 다시 보내거나, 서버 하나가 잠시 멈춰도 같은 일이 생깁니다. 그래서 데이터는 일어난 순서대로 도착하지 않습니다. 10시 3분의 일이 10시 1분의 일보다 먼저 올 수 있습니다.
윈도를 처리 시간으로 자르면 간단합니다. 엔진의 시계가 10시 5분을 가리킬 때 닫으면 됩니다. 대신 10시 1분에 눌린 버튼이 10시 6분에 도착하면 다음 윈도에 섞입니다. 일어난 시각대로 세려면 윈도를 이벤트 시간으로 잘라야 합니다.
윈도를 닫는 시점
이벤트 시간으로 자르면 물음 하나가 남습니다. 10시부터 10시 5분까지의 윈도를 언제 닫느냐입니다. 엔진의 시계가 10시 5분을 지나도 그 윈도의 데이터가 다 왔다는 보장이 없습니다.
닫는 시점은 두 실패 사이에 있습니다. 끝까지 기다리면 결과가 영영 안 나옵니다. 너무 일찍 닫으면 늦게 온 데이터가 빠져 숫자가 틀립니다.
이 물음은 윈도를 이벤트 시간으로 자를 때만 생깁니다. 처리 시간으로 자르거나, 데이터를 다 모은 뒤 한 번에 돌리는 배치 처리라면 워터마크가 필요 없습니다.
워터마크가 하는 일
워터마크는 이 물음에 답하는 시각 값입니다. 워터마크가 10시 5분이라는 것은 「이벤트 시간이 10시 5분보다 이른 데이터는 이제 거의 다 왔다」는 엔진의 판단입니다. 엔진은 데이터를 처리하는 동안 이 값을 계속 앞으로 옮깁니다.
윈도는 워터마크가 자기 끝에 닿으면 닫힙니다. 워터마크가 10시 5분에 닿거나 넘으면 10시부터 10시 5분까지의 윈도가 결과를 냅니다. 엔진의 시계, 곧 처리 시간이 몇 시인지는 상관이 없습니다.
워터마크는 뒤로 가지 않습니다. 한번 「10시 5분 이전은 다 왔다」고 했으면 그 판단을 무르지 않습니다. 뒤로 가면 이미 닫고 결과를 낸 윈도를 다시 열어야 하기 때문입니다.
워터마크는 짐작입니다. 데이터를 보내는 쪽이 시각 순서를 지켜 보낸다면 워터마크를 틀림없이 정할 수 있습니다. 그렇게 보내 주는 쪽은 드물어서 대개 지금까지 받은 데이터를 보고 짐작합니다.
짐작이 틀리면 워터마크가 지나간 뒤에 데이터가 도착합니다. 이런 데이터를 늦은 데이터라고 부릅니다. 이미 결과를 낸 윈도에 속하는 데이터라 따로 다룰 방법이 있어야 합니다.
Apache Beam과 Apache Flink 같은 스트림 처리 엔진이 이 개념을 갖추고 있습니다.
워터마크를 정하는 법
흔한 방법은 「지금까지 본 가장 큰 이벤트 시간에서 일정한 여유를 뺀다」입니다. 여유가 5초면 「지금까지 본 가장 나중 일보다 5초 넘게 앞선 데이터는 더 안 온다」고 보는 셈입니다. 여유는 데이터가 평소 얼마나 뒤처져 도착하는지를 보고 사람이 정합니다.
아래 코드는 이 방법을 옮긴 것입니다. 시각은 초 단위 숫자로 적었습니다. 여유는 5초입니다. 각 줄의 주석이 그 데이터를 받은 뒤의 워터마크입니다.
DELAY = 5 # 기다려 줄 여유(초)
max_seen = 0
def on_event(t):
global max_seen
max_seen = max(max_seen, t)
return max_seen - DELAY
on_event(100) # 95
on_event(103) # 98
on_event(101) # 98
on_event(110) # 105
on_event(102) # 105
세 번째로 온 101 은 103 다음에 도착했지만 일어난 것은 먼저입니다. 가장 큰 이벤트 시간이 여전히 103 이라 워터마크는 98 에 머뭅니다. 101 은 워터마크 98 보다 뒤라 늦은 데이터가 아닙니다. 여유 5초가 이런 뒤바뀜을 받아 줍니다.
마지막 102 는 사정이 다릅니다. 110 을 받은 뒤 워터마크는 이미 105 로 올라갔습니다. 102 는 워터마크보다 이르니 늦은 데이터입니다. 100 부터 105 까지를 세는 윈도가 있었다면 워터마크가 그 끝 105 에 닿았으니 이미 결과를 냈습니다.
여유의 길이
여유를 얼마로 잡느냐가 워터마크의 성격을 정합니다. 결과를 일찍 내는 것과 숫자를 맞추는 것이 서로 당기기 때문입니다. 아래 표가 두 끝을 나란히 놓습니다.
| 여유가 짧으면 | 여유가 길면 | |
|---|---|---|
| 결과가 나오는 때 | 이르다 | 늦다 |
| 늦은 데이터 | 많아진다 | 줄어든다 |
| 엔진이 쥐고 있는 데이터 | 적다 | 많다 |
셋째 줄은 메모리 이야기입니다. 엔진은 닫히지 않은 윈도마다 지금까지 센 주문 수 같은 중간 값을 들고 있어야 합니다. 여유가 길면 열린 윈도가 오래 남아 그만큼 메모리를 씁니다.
늦은 데이터를 다루는 법
워터마크가 짐작인 이상 늦은 데이터는 언젠가 옵니다. 그래서 그 데이터를 어떻게 할지 미리 정해 둡니다. 이 소절은 흔한 선택 셋을 봅니다. 이어서 데이터 한 건이 도착했을 때 엔진이 거치는 판단을 그림으로 봅니다.
윈도가 닫힌 뒤에도 늦은 데이터를 받아 주는 기간을 허용 지연이라고 부릅니다. 허용 지연을 10분으로 두면 워터마크가 윈도 끝을 10분 넘어설 때까지 늦은 데이터를 더 받습니다. 이 10분은 엔진의 시계가 아니라 워터마크로, 곧 이벤트 시간으로 잽니다.
| 방법 | 하는 일 | 대가 |
|---|---|---|
| 버린다 | 결과를 한 번만 낸다 | 늦게 온 만큼 숫자가 모자란다 |
| 허용 지연 동안 받는다 | 늦은 데이터가 올 때마다 고친 결과를 다시 낸다 | 받는 쪽이 같은 윈도의 결과를 여러 번 받는다 |
| 따로 빼 둔다 | 늦은 데이터만 다른 곳에 모은다 | 나중에 맞춰 넣는 일을 따로 짜야 한다 |
결과를 언제 몇 번 내보낼지는 트리거가 정합니다. 워터마크가 윈도 끝에 닿을 때 한 번 내는 것이 흔한 기본값입니다.
아래 그림은 허용 지연을 둔 엔진이 데이터 한 건을 받았을 때 거치는 판단입니다. 표의 둘째 줄(허용 지연 동안 받는다)에, 그 기간이 지나면 버리는 경우를 더해 그렸습니다. 따로 빼 두는 방법을 쓰면 맨 아래 「버린다」 대신 다른 곳에 모읍니다.
flowchart TD
A["데이터 한 건이 도착한다"] --> B{"속한 윈도가 아직 열려 있나"}
B -->|예| C["윈도에 더한다"]
B -->|아니오| D{"워터마크가 윈도 끝 + 허용 지연에 아직 안 닿았나"}
D -->|예| E["더한 뒤 고친 결과를 다시 낸다"]
D -->|아니오| F["버린다"]
입력이 여럿일 때
스트림은 대개 여러 갈래로 나뉘어 들어옵니다. 데이터를 나눠 담은 갈래 하나를 파티션이라고 부릅니다. 파티션마다 데이터가 오는 속도가 다르니 워터마크도 파티션마다 따로 갑니다.
여러 파티션을 합쳐 받는 처리 단계는 그중 가장 이른 워터마크를 자기 워터마크로 삼습니다. 가장 앞선 값을 따르면 뒤처진 파티션에서 오는 데이터가 전부 늦은 데이터가 되기 때문입니다.
flowchart TD
subgraph 입력
P1["파티션 1 · 워터마크 10시 7분"]
P2["파티션 2 · 워터마크 10시 9분"]
P3["파티션 3 · 워터마크 10시 3분"]
end
P1 --> M["가장 이른 값을 고른다"]
P2 --> M
P3 --> M
M --> W["합쳐 받는 단계의 워터마크 · 10시 3분"]
그림에서 파티션 3 이 10시 3분에 머물러 있으니 합쳐 받는 단계도 10시 3분입니다. 파티션 1 과 2 가 앞서 가도 10시 5분에 끝나는 윈도는 아직 닫히지 않습니다.
이 규칙에는 대가가 따릅니다. 데이터가 한동안 안 들어오는 파티션이 하나 있으면 그 파티션의 워터마크가 멈춥니다. 그러면 전체 결과도 같이 멈춥니다. 그래서 엔진들은 조용한 파티션을 계산에서 잠시 빼는 설정을 두기도 합니다.
이름이 같은 다른 워터마크
「워터마크」는 본래 종이에 비쳐 보이게 넣은 무늬를 가리킵니다. 개발에서도 몇 군데서 이 이름을 씁니다. 가리키는 것은 서로 다릅니다. 이 항목이 다룬 것은 아래 표의 첫 줄 뜻입니다.
| 맥락 | 가리키는 것 |
|---|---|
| 스트림 처리 | 이 시각 이전의 데이터는 거의 다 왔다는 추정 시각 |
| 메모리 관리 | 남은 메모리 양에 그어 둔 기준선. 그 아래로 떨어지면 운영체제가 쓰지 않는 메모리를 거둬들이는 페이지 회수를 시작한다 |
| 버퍼 | 쌓인 양에 그어 둔 기준선. 넘으면 보내는 쪽에 잠시 멈추라고 알리는 배압이 걸린다 |
| 증분 처리 | 지난번 실행이 어디까지 처리했는지 적어 둔 끝 값. 하이 워터마크라고 부른다 |
| 이미지 · 영상 | 저작권자를 밝히려고 콘텐츠에 넣는 표식. 디지털 워터마크라고 부른다 |
이 가운데 스트림 처리의 워터마크와 증분 처리의 하이 워터마크가 가장 섞이기 쉽습니다. 둘 다 데이터 파이프라인에서 「어디까지 왔나」를 나타내는 값이기 때문입니다. 앞의 것은 엔진이 데이터를 받으며 짐작하는 이벤트 시간입니다. 뒤의 것은 처리를 마친 뒤 적어 두는 기록입니다.
관련 항목
워터마크가 기준으로 삼는 시간 개념
이벤트 시간 · 처리 시간 · 스트림 시간 · 벽시계 시간
워터마크가 닫는 윈도의 종류
윈도 · 고정 윈도 · 텀블링 윈도 · 슬라이딩 윈도 · 세션 윈도
워터마크 뒤에 도착한 데이터를 다루는 수단
늦은 데이터 · 허용 지연 · 트리거 · 유예 기간 · 사이드 출력
워터마크와 함께 스트림 집계를 이루는 구성 요소
집계 · 상태 저장 처리 · 파티션 · 체크포인트 · 정확히 한 번
워터마크를 갖춘 스트림 처리 엔진
Apache Beam · Apache Flink · Apache Spark · Spark Structured Streaming · Google Cloud Dataflow
워터마크가 속하는 상위 분류
스트림 처리 · 이벤트 스트림 · 데이터 엔지니어링 · 실시간 분석
스트림 처리와 맞세워지는 처리 방식
배치 처리 · 마이크로 배치 · 람다 아키텍처 · 카파 아키텍처
워터마크와 이름이 겹치는 다른 뜻
하이 워터마크 · 메모리 워터마크 · 디지털 워터마크 · 페이지 회수 · 배압
다른 이름: watermark · 이벤트 시간 워터마크 · event-time watermark · 스트림 워터마크