가상 면접 사례로 배우는 대규모 시스템 설계 기초 | 알렉스 쉬 - 교보문고

가상 면접 사례로 배우는 대규모 시스템 설계 기초 | 페이스북의 뉴스 피드나 메신저,유튜브, 구글 드라이브 같은 대규모 시스템은 어떻게 설계할까? IT 경력자라도 느닷없이 대규모 시스템을 설

product.kyobobook.co.kr


11장, 뉴스 피드 시스템 설계

  1. 문제 이해 및 설계 범위 확정
    • 웹/앱 둘 다 지원해야 함
    • 중요 기능
      • 사용자는 뉴스 피드 페이지에 새로운 스토리를 올릴 수 있어야 함
      • 친구들이 올리는 스토리도 볼 수 있어야 함
    • 뉴스 피드에는 시간 흐름 역순으로 스토리가 표시
    • 한 명의 사용자는 최대 5,000명의 친구를 가질 수 있음
    • 트래픽 규모는 매일 천만 명
    • 스토리에는 이미지나 비디오 등의 미디어 파일이 포함될 수 있음

  1. 개략적 설계안 제시 및 동의 구하기
    • 뉴스 피드 API
      • 클라이언트가 서버와 통신하기 위해 사용하는 수단
      • HTTP 프로토콜 기반
      • 상태 정보를 업데이트하거나, 뉴스 피드를 가져오거나, 친구를 추가하는 등 다양한 작업 수행
      • 피드 발행 API
        • 새 스토리를 포스팅하기 위한 API
        • HTTP POST 형태로 요청
        • POST /v1/me/feed
      • 피드 읽기 API
        • 뉴스 피드를 가져오는 API
        • HTTP GET 형태로 요청
        • GET /v1/me/feed

  1. 상세 설계
    • 웹 서버
      • 클라이언트와 통신할 뿐 아니라 인증이나 처리율 제한 등의 기능도 수행
      • 올바른 인증 토큰을 Authorization 헤더에 넣고 API를 호출하는 사용자만 포스팅할 수 있어야 한다.
      • 스팸을 막고 유해한 콘텐츠가 자주 올라오는 것을 방지하기 위해 특정 기간 동안 한 사용자가 올릴 수 있는 포스팅의 수에 제한을 두어야 한다.
    • 포스팅 전송(팬 아웃) 서비스
      • 어떤 사용자의 새 포스팅을 그 사용자와 친구 관계에 있는 모든 사용자에게 전달하는 과정
      • 팬 아웃에는 두가지 모델이 있는데 하나는 쓰기 시점에 팬아웃하는 모델이고, 다른 하나는 읽기 시점에 팬아웃 하는 모델이다.
      • 쓰기 시점에 팬 아웃하는 모델 (Push 모델)
        • 새로운 포스팅을 기록하는 시점에 뉴스 피드를 갱신
        • 포스팅이 완료되면 바로 해당 사용자의 캐시에 해당 포스팅을 기록
        • 장점
          • 뉴스 피드가 실시간으로 갱신
          • 친구 목록에 있는 사용자에게 즉시 전송
          • 새 포스팅이 기록되는 순간 뉴스 피드가 이미 갱신되므로 뉴스 피드를 읽는 데 드는 시간이 짧아짐
        • 단점
          • 친구가 많은 사용자의 경우 친구 목록을 가져오고 그 목록에 있는 사용자 모두의 뉴스 피드를 갱신하는 데 많은 시간이 소요될 수도 있다. (핫키 문제)
          • 서비스를 자주 이용하지 않는 사용자의 피드까지 갱신해야 하므로 컴퓨팅 자원이 낭비
      • 읽기 시점에 팬 아웃하는 모델 (Pull 모델)
        • 피드를 읽어야 하는 시점에 뉴스 피드를 갱신
        • 요청 기반 모델 (On-demand)
        • 사용자가 본인 홈페이지나 타임 라인을 로딩하는 시점에 새로운 포스트를 가져온다
        • 장점
          • 비활성화된 사용자, 또는 서비스에 거의 로그인하지 않는 사용자의 경우에는 이 모델이 유리
          • 로그인하기까지는 어떤 컴퓨팅 자원도 소모하지 않는다.
          • 데이터를 친구에 각각 푸시하는 작업이 필요 없으므로 핫키 문제도 생기지 않는다.
        • 단점
          • 뉴스 피드를 읽는 데 많은 시간이 소요될 수 있다.
    • 이번 장에서는 두 가지 방법을 결합하여 장점은 취하고 단점은 버리는 전략을 취한다.
    • 뉴스 피드를 빠르게 가져오는 것은 아주 중요하므로 대부분 푸시 모델을 사용한다. 친구나 팔로어가 아주 많은 사용자의 경우 팔로어로 하여금 해당 사용자의 포스팅을 필요할 때 가져가도록 하는 풀 모델을 사용하여 시스템 과부하를 방지할 수 있다.
    • 아울러 안정 해시를 통해 요청과 데이터를 보다 고르게 분산하여 핫키 문제를 줄여볼 것이다.

  • 느낀 점
    • 캐시를 필요에 따라 여러 계층으로 나누어 활용할 수 있음
    • Push-Pull 모델을 필요에 따라 결합하여 핫키 문제를 방지하고 두 전략의 장점만을 가져올 수 있음
 

