41P by xguru 2023-11-13 | favorite | 댓글 1개

교훈들

  • 잘 알려진, 검증된 기술 사용
  • Keep it Simple
  • 너무 창의적으로 생각하지 않기(동일한 노드를 추가하여 확장가능한 아키텍처로 결정)
  • 옵션을 제한하기
  • DB 샤딩 > 클러스터링
  • 즐겁게! (신입 엔지니어도 첫주부터 코드에 기여 가능)

2010년 3월: 클로즈 베타, 엔지니어 1명

  • MySQL 1대 + 웹서버(Django + Python) 1대 + 엔지니어 1명(2 명의 공동창업자 포함). Rackspace에 호스팅

2011년 1월: 1만명 사용자(MAU), 엔지니어 2명

  • AWS EC2 웹 서버 스택(EC2 + S3 + CloudFront)
  • Django + Python
  • Redundacy를 위한 4대의 웹서버
  • NGINX 를 리버스 프록시이자 로드 밸런서로
  • MySQL 1대에 Read-only 세컨더리 1대
  • Counter 용 MongoDB
  • 1개의 태스크 큐와 2대의 태스크 프로세서(비동기 작업)

2011년 10월: 320만 MAU, 엔지니어 3명

  • 10개월간 급속도로 성장해서 1.5달에 2배씩 사용자가 늘어남
  • 2011년 3월 아이폰 앱 출시가 성장을 주도한 것중 하나
  • 빠르게 성장하면서 기술 쪽 문제가 더 자주 발생
  • 핀터레스트는 이때 실수를 함 : "아키텍처를 지나치게 복잡하게 만들었음"
  • 엔지니어가 3명밖에 없는데, 데이터에 사용하는 DB 기술이 5가지였음
  • 수동으로 MySQL을 샤딩하면서 동시에 Cassandra 와 Membase(현재 Couchbase)를 사용하여 데이터를 클러스터링함
  • 그들의 "너무 복잡한 스택"
    • 웹서버 스택(EC2 + S3 + Cloudnfront)
      • Flask(Python)으로 백엔드를 옮기기 시작
    • 웹서버 16대
    • API 엔진 2대
    • NGINX 프록시 2대
    • 수동으로 샤딩된 5대의 MySQL DB + 9대의 읽기 전용 세컨더리
    • 카산드라 노드 4개
    • Membase 노드 15개(3개의 별도 클러스터)
    • Memcache 노드 8개
    • Redis 노드 10개
    • Task 라우터 3대 + Task 프로세서 4대
    • Elastic Search 노드 4개
    • Mongo 클러스터 3개
  • 클러스터링이 잘못됨
    • 이론적으로는 클러스터링이 자동적으로 데이터스토어를 확장, 고가용성 및 로드밸런싱 해주면서 SPOF를 없애주지만
    • 안타깝게도 실제로는 클러스터링은 너무 복잡하고, 업그레이드 메커니즘이 어려우며, 큰 SPOF 를 가짐
    • 각 DB에는 DB에서 DB로 라우팅하는 클러스터 관리 알고리듬이 있음
      • DB에 문제가 발생하면 새 DB가 추가되고 이를 관리해줘야 하지만
      • Pinterest의 클러스터 관리 알고리듬에 버그가 발생해서 모든 노드의 데이터가 손상되고 데이터 리밸런싱이 중단되었으며 몇 가지 수정할 수 없는 문제가 발생
  • Pinterest의 해결책은?
    • 시스템에서 모든 클러스터링 기술(카산드라, 멤베이스)을 제거
    • (더 검증된) MySQL + Memcached로 올인

2012년 1월: 1100만 MAU, 엔지니어 6명

  • 약 1200만 에서 2100 DAU
  • 이 시점에 아키텍처를 단순화하는데 시간을 할애함
  • 클러스터링 및 카산드라를 제거하고 MySQL, Memcache, 샤딩으로 대체
  • 단순화된 스택
    • Amazon EC2 + S3 + Akamai (CloudFront 대체)
    • AWS ELB (Elastic Load Balancing)
    • 90 Web Engines + 50 API Engines (Flask 이용)
    • 66 MySQL DBs + 66 secondaries
    • 59 Redis Instances
    • 51 Memcache Instances
    • 1 Redis Task Manager + 25 Task Processors
    • 샤딩된 Apache Solr (Elasticsearch 대체)
    • 제거한 것들: Cassanda, Membase, Elasticsearch, MongoDB, NGINX

