가상 면접 사례로 배우는 대규모 시스템 설계 기초 | 알렉스 쉬 - 교보문고
가상 면접 사례로 배우는 대규모 시스템 설계 기초 | 페이스북의 뉴스 피드나 메신저,유튜브, 구글 드라이브 같은 대규모 시스템은 어떻게 설계할까? IT 경력자라도 느닷없이 대규모 시스템을 설
product.kyobobook.co.kr
1장, 사용자 수에 따른 규모 확장성
- 한 명의 사용자를 지원하는 시스템에서 시작하여, 몇백만 사용자를 지원하는 시스템을 설계하는 과정을 담은 책
- 단일 서버
- 모든 컴포넌트가 단 한 대의 서버에서 실행
- 웹 앱, 데이터베이스, 캐시 등이 전부 서버 한 대에서 실행
- 데이터베이스 분리
- 웹 서버와 데이터베이스 서버로 분리
- 어떤 데이터베이스를 사용할 것인가?
- RDBMS
- 관계형 데이터베이스 관리 시스템 (Relational Data-base Management System)
- MySQL, Oracle, PostgreSQL 등
- 자료를 테이블과 열, 칼럼으로 표현
- 여러 테이블에 있는 데이터를 그 관계(Relation)에 따라 조인(Join)하여 합칠 수 있다.
- NoSQL
- 비 관계형 데이터베이스 (Not only SQL)
- CouchDB, Neo4j, Cassandra, HBase, Amazon DynamoDB, MongoDB 등
- NoSQL은 다시 네 부류로 나눌 수 있다.
- 키-값 저장소 (Key-Value Store)
- 그래프 저장소 (Graph Store)
- 칼럼 저장소 (Column Store)
- 문서 저장소 (Document Store)
- NoSQL은 일반적으로 조인 연산은 지원하지 않는다.
- NoSQL이 사용되는 경우
- 아주 낮은 응답 지연시간 (Latency)가 요구되는 경우
- 다루는 데이터가 비정형 (Unstructured)이라 관계형 데이터가 아닌 경우
- 데이터 (JSON, YAML, XML 등)를 직렬화하거나 (Serialize) 역질렬화 (Deserialize) 할 수 있기만 하면 되는 경우
- 아주 많은 양의 데이터를 저장할 필요가 있는 경우
- RDBMS
- 수직적 규모 확장과 수평적 규모 확장
- 수직적 규모 확장 (Vertical Scaling) == 스케일 업 (Scale Up)
- 서버에 고사양 자원 (더 좋은 CPU, 더 많은 RAM)을 추가하는 행위
- 즉 서버 스펙을 올리는 행위를 수직적 규모 확장 / 스케일 업이라 함
- 장점
- 서버로 유입되는 트래픽의 양이 적을 때 좋음
- 단순함
- 단점
- 한 대의 서버에 CPU나 메모리를 무한대로 증설할 수 없는 한계가 존재
- 자동 복구 (Failover) 방안이나 다중화 (Redundancy) 방안 X
- 즉 한 대의 서버만으로 운용되기에 서버 장애 발생시 서비스는 완전히 중단
- 이런 단점 때문에, 대규모 애플리케이션 서비스에서는 수평적 규모 확장법 / 스케일 아웃이 적절
- 수평적 규모 확장 (Horizontal Scaling) == 스케일 아웃 (Scale Out)
- 더 많은 서버를 추가하여 성능을 개선하는 행위
- 수직적 규모 확장 (Vertical Scaling) == 스케일 업 (Scale Up)
- 로드밸런서 (Load Balancer)
- 부하 분산 집합 (Load Balancing Set)에 속한 웹 서버들에게 트래픽 부하를 고르게 분산하는 역할
- 도로 위의 교통 경찰, 모범 운전 신호수로 비유 가능
- 사용자는 로드밸런서의 공개 IP 주소로 접속
- 웹 서버는 클라이언트의 직접 접속을 처리하지 않음
- 로드 밸런서와 웹 서버간에는 보안을 위한 사설 IP 주소로 통신 (같은 네트워크에 속해있음)
- 로드 밸런서를 사용하면 장애를 자동복구하지 못하는 문제 (Failover)는 해소되며, 웹 계층의 가용성 (Availability)는 향상된다.
- 로드 밸런서의 자동 복구 과정
- 서버 1이 다운되면 모든 트래픽은 서버 2로 전송
- 따라서 웹 사이트 전체가 다운되는 일은 방지
- 부하를 나누기 위해 새로운 서버를 추가할 수도 있음
- 웹 사이트로 유입되는 트래픽이 가파르게 증가하면 두 대의 서버로 트래픽을 감당할 수 없는 시점이 옴
- 더 많은 웹 서버를 추가하여 로드밸런서를 통해 트래픽을 분산시켜 해결할 수 있음
- 서버 1이 다운되면 모든 트래픽은 서버 2로 전송
- 데이터베이스 다중화 (Database Replication)
- 데이터베이스 서버 사이에 Master-Slave 관계를 설정하고, 데이터 원본은 주 서버 (Master)에, 사본은 부 (Slave) 서버에 저장하는 방식
- 쓰기 연산 (Write Operation)은 마스터에서만 지원한다. 부 데이터베이스는 주 데이터베이스로부터 그 사본을 전달받으며, 읽기 연산 (Read Operation)만을 지원한다.
- DB를 변경하는 명령어 (Insert, Delete, Update 등)은 주 데이터베이스로만 전달된다.
- 대부분의 애플리케이션은 읽기 연산의 비중이 쓰기 연산보다 훨씬 높기 때문에 통상 부 데이터베이스의 수가 주 데이터베이스의 수보다 많다.
- 데이터베이스 다중화의 장점
- 더 나은 성능 보장
- 안정성
- 가용성
- 데이터베이스 서버 가운데 하나가 다운된다면?
- 부 서버가 한 대 뿐인데 다운된 경우
- 읽기 연산은 한시적으로 모두 주 데이터베이스에 전달
- 주 데이터베이스 서버가 다운된 경우
- 한 대의 부 데이터베이스가 있는 경우 해당 부 데이터베이스 서버가 새로운 주 서버가 됨
- 모든 데이터베이스 연산은 일시적으로 새로운 주 서버상에서 수행
- 프로덕션 환경에서는 훨씬 복잡한데, 부 서버에 보관된 데이터가 최신 상태가 아닐 가능성이 있기 때문.
- 없는 데이터는 복구 스크립트를 돌려 추가해야 함.
- 다중 마스터(Multi-Master)나 원형 다중화 (Circular Replication) 방식을 도입하여 이런 상황에 대처할 수 있지만, 해당 구성은 훨씬 복잡함
- 부 서버가 한 대 뿐인데 다운된 경우
- 캐시를 활용한 응답 시간 (Latency) 개선
- 캐시 (Cahce)를 붙이고 정적 콘텐츠를 콘텐츠 전송 네트워크 (Content Delivery Network, CDN)로 옮겨 개선
- 캐시란 (Cache)
- 캐시는 값 비싼 연산 결과 또는 자주 참조되는 데이터를 메모리 안에 두고, 뒤이은 요청이 보다 빨리 처리될 수 있도록 하는 저장소
- 웹 페이지를 새로고침 할 때마다 표시할 데이터를 가져오기 위해 한 번 이상의 데이터베이스 호출이 발생하는데, 캐시는 이런 문제를 완화할 수 있다.
- 캐시 계층 (Cache Tier)
- 데이터가 잠시 보관되는 공간, 데이터베이스보다 훨씬 빠르다.
- 별도의 캐시 계층을 통해 성능 개선과 데이터베이스 부하 절감 가능
- 캐시 계층의 규모를 독립적으로 확장시키는 것도 가능
- 읽기 주도형 캐시 전략 (Read-Through Caching Strategy) 요청 과정
- 요청을 받는 웹 서버는 캐시에 응답이 저장되어 있는지 확인
- 저장되어 있다면 (Cache Hit)
- 해당 데이터를 캐시에서 클라이언트에 반환
- 저장되어 있지 않다면 (Cache Miss)
- 데이터베이스 질의를 통해 데이터를 찾아 캐시에 저장한 후 클라이언트에 반환
- 이외에도 캐시할 데이터 종류, 크기, 액세스 패턴에 맞는 다양한 캐시 전략이 있음
- 캐시 서버를 사용할 때 유의할 점
- 캐시는 어떤 상황에 바람직한가?
- 데이터 갱신은 자주 일어나지 않지만 참조는 빈번하게 일어날 때
- 어떤 데이터를 캐시에 두어야 하는가?
- 캐시는 데이터를 휘발성 메모리에 두므려 영속적(Persistence)으로 보관할 데이터를 캐시에 두는 것은 바람직하지 않다.
- 캐시 서버가 재시작 되면 캐시 내의 모든 데이터는 사라진다.
- 중요 데이터는 여전히 지속적 저장소 (Persistent Data Store)에 두어야 안전
- 캐시는 데이터를 휘발성 메모리에 두므려 영속적(Persistence)으로 보관할 데이터를 캐시에 두는 것은 바람직하지 않다.
- 캐시에 보관된 데이터는 어떻게 만료되는가?
- 캐시 데이터 만료 정책을 마련하는 것은 좋은 습관
- 만료된 데이터는 캐시에서 삭제되어야 한다.
- 만료 정책이 없으면 데이터는 캐시에 계속 남게 됨.
- 만료 기한이 너무 짧으면 데이터베이스를 너무 자주 읽게 되고, 만료 기한이 너무 길면 원본과 캐시가 가진 데이터의 차이가 날 가능성이 높다.
- 일관성은 어떻게 유지되는가?
- 일관성 : 데이터 저장소의 원본과 캐시 내의 사본이 같은지 여부
- 저장소의 원본을 갱신하는 연산과 캐시를 갱신하는 연산이 단일 트랜잭션으로 처리되지 않는 경우 이 일관성은 깨질 수 있다.
- 여러 지역에 걸쳐 시스템을 확장해 나가는 경우 캐시와 저장소 사이의 일관성을 유지하는 것은 어려운 문제가 된다.
- 장애는 어떻게 대처할 것인가?
- 캐시 서버를 한 대만 두는 경우 해당 서버는 단일 장애 지점 (Single Point of Failure, SPOF)이 되어버릴 가능성이 있다.
- 단일 장애 지점 (SPOF)
- 어떤 특정 지점에서의 장애가 전체 시스템의 동작을 중단시켜버릴 수 있는 경우, 해당 지점
- 단일 장애 지점 (SPOF)
- SPOF를 피하기 위해 여러 지역에 걸쳐 캐시 서버를 분산해야 한다.
- 캐시 서버를 한 대만 두는 경우 해당 서버는 단일 장애 지점 (Single Point of Failure, SPOF)이 되어버릴 가능성이 있다.
- 캐시는 어떤 상황에 바람직한가?
- 캐시 메모리는 얼마나 크게 잡을 것인가?
- 캐시 메모리가 너무 작으면 액세스 패턴에 따라 데이터가 너무 자주 캐시에서 밀려나(Eviction) 캐시 성능이 떨어지게 된다.
- 캐시 메모리를 과할당 (OverProvision)하여 캐시에 보관될 데이터가 갑자기 늘어났을 때 생길 문제를 방지할 수 있다.
- 데이터 방출 (Evction) 정책은 무엇인가?
- 캐시가 꽉 차버리면 추가로 캐시에 데이터를 넣어야 할 경우 기존 데이터를 내보내야 한다.
- 가장 널리 쓰이는 것은 LRU (Least Recently Used)
- 마지막으로 사용된 시점이 가장 오래된 데이터를 내보내는 정책
- 다른 정책으로는 LFU (Least Frequently Used)
- 사용된 빈도가 가장 낮은 데이터를 내보내는 정책
- FIFO (First In First Out)
- 가장 먼저 캐시에 들어온 데이터를 가장 먼저 내보내는 정책
- 경우에 맞게 적합한 정책을 채택해야 한다.
- 콘텐츠 전송 네트워크 (CDN)
- CDN은 정적 콘텐츠를 전송하는 데 쓰이는, 지리적으로 분산된 서버의 네트워크
- 이미지, 비디오, CSS, JavaScript 파일 등
- CDN 동작 과정
- 웹 사이트 방문
- 사용자에게 지리적으로 가장 가까운 CDN 서버가 정적 콘텐츠를 전달
- 사용자가 CDN 서버로부터 멀 수록 웹 사이트는 천천히 로드
- CDN 서버에 해당 정적 콘텐츠가 없는 경우, 서버는 원본 (Origin) 서버에 요청하여 파일을 가져온다.
- 원본 서버는 웹 서버일 수도 있고, 아마존 S3와 같은 온라인 저장소일수도 있다.
- 원본 서버가 파일을 CDN 서버에 반환
- 응답의 HTTP 헤더에는 해당 파일이 얼마나 오래 캐시될 수 있는지를 설명하는 TTL(Time To Live) 값이 들어있음
- CDN 서버는 파일을 캐시하고 사용자 A에게 반환. 이미지는 TTL에 명시된 시간이 끝날 때 까지 캐시
- 사용자 B가 같은 이미지에 대한 요청을 CDN 서버에 전송
- 만료되지 않은 이미지에 대한 요청은 캐시를 통해 처리
- CDN 사용시 고려해야 할 사항
- 비용
- 보통 제 3 사업자 (Third-Party Providers)에 의해 운영되며, CDN으로 들어가고 나가는 데이터 전송 양에 따라 요금이 부과
- 자주 사용되지 않는 콘텐츠를 캐싱하는 것은 손해
- 적절한 만료 시한 설정
- 시의성(Time-Sensitive)이 중요한 콘텐츠의 경우 만료 시점을 잘 정해야 한다.
- CDN 장애에 대한 대처 방안
- CDN 자체가 죽었을 경우 웹사이트/애플리케이션이 어떻게 동작해야 할지 고려
- 가령 일시적으로 CDN이 응답하지 않을 경우, 해당 문제를 감지하여 원본 서버로부터 직접 콘텐츠를 가져오도록 클라이언트를 구성해야 함
- 콘텐츠 무효화 (Invalidation) 방법
- 아직 만료되지 않은 콘텐츠라 하더라도 아래 방법 가운데 하나를 통해 CDN에서 제거 가능
- CDN 서비스 사업자가 제공하는 API를 이용하여 콘텐츠 무효화
- 콘텐츠의 다른 버전을 서비스하도록 오브젝트 버저닝 (Obejct Versioning)
- 콘텐츠의 새로운 버전을 지정하기 위해 URL 마지막에 버전 번호를 인자로 줌
- ex) image.png?v=2
- 아직 만료되지 않은 콘텐츠라 하더라도 아래 방법 가운데 하나를 통해 CDN에서 제거 가능
- 비용
- 무상태 (Stateless) 웹 계층
- 웹 계층을 수평적으로 확장하는 방법을 고민해보자.
- 상태 정보 (사용자 세션 데이터 등)를 웹 계층에서 제거해보자
- 상태 정보를 RDB나 NoSQL 같은 지속성 저장소에 보관하고, 필요할 때 가져오기
- 이렇게 구성된 웹 계층을 무상태 웹 계층이라 부른다.
- 상태 정보 의존적 아키텍처
- 상태 정보를 보관하는 서버는 클라이언트 정보 (상태)를 유지하여 요청들 사이에 공유되도록 한다. 무상태 서버에는 이런 장치가 없다.
- 상태 정보 의존적 아키텍처에서 같은 클라이언트로부터 요청은 항상 같은 서버로 전송되어야 한다.
- 대부분의 로드밸런서가 이를 지원하기 위해 고정 세션 (Sticky Sesion)이라는 기능을 제공하고 있는데, 이는 로드밸런서에 부담을 준다.
- 로드밸런서 뒷단에 서버를 추가하거나 제거하기도 까다로워진다.
- 서버의 장애를 처리하기도 복잡해진다.
- 무상태 아키텍처
- 무상태 아키텍처에서 사용자로부터의 요청은 어떤 웹 서버로도 전달될 수 있다.
- 웹 서버는 상태 정보가 필요할 경우 공유 저장소 (Shared Storage)로부터 데이터를 가져온다.
- 상태 정보는 웹 서버로부터 물리적으로 분리되어 있고, 이런 구조는 단순하고, 안정적이며, 규모 확장이 쉽다.
- 데이터 센터
- 두 개의 데이터 센터를 사용한다고 가정
- 장애가 없는 상황에서 사용자는 가장 가까운 데이터 센터로 안내된다.
- 이 절차를 지리적 라우팅 (geoDNS-Routing / geo-routing)이라 부른다.
- 지리적 라우팅에서의 geoDNS는 사용자의 위치에 따라 도메인 이름을 어떤 IP 주소로 변환할지 결정해주는 DNS 서비스
- 데이터 센터 중 하나에 심각한 장애가 발생하면 모든 트래픽은 장애가 없는 데이터 센터로 전송
- 이 사례와 같은 다중 데이터센터 아키텍처를 만드려면 몇 가지 기술적 난제를 해결해야 함
- 트래픽 우회
- 올바른 데이터 센터로 트래픽을 보내는 효과적인 방법을 찾아야 함. GeoDNS는 사용자에게서 가장 가까운 데이터 센터로 트래픽을 보냄
- 데이터 동기화
- 데이터 센터마다 별도의 데이터베이스를 사용하고 있는 상황이라면, 장애가 자동으로 복구되어 트래픽이 다른 데이터베이스로 우회된다 해도, 해당 데이터센터에는 데이터가 없을 수 있음. 이런 상황을 막기 위해 데이터를 여러 데이터 센터에 걸쳐 다중화할 수 있다 (Netflix 사례)
- 테스트와 배포
- 웹 사이트 또는 애플리케이션을 여러 위치에서 테스트해 보는 것이 중요
- 자동화된 배포 도구는 모든 데이터 센터에 동일한 서비스가 설치되도록 하는데 중요한 역할
- 트래픽 우회
- 시스템을 더 큰 규모로 확장하기 위해서는 시스템의 컴포넌트를 분리하여 각기 독립적으로 확장될 수 있도록 하여야 한다.
- 메시지 큐 (Message Queue)는 많은 실제 분산 시스템이 채택한 핵심 전략 중 하나이다.
- 메시지 큐 (Message Queue)
- 메시지의 무손실을 보장하는 비동기 통신을 지원하는 컴포넌트
- 메시지의 버퍼 역할을 하며 비동기적으로 전송한다.
- 메시지 큐의 아키텍처
- 생산자 또는 발행자 (Producer / Publisher)라 불리는 입력 서비스가 메시지를 만들어 메시지 큐에 발행 (Publish)한다.
- 큐에는 보통 소비자 혹은 구독자 (Consumer / Subscriber)라고 불리는 서비스 혹은 서버가 연결되어 있는데, 메시지를 받아 그에 맞는 동작을 수행하는 역할을 한다.
- 메시지 큐를 이용하면 서비스 또는 서버 간 결합이 느슨해져서, 규모 확장성이 보장되어야 하는 안정적 애플리케이션을 구성하기 좋다.
- 생산자는 소비자 프로세스가 다운되어 있어도 메시지를 발행할 수 있고, 소비자는 생산자 서비스가 가용한 상태가 아니더라도 메시지를 수신할 수 있다.
- 로그, 메트릭, 자동화
- 웹 사이트와 함께 사업 규모가 커지고 나면, 필수적으로 로그, 메트릭, 자동화에 투자해야 함
- 로그
- 에러 로그를 모니터링
- 시스템의 오류와 문제들을 보다 쉽게 찾아내기 위함
- 서버 단위로 모니터링 할 수도 있지만, 로그를 단일 서비스로 모아주는 도구를 활용하여 편리하게 검색하고 조회할 수 있다.
- 메트릭
- 사업 현황에 관한 유용한 정보를 얻을 수 있고, 시스템의 현재 상태를 손쉽게 파악할 수 있다.
- 유용한 몇 가지 메트릭
- 호스트 단위 메트릭
- CPU, 메모리, 디스크 I/O
- 종합 (Aggregated) 메트릭
- 데이터베이스 계층의 성능, 캐시 계층의 성능
- 핵심 비즈니스 메트릭
- 일별 능동 사용자, 수익, 재방문
- 호스트 단위 메트릭
- 자동화
- 지속적 통합 (CI), 빌드, 테스트, 배포 절차 자동화
- 데이터베이스 규모 확장
- 수직적 규모 확장법 (스케일 업)
- 데이터베이스 서버 하드웨어의 한계가 있어 한 대의 서버를 무한히 증설할 수는 없다.
- SPOF (Single Point of Failure) 위험
- 고비용
- 수평적 규모 확장법 (스케일 아웃)
- 데이터베이스의 수평적 확장 (스케일 아웃)은 샤딩(Shardign)이라고 부른다.
- 샤딩 (Sharding)
- 데이터베이스를 샤드 (Shard)라고 부르는 작은 단위로 분할
- 모든 샤드는 같은 스키마를 쓰지만 샤드에 보관되는 데이터 사이에는 중복이 없다
- 샤딩 전략을 구현할 때 샤딩 키(Sharding Key)를 어떻게 정할지 고려해야 한다.
- 샤딩 키 (Sharding Key)는 파티션 키(Partition Key)라고도 부른다.
- 데이터가 어떻게 분산될지 정하는 하나 이상의 칼럼으로 구성된다.
- 샤딩 키가 user_id, 분할할 DB가 4개일경우 user_id % 4로 중복 없이 데이터를 분할할 수 있다.
- 샤딩 키를 통해 올바른 데이터베이스에 질의를 보내어 데이터 조회나 변경을 처리하므로 효율을 높일 수 있다.
- 샤딩 키를 정할 때는 데이터를 고르게 분할 할 수 있도록 하는게 가장 중요하다.
- 샤딩은 데이터베이스 규모 확장을 실현하는 훌륭한 기술이지만 완벽하진 않다.
- 샤딩을 도입하면 시스템이 복잡해지고 풀어야 할 새로운 문제도 생긴다.
- 데이터의 재 샤딩 (Resharding)
- 데이터가 너무 많아져서 하나의 샤드로는 더 이상 감당하기 어려울 때
- 샤드 간 데이터의 분포가 균등하지 못하여 어떤 샤드에 할당된 공간 소모가 다른 샤드에 비해 빨리 진행될 때
- 샤드 소진(Shard Exhaustion)이라고도 불르는 현상이 발생되면 샤드 키를 계산하는 함수를 변경하고 데이터를 재배치하여야 한다.
- 추후 기술할 안정 해시 (Consistent Hashing) 기법을 통해 해결 가능
- 유명 인사 (Celebrity) 문제
- 핫스팟 키 (Hotspot Key) 문제라고도 부르는데, 특정 샤드에 질의가 집중되어 서버에 과부하가 걸리는 문제
- 유명인사가 전부 같은 샤드에 저장되는 데이터베이스가 있다고 가정
- 이 데이터로 SNS 서비스를 구축하게 되면 결국 해당 샤드에는 Read 연산으로 인한 과부하에 걸리게 될 것
- 해결하기 위해 유명인사 각각에 샤드 하나씩을 할당해야 할 수도 있고, 심지어는 더 잘게 쪼개야 할 수도 있다.
- 조인과 비정규화 (Join and De-normalization)
- 일단 하나의 DB를 여러 샤드 서버로 쪼개고 나면, 여러 샤드에 걸친 데이터를 조인하기가 힘들어진다.
- 이를 위해 DB를 비정규화하여 하나의 테이블에서 질의가 수행될 수 있게 해야 한다.
- 데이터의 재 샤딩 (Resharding)
- 수직적 규모 확장법 (스케일 업)
- 백만 사용자, 그리고 그 이상
- 시스템의 규모를 확장하는 것은 지속적으로 반복적인 과정이다.
- 1장에서 다룬 내용을 반복하다 보면 우리는 원하는 규모의 시스템에 달성할 수 있다
- 그러나 수백만 사용자 이상을 지원하려면 새로운 전략을 도입해야 하며, 지속적으로 시스템을 가다듬어야 한다.
- 예를 들어, 시스템을 최적화 하고 더 작은 단위의 서비스로 분할해야 할 수도 있다.
- 정리
- 웹 계층은 무상태 (Stateless) 계층으로
- 모든 계층에 다중화 도입
- 가능한 한 많은 데이터를 캐시할 것
- 여러 데이터 센터를 지원할 것
- 정적 콘텐츠는 CDN을 통해 서비스할 것
- 데이터 계층은 샤딩을 통해 그 규모를 확장할 것
- 각 계층은 독립적 서비스로 분할할 것
- 시스템을 지속적으로 모니터링하고, 자동화 도구들을 활용할 것
느낀 점
- 대규모 트래픽을 감당할수 있는 안정적인 고가용성 서버를 구성하기 위한 기초 지식을 쌓기 위해 해당 책을 공부하기 시작했다.
- 지금껏 해왔던 프로젝트에서 어떤 부분이 미흡했고, 어떤 식의 확장 전략을 세울 수 있을지 고민해보며 책을 읽는다면 좋을 것 같다.
'개발 이야기 (Dev Story)' 카테고리의 다른 글
[아키텍처 패턴] 레이어 패턴 (Layered Pattern) (0) | 2024.05.10 |
---|---|
"가상 면접 사례로 배우는 대규모 시스템 설계 기초"를 읽고 - 3장 (0) | 2024.05.10 |
"그림으로 공부하는 마이크로서비스 구조" 을 읽고 (5장 - 끝) (2) | 2024.01.24 |
"그림으로 공부하는 마이크로서비스 구조" 을 읽고 (1장 - 4장) (0) | 2024.01.20 |
Apple Developer Program 애플 개발자 등록 오류, 안될 때 (0) | 2023.09.06 |