스트림 처리에서 가장 중요한 개념. 대부분의 스트림 애플리케이션이 시간 윈도우에 대해 작업하므로, 시간이 무엇을 뜻하는지 공통 개념을 갖는 것이 필수다.

이벤트 시간, 로그 추가 시간, 처리 시간

언제신뢰성
이벤트 시간이벤트가 발생해 레코드가 생성된 시점대부분의 경우 가장 중요하다
로그 추가 시간이벤트가 카프카 브로커에 저장된 시점이벤트 시간의 합리적 근사값
처리 시간애플리케이션이 연산하려고 이벤트를 받은 시점매우 낮다. 피하는 것이 좋다

이벤트 시간은 카프카 0.10.0부터 프로듀서가 레코드를 만들 때 현재 시각을 자동으로 넣어준다. 애플리케이션의 이벤트 시간 개념과 일치하지 않는다면 레코드에 이벤트 시간 필드를 따로 추가해서 두 시간을 모두 활용하는 편이 권장된다.

로그 추가 시간은 접수 시간이라고도 한다. 레코드가 생성된 다음부터는 변하지 않으므로 이벤트 시간이 기록되지 않은 경우 일관성 있는 기준이 된다.

처리 시간은 이벤트 발생 후 몇 밀리초일 수도, 며칠 뒤일 수도 있다. 같은 이벤트라도 언제 읽었느냐에 따라 전혀 다른 타임스탬프가 붙고 애플리케이션 안에서도 스레드마다 다르다.

카프카 스트림즈는 TimestampExtractor 인터페이스로 각 이벤트에 시간을 부여한다. 구현체를 바꿔서 셋 중 하나를 고르거나, 이벤트 내용에서 타임스탬프를 뽑아내는 완전히 다른 개념을 쓸 수도 있다.

결과 레코드의 타임스탬프

스트림즈가 결과를 토픽에 쓸 때 타임스탬프를 정하는 규칙도 정해져 있다. 입력 레코드에 직접 대응하는 결과는 입력과 동일한 타임스탬프를 쓴다. 집계의 결과는 집계에 쓰인 레코드들의 최대값이다. 두 스트림을 조인한 결과는 두 타임스탬프 중 큰 쪽이고, 스트림과 테이블을 조인한 결과는 스트림 쪽의 타임스탬프다. punctuate()처럼 입력과 무관하게 스케줄로 생성된 결과는 애플리케이션의 현재 내부 시각을 따른다.

시간대 표준화

전체 데이터 파이프라인이 표준화된 시간대 하나를 쓰지 않으면 스트림 작업의 결과가 의미를 잃는다. 서로 다른 시간대의 스트림을 다뤄야 한다면 윈도우 작업 전에 하나의 시간대로 변환해야 하고, 아예 레코드에 시간대 정보를 저장해 넣는 경우도 많다.

비순차 이벤트

비순차 이벤트도 생각보다 자주 발생한다. 몇 시간 동안 연결이 끊겼던 기기가 재접속하면 몇 시간 치 이벤트를 한꺼번에 보낸다. 네트워크 장비 모니터링이나 제조업 현장에서 흔하다. 이것을 처리하려면 네 가지가 필요하다.

  1. 이벤트가 순서를 벗어났음을 알아야 한다. 이벤트 시간이 현재보다 이전인지 확인할 수 있어야 한다
  2. 복구할 시간 영역을 정해야 한다. N시간까지는 복구하고, N주 이상 오래된 것은 포기한다
  3. 순서를 복구하기 위해 이벤트를 묶을 수 있어야 한다
  4. 결과를 변경할 수 있어야 한다

3번이 배치와의 결정적 차이다. 배치 작업은 어제 것을 다시 돌리면 되지만 스트림에는 그런 개념이 없다. 계속 돌아가는 하나의 프로세스가 오래된 이벤트와 새 이벤트를 동시에 처리해야 한다. 4번도 현실적인 제약이다. DB에 쓰는 결과라면 update로 충분하지만 이메일로 보냈다면 변경이 곤란하다.

늦게 온 이벤트의 반영

카프카 스트림즈는 결과 토픽에 로그 압착을 걸어두는 것으로 이 문제를 푼다. 각 키의 마지막 값만 유지되므로, 늦게 도착한 이벤트로 집계 결과가 바뀌어야 하면 그냥 새 결과값을 써서 기존 값을 대체한다. 프레임워크 쪽에서는 로컬 상태에 다수의 집계 윈도우를 변경 가능한 상태로 유지하고, 개발자가 얼마나 오래 유지할지 정하게 한다. 오래 유지할수록 메모리를 더 쓴다.

관련

출처