가상 면접 사례로 배우는 대규모 시스템 설계 기초 | 알렉스 쉬 - 교보문고

가상 면접 사례로 배우는 대규모 시스템 설계 기초 | 페이스북의 뉴스 피드나 메신저,유튜브, 구글 드라이브 같은 대규모 시스템은 어떻게 설계할까? IT 경력자라도 느닷없이 대규모 시스템을 설

product.kyobobook.co.kr


10장, 알림 시스템 설계


  • 알림 시스템 (Notification System)은 최근 많은 프로그램이 채택한 인기 있는 기능
  • 알림 시스템을 통해 최신 뉴스, 제품 업데이트, 이벤트, 선물 등 고객에게 중요할 만한 정보를 비동기적으로 제공한다.
  • 단순히 모바일 푸시 알림에 한정되지 않는다.
  • 알림 시스템의 종류
    • 모바일 푸시 알림
    • SMS 메시지
    • 이메일

  1. 문제 이해 및 설계 범위 확정
    • 하루에 백만 건 이상의 알림을 처리하는 확장성 높은 시스템을 구축하는 건 어렵다.
    • 알림 시스템이 어떻게 구현되는지에 대한 깊은 이해가 필요
    • 적절한 질문을 통해 요구 사항이 무엇인지 지원자 스스로 알아내야 한다.
    • 질의응답
      • 어떤 종류의 알림을 지원하는가?
        • 푸시 알림, SMS 메시지, 이메일
      • 실시간 시스템이어야 하는가?
        • 연성 실시간 시스템 (Soft Real-Time)
        • 알림은 가능한 빨리 전달되어야 하지만 시스템에 높은 부하가 걸렸을 때 약간의 지연은 무방
      • 어떤 종류의 단말을 지원해야 하는가?
        • iOS 단말, 안드로이드 단말, 랩톱/데스크톱
      • 사용자에게 보낼 단말은 누가 만들 수 있는가?
        • 클라이언트 애플리케이션 프로그램, 서버 측 스케쥴링
      • 사용자가 알림을 받지 않도록 설정할 수 있는가?
        • 그렇다. 해당 설정을 마친 사용자는 더 이상 알림을 받지 않아야 한다.
      • 하루에 몇 건의 알림을 보낼 수 있어야 하는가?
        • 천만 건의 모바일 푸시 알림, 백만 건의 SMS 메시지, 5백만 건의 이메일

  1. 개략적 설계안 제시 및 동의 구하기
    • 알림 유형별 지원 방안
      • iOS 푸시 알림
        • 알림 제공자 (Provider)
          • 알림 요청을 만들어 애플 푸시 알림 서비스 APNS로 보내는 주체
          • 알림 요청을 만들려면 다음과 같은 데이터가 필요하다
            • 단말 토큰 (Device Token)
              • 알림 요청을 보내는 데 필요한 고유 식별자
            • 페이로드 (Payload)
              • 알림 내용을 담은 JSON 딕셔너리
        • APNS (Apple Push Notification Service)
          • 애플이 제공하는 원격 서비스
          • 푸시 알림을 iOS 장치로 보내는 역할
        • iOS 단말
          • 푸시 알림을 수신하는 사용자 단말

      • 안드로이드 푸시 알림
        • iOS와 비슷한 절차
        • APNS 대신 FCM(Firebase Cloud Messaging)을 사용

      • SMS 메시지
        • 트윌리오(Twilio), 넥스모(Nexmo)와 같은 서드파티 서비스를 이용
        • 대부분 상용 서비스로, 이용요금을 내야 함.

      • 이메일
        • 대부분 회사는 고유 이메일 서버를 구축할 역량은 갖추고 있다.
        • 그럼에도 많은 회사가 상용 이메일 서비스를 이용
        • 대표적으로 샌드그리드 (Sendgrid), 메일침프 (Mailchimp)가 있다.
        • 전송 성공률도 높고, 데이터 분석 서비스도 제공한다.

    • 연락처 정보 수집 절차
      • 알림을 보내려면 모바일 단말 토큰, 전화번호, 이메일 주소 등의 정보가 필요
      • 사용자가 우리 앱을 설치하거나 처음으로 계정을 등록하면 API 서버는 해당 사용자의 정보를 수집하여 데이터베이스에 저장한다.

    • 개략적 설계안 (초안)
      • 1 부터 N 까지의 서비스
        • 이 서비스 각각은 마이크로서비스일 수도 있고, 크론잡일 수도 있고, 분산 시스템 컴포넌트일 수도 있다.
        • 사용자에게 납기일을 알리고자 하는 과금 서비스, 배송 알림을 보내려는 쇼핑몰 웹사이트 등이 그 예다.
      • 알림 시스템
        • 알림 전송/수신 처리의 핵심
        • 우선 1개 서버만 사용하는 시스템으로 가정
        • 이 시스템은 서비스 1-N에 알림 전송을 위한 API를 제공해야 하고, 서드파티 서비스에 전달할 알림 페이로드(Payload)를 만들어 낼 수 있어야 한다.
      • 제 3자 서비스 (서드 파티 서비스)
        • 사용자에게 알림을 실제로 전달하는 역할
        • 확장성을 유의해야 한다.
        • 쉽게 새로운 서비스를 통합하거나 기존 서비스를 제거할 수 있어야 한다.
        • 가령 FCM은 중국에서는 사용할 수 없고, 중국 시장에서는 JPush, PushY 같은 서비스를 이용해야 한다.
      • iOS, 안드로이드, SMS, 이메일 단말
        • 사용자는 자기 단말에서 알림을 수신한다.

      • 위 설계에는 몇 가지 문제가 존재한다.
        • SPOF (Single-Point-Of-Failure)
          • 알림 서비스에 서버가 하나 밖에 없다는 것은 그 서버에 장애가 생기면 전체 서비스의 장애로 이어진다는 뜻
        • 규모 확장성
          • 한 대 서비스로 푸시 알림에 관계된 모든 것을 처리하므로, 데이터베이스나 캐시 등 중요 컴포넌트의 규모를 개별적으로 늘릴 방법이 없다.
        • 성능 병목
          • 알림을 처리하고 보내는 것은 자원을 많이 필요로 하는 작업일 수 잇다.
          • 모든 것을 한 서버로 처리하면 사용자 트래픽이 많이 몰리는 시간에는 시스템 과부하 상태에 빠질 수 있다.

    • 개략적 설계안 (개선 버전)
      • 데이터 베이스와 캐시를 알림 시스템의 주 서버에서 분리
      • 알림 서버를 증설하고 오토 스케일링이 이루어질 수 있도록 설계
      • 메시지 큐를 이용해 시스템 컴포넌트 사이의 강한 결합을 끊기
      • 알림 서버
        • 알림 전송 API
          • 스팸 방지를 위해 사내 서비스 또는 인증된 클라이언트만 이용
        • 알림 검증
          • 이메일 주소, 전화번호 등에 대한 기본적 검증
        • 데이터베이스 또는 캐시 질의
          • 알림에 포함시킬 데이터를 가져오는 기능
        • 알림 전송
          • 알림 데이터를 메시지 큐에 넣는다.
      • 캐시
        • 사용자 정보, 단말 정보, 알림 템플릿 등을 캐시
      • 데이터베이스
        • 사용자, 알림, 설정 등 다양한 정보를 저장
      • 메시지 큐
        • 시스템 컴포넌트 간 의존성을 제거하기 위해 사용
        • 다량의 알림이 전송되어야 하는 경우를 대비한 버퍼 역할
        • 알림의 종류별로 별도 메시지 큐를 사용하여 SPOF 제거
      • 작업 서버
        • 메시지 큐에서 전송할 알림을 꺼내 서드 파티 서비스로 전달
      • 서드 파티 서비스
      • iOS, 안드로이드 SMS, 이메일 단말

    • 개략적 설계안 (개선 버전)의 작동 순서
      1. API를 호출하여 알림 서버로 알림을 보냄
      2. 알림 서버는 사용자 정보, 단말 토큰, 알림 설정 같은 메타데이터를 캐시나 데이터베이스에서 가져옴
      3. 알림 서버는 전송할 알림에 맞는 이벤트를 만들어서 해당 이벤트를 위한 큐에 넣음.
      4. 작업 서버는 메시지 큐에서 알림 이벤트를 꺼냄
      5. 작업 서버는 알림을 서드 파티 서비스로 보냄
      6. 서드 파티 서비스는 사용자 단말로 알림을 전송

  1. 상세 설계
    • 안정성
      • 분산 환경에서 운영될 알림 시스템을 설계할 때는 안정성을 확보하기 위한 사항 몇 가지를 고려해야만 한다.
      • 데이터 손실 방지
        • 어떤 상황에서도 알림이 소실되면 안된다.
        • 알림이 지연되거나 순서가 틀려도 괜찮지만, 사라지면 곤란하다.
        • 알림 시스템은 알림 데이터를 데이터베이스에 보관하고, 재시도 매커니즘을 구현해야 한다.
      • 알림 중복 전송 방지
        • 중복을 탐지하는 매커니즘을 도입하고, 오류를 신중하게 처리
        • 보내야 할 알림이 도착하면 그 이벤트 ID를 검사하여 이전에 본 적이 있는 이벤트인지 살핀다. 중복된 이벤트라면 버리고, 그렇지 않으면 알림을 발송한다.

    • 추가로 필요한 컴포넌트 및 고려 사항
      • 알림 템플릿
        • 대형 알림 시스템은 하루에도 수백만 건 이상의 알림을 처리한다.
        • 대부분 비슷한 형식의 알림을 전송하는데, 이런 유사성을 고려하여 알림 메시지의 모든 부분을 처음부터 다시 만들 필요 없이 해준다.
        • 알림 템플릿은 인자나 스타일, 추적 링크를 조정하기만 하면 사전에 저장한 형식에 맞추어 알람을 만들어내는 틀이다.
        • 템플릿을 사용하면 전송될 알림들의 형식을 일관성 있게 유지할 수 있고, 오류 가능성 뿐만 아니라 알림 작성에 드는 시간도 줄일 수 있다.

      • 알림 설정
        • 사용자는 이미 너무 많은 알림을 받고 있어 쉽게 피곤함을 느낀다.
        • 많은 웹사이트와 앱에서는 사용자가 알림 설정을 상세히 조정할 수 있도록 하고 있다.

      • 전송률 제한
        • 사용자에게 너무 많은 알림을 보내지 않도록 한 사용자가 받을 수 있는 알림의 빈도를 제한
        • 알림을 너무 많이 보내기 시작하면 사용자가 알림을 꺼버릴 수도 있기 때문

      • 재시도 매커니즘
        • 서드 파티 서비스가 알림 전송에 실패하면, 해당 알림을 재시도 전용 큐에 넣는다.
        • 같은 문제가 지속 발생하면 서드 파티 개발자에게 통지한다 (Alert)

      • 푸시 알림과 보안
        • iOS와 안드로이드 앱의 경우 알림 전송 API는 appKey와 AppSecret을 사용하여 보안을 유지
        • 따라서 인증된/승인된 (Authenticated/Verified) 클라이언트만 해당 API를 사용하여 알림을 보낼 수 있다.

      • 큐에 보관된 알림에 대한 모니터링과 이벤트 추적
        • 알림 시스템을 모니터링 할 때 중요한 메트릭 하나는 큐에 쌓인 알림의 개수이다.
        • 이 수가 너무 크면 작업 서버들이 이벤트를 빠르게 처리하고 있지 못하다는 뜻이다.
        • 그런 경우에는 작업 서버를 증설하는 게 바람직할 것이다.
        • 이벤트 추적
          • 알림 확인율, 클릭율, 실제 앱 사용으로 이어지는 비율 같은 메트릭은 사용자를 이해하는데 중요하다.
          • 데이터 분석 서비스는 보통 이벤트 추적 기능도 제공한다.
          • 따라서 보통 알림 시스템을 만들면 데이터 분석 서비스와도 통합해야만 한다.

    • 개선된 설계안
      • 알림 서버에 인증과 전송률 제한 기능 추가
      • 전송 실패에 대응하기 위한 재시도 기능 추가
      • 전송 템플릿을 사용하여 생성 과정을 단순화하고 내용의 일관성을 유지
      • 모니터링과 추적 시스템을 추가하여 시스템 상태를 확인하고 추후 시스템을 개선하기 쉽게 함

  1. 마무리
    • 알림은 중요 정보를 계속 알려준다는 점에서 필요불가결한 기능
    • 이번 장에서 우리는 규모 확장이 쉬울 뿐 아니라 푸시 알림, SMS 메시지, 이메일 등 다양한 정보 전달 방식을 지원하는 알림 시스템을 만들어 보았다.
    • 시스템 컴포넌트 사이의 결합도를 낮추기 위해 메시지 큐를 적극적으로 사용
    • 개략적 설계안과 더불어 각 컴포넌트의 구현 방법과 최적화 기법에 대해서도 심도 있게 알아보았다.
      • 안정성, 보안, 이벤트 추적 및 모니터링, 사용자 설정, 전송률 제한

  • 느낀 점
    • 대규모 알림 시스템을 책을 읽으며 함께 설계하고, 구상해보았다.
    • SPOF를 예상하여 단일 알림 서버를 피하고 데이터베이스와 캐시를 붙여 API 요청시 자주 Read되는 사용자 정보를 제공하는 것 까지는 예상했으나 알림 서버와 작업 서버를 구분하고, 그 사이에 메시지 큐를 두어 누락 없는 순차적 메시지 발송과 오류시 재시도 기능을 추가한 것을 보았을때 환희에 차 올랐다. 뭐랄까, 조금씩 안 맞는 퍼즐들이 한 번에 맞춰진 느낌이랄까?
    • 대규모 시스템을 설계하는 과정은 분명히 어렵고, 완벽할 수 없다. 완벽을 꿈꾸며 수 많은 오류의 강을 헤쳐나가며 우리는 많은 난관을 경험하고, 나아간다.
    • 분산 시스템, 마이크로 서비스 아키텍처, SPOF 개선, 오류 시 재시도, 인증/인가 권한 확인, 캐시, 데이터베이스 샤딩.. 기술은 완벽을 향해 한 걸음 한 걸음 나아가고 있다.
    • 나는 어떤 기술을 통해, 어떤 완벽을 만들 것인가?
    • 나는 개발자로서 사용자에게 어떤 완벽함을 선사할 것인가?
    • 우리는 누군가에게 완벽한 존재일 수 있는가?
 

