[Review] 시스템 디자인 스터디2 - 5~6주차 후기 + 스터디 완료 공유

안녕하세요!
K-DEVCON (이하 “데브콘”) 그로스 매니저 박종훈입니다.

어느새 2월이 되었습니다.
이번 시스템 디자인 스터디도 마무리 되었습니다.

진작에 써야 했던 스터디 리뷰글과 스터디 마무리에 대한 글을 작성해 보고자 합니다.

5회차 스터디 에서는 “지표 모니터링 및 경보 시스템”
6회차 스터디 에서는 “광고 클릭 이벤트 집계” 를 다뤘습니다.
두 주제 모두 데이터를 어떻게 수집할지에 대한 이야기를 공통적으로 다루고 있습니다.

두 스터디에서 아직까지 기억에 남는 2가지 주제에 대해서 이야기 해보겠습니다.


[1] 데이터 압축하기 - Gorilla


“Gorilla: A Fast, Scalable, In-Memory Time Series Database” 는 구 facebook, 현 Meta 에서 낸 논문입니다.

이 논문에서는 시계열 데이터 베이스 설계에 대한 이야기도 나오지만, 이번 리뷰에서 볼 이야기는 데이터 압축에 대한 컨셉입니다.
이 논문에서 나오는 데이터 압축 컨셉은 이후 등장할 많은 시계열 데이터베이스에 영향을 미쳤습니다.

대규모 모니터링 시스템은 초당 엄청난 양의 데이터를 쏟아냅니다. 따라서 어떻게 데이터를 줄일 수 있을지는 중요한 문제입니다. (저장 비용과 메모리 사용량을 줄일 수 있습니다.)

[Review] 시스템 디자인 스터디2 - 5~6주차 후기 + 스터디 완료 공유
논문에 있는 알고리즘 소개 이미지

1. 타임스탬프 압축하기
보통 모니터링 시스템에는 규칙적으로 데이터가 들어옵니다. (ex. 10초마다 한번씩 전송)
이러한 특징을 이용해서 수집되는 데이터를 줄입니다.

gorilla 에서는 delta-of-delta 라는 컨셉을 제시합니다. 사실 delta만 생각해도 효율적이었을 것 같은데, delta-of-delta는 그보다 더 적은 범위를 보장할 수 있습니다.

다음과 같은 규칙으로 데이터가 저장됩니다.

  1. 데이터 블록은 2시간 단위로 구성됩니다. 데이터 블록 헤드에 시작 타임스탬프가 저장됩니다.
  2. 블록의 첫 번째 타임스탬프에는 차이값(delta)을 계산하여 14비트 크기로 저장됩니다.
  3. 이후에 이어지는 타임스탬프들에 대하여 델타의 델타(Delta of Delta)를 계산합니다.
    1. Delta of Delta 가 0이라면, 비트 '0'을 하나 저장합니다.
    2. Delta of Delta 가 [-63, 64] 범위 내에 있으면, '10'을 저장한 뒤 그 값(7비트)을 저장합니다.
    3. Delta of Delta 가 [-255, 256] 범위 내에 있으면, '110'을 저장한 뒤 그 값(9비트)을 저장합니다.
    4. Delta of Delta 가 [-2047, 2048] 범위 내에 있으면, '1110'을 저장한 뒤 그 값(12비트)을 저장합니다.
    5. 그 외의 경우, '1111'을 저장한 뒤 그 값을 32비트로 저장합니다.

이를 통해 데이터가 규칙적으로 들어온다면 많은 bit를 사용하지 않고도 데이터를 보관할 수 있게 됩니다.

2. 값 압축 - XOR Compression

모니터링 시스템에서 들어오는 값은 거의 일정하거나, 급격하게 변하지 않고 연속되는 경우가 많습니다. 이러한 경우 값을 효율적으로 저장하기 위해 XOR 을 사용하여 변동된 값만 저장할 수 있습니다.

