가상 면접 사례로 배우는 대규모 시스템 설계 기초 2

2장 주변 친구

  • p51 굳이 타임스탬프를 보내는 이유. 계산한 거리가 검색 반경을 넘지않는 경우 즉, 지속 추적이 필요한 경우라면 아무런값이나 보내도 되는게 아닐까? 클라이언트가 타임스탬프를 사용할일이 있을까?
    • 필터링 용도 -> 타임스탬프가 없으면 반경에 있었던 모든 사용자를 검색하느냐 vs 특정 시간 이후의 사용자만 검색하느냐?
  • p55 “위치 정보 캐시에 일괄 요청을 보내어 모든 친구의 위치를 한번에 가져온다”에서, 레디스 클러스터 모드인 경우 데이터가 각각 다른 해시 슬롯에 분산되어 있을텐데 조회 시 부하는 없을까? 위치 캐시만 동일 슬롯에 저장하도록 하는게 좋을까?
    • 다른 해시 슬롯에 있어서 오히려 부하가 줄어들지 않을까? lettuce 가 슬롯이 분산되어있으면 100개를 단건으로 조회하는 future 를 만들어서 반환됨 -> key exist (요건 부하가 적은 command)
      • 하나의 클러스터 내지는 한 곳에서만 조회하는 경우에는 장애를 분산시키는 의도도 있지 않을까? -> 성능이 엄청 좋은 redis cluster 를 사용하게 한다.
  • p57 주변 친구 기능에서 사용자에게 부여되는 채널은 사용자 접속이 끊기면 삭제되는게 좋을지 아니면 계정탈퇴시까지 계속 유지하는게 좋을지
    • redis channel 인 경우 -> channel 도 용량을 차지함 -> channel 또한 최적화가 필요할 수도 있음 -> TTL 최종 사용자 접속 얼마 이후 channel 을 반환 -> 다시 사용할 때 channel 받음
  • 통신 프로토콜로 소켓과 HTTP를 사용했을 때의 성능 차이
    • OSI 7 계층
    • 소켓 통신을 가지고 규약을 만들어서 만든게 HTTP 통신
    • HTTP/2 로 하면 더 빨라진다.
    • TCP/UDP 에 속도가 빠른 구현체를 사용(gRPC) 하면 더 빠를질 수 있다.
    • TCP/UDP stateful
    • HTTP 왔다갔다 하면 끝
    • websocket -> 풀링 / 푸시
    • TCP/UDP 연결이 한번 이루어지면 -> header 정보를 확인할 필요 없이 빨라짐 -> http 로 요청 보내고 socket 번호 가지고 session 을 맺음
    • [Network] 프로토콜(Protocal)과 소켓(Socket)
    • WebSocket 대 HTTP 통신 프로토콜
  • 무상태서버에서와 유상태 서버에서의 로드밸런싱 방법의 차이
    • sticky session 배포
  • stateless 어느 서버로 재요청이 들어가도 상관 없음
    • stateful 내가 처음에 연결 맺은 서버로 요청을 또 보내야함 -> stateful 인 경우에 확장/축소를 할 때 신경을 써야함
  • 레디스 펍/섭 서버와 메시지 버스(카프카/MQ)의 작동 방식
    • 브로드캐스트를 하지 않는다고 하면 작동 자체는 동일 함
      • 펍/섭의 경우 되감기가 안됨 vs 카프카의 되감기를 할 수 있음
        • 레디스 펍/섭 확장할 때 신경 많이 써야 함, 카프카는 broker 와 consumer 만 늘리면 됨(리밸런싱이나 메시지가 소비가 안되면 장애유발)
  • id 기반 샤딩이 아니라, 다른 기준을 두고 샤딩을 하는 경우가 있다면 어떤 예시가 있을지
    • 대부분 id 기반으로 샤딩을 하거나, 필요성에 의해서 timestamp 로 샤딩함
    • A/B 테스트에서의 샤딩
    • id 기반으로 샤드 갯수로 나머지 연산 -> 어느 샤드에 들어갈지 정함 -> 리밸런싱할 때 어플리케이션에서 리밸런싱을 구현하거나, 샤딩 지원 데이터베이스를 사용함
    • hash 값을 만들 때 id 기반으로 만들래? 타임스탬프 기반으로 만들래? UUID 기반으로 만들래? 차이점
    • UUID 기반으로 겹치지 않는 PK 만들기 -> 샤드에 넣음
    • twitter의 snowflake id도 참고 분산 처리 시스템에서 유일한 식별자를 만드는 방법(twitter snowflake)
  • 위치 이동 이력을 작성하는 업무를 웹소켓 서버가 담당하지 않고, Redis Pub/Sub의 subscriber로 담당 컴포넌트를 추가하면 웹소켓의 병렬 작업을 줄여서 성능을 향상시킬 수 있지 않을까?
    • redis pub/sub 이랑 브라우저가 바로 연결이 안됨
    • 위치 이동 이력을 특정 시간 동안 모아뒀다가 http 로 한번에 서버 전송
  • 주변 친구 기능의 경우 아키텍처를 단순하게 만들 수 있다면 더 많은 메모리를 투입할 만한 가치가 있다 꼭집어 표현한 이유는? 이 시스템 자체가 복잡하기 때문에 관리를 용이하게 만드는게 주 목적인지?
    • 인건비? 시스템이 복잡하면 사람이 많이 필요하게 됨
    • 단순하게 만드는게 관리 측면에서 좋음 -> 유지보수할 때 좋음
    • 변화에 열려있어서 단순하게 하는게 좋음
    • 주변 친구 기능이 돈을 벌수 있는게 확정이고 이걸 잘 만들어야 함 -> 복잡하고 노력을 많이 들일 가치가 있는 서비스
  • 분산 레디스 펍/섭 클러스터 - 수백대의 레디스 서버 채널을 분산 시, userID 기준으로 펍/섭 서버를 샤딩을 하게 되면 유저의 지역과 펍/섭 서버의 위치가 물리적으로 멀어져 네트워크 시간이 지연되지 않을지? userId보다 user의 지역을 기준으로 샤딩을 하는 것이 더 좋지 않을지?
    • 서버의 위치가 물리적으로 멀어지더라도 -> 같은 네트워크 망으로 되어 있으면 속도가 빠를 수 있음
  • p63 운영 시 문제 발생 시에 해시링 키의 값을 장애 발생 노드 -> 대기중인 노드로 교체한다고 하는데 어플리케이션 로직의 해시링을 수작업으로 갱신하는 api와 같은 것으로 미리 구현을 해둬야 하는 걸까?
    • 카우치베이스/카산드라 같은 어플리케이션을 사용하면 클릭 한번으로 갱신 리밸런싱 다 해줌
    • 오픈소스가 아닌 경우 수작업 갱신하는 api 또는 배치 만들어야함 -> 샤드에 변화가 생김 -> 샤드 추가 하고 -> 작업에 해당 하는 데이터만 샤드 옮기는 기능 수행
  • 데이터 샤딩 시에 샤딩 키가 변경되는 경우에 데이터 리밸런싱을 최소화하기 위해 어떤 전략을 취할 수 있을까?
    • 리밸런싱 해야하는 대상만 추출 -> 리밸런싱 -> 구현 난이도가 어려울 수 있음
    • 모든 데이터를 리밸런싱 하는 방식 -> 구현 난이도가 쉬움 -> 우아한 형제들 주문 MSA 에서는 샤드를 사용하는 데이터는 최근 날짜 기준 2달치만 저장함 -> 모든 데이터를 리밸런싱 하는 방식
  • 데이터 리밸랜성이 필요한 경우, 마이그레이션 전략과 새로운 데이터 저장공간에서 먼저 읽고, 없으면 과거 데이터 저장공간에서 읽는 전략 중에 선택이 필요할 때, 각 전략마다 어떤 점을 고려하면 좋을까?
    • 리밸런싱 할 때 -> 새벽에 트래픽 적을 때 -> 사용자 요청이 많은 시간에 리밸런싱을 굳이 하지 않음 -> 리밸런싱이 필요하다의 판단을 사용량을 보고 예측함
  • 해시링을 사용해도 노드 부하 불균형 이슈가 있고, 해시 충돌 가능성 역시 무시할순 없는데 이부분을 해소하려면 어떤 리벨런싱 전략을 가지면 좋을지?
    • 자동화가 되어 있는 경우 -> 불균형이 몇 % 이상이면 배치로 트래픽이 제일 적은 시간 리밸런싱
    • 해시링 하나 더 큰거를 만들어서 데이터를 넣고 엔도포인트를 갈아끼움