Pinterest가 DB를 수동 샤딩한 방법

데이터베이스 샤딩은 단일 데이터세트를 여러 개의 데이터베이스로 분할하는 방법
장점: 고가용성, 로드 밸런싱, 데이터 배치를 위한 간단한 알고리듬, 데이터베이스를 쉽게 분할하여 용량 추가, 데이터 찾기 쉬움

  • 처음 샤딩했을때 문제가 있어서, 몇달에 걸쳐서 점짐적으로 수동 샤딩을 진행
  • 전환 순서
    1. 1 DB + Foreign Keys + Joins
    2. 1 DB + Denormalized + Cache
    3. 1 DB + Read Slaves + Cache
    4. 여러대의 기능적으로 샤딩된 DB들 + Read Slaves + Cache
    5. ID로 샤딩된 DB들 + Backup Slaves + Cache
  • 데이터베이스 계층에서 테이블 조인과 복잡한 쿼리를 제거하고 많은 캐싱을 추가
  • 데이터베이스 전반에 걸쳐 고유한 제약 조건을 유지하는 데 많은 노력이 필요했기 때문에 사용자 이름과 이메일과 같은 데이터는 거대한 샤딩되지 않은 데이터베이스에 보관
  • 모든 테이블이 샤드에 올라감

2012년 10월: 2200만 MAU, 엔지니어 40명

  • 아키텍처는 그대로 유지하면서, 몇대의 똑같은 시스템들을 추가
    • Amazon EC2 + S3 + CDNs (EdgeCast, Akamai, Level 3)
    • 180 web servers + 240 API engines (Flask)
    • 88 MySQL DBs + 88 secondaries each
    • 110 Redis instances
    • 200 Memcache instances
    • 4 Redis Task Managers + 80 Task Processors
    • Sharded Apache Solr
  • 하드디스크에서 SSD로 옮기기 시작
  • 중요한 교훈: 제한적이고 검증된 선택(limited, proven choices)이 좋았다는 것
  • EC2와 S3를 고수하다 보니 구성 선택의 폭이 제한되어 골칫거리가 줄어들고 단순성이 높아졌음
  • 하지만 새로운 인스턴스는 몇 초 만에 준비될 수 있게 됨. 즉, 단 몇 분 만에 10개의 멤캐시 인스턴스를 추가 가능

Pinterest 의 데이터베이스 구조

  • IDs
    • Instragram과 비슷하게, 샤딩 때문에 유니크한 ID 구조를 가지고 있음
    • 64bit ID의 구성
      • Shard ID : 어떤 샤드인지. 16 bit
      • Type : 객체 타입(Pin 같은 것 ) 10 bit
      • Local ID : 테이블에서의 포지션. 38 bit
    • 이 ID의 Lookup 구조는 그냥 간단한 파이썬 딕셔너리
  • Tables
    • 개체 테이블과 매핑 테이블이 있었음
    • 객체 테이블은 핀, 보드, 댓글, 사용자 등을 위한 것. MySQL Blob(JSON)에 매핑된 로컬 ID
    • 매핑 테이블은 보드를 사용자에 매핑하거나 좋아요를 핀에 매핑하는 등 객체 간의 관계형 데이터를 위한 테이블. 전체 ID와 타임스탬프에 매핑된 전체 ID
    • 모든 쿼리는 효율성을 위해 PK(기본 키) 또는 인덱스 조회. 모든 조인을 제거

인스타그램이 오직 3명의 엔지니어로 1400만 사용자를 확보한 방법
이것과 같은 시리즈의 글이면서, 내용도 연결되네요.
"간단하게 유지할 것. 잘 알려지고, 검증된 기술들을 사용할 것"