다음과 같은 규칙으로 데이터가 저장됩니다.

  1. 첫 번째 값: 압축하지 않고 그대로 저장합니다.
  2. 이후에 저장되는 값들에 대해서는 XOR 연산을 사용합니다.
    1. 값이 이전과 똑같을 때 (XOR 결과가 0)
      비트 0 하나만 딱 저장하고 끝냅니다.
    2. 값이 다를 때 (XOR 결과가 0이 아님)
      일단 비트 1을 써서 "값이 달라졌다"는 신호를 보낸 뒤, 아래 두 가지 케이스 중 하나로 진행합니다.
      1. 이전과 '유효 비트 범위'가 비슷할 때 (컨트롤 비트 0)
        위치 정보를 새로 저장할 필요 없이, 이전의 위치 정보를 그대로 재사용하고 알맹이(유효 비트)만 저장합니다.
      2. 유효 비트 범위가 달라졌을 때 (컨트롤 비트 1)
        범위가 달라졌으니 정보를 새로 갱신해야 합니다. 앞쪽 0의 개수(5비트) + 유효 비트의 길이(6비트)를 먼저 적어줍니다. 그다음 실제 유효 비트 내용을 저장합니다.

사실 XOR bit 연산의 개념에 대해서는 알고 있지만, 실제로 어디에 사용되는지는 잘 알지는 못했는데 사용 되는곳을 접해보니 재밌게 느껴졌습니다.


[2] 분산 환경에서의 Exactly-once


분산 환경에서의 데이터 정합성을 유지하는 것은 매우 어려운 일입니다. 그럼에도 엔지니어들은 이것을 해내야 했습니다.

한번만 처리되어야 하는 일이 여러번 처리된다면, 큰 문제가 발생될 수 있습니다.

저도 최근에 카프카를 사용한 이벤트 처리를 고려하고 있는데, 어떻게 중복되게 처리하지 않을지(혹은, 중복으로 처리되어도 문제 없게 설계하기)가 참 중요한 문제인 것 같습니다. 많은 고민이 필요한 부분이라고 생각됩니다.

사례 1: yelp
End-to-end Exactly-once Aggregation Over Ad Streams

[Review] 시스템 디자인 스터디2 - 5~6주차 후기 + 스터디 완료 공유 - 이미지 2
exactly-once aggregation

yelp 의 경우 데이터에 버저닝을 사용하여 해결하였다고 합니다.

집계 데이터에 카프카의 오프셋을 활용하여 버전(Version)을 부여하여, 동일한 데이터가 다시 들어와도 "이것은 이미 이전 버전에서 처리된 데이터"임을 식별할 수 있도록 하였습니다.
처리가 완료된 후 버전을 결정하고, 버전보다 높은 오프셋을 가진 데이터만 처리하는 방식으로 중복 처리되는 것을 방지하였습니다.

영상에서 “분산 시스템 설계의 주된 관심사는 실패(Failures)에 대비하는 것” 이라는 표현을 하였는데 인상 깊었습니다.

사례 2: flink
An Overview of End-to-End Exactly-Once Processing in Apache Flink

[Review] 시스템 디자인 스터디2 - 5~6주차 후기 + 스터디 완료 공유 - 이미지 3
2pc.png 452.38 KB

Flink는 2PC(Two-Phase Commit) 프로토콜을 사용하여 Exactly-once 를 달성 하였습니다.

조율(Coordinator): JobManager가 체크포인트를 주도하며 각 운영자(Operator)에게 배리어를 전달합니다.

1단계 - 사전 커밋(Pre-commit): 각 Sink는 외부 시스템(Kafka 등)에 트랜잭션을 시작하고 데이터를 쓴 뒤, 준비 상태를 체크포인트에 저장합니다. 이 중 하나라도 실패하면 즉시 전체를 중단하고 이전 체크포인트로 롤백합니다.

2단계 - 최종 커밋(Commit): 모든 운영자가 사전 커밋을 마치면 JobManager가 이를 알리고 최종 커밋을 수행합니다. 이 단계는 반드시 성공해야 합니다. 만약 실패한다면 성공할 때까지 애플리케이션 재시작을 통해 커밋을 재시도합니다.