가상 면접 사례로 배우는 대규모 시스템 설계 기초 | 알렉스 쉬 - 교보문고

가상 면접 사례로 배우는 대규모 시스템 설계 기초 | 페이스북의 뉴스 피드나 메신저,유튜브, 구글 드라이브 같은 대규모 시스템은 어떻게 설계할까? IT 경력자라도 느닷없이 대규모 시스템을 설

product.kyobobook.co.kr


7장,  분산 시스템을 위한 유일 ID 생성기 설계

  • 다중 마스터 복제 (Multi-Master Replication)
    • 데이터베이스의 auto_increment 기능 활용
    • 다음 ID 값을 구할 때 1만큼 증가시키는 것이 아닌, k만큼 증가시킨다.
    • k는 현재 사용 중인 데이터베이스 서버의 수다.
    • 이렇게 하면 규모 확장성 문제를 어느 정도 해결할 수 있는데, 데이터베이스 수를 늘리면 초당 생산 가능 ID 수도 늘릴 수 있기 때문이다.
    • 단점
      • 여러 데이터 센터에 걸쳐 규모를 늘리기 어렵다
      • ID 유일성은 보장되겠지만, 그 값이 시간 흐름에 맞추어 커지도록 보장할 수 없다.
      • 서버를 추가하거나 삭제할 때도 잘 동작하도록 만들기 어렵다.

  • UUID (Universally Unique Indetifier)
    • 유일성이 보장되는 ID를 만드는 간단한 방법
    • 컴퓨터 시스템에 저장되는 정보를 유일하게 식별하기 위한 128비트의 수
    • 충돌 가능성이 지극히 낮다.
      • 중복 ID가 1개 생길 확률을 50%로 끌어 올리려면, 초당 10억 개의 UUID를 100년 동안 계속해서 만들어야 한다.
    • UUID 값은 58c76s98-10x9-483w-ag9q-c94l1096pcj2와 같은 형태를 띤다
    • UUID는 서버 간 조율 없이 독립적으로 생성 가능하다.
    • 장점
      • 만들기 단순하다.
      • 서버 사이 조율이 필요 없으므로 동기화 이슈도 없다.
      • 각 서버가 자기가 쓸 ID를 알아서 만드는 구조이므로 규모 확장도 쉽다.
    • 단점
      • ID가 128비트로 길다.
      • ID를 시간순으로 정렬할 수 없다.,
      • ID에 숫자가 아닌 값이 포함될 수 있다.

  • 티켓 서버 (Ticket Server)
    • 유일성이 보장되는 ID를 만드는 데 쓰일 수 있는 방법
    • 핵심은 auto_increment 기능을 갖춘 데이터베이스 서버, 즉 티켓 서버를 중앙 집중형으로 하나만 사용하는 것
    • 장점
      • 유일성이 보장되는 오직 숫자로만 구성된 ID를 쉽게 만들 수 있다.
      • 구현하기 쉽고, 중소 규모 애플리케이션에 적합하다.
    • 단점
      • 티켓 서버가 SPOF(Single-Point-Of-Failure)가 된다.
      • 티켓 서버에 장애가 발생하면 해당 서버를 이용하는 모든 시스템이 영향을 받는다.
      • SPOF를 피하기 위해 티켓 서버를 여러 대 준비해야 하는데, 이 경우 데이터 동기화 같은 문제가 발생된다.

  • 트위터 스노플레이크 (Twitter Snowflake) 접근법
    • 트위터에서 사용하는 독창적인 ID 생성 기법
    • ID를 저장하기 위해 64비트를 사용
    • 64비트의 각 부분을 여러 섹션 (타임스탬프, 데이터센터 ID, 서버 ID, 일련번호)로 분할
    • 장점
      • 해당 방식을 사용할 경우 다른 서버와 통신할 필요가 없이 독립적으로 ID 생성이 가능
      • 성능과 확장성에서 이점을 가짐
      • 타임 스탬프가 초반 비트를 차지하기에 시간순으로 ID를 정렬할 수 있음
    • 단점
      • ID를 저장하기 위해 64비트를 사용

  • 느낀 점
    • 지금껏 프로젝트를 진행하며 일반적인 auto_increment와 UUID 기법을 사용하곤 했다.
    • auto_increment의 경우엔 분산 시스템에서 일관성을 유지할 수 없고, UUID는 최고의 유일성을 제공하지만 너무 큰 비트 수 (128bit)를 가져감으로써 고려 사항이 생기게 된다.
    • 티켓 서버와 트위터 스노플레이크를 새로 알게 되었고, 티켓 서버는 단일 서버를 티켓 서버로 사용할 경우 SPOF 문제가 발생될수 있음을 꺠달았다.
    • 트위터 스노플레이크를 조금 더 깊게 공부하여 개인 프로젝트나 현업에서도 적용할 수 있는지 알아봐야겠다.
 

