TIL

9장 S3와 유사한 객체 저장소

저장소 시스템 101

용어 정리

1단계: 문제 이해 및 설계 범위 확정

2단계: 개략적 설계안 제시 및 동의 구하기

객체 저장소의 속성

개략적 설계안

graph LR
    User([사용자]) --> LB[로드밸런서]
    LB --> API[API 서비스]
    API --> IAM[IAM]
    API --> MDS
    MD --> MDB[(메타데이터 DB)]
    
    subgraph MDS[메타데이터 저장소]
	    MD[메타데이터 서비스]
	    MDB
    end
    
    API --> DS
    
    subgraph DS[데이터 저장소]
        DSS1[데이터 저장소 서비스] --> SN1[(저장소 노드)]
        DSS2[데이터 저장소 서비스] --> SN2[(저장소 노드)]
        DSS3[데이터 저장소 서비스] --> SN3[(저장소 노드)]
        
        %% 주 노드(Primary)에서 부 노드(Secondary)로의 요청
        DSS2 --> DSS1
        DSS2 --> DSS3
        
        %% 주 노드 표시
        class DSS2,SN2 primary
        class DSS1,SN1,DSS3,SN3 secondary
    end

객체 업로드

  1. 클라이언트는 버킷 생성을 의한 PUT 요청 전송
  2. API 서비스는 IAM을 호출하여 사용자가 WRITE 권한을 가지는 지 확인
  3. API 서비스는 메타데이터 데이터베이스에 버킷 정보 등록을 위해 메타데이터 저장소를 호출
  4. 버킷 생성 후 클라이언트는 업로드할 객체를 생성하기 위한 PUT 요청 전송
  5. API 서비스는 해당 사용자의 신원과 WRITE 권한을 확인
  6. API 서비스는 PUT 요청 안의 데이터를 데이터 저장소로 보낸 후 객체의 UUID를 반환한다.
  7. API 서비스는 메타데이터 저장소에 새로운 항목을 등록한다.

객체 다운로드

  1. 클라이언트는 GET /{버킷 이름}/{객체 ID} 요청을 로드밸런서로 전송
  2. API 서비스는 IAM을 통해 READ 권한이 있는지 확인
  3. API 서비스는 해당 객체의 UUID를 메타데이터 저장소에서 가져온다.
  4. API 서비스는 UUID로 데이터 저장소에 질의하여 객체 데이터를 가져온다.
  5. API 서비스는 GET 요청의 응답으로 객체 데이터를 반환한다.

3단계: 상세 설계

데이터 저장소

graph LR
    DR[데이터 라우팅 서비스]
    BS[배치 서비스]
    
    DN1[(데이터 노드_주)]
    DN2[(데이터 노드_부)]
    DN3[(데이터 노드_부)]
    
    DR <--> BS
    
    BS <-.-> |박동 메시지| DN1
    BS <-.-> |박동 메시지| DN2
    BS <-.-> |박동 메시지| DN3
    
    DN1 --> |데이터 다중화| DN2
    DN1 --> |데이터 다중화| DN3
    
    DR <--> |데이터 트래픽| DN1
   

데이터 저장흐름

graph LR
		API[API 서비스]
    DR[데이터 라우팅 서비스]
    BS[배치 서비스]
    
    DN1[(데이터 노드_주)]
    DN2[(데이터 노드_부)]
    DN3[(데이터 노드_부)]
    
    API -->|1.데이터 기록| DR
    DR -->|5.객체 ID를 응답| API
    DR <-->|2.주 노드 선정| BS
    
    BS <-.-> |박동 메시지| DN1
    BS <-.-> |박동 메시지| DN2
    BS <-.-> |박동 메시지| DN3
    
    DN1 --> |4.데이터 다중화| DN2
    DN1 --> |4.데이터 다중화| DN3
    
    DR -->|3.데이터를 주 노드에 전송| DN1
   

  1. API 서비스는 객체 데이터를 데이터 저장소로 포워딩
  2. 라우팅 서비스가 객체에 UUID 할당 후 배치 서비스에 해당 객체를 보관할 데이터 노드를 질의 (주 노드를 반환)
  3. 데이터 라우팅 서비스는 UUID와 함께 주 데이터 노드에 객체를 직접 전송
  4. 주 데이터 노드는 데이터를 지역적으로 저장하고 다른 부 데이터 노드에 다중화
  5. 객체의 UUID를 API 서비스에 반환

데이터는 어떻게 저장되는가

graph TD
    A[객체 저장 요청] -->|새로운 데이터| B[쓰기 가능한 파일 열기]
    B -->|파일에 데이터 추가| C[쓰기 중인 파일]
    C -->|파일 용량 확인| D{파일 용량 초과?}
    D -->|아니오| B
    D -->|예| E[쓰기 파일을 읽기 전용으로 변경]
    E --> F[새로운 쓰기 가능한 파일 생성]
    F --> B

객체 소재 확인

graph LR
		API[API 서비스]
    DN[데이터 노드 서비스]
    
    subgraph FLS[지역 파일 시스템]
	    RDF1[읽기 전용 파일]
	    RDF2[읽기 전용 파일]
	    RWF[읽기-쓰기 파일]
    end
    
    OPD[(객체 위치 데이터베이스)]
    
    API -->|1| DN
    DN -->|2| RWF
    DN -->|3| OPD
    DN -->|4| API
    
  1. API 서비스가 새로운 객체를 저장하기 위해 데이터 노드 서비스에 요청
  2. 데이터 노드 서비스는 객체를 읽기-쓰기 파일의 마지막 부분에 추가
  3. 해당 객체에 대한 새로운 레코드를 위치 데이터베이스의 레코드로 추가
  4. 데이터 노드 서비스는 API 서비스에 해당 객체의 UUID를 반환

데이터 내구성

99.9999%(six-nine) 수준 데이터 내구성을 제공하려면 무엇이 필요할까?

  다중화 소거 코드
내구성 99.9999%(3중 복제의 경우) 99.999999999(8+4 소거 코드인 경우)
저장소 효율성 200% 저장 용량 오버 헤드 50% 저장 용량 오버 헤드
계산 자원 계산이 필요 없음 패티이 계산에 자원이 소모
쓰기 성능 추가 계산 작업이 필요 없이 데이터를 여러 노드에 복제 데이터를 기록하기 전 패리티 계산이 필요하므로 쓰기 지연 발생
읽기 성능 멀쩡한 노드에서 단순히 데이터를 읽음 데이터를 읽을 때마다 여러 노드에서 데이터를 가져와야 함. 장애 발생 시 복원 지연 시간 증가

메타데이터 데이터 모델

버킷 내 객체 목록 확인

단일 데이터베이스 서버

분산 데이터베이스

객체 버전

  1. 클라이언트는 script.txt 객체를 업로드하기 위한 PUT 요청을 전송
  2. API 서비스는 버킷에 쓰기 권한을 가지는 지 확인
  3. 문제가 없으면 데이터를 데이터 저장소에 업로드 후 API 서비스에 새로운 UUID 반환
  4. API 서비스는 메타데이터 저장소를 호출해 새 객체의 메타데이터를 보관
  5. 버전 기능 지원을 위해 메타데이터 객체 테이블엔 object_version 열이 존재한다.
    • 같은 이름의 객체를 업로드하는 경우 기존 레코드를 덮어쓰는 대신 bucket_id와 bucket_name은 같은, object_id와 object_version이 새로운 값인 레코드를 추가한다.
    • object_Version은 TIMEUUID 값이기에 큰 것이 최신 버전이다.

큰 파일의 업로드 성능 최적화

쓰레기 수집