사례 3: uber

책에서는 Real-Time Exactly-Once Ad Event Processing with Apache Flink, Kafka, and Pinot 이라는 글을 소개하고 있습니다. 관심 있으신 분은 읽어보시면 좋을 것 같습니다.


[3] 스터디 후기


서울로 올라와서 2번째 스터디를 운영을 마쳤습니다.
이번 스터디도 참여자 분들이 적극적으로 참여해주셔서 잘 마무리 될 수 있었습니다.
어떻게 해야 좋은 스터디로 만들 수 있을까 많이 고민을 하며, 제가 더 많이 학습하여 스터디원분들께 공유해드리고 싶어 노력했었습니다.

다양한 도메인에 계신분들과 이야기를 나눌 수 있어서 좋은 시간이였습니다.

이번 스터디 참여자 분들이 다음과 같은 후기도 남겨주셨습니다.

“다양한 회사에서 일하는 분들과 함께 공부하면서 각자 다른 환경에서의 시스템 설계 경험을 공유받을 수 있어서 좋았습니다. 책에서 다루는 대규모 시스템 설계 패턴들을 실무에 어떻게 적용하고 있는지 여러 관점에서 들을 수 있었고, 평소 혼자 책을 읽었다면 그냥 넘어갔을 부분들도 토론을 통해 더 깊이 고민해볼 수 있었습니다. 또한 정기적인 스터디 일정 덕분에 꾸준히 학습 페이스를 유지할 수 있었던 점도 만족스러웠습니다.”

“책만 보고는 이해가 100프로 안됐던 부분들을 스터디를 통해 더 잘 이해할 수 있었습니다. 편안한 분위기에서 의견을 나눌 수 있어서 좋았어요 :)”

“항상 열심히 준비 해주셔서 감사합니다.. 덕분에 더 알찬 스터디가 되었던 것 같아요. 다음 스터디는 미리 많이 준비 해둬야겠어요!!! 감사합니다 :>”

“다양한 도메인에서 일하는 분들과 함께 스터디하면서 다양한 경험들, 이야기들을 들을 수 있어서 좋았습니다. 혼자 읽을 땐 생각하지 못했던 부분도 생각할 수 있어서 유익했던 거 같아요!”

“스터디원들과의 대화를 통해 혼자 책을 읽을 때는 미처 생각하지 못했던 관점들을 많이 접할 수 있었습니다. 같은 글을 읽고도 각자가 주목하는 지점이 달랐고, 그 과정에서 ‘이 글에서는 이런 고민까지 확장해볼 수 있겠구나’라는 생각을 자주 했습니다. 특히 제가 당연하게 넘겼던 부분에 대해 다른 스터디원들이 던지는 질문을 통해, 스스로의 사고가 얼마나 제한적이었는지를 돌아볼 수 있었습니다. 놓치고 있던 부분을 발견할 수 있었다는 점에서 스터디가 의미있었습니다.”

감사하게도, 대부분의 분들이 다음 스터디에도 참여 하고 싶다고 의사를 남겨주셨습니다.
다음 스터디는 2월 26일 부터 다시 시작합니다. 다음 스터디도 파이팅 해보겠습니다.

[Review] 시스템 디자인 스터디2 - 5~6주차 후기 + 스터디 완료 공유 - 이미지 4
5회차 스터디 인증!

[Review] 시스템 디자인 스터디2 - 5~6주차 후기 + 스터디 완료 공유 - 이미지 5
6회차 스터디 인증!



우리 스터디에서는 실제 사례들을 통해 문제를 어떻게 해결해 나갔을까 많은 고민을 해보고 이야기를 나눠보고 있습니다. 이번주도 다들 열심히 참여해주셔서 더 풍성한 스터디가 될 수 있었습니다.


직접 스터디를 개설해보고 싶은 분이 계시다면, K-DEVCON에서 운영을  도와드리겠습니다. 데브콘의 '랩짱'에 도전하여 커뮤니티 성장을 함께 이끌어주세요! 슬랙을 통해 운영진에게 DM 부탁드리겠습니다😉