가상 면접 사례로 배우는 대규모 시스템 설계 기초 | 알렉스 쉬 - 교보문고

가상 면접 사례로 배우는 대규모 시스템 설계 기초 | 페이스북의 뉴스 피드나 메신저,유튜브, 구글 드라이브 같은 대규모 시스템은 어떻게 설계할까? IT 경력자라도 느닷없이 대규모 시스템을 설

product.kyobobook.co.kr


6장, 키-값 저장소 설계

  • 키-값 저장소 (Key-Value Store)는 키-값 데이터베이스라고도 불리는 비관계형 데이터베이스이다.
  • 이 저장소에 저장되는 값은 고유 식별자를 키로 가져야 한다.
  • 키와 값 사이의 이런 연결 관계를 ‘키-값’ 쌍 (Pair)이라 지칭한다.
  • 키-값 쌍에서의 키는 유일해야 하며 해당 키에 매달린 값은 키를 통해서만 접근할 수 있다.
  • 키는 일반 텍스트일 수도 있고 해시 값일 수도 있다.
  • 성능 상의 이유로, 키는 짧을수록 좋다.
    • ex) 일반 텍스트 키 : “last_logged_in_at”
    • ex) 해시 키 : 253DDEC4
  • 키-값 쌍에서의 값은 문자열일 수도 있고 리스트일 수도 있고 객체일 수도 있다.
  • 키-값 저장소는 보통 값으로 무엇이 오든 상관하지 않는다.
  • 대표적 예로 Amazon DynamoDB, Memcached, Redis 등이 있다.

  • 단일 서버 키-값 저장소
    • 한 대 서버만 사용하는 키-값 저장소를 설계하는 것은 쉽다.
    • 가장 직관적인 방법은 키-값 쌍 전부를 메모리에 해시 테이블로 저장하는 것
    • 이 접근법은 빠른 속도를 보장하긴 하나 모든 데이터를 메모리 안에 두는 것이 불가능할 수도 있다는 약점을 가진다.
      • 개선책
        • 데이터 압축 (Compression)
        • 자주 쓰이는 데이터만 메모리에 두고 나머지는 디스크에 저장
      • 그러나 이렇게 개선한다고 해도, 한 대 서버로 부족한 때가 곧 찾아온다.
      • 많은 데이터를 저장하려면 분산-키 값 저장소(Distributed Key-Value Store)를 만들 필요가 있다.

  • 분산 키-값 저장소
    • 분산 해시 테이블이라고도 불림
    • 키-값 쌍을 여러 서버에 분산
    • CAP 정리 (Consistency, Availability, Partition Tolerance Theorem)을 이해하고 있어야 함
      • 세 가지 요구사항을 동시에 만족하는 분산 시스템을 설계하는 것은 불가능하다는 정리
        • 데이터 일관성 (Consistency)
          • 어떤 노드에 접속했느냐에 관계 없이 언제나 같은 데이터를 보게 되어야 한다.
        • 가용성 (Availability)
          • 일부 노드에 장애가 발생하더라도 항상 응답을 받을 수 있어야 한다.
        • 파티션 감내 (Parition Tolerance)
          • 파티션은 두 노드 사이에 통신 장애가 발생하였음을 의미
          • 네트워크에 파티션이 생기더라도 시스템은 계속 동작하여야 한다는 의미


      • 키-값 저장소는 세 가지 요구사항 가운데 어느 두 가지를 만족하냐에 따라 다음과 같이 분류할 수 있다.
        • CP 시스템
          • 일관성과 파티션 감내를 지원하는 키-값 저장소, 가용성을 희생
        • AP 시스템
          • 가용성과 파티션 감내를 지원하는 키-값 저장소, 데이터 일관성을 희생
        • CA 시스템
          • 일관성과 가용성을 지원하는 키-값 저장소, 파티션 감내를 희생
          • 그러나 통상 네트워크 장애는 피할 수 없는 일로 여겨지므로, 분산 시스템은 반드시 파티션 문제를 감내할 수 있도록 설계되어야 한다.
          • 따라서 실세계에 CA 시스템은 존재하지 않는다.

      • 다양한 상태의 분산 시스템
        • 이상적 상태
          • 네트워크가 파티션되는 상황은 일어나지 않는다. (P 만족)
          • 어떤 단일 저장소에 기록된 내용은 자동적으로 모든 분산 서비스 내 저장소로 복제된다.
          • 데이터 일관성과 가용성도 만족된다. (C, A 만족)

        • 실세계 분산 시스템
          • 분산 시스템은 파티션 문제를 피할 수 없기에, 일관성과 가용성 사이에서 하나를 선택해야 한다.
          • 일관성을 선택한 경우 (CP 시스템)
            • 분산 서버 사이에 생길 수 있는 데이터 불일치 문제를 피하기 위해 장애가 발생하지 않은 서버에 쓰기 연산을 중단시켜야 하는데, 그렇게 하면 가용성이 깨진다.
            • 은행권 시스템은 보통 데이터 일관성을 양보하지 않는다.
              • 온라인 뱅킹 시스템이 계좌 최신 정보를 출력하지 못하면 큰 문제
              • 네트워크 파티션 때문에 일관성이 깨질 수 있는 상황이 발생한다면 이런 시스템은 상황이 해결될 때 까지 오류를 반환해야 한다.
          • 가용성을 선택한 경우 (AP 시스템)
            • 낡은 데이터를 반환할 위험이 있더라도 계속 쓰기 연산을 허용
            • 파티션 문제가 해결된 뒤에 새 데이터를 복구된 오류 발생 서버에 전송
      • 분산 키-값 저장소를 만들 때는 그 요구사항에 맞도록 CAP 정리를 적용해야 한다.

    • 데이터 파티션
      • 대규모 애플리케이션의 경우 전체 데이터를 한 대 서버에 몰아넣는 것은 불가능
      • 가장 단순한 해결책은 데이터를 작은 파티션들로 분할한 다음 여러 대 서버에 저장하는 것
      • 데이터를 파티션 단위로 나눌 때는 다음 문제를 중요하게 따져봐야 한다.
        • 데이터를 여러 서버에 고르게 분산할 수 있는가
        • 노드가 추가되거나 삭제될 때 데이터의 이동을 최소화할 수 있는가
      • 안정 해시를 통해 위 문제를 적절히 해결할 수 있다.

    • 일관성 모델 (Consistency Model)
      • 데이터 일관성 수준을 결정하는 방법으로, 종류가 다양하다
        • 강한 일관성 (Strong Consistency)
          • 모든 읽기 연산은 가장 최근에 갱신된 결과를 반환
          • 클라이언트는 절대 낡은 (Out-Of-Date) 데이터를 보지 못함
          • 모든 사본에 현재 쓰기 연산의 결과가 반영될 때 까지 해당 데이터에 대한 읽기/쓰기를 금지
          • 새로운 요청의 처리가 중단되기에 고가용성 시스템에 적합하지 않다.
        • 약한 일관성 (Weak Consistency)
          • 읽기 연산은 가장 최근에 갱신된 결과를 반환하지 못할 수 있음
        • 최종 일관성 (Eventual Consistency)
          • 약한 일관성의 한 형태로, 갱신 결과가 결국에는 모든 사본에 반영(동기화)되는 모델
          • 다이나모 또는 카산드라 같은 저장소에서 채택한 모델
          • 쓰기 연산이 병렬적으로 발생하면 시스템에 저장된 값의 일관성이 깨질 수 있는데, 이 문제는 클라이언트가 해결해야 한다.
          • 클라이언트 측에서 데이터의 버전 정보를 활용해 일관성이 깨진 데이터를 읽지 않도록 하는 기법

          • 비 일관성 해소 기법 : 데이터 버저닝
            • 데이터를 다중화하면 가용성은 높아지지만 사본 간 일관성이 깨질 가능성이 높다.
            • 버저닝과 벡터 시계는 그 문제를 해소하기 위해 등장한 기술
            • 버저닝 (Versioning)
              • 데이터를 변경할 때 마다 해당 데이터의 새로운 버전을 만드는 것
              • 각 버전의 데이터는 변경 불가능 (immutable)

            • 벡터 시계 (Vector Clock)
              • 충돌을 발견하고 자동으로 해결해 낼 버저닝 시스템
              • 어떤 버전 X가 어떤 버전 Y의 이전 버전인지 (따라서 충돌이 없는지) 쉽게 판단할 수 있음
              • 버전 Y에 포함된 모든 구성요소의 값이 X에 포함된 모든 구성요소 값보다 같거나 큰지만 보면 됨
              • 단점
                • 충돌 감지 및 해소 로직이 클라이언트에 들어가야 하므로, 클라이언트 구현이 복잡해진다.
                • [서버: 버전]의 순서쌍 개수가 굉장히 빨리 늘어난다. 이를 해결하기 위해 길이에 어떤 임계치를 설정하고, 임계치 이상으로 길이가 길어지면 오래된 순서쌍을 벡터 시계에서 제거하도록 해야 함
                • 그러나 오래된 순서쌍을 벡터 시계에서 제거한다면 버전 간 선후 관계가 정확하게 결정될 수 없기 때문에 충돌 해소 과정의 효율성이 낮아지게 된다.
                • 하지만 다이나모 데이터베이스 문헌에 따르면 아마존은 실제 서비스에서 위와 같은 문제가 벌어지는 것을 발견한 적이 없다고 공표하였으며, 대부분의 기업에서 벡터 시계는 적용해도 괜찮은 솔루션으로 평가됨

            • 장애 처리
              • 장애는 불가피하기만 한 것이 아닌 흔하게 벌어지는 사건
              • 장애를 어떻게 처리할 것이냐 하는 것은 굉장히 중요한 문제
            • 장애 감지 (Failure Detection)
              • 분산 시스템에서는 그저 한 대 서버가 “지금 서버 A가 죽었습니다.” 라고 한다고 해서 바로 서버 A를 장애처리 하지는 않는다.
              • 보통 두 대이상의 서버가 똑같이 서버 A의 장애를 보고해야 해당 서버에 실제 장애가 발생했다고 간주한다.
              • 모든 노드 사이에 멀티캐스팅 (Multicasting) 채널을 구축하는 것이 서버 장애를 감지하는 가장 손쉬운 방법이나, 서비스가 많을 때 비효율적
              • 가십 프로토콜 (Gossip Protocol) 같은 분산형 장애 감지 (Decentralized Failure Detection) 솔루션을 채택하는 편이 효율적

  • 느낀 점
    • Key-Value DB의 종류와 그 내부 로직들을 더 깊이 있게 배울 수 있었다.
    • CAP 정리에 대해 대략적으로만 알고 있었는데, 이번 기회에 정확히 CAP가 무엇인지, 어떤 구분을 가지는지 파악할 수 있었다.
    • 오류 없는 완전한 시스템이란 없다. 오류에 적절히 대처하고, 빠르게 대처하고, 더 나은 대처를 할 수 있는 방안을 계속해서 강구하는 것이 올바른 개발자의 자세겠다.

CAP 정리

+ Recent posts