3장 구글 맵

  • p86 “15초마다 한번 보내는 기능”을 직접 구현한다면 어떻게 구현하면 좋을지? 15초동안 쌓이는 데이터를 어디에 어떻게 저장할 것인지
    • 메모리? 어떤 방식으로 서버로 전송할 것인지 → 스케줄러? 메모리에 저장한다고 가정했을 때 만약 데이터가 유실에 민감한 데이터라면 어떻게 안전성을 높일 수 있을지, 유실에 민감한 데이터를 메모리에 저장하는게 맞는지 그 외 어떤 점들을 고려하면 좋을지
      1. 클라이언트용 database 를 이용한다.
      2. memeory 에 다 올린다.
      3. file 에 쓴다.
  • database 를 활용해서 timestamp 를 이용해서 위치 정보를 저장함 -> 마지막에 내가 어디까지 보냈는지도 column 에 표기함 -> api 통신해서 한번에 보내는 기능을 구현

  • p92 “위/경도 및 확대 수준을 타일 URL로 변환하는 알고리즘 구현을 별도 서비스에 둔다”했는데 어떤 기능을 별도 서비스로 분리하는걸 고민할 때 판단의 기준이나 고려사항이 있는지, 어느정도의 기능을 별도의 서비스로 분리하는 편인지
    • 별도 어플리케이션으로 분리하는 기준 -> 장애가 발생할 가능성이 높음, 기능이 동떨어져있음, 한 API 에 트래픽이 몰림
      • 독립적인 배포 가능성 -> 기능 단위 -> 보안 단위
  • p93 ## 타일을 가져오는 데 필요한 URL 집합을 계산하는 플로우 설명 중 “표시할 타일 하나와 8개의 주변 타일이 응답에 포함” 된다고 하는데 이는 사용자가 확대 수준(zoom level)을 얼마나 했느냐에 따라서 주변 타일의 갯수가 달라지는건 아닐까?
  • 타일의 갯수는 총 9개 인데 scale 숫자가 다르지 않을까?

  • p95 경로 안내 타일을 s3에 파일 형식으로 저장하면 읽기 성능이 떨어지지 않을까? 대안이 있다면 어떤 것이 있을까?
  • s3 읽고 -> 메모리에 올려두지 않을까? (캐시) -> CDN 무조건 쓴다. (https://jojoldu.tistory.com/779)
  • 서버 메모리에 경로 안내 타일을 다 local cache 로 만들어서 올려놓는 방법이 있을수도 있음 -> 데이터 파편 문제가 발생할 수 있음
  • 전국 주소 우편번호 -> 잘 안변하는데 자주 쓰는 것 -> S3 / CDN 을 사용많이 함

  • p97 key-value 저장소를 사용할 때 key값 외의 다른 값(A)을 기준으로 데이터를 검색해야 하는 경우가 꽤 빈번하게 발생한다면 어떻게 하는게 좋을까? A를 key로 하는 key-value값을 저장한다?
    • map 을 이야기 하는 건지, dynamodb key-value database 를 이야기하는 것인지에 따라서 다를 것 같아요. -> pk key + fk key 설정할 수 있음
    • redis 를 사용했을 때는 새로운 key value
  • p98 사용자 위치 데이터베이스에서 데이터베이스 키에 timestamp가 추가될 필요가 있을까? 서비스에 직접적으로 활용되는 것은 ‘유저의 가장 최신 위치’ 뿐이므로 user_id만 key로 해서 계속 수정하고, 히스토리가 필요하다면 서비스에 사용하는 영역이 아닌 곳에서 로그를 쌓는 것이 좋지 않을까?
    • 히스토리가 필요하기 때문에 히스토리 테이블 따로, 최근 위치 테이블 따로
    • timestamp 을 hash 값으로 데이터 정합성 체크 -> 다목적으로 쓸 수 있는 데이터
    • timestamp 을 hash 하는 이유가 혹시 있을까요? -> 요구사항에 따라서 다름 -> 데이터가 갱신 되었을 때 새로운 데이터인지 확인하는 용도로 hash 값 비교
  • p107 상위 타일의 상위 타일을 출발지와 목적지다 모두 포함된 타일을 찾을 때까지 재귀적으로 더하여 보관할 때, 적절한 데이터 베이스 및 자료구조는 어떤 것이 있을까?
    • 책에서는 그래프, noSQL 로 row 를 다 저장
  • p108 왜 ‘교통사고’ 상황과는 달리 ‘교통상황 개선’의 경우 경로를 재설정할 사용자를 특정하지 못하는지 이해가 어려웠습니다.
    • B 를 접근하지 못하는데 B가 다시 접근 가능하게 되었을 때 -> B의 경로를 사용할 수 있는 사용자를 찾을 수 없음 -> (이미 다른 경로 C 로 안내받고 있어서) -> B 점 인근을 통과하는 경로를 모두 추출 -> 이거 기준으로 재계산
    • 출발지/목적지로 다시 경로 검색
  • 어느 정도 용량까지 지도 이미지를 cdn에 저장해야할지? (네이버/카카오지도는 대한민국 한정이어서 모든 지도 데이터를 올려도 될 것 같지만, google의 경우는 크기가 굉장히 커서 선택적인 캐싱을 해야할 것 같음)
    • 특정 용량이나 크기로 지도를 잘라서 cdn 에 저장하지 않을까?, 네이버, 카카오지도도 마찬가지 일 것 같다.
    • 머신러닝 사용
    • 사막은 크게 블록을 나누고, 도심지는 작게작게 블록을 나눠서 cdn 에 올림
  • 오리진 서버에 이미지 격자를 어디까지 올리면 될까?
    • 요청이 많거나 확대를 많이 하는 곳은 해상도를 낮춤 높이고, 요청이 적은 부분은 해상도를 낮춤
    • 사용자 기준으로 이미지를 저장 -> 구글맵을 예시로 들면 -> 모든 구글 맵에 대한 정보가 있지 않을까
    • PC/MOBILE 에 따라서 원본 고해상도 이미지가 있고, 해상도를 낮춘 이미지가 있어서, 접근한느 디바이스나 설정에 따라서 이미지 격자를 내려줌
    • 지역별로 자주 접근하는 위치 지도가 올라가있긴 하지만 그래서 모든 지도에 대한 것을 regeion 별로 복제해두지 않았을까?
  • 경유지 설정 기능을 어떻게 제공하면 좋을지?
    • 경유지 까지의 최단 경로 + 경유지부터 목적지 까지 최단 경로 -> 하나로 표현
    • 경유지가 늘어날수록 계산이 늘어남 경우의 수를 다 추출
    • 경유지 수가 늘어날수록 주고 받아야 할 데이터가 늘어남 -> max 를 제한 해둠끝
    • 경유지 수 만큼 경유지의 좌표를 기준으로 경로를 찾는다
  • 모바일 단말 서비스 설계시 데이터 사용량과 배터리 효율을 따져 보아야 했다. 저장소 사용량, 서버 대역폭을 고려해보았다. 실제 현업에서 모바일 서비스를 설계할 때 효율 측면에서 어떠한 것을 고려하는가?