2. Contents
• 00 intro
• Flink @KADP
• 01 interval join 과 친해지기
• interval join 훑어보기
• 조금 더 깊이 알아보기
• 02 실제 적용한 사례와 방법
• interval join 을 적용할 사례
• 왜 적용을 해보게 되었는지
• 적용 방법
• 03 예상치 못한 문제 발생과 해결 및 모니터링
• 트러블슈팅
• 모니터링 개선사항
• 04 앞으로..
• 한계와 할일
3. Flink
@KADP (Kakao Ad Data Pipeline)
• 실시간 대용량 이벤트 스트림 처리 (DataStream API)
• 클러스터 유휴 자원이 있는 한 자유롭게 rescale 가능
• 카프카로 받은 데이터를 여러 스토리지에 또는 큐에 저장하기 편리
Stream source
On
Stream sink
| 00 Intro
4. Flink Interval Join Overview
orangeElem.key == greenElem.key
&&
orangeElem.ts + lowerBound <= greenElem.ts <= orangeElem.ts + upperBound
• 두 개의 스트림을 하나로 조인하는 operator
• 두 input stream에서 element 의 키가 같고, 이벤트의 시간차이가 경계조건 안에 있으면
join 되어 다음 stream 으로 흘러간다.
• 현재는 inner join 만 허용
| 01 Interval join 과 친해지기
5. Flink Interval Join Overview
orangeElem.key == greenElem.key
&&
orangeElem.ts + lowerBound <= greenElem.ts <= orangeElem.ts + upperBound
• 두 개의 스트림을 하나로 조인하는 operator
• 두 input stream에서 element 의 키가 같고, 이벤트의 시간차이가 경계조건 안에 있으면
join 되어 다음 stream 으로 흘러간다.
• 현재는 inner join 만 허용
| 01 Interval join 과 친해지기
6. Event Time
• Interval join 은 현재 event time 만 지원
• Event 를 발생시키는 곳에서 각 event 가 발생한 시간
• 보통 event 자체의 데이터로부터 event timestamp 값을 얻을 수 있다
• 현실의 시간과는 무관하게 흘러간다
• Stream processor 에서 event time 이 어디까지 진행되었는지 알
수 있는 방법 필요
• (Event time + WindowedStream)
| 01 Interval join 과 친해지기
7. Watermark
• Data stream 을 따라서 흘러가며, timestamp 값을 전달
• Watermark(t) 는 ( 그림에서는 W(t) )
스트림 내의 event time 이 t 까지 진행되었고,
W(t) 이후에는 t 보다 먼저 발생한 이벤트가 더 이상 없어야 함을 의미
• 늦게 들어오는 이벤트에 대한 처리는 operator 마다 다름
• operator 가 흘러온 watermark 를 받으면,
내부 event time clock 을 해당 워터마크의 값으로 진행시킴
| 01 Interval join 과 친해지기
Simple stream Parallel stream
8. IntervalJoinOperator 동작 방식
• 처리 로직의 메인이 되는 processElement() 함수 내부
• event timestamp < operator 의 워터마크 이면 버림
• Left 면 leftBuffer에, right 면 rightBuffer 에 넣는다
• 반대쪽 버퍼에서 조건에 맞는 element 를 찾는다
• 있을 경우 collect 한다
• context의 timestamp 를 업데이트 해주고,
해당 이벤트쌍으로 사용자의 processFunction 호출
• 버퍼에 주기적으로 삭제하기 위해 eventTimer 를 설정
• Operator 의 워터마크가 갱신될 때 마다
등록된 이벤트 타이머가 있으면 실행시켜 준다
• 현재 워터마크 + 시간차 경계조건 보다 오래된 데이터
는 삭제
| 01 Interval join 과 친해지기
9. 기존 시스템 구성
• 이벤트 흐름은 Content Enricher 패턴과 동일
• https://camel.apache.org/manual/latest/content-enricher.html
Flink 로 이관!
| 02 적용한 사례와 그 방법
10. 시스템 특성
• 피크타임 기준 트래픽
• Win : 초당 5만건
• Bid : 초당 10만건
• Win 이 발생하는 경우 반드시 대응되는 (같은 키를 가지는) Bid 이벤트가 있
음
• 대부분의 경우 win 과 bid 이벤트 발생 시간차는 매우 작음
• 0 < Win event time - Bid event time < 2s
• Interval join 적용에 적합한 모양
•Win 이벤트가 bid 이벤트보다 다소 늦게 들어오더라도 처리 해주어야 함
• Interval join 은 inner join > 따라서 left outer join 필요!
• Flink 로 변경 후 이벤트 흐름
| 02 적용한 사례와 그 방법
11. Interval join 적용 계기
• 기술적 측면
• Kotlin
• Extension 함수를 사용해 기존 클래스 변경 없이 새로운
operator 를 추가하기 쉬움
• 외부 요인
• Akka Stream
• Cassandra
| 02 적용한 사례와 그 방법
12. Left interval join 붙이기 (1)
| 02 적용한 사례와 그 방법
• 기존 intervalJoin @KeyedStream.java
결과적으로
IntervalJoinOperator 반환
13. Left interval join 붙이기 (2)
| 02 적용한 사례와 그 방법
IntervalJoined 와 같이 LeftIntervalJoinOperator 를 생성
leftIntervalJoin 함수는 kotlin 확장함수로 쉽게 붙임
LeftIntervalJoin, LeftIntervalJoined 는
KeyedStream 클래스 코드를 기반으로 (복붙) 필요한 파라미터만 추가
14. Left Interval Join 구현
• LeftIntervalJoinOperator 에서 추가된 내용
• Side output 추가
• 원하는 쪽의 sideOutputTag 를 넣어주면 join 되지 않은 이벤트들
을 side output 으로 받을 수 있음
• processElement 함수에서 늦은 이벤트일 경우
• onEventTime 함수에서 삭제할 때 join 되지 않은 경우
| 02 적용한 사례와 그 방법
15. Troubleshooting (1)
• Idling sources - 한쪽 input stream 이 이벤트가 없을 시 죽는 문제
| 03 예상치 못한 문제 발생과 해결 및 모니터링
• event time 을 사용할 때,
timestampAssigner 로 element 별 timestamp 를 부여해야 한다
• 해당 operator 의 워터마크도 event time 값에 따라 업데이트 된다
• Win 이벤트는 들어오고, bid 이벤트는 들어오지 않는 경우
• Bid stream 쪽 워터마크도 갱신되지 않음
• Interval Join 워터마크는 두 input stream 의 워터마크 중 작은 값으로 계산됨
• 워터마크가 갱신되지 않아서 버퍼를 비우지 못하고 잡이 죽음
16. Troubleshooting (1) - 해결
• 이벤트 유입이 일정 시간 중단될 경우
현재시간을 워터마크로 사용하게 하는 TimestampAssigner 구현
| 03 예상치 못한 문제 발생과 해결 및 모니터링
17. Troubleshooting (2)
• 두 input stream의 시간대가 서로 많이 차이나는 경우 (약 10분)
스트림 처리가 지연되면서 GC Overhead 발생
• 근본적인 원인은 (1) 과 동일
• leftIntervalJoin 오퍼레이터의 두 input stream의 워터마크 중
작은 값을 해당 연산자의 워터마크 값으로 계산하고
해당 워터마크값 이후의 이벤트를 모두 메모리에 담아두기 때문
| 03 예상치 못한 문제 발생과 해결 및 모니터링
18. Troubleshooting (2) - 해결
• 해결 방법
• leftIntervalJoin 오퍼레이터의 워터마크를
현재시간 (processing time) 과 가깝게 직접 갱신하거나
지금까지의 최신 이벤트 시간을 기준으로 직접 갱신
• @LeftIntervalJoinOperator.java : processElement
| 03 예상치 못한 문제 발생과 해결 및 모니터링
19. 추가 모니터링 개선 (1)
• Sentry 연동
• io.sentry:sentry-log4j 의존성 필요
• log4j.properties 와 sentry.properties 를 활용
| 03 예상치 못한 문제 발생과 해결 및 모니터링
20. 추가 모니터링 개선 (2)
• metric 저장소로 Elasticsearch 사용
• ESReporter 를 작성하여 metric 수집 > grafana 로 모니터링
• 기존 accumulator 대신 metric 사용 가능
• Task 별 지표를 모아서 Job 단위로 볼 수 있는 것이 장점
• Reporter 작성시 참고한 코드
https://github.com/zentol/log4jreporter/blob/master/src/main/java/org/apache/flink/metrics/log4j/Log4JReporter.java
| 03 예상치 못한 문제 발생과 해결 및 모니터링
21. 한계 + TODO
• checkpointing, 2pc 등이 적용되어 있지 않아
배포시 유실이 있을 수 있음
• 적당한 리소스의 양은 성능테스트를 필히 거쳐야 알 수 있음
• Task manager / slot
• 리소스 부족을 자동으로 탐지해서 리소스를 늘려 재배포하는 기능
• job health check 모니터링 정리하기
• Flink 1.9 대 버전 적용하기
• 실시간 데이터 정합성 체크에 적용하기
| 04 앞으로..