Google Cloud Storage
고친 사람 github-actions[bot]
Google Cloud Storage 는 파일을 구글에 맡겨 두고 이름 하나로 다시 꺼내 주는 저장 서비스입니다. 쓰는 쪽은 디스크를 사거나 늘리지 않고 웹 요청으로 넣고 꺼냅니다. 맡긴 파일은 고쳐 쓰는 대신 새 파일로 통째로 바꿉니다.
쉽고 빠른 이해
- 무슨 일을 하나 — 파일을 구글 쪽 창고에 맡겨 두고 이름으로 꺼냅니다.
puppy.png라는 이름으로 사진을 올려 두면 나중에 같은 이름으로 받습니다. - 왜 이렇게 하나 — 디스크를 사서 늘리지 않아도 됩니다. 데이터를 분석하던 클러스터를 내려도 맡긴 데이터는 남아서 계속 읽힙니다.
- 어떻게 도나
- 버킷이라는 통을 만듭니다. 만들 때 데이터를 둘 지역을 고릅니다.
- 파일에 이름을 붙여 올립니다. 올릴 때마다 그 파일에 새 판 번호가 붙습니다.
- 덮어쓸 때 「판 번호가 아직 이것일 때만」 조건을 겁니다. 다른 쪽이 먼저 썼으면 요청이 거절됩니다.
- 대가 — 파일 가운데 일부만 고치거나 뒤에 덧붙일 수 없습니다. 같은 이름에는 1초에 한 번꼴로만 쓸 수 있습니다. 일부 보관 등급은 정해진 기간 전에 지우면 그 기간을 다 채운 만큼 요금을 냅니다.
상세
이 절은 사진 한 장 puppy.png 를 올려 두는 일을 놓고 씁니다. 그 파일이 누구 것이 되는지, 어디에 놓이는지, 어떤 요청으로 불리는지, 어떤 번호로 판을 가리키는지를 차례로 짚습니다.
Google Cloud Storage, 줄여서 GCS 는 구글 클라우드가 운영하는 저장 서비스입니다. 데이터를 오브젝트라는 단위로 버킷이라는 통에 담습니다. 오브젝트는 파일 하나를 담은 데이터 덩어리입니다. 파일 형식은 가리지 않습니다. 버킷 하나에 담는 오브젝트 수에는 사실상 한도가 없습니다.
같은 일을 하는 서비스로 Amazon S3(Simple Storage Service)가 있습니다. 아마존 웹 서비스, 줄여서 AWS(Amazon Web Services)가 운영하는 서비스입니다. 버킷에 오브젝트를 넣고 웹 요청으로 꺼낸다는 뼈대는 둘이 같습니다. 아래 소절들은 둘이 다른 대목에 무게를 둡니다.
버킷의 주인인 프로젝트
GCS 의 버킷은 전부 어느 한 프로젝트에 속합니다. 프로젝트는 구글 클라우드가 자원을 묶는 단위입니다. 사용자 목록과 쓸 수 있는 API(Application Programming Interface, 프로그램이 다른 프로그램을 부르는 창구), 그리고 요금·인증·감시 설정을 한데 담습니다. 버킷과 오브젝트, 그것을 읽을 수 있는 사람의 권한도 프로젝트 안에 삽니다. S3 에는 프로젝트가 없습니다.
프로젝트 위로 계층이 둘 더 있습니다. 프로젝트를 묶는 조직과, 조직 안에서 프로젝트를 다시 묶는 폴더입니다. 이 폴더는 프로젝트를 묶는 관리 단위입니다. 뒤 「진짜 폴더」 소절에 나오는 버킷 안의 폴더와는 다른 것입니다.
권한은 IAM(Identity and Access Management, 신원과 접근 관리)으로 줍니다. 사용자에게 역할을 주면 그 역할에 묶인 권한을 얻습니다. 조직이나 폴더에 준 역할은 그 아래 모든 프로젝트로 내려갑니다.
flowchart TD
O["조직 · 준 역할이 아래로 내려간다"] --> F["폴더 · 프로젝트를 묶는 관리 단위"]
F --> P["프로젝트 · 사용자 · API · 요금 설정"]
P --> B["버킷 · 만들 때 위치를 정한다"]
B --> K["오브젝트 · puppy.png"]
프로젝트에 역할을 주면 그 프로젝트의 모든 버킷과 오브젝트에 걸립니다. 버킷 하나에 주면 그 버킷과 안의 오브젝트에만 걸립니다. 위 계층에서 받은 권한과 버킷에서 받은 권한은 더해집니다.
버킷 위치의 네 종류
버킷을 만들 때 데이터를 둘 지리적 위치를 고릅니다. 위치의 종류가 데이터를 어떻게 복제하는지와 요금을 정합니다.
표에 앞서 낱말 넷을 풉니다. 리전은 아이오와처럼 특정한 지역 하나입니다. 가용 영역은 한 리전을 나눈 구역입니다. 동기 복제는 쓰기를 마치기 전에 모든 복제본을 맞춰 두는 방식입니다. 비동기 복제는 쓰기를 먼저 마칩니다. 다른 복제본에는 그 뒤에 옮깁니다.
존은 리전 안의 한 구역입니다. 존 위치는 Rapid Bucket 으로만 고릅니다. Rapid Bucket 은 버킷을 존 하나에 두는 기능입니다. 이렇게 만든 버킷을 존 버킷이라 부릅니다. 존 버킷은 낮은 지연과 높은 처리량을 줍니다.
| 위치 종류 | 무엇인가 | 복제와 조건 |
|---|---|---|
| 리전 | 특정한 지역 하나. 아이오와의 US-CENTRAL1 |
리전 안의 가용 영역 사이에서 동기로 |
| 이중 리전 | 정해진 리전 한 쌍. 도쿄와 오사카를 묶은 ASIA1 |
리전 사이에서 비동기로. 15분 안에 복제를 마치는 터보 복제를 고를 수 있습니다 |
| 멀티 리전 | 리전 둘 이상을 담는 넓은 지역. 미국 전체인 US |
리전 사이에서 비동기로 |
| 존 | 리전 안의 한 구역. US-CENTRAL1-A |
Rapid Bucket 으로 만든 존 버킷만 이 위치를 고릅니다 |
위치는 만들 때 정합니다. 다 만든 버킷을 다른 위치로 옮기는 버킷 재배치도 있습니다. 다만 Storage Intelligence 라는 별도 설정을 해 둔 경우에만 쓸 수 있습니다. 그 밖에는 다른 위치에 버킷을 새로 만들어 데이터를 옮깁니다.
JSON API 와 XML API
GCS 를 부르는 REST(Representational State Transfer) API 는 둘입니다. JSON(JavaScript Object Notation)으로 주고받는 JSON API 와, XML(Extensible Markup Language)로 주고받는 XML API 입니다. 터미널에서는 gcloud storage 명령으로 부릅니다.
XML API 는 S3 같은 서비스를 상대로 만든 도구와 라이브러리 가운데 일부와 함께 쓸 수 있습니다. 그런 도구를 GCS 에 붙이려면 요청 주소를 https://storage.googleapis.com 으로 바꿉니다. 그리고 GCS 의 HMAC(Hash-based Message Authentication Code, 해시 기반 메시지 인증 코드) 키를 쓰게 합니다. HMAC 키는 접근 ID 와 비밀 값 한 쌍입니다. 도구가 요청에 서명할 때 쓰던 AWS 접근 키와 비밀 키를 이것으로 바꿔 넣습니다.
고칠 것은 넷입니다.
- 기본 프로젝트를 정합니다. S3 에는 프로젝트가 없어서, 도구에 따라서는 요청에 프로젝트를 실어 보낼 수 없습니다.
- HMAC 키를 받습니다.
- 요청 주소를 바꿉니다.
x-amz-로 시작하는 헤더에 GCS 가 받는 값을 넣습니다. 이를테면x-amz-storage-class에는 GCS 의 보관 등급 이름이 가야 합니다.
보관 등급(storage class)은 오브젝트마다 붙는 저장 등급입니다. 등급마다 최소 보관 기간과 꺼내기 요금이 다릅니다. 등급 다섯과 그 값은 포기한 것 절의 표에 있습니다.
헤더 이름에도 짝이 있습니다. x-amz- 로 시작하는 헤더는 S3 쪽 헤더입니다. GCS 의 XML API 에는 x-goog- 로 시작하는 GCS 자신의 헤더가 있습니다. GCS 는 x-amz- 헤더 가운데 같은 일을 하는 x-goog- 헤더가 따로 있는 것을 처리합니다. 그 밖에 x-amz-decoded-content-length 헤더도 처리합니다.
세대 번호와 프리컨디션
GCS 의 오브젝트는 숫자 둘을 늘 달고 다닙니다. 세대 번호(generation)와 메타세대 번호(metageneration)입니다. 둘 다 오브젝트 메타데이터에 들어 있습니다.
세대 번호는 오브젝트의 판을 가리킵니다. 같은 이름으로 오브젝트를 새로 올리면 내용이 바뀐 새 오브젝트가 옛것을 대신합니다. 새 오브젝트는 새 세대 번호를 받습니다. 판마다 번호가 다르다는 것만 약속합니다. 뒤에 나온 판의 번호가 더 크다는 약속은 없습니다. 그래서 두 번호는 같은지 다른지만 견줍니다.
오브젝트 이름과 세대 번호를 함께 대면 버킷 안의 오브젝트 하나가 정해집니다. 덮인 옛 판을 지우지 않고 남기는 기능이 오브젝트 버전 관리입니다. 이 기능을 켜지 않은 버킷에서도 세대 번호는 붙습니다.
메타세대 번호는 같은 세대 안에서 메타데이터의 판을 가리킵니다. 새 세대가 생기면 1에서 시작합니다. 그 뒤로 메타데이터를 고칠 때마다 늘어납니다. 세대 번호 없이 메타세대 번호만 보면 아무 뜻이 없습니다.
이 번호가 쓰이는 곳이 프리컨디션입니다. 프리컨디션은 요청에 「대상이 이 상태일 때만 진행하라」는 조건을 붙이는 것입니다. 조건이 안 맞으면 요청은 412 Precondition Failed 로 실패합니다. 이렇게 실패시키면 요청이 예상하지 못한 판에 닿지 않습니다.
두 앱이 같은 오브젝트를 읽고 고쳐 다시 올리는 경우를 그리면 이렇습니다.
sequenceDiagram
participant A as 앱 A
participant G as GCS
participant B as 앱 B
A->>G: 메타데이터를 읽는다
G-->>A: 세대 G1
B->>G: 메타데이터를 읽는다
G-->>B: 세대 G1
A->>G: 세대가 G1 일 때만 올려라
G-->>A: 성공 · 새 세대 G2
B->>G: 세대가 G1 일 때만 올려라
G-->>B: 412 Precondition Failed
앱 B 의 쓰기는 거절됩니다. 앱 A 가 먼저 덮어써 세대가 바뀌었기 때문입니다. 조건 없이 올렸다면 앱 B 가 앱 A 의 쓰기를 모른 채 덮었을 것입니다.
세대 조건에 0 을 넣으면 뜻이 바뀝니다. 그 이름의 현재 오브젝트가 없을 때만 진행합니다. 「없을 때만 만든다」가 됩니다.
S3 에서는 오브젝트 이름을 키라고 부릅니다. 앞 소절의 접근 키와는 다른 낱말입니다. S3 에도 조건을 건 쓰기가 있습니다. If-None-Match 헤더를 달면 같은 키의 오브젝트가 없을 때만 씁니다. If-Match 헤더는 오브젝트의 ETag(entity tag, 내용이 바뀌면 함께 바뀌는 문자열)를 견줍니다. 버전 관리를 켜지 않은 S3 버킷에 조건 없이 쓰면 덮어씁니다. 이 점도 GCS 와 같습니다.
다른 것은 판을 무엇으로 가리키느냐입니다. GCS 는 세대·메타세대 번호를 내놓습니다. 그리고 대개 ETag 조건보다 이 번호 조건을 쓰라고 권합니다. 두 번호를 함께 보면 메타데이터 변경까지 포함해 모든 갱신을 추적합니다. 두 번호는 JSON API 로 보든 XML API 로 보든 같은 값입니다. ETag 는 그렇지 않습니다.
프리컨디션을 쓰는 설계 가운데 많은 수는 본 요청 앞에 메타데이터 요청을 한 번 더 보내야 합니다. 현재 세대를 알아야 조건을 걸 수 있기 때문입니다. 왕복이 한 번 느는 만큼 전체 지연 가운데 네트워크 몫이 최대 두 배까지 늘 수 있습니다.
포기한 것
안 하기로 한 것이 셋입니다. 오브젝트를 고쳐 쓰는 일, 버킷 안의 진짜 폴더, 보관 기간을 채우기 전에 요금 없이 빼는 일입니다.
고쳐 쓰기
오브젝트는 한번 올리면 지울 때까지 바뀌지 않습니다. 뒤에 덧붙이는 이어 쓰기도, 뒷부분을 잘라 내는 일도 없습니다. 이름 바꾸기도 없습니다. 이름을 바꾸려면 새 이름으로 복사한 뒤 옛것을 지웁니다.
할 수 있는 것은 같은 이름으로 통째로 바꿔 올리기입니다. 이 교체는 원자적입니다. 새 업로드가 끝날 때까지 읽는 쪽은 옛 판을 받습니다. 끝난 뒤로는 새 판을 받습니다. 반쯤 올라간 파일을 읽는 일이 없습니다.
얻은 것은 번호 하나로 판을 가리킬 수 있다는 점입니다. 내용이 바뀌는 길이 교체 하나뿐입니다. 그래서 교체마다 바뀌는 세대 번호가 곧 바뀌지 않는 오브젝트 하나를 가리킵니다. 상세의 프리컨디션이 이 번호를 씁니다.
덧붙이고 싶을 때는 합치기(compose)를 씁니다. 같은 버킷, 같은 보관 등급의 오브젝트를 1개에서 32개까지 순서대로 이어 붙여 새 오브젝트를 만듭니다. 데이터를 다시 올리지 않습니다. 나눠서 나란히 올린 조각을 하나로 다시 만들 때도 씁니다.
예외가 하나 있습니다. Rapid Bucket 으로 만든 존 버킷의 오브젝트는 전부 다시 쓰지 않고 뒤에 덧붙일 수 있습니다. 리전·이중 리전·멀티 리전 버킷에는 이 예외가 없습니다.
진짜 폴더
이 소절의 폴더는 버킷 안에서 오브젝트를 담는 폴더입니다. 상세에서 프로젝트를 묶던 폴더와는 다른 것입니다.
네임스페이스는 이름이 놓이는 공간입니다. 기본 버킷은 네임스페이스가 평평합니다. 오브젝트는 전부 버킷 바로 밑에 놓입니다. 버킷 안에 폴더가 없습니다. folder1/file.txt 라는 오브젝트를 올려도 folder1 이라는 폴더는 생기지 않습니다. folder1/ 은 오브젝트 이름의 앞부분일 뿐입니다.
그래서 폴더처럼 보이는 것의 이름을 바꾸려면 그 이름으로 시작하는 오브젝트를 하나씩 복사한 뒤 지워야 합니다. 오브젝트가 많으면 이 일은 비효율적일 수 있습니다. 비용도 클 수 있습니다. 원자적이지도 않습니다. 중간에 실패하면 일부만 옮겨진 채로 버킷이 남을 수 있습니다.
flowchart TD
subgraph 평평한["평평한 네임스페이스"]
B1["버킷"] --> O1["오브젝트 · folder1/file.txt"]
end
subgraph 계층["계층 네임스페이스"]
B2["버킷"] --> D2["폴더 · folder1"]
D2 --> O2["오브젝트 · file.txt"]
end
계층 네임스페이스를 켠 버킷은 폴더를 진짜 자원으로 갖습니다. 폴더 이름 바꾸기가 요청 한 번에 원자적으로 끝납니다. 아래 폴더까지 함께 바뀝니다.
버킷마다 처음에 받아 주는 초당 요청 수가 정해져 있습니다. 계층 네임스페이스 버킷은 이 값이 최대 8배 높습니다. 값 자체는 운영 절에 있습니다.
제약도 셋입니다. 계층 네임스페이스는 버킷을 만들 때만 켤 수 있습니다. 만든 뒤에는 바꿀 수 없습니다. 버킷 단위 IAM 으로 권한을 정하는 균일한 버킷 수준 액세스도 함께 켜야 합니다. 그리고 오브젝트 버전 관리 · 오브젝트 단위 ACL(Access Control List, 접근 제어 목록) 같은 기능 일곱 가지를 그 버킷에서 못 씁니다.
S3 에도 같은 구분이 있습니다. S3 범용 버킷은 평평합니다. S3 디렉터리 버킷은 데이터를 디렉터리 계층으로 나눕니다. 그래서 이 차이는 GCS 와 S3 의 차이가 아니라 버킷 종류의 차이입니다.
보관 기간 전의 이른 삭제
오브젝트마다 붙는 보관 등급은 다섯입니다. 등급마다 최소 보관 기간과 꺼내기 요금이 다릅니다. Rapid 는 존 버킷의 오브젝트가 늘 놓이는 등급입니다.
| 보관 등급 | API 이름 | 최소 보관 기간 | 꺼내기 요금 |
|---|---|---|---|
| Rapid | RAPID |
없음 | 없음 |
| Standard | STANDARD |
없음 | 없음 |
| Nearline | NEARLINE |
30일 | 있음 |
| Coldline | COLDLINE |
90일 | 있음 |
| Archive | ARCHIVE |
365일 | 있음 |
Nearline · Coldline · Archive 세 등급은 최소 보관 기간을 둡니다. 그 기간을 채우기 전에 지우거나 바꿔 올리거나 옮기면, 기간을 다 채운 것으로 치고 요금을 냅니다. 이 셋은 꺼내기 요금도 받습니다.
보관 등급을 손으로 바꾸는 것도 오브젝트를 다시 쓰는 일이라 이 요금이 붙습니다. 예외는 둘입니다. 하나는 수명 주기 관리(Object Lifecycle Management) 기능이 오브젝트의 등급을 바꿀 때입니다. 다른 하나는 Autoclass 라는 버킷 설정을 켠 버킷입니다.
등급이 달라도 읽는 방식은 같습니다. 모든 보관 등급이 낮은 지연으로 읽힙니다. 오프라인으로 내려가 꺼낼 때 기다려야 하는 데이터는 없습니다. 가장 싼 등급인 Archive 에 넣은 데이터도 밀리초 안에 읽힙니다.
예시
실물 셋입니다. 세대 조건을 건 덮어쓰기, 그 조건으로 잠금을 만든 Terraform, S3 서명을 단 채 GCS 로 가는 요청입니다.
세대 조건을 건 덮어쓰기
명령줄에서는 cp 에 플래그 하나를 붙입니다.
gcloud storage cp OBJECT_LOCATION gs://DESTINATION_BUCKET_NAME --if-generation-match=GENERATION
GENERATION 에는 덮어쓰려는 오브젝트의 세대 번호를 넣습니다. 이를테면 1122334455667788 입니다. 다른 쪽이 먼저 덮어써 세대가 바뀌었으면 이 업로드는 412 Precondition Failed 로 실패합니다.
JSON API 로는 같은 조건을 쿼리 파라미터로 붙입니다.
curl -X POST --data-binary @OBJECT_LOCATION \
-H "Authorization: Bearer $(gcloud auth print-access-token)" \
-H "Content-Type: OBJECT_CONTENT_TYPE" \
"https://storage.googleapis.com/upload/storage/v1/b/BUCKET_NAME/o?uploadType=media&name=OBJECT_NAME&ifGenerationMatch=GENERATION"
XML API 에서는 같은 조건이 x-goog-if-generation-match 헤더로 갑니다. 세대 번호는 오브젝트 메타데이터의 generation 필드에 있습니다. 메타세대 번호는 metageneration 필드에 있습니다. 둘 다 long 값입니다.
Terraform 상태 잠금
Terraform 은 만들어 둔 인프라의 상태를 상태 파일에 적어 둡니다. 둘이 동시에 그 파일을 고치지 못하게 막는 것이 상태 잠금입니다. GCS 를 상태 저장소로 쓰면 이 잠금을 세대 조건으로 만듭니다.
잠글 때는 잠금 파일을 「없을 때만」 조건으로 만듭니다. 세대 조건에 0 을 건 것과 같은 뜻입니다. 이미 누가 잠갔으면 파일이 있으므로 만들기가 실패합니다. 만들기에 성공하면 그 잠금 파일의 세대 번호를 잠금 ID 로 돌려줍니다.
w := lockFile.If(storage.Conditions{DoesNotExist: true}).NewWriter(ctx)
...
info.ID = strconv.FormatInt(w.Attrs().Generation, 10)
풀 때는 「세대가 이 번호일 때만」 조건으로 지웁니다. 그사이 잠금 파일이 다른 판으로 바뀌었다면 엉뚱한 잠금을 지우지 않습니다.
if err := c.lockFile().If(storage.Conditions{GenerationMatch: gen}).Delete(ctx); err != nil {
return c.lockError(err)
}
두 Terraform 실행이 같은 상태를 잠그려 할 때를 그리면 이렇습니다.
sequenceDiagram
participant A as Terraform A
participant G as GCS
participant B as Terraform B
A->>G: 잠금 파일을 없을 때만 만든다
G-->>A: 성공 · 세대 번호를 잠금 ID 로
B->>G: 잠금 파일을 없을 때만 만든다
G-->>B: 실패 · 파일이 이미 있다
A->>G: 세대가 그 번호일 때만 지운다
G-->>A: 성공 · 잠금이 풀린다
S3 서명 그대로 가는 요청
S3 용 도구가 GCS 의 XML API 로 보내는 업로드 한 줄입니다.
PUT europe/france/paris.jpg HTTP/1.1
Host: my-travel-maps.storage.googleapis.com
x-amz-acl: public-read
Authorization: AWS4-HMAC-SHA256 Credential=GOOG-ACCESS-ID/20190311/us-east-1/s3/aws4_request, SignedHeaders=...
버킷 이름 my-travel-maps 가 호스트 이름 앞에 붙습니다. 오브젝트 이름은 europe/france/paris.jpg 입니다. Authorization 헤더는 S3 의 서명 방식 표기를 달고 있습니다. 접근 ID 칸에는 AWS 키 대신 GCS HMAC 키의 접근 ID 가 들어갑니다. 이 서명 표기를 보고 GCS 는 요청에 x-amz- 헤더와 S3 ACL 문법이 온다고 알아듣습니다.
사용처
GCS 를 저장소로 받는 시스템 넷입니다. Terraform · Grafana Loki · Grafana Mimir 는 구글 밖에서 만든 것입니다. Hadoop · Spark 커넥터는 구글이 내놓은 오픈 소스 라이브러리입니다.
| 시스템 | 무엇을 GCS 에 두나 | GCS 에서 얻는 것 |
|---|---|---|
Terraform gcs 백엔드 |
인프라 상태 파일 | 상태를 오브젝트 하나로 둡니다. 잠금은 세대 조건으로 겁니다 |
| Grafana Loki · Mimir | 압축한 로그 덩어리 · 메트릭 블록 · 알림 설정 · 규칙 | 관리형 오브젝트 저장소. Loki 는 이미 구글 클라우드에서 돌릴 때 특히 맞다고 꼽습니다 |
| Hadoop · Spark 커넥터 | 분석할 원본 데이터 | 하둡 분산 파일 시스템으로 옮기지 않고 바로 읽습니다 |
Terraform gcs 백엔드
Terraform 은 상태를 미리 만들어 둔 버킷 안, 정해 둔 접두어 아래의 오브젝트 하나로 둡니다. 버킷은 백엔드를 설정하기 전에 있어야 합니다.
terraform {
backend "gcs" {
bucket = "tf-state-prod"
prefix = "terraform/state"
}
}
이 백엔드는 상태 잠금을 지원합니다. 그 잠금이 앞 절 예시의 세대 조건입니다. Terraform 은 그 버킷에 오브젝트 버전 관리를 켜 두기를 강하게 권합니다. 실수로 지웠을 때 상태를 되살리기 위해서입니다.
버킷 권한을 바꾸면 반영되기까지 최대 몇 분이 걸릴 수 있습니다. 그동안 Terraform 은 403 오류를 냅니다. 권한 변경이 최종 일관성으로 퍼지기 때문입니다. 최종 일관성은 바뀐 값이 곧바로가 아니라 시간이 조금 지난 뒤에야 모든 곳에 보이는 성질입니다.
Grafana Loki 와 Mimir
Loki 는 로그를 압축해 덩어리로 묶습니다. 그 덩어리를 S3 나 GCS 같은 오브젝트 저장소에 둡니다. Loki 는 GCS 를 운영 환경에 써도 되는 관리형 오브젝트 저장소 후보로 꼽습니다. 이미 GCP(Google Cloud Platform, 구글 클라우드 플랫폼)에서 돌리고 있을 때 특히 그렇다고 합니다.
storage_config:
gcs:
bucket_name: <bucket>
Mimir 는 backend: gcs 로 저장소를 고릅니다. 메트릭 블록과 알림 관리자와 규칙 평가기의 데이터는 버킷 셋에 나눠 둡니다. 예시 설정의 버킷 이름은 mimir-blocks · mimir-alertmanager · mimir-ruler 입니다. Mimir 가 GCS 를 고른 까닭은 자료에 없습니다(미확인).
Hadoop · Spark 커넥터
Cloud Storage 커넥터는 Hadoop 의 파일 시스템 인터페이스를 구현한 오픈 소스 자바 라이브러리입니다. 구글의 GoogleCloudDataproc/hadoop-connectors 저장소에서 나옵니다. 이것을 끼우면 Apache Hadoop 이나 Apache Spark 작업이 GCS 의 데이터를 바로 읽습니다. 경로는 hdfs:// 대신 gs:// 로 씁니다.
고르는 까닭은 둘입니다. 데이터를 먼저 HDFS(Hadoop Distributed File System, 하둡 분산 파일 시스템)로 옮기지 않아도 됩니다. 그리고 Hadoop 클러스터를 내려도 데이터가 GCS 에 남아 계속 읽힙니다.
운영
굴릴 때 부딪히는 한도는 숫자로 적혀 있습니다. 쓰기 속도, 처음 요청률, 크기, 버킷 이름, 일관성, 삭제 순으로 적습니다.
같은 이름에 쓰기
같은 오브젝트 이름에는 초당 한 번까지 씁니다. 이보다 자주 바꿔 올리면 429 Too Many Requests 가 돌아올 수 있습니다. 한 오브젝트의 메타데이터 고치기도 초당 한 번입니다. 버킷 메타데이터 고치기도 버킷마다 초당 한 번입니다.
애플리케이션은 한 오브젝트에 초당 한 번을 넘게 올리지 않게 설계해야 합니다. 가끔 오는 429 는 지수 백오프로 다시 보냅니다. 지수 백오프는 실패할 때마다 기다리는 시간을 몇 배씩 늘려 가며 다시 보내는 방식입니다.
버킷의 처음 요청률
GCS 는 여러 사용자가 같은 바탕 자원을 나눠 쓰는 서비스입니다. 그래서 버킷은 처음에 받는 요청 수가 정해져 있습니다.
| 요청 | 처음 받는 양 | 포함하는 것 |
|---|---|---|
| 쓰기 | 초당 약 1,000회 | 올리기 · 고치기 · 지우기 |
| 읽기 | 초당 약 5,000회 | 목록 · 데이터 읽기 · 메타데이터 읽기 |
이보다 적게 쓰면 따로 할 일이 없습니다. 넘길 것 같으면 이 값 근처나 그 아래에서 시작합니다. 그 뒤로 20분에 두 배를 넘지 않게 올립니다. 버킷이 한도에 다가가면 GCS 가 그것을 알아채 부하를 서버 여럿에 다시 나눕니다. 여기에 대개 몇 분이 걸립니다. 계층 네임스페이스 버킷은 처음 받는 양이 최대 8배입니다.
오브젝트 이름이 순서대로 늘어나면 이 확장이 느려질 수 있습니다. GCS 는 버킷마다 오브젝트 이름을 사전 순으로 정렬한 색인을 둡니다. 숫자나 타임스탬프로 이어지는 이름은 쓰기가 색인의 좁은 구간에 몰립니다. 순서 있는 이름을 쓰려면 그 앞에 해시 값을 붙여 흩습니다.
flowchart TD
subgraph 순서["순서대로 이어지는 이름"]
S1["쓰기 · 순번 1"] --> R1["사전 순 색인의 좁은 한 구간"]
S2["쓰기 · 순번 2"] --> R1
S3["쓰기 · 순번 3"] --> R1
end
subgraph 해시["앞에 해시 값을 붙인 이름"]
H1["쓰기 · 해시 + 순번 1"] --> Q1["색인의 한 구간"]
H2["쓰기 · 해시 + 순번 2"] --> Q2["색인의 다른 구간"]
H3["쓰기 · 해시 + 순번 3"] --> Q3["색인의 또 다른 구간"]
end
408 · 429 · 5xx 응답은 지수 백오프로 다시 보냅니다.
크기와 개수의 한도
| 항목 | 한도 |
|---|---|
| 오브젝트 하나의 최대 크기 | 5 TiB. 합치기 · 재개 가능 업로드 · 멀티파트 업로드 어느 길로 써도 같습니다 |
| 합치기 한 번에 넣는 원본 수 | 32개 |
| 멀티파트 업로드의 조각 수 | 10,000개 |
| 재개 가능 업로드 세션을 마치는 기한 | 7일 |
| 프로젝트당 버킷 만들기 · 지우기 | 약 2초에 한 번 |
버킷 이름 네임스페이스
버킷 이름은 모든 GCS 사용자가 함께 쓰는 하나의 네임스페이스에 놓입니다. 버킷 안의 오브젝트 이름이 놓이는 네임스페이스와는 다른 것입니다. 이미 있는 버킷의 이름은 바꿀 수 없습니다. 지운 버킷의 이름은 누구든 다시 가져갈 수 있습니다.
가용성이 중요한 애플리케이션은 요청을 처리하는 경로에서 버킷을 만들거나 지우거나 나열하지 말아야 합니다. 이 네임스페이스는 한곳에서 관리하는 전역 공간입니다. 여기에 기대면 이 공간이 애플리케이션의 단일 장애점이 됩니다. 단일 장애점은 그것 하나가 멈추면 전체가 멈추는 지점입니다.
강한 일관성의 범위
강한 일관성은 쓰기가 끝난 직후의 읽기가 어디서나 새 값을 보는 성질입니다. GCS 는 다음 작업에서 전 세계에 걸쳐 강한 일관성을 지킵니다. 오브젝트를 쓴 뒤 읽기, 메타데이터를 고친 뒤 읽기, 지운 뒤 읽기, 오브젝트 목록, 버킷 목록입니다.
이 약속이 안 닿는 경우가 넷입니다. 앞의 둘은 최종 일관성을 따릅니다.
| 경우 | 무엇이 늦나 |
|---|---|
| 권한을 주거나 빼기 | 대개 1분쯤, 때로 몇 분 더 걸려 반영됩니다. 그동안 뺀 사용자가 계속 읽을 수 있습니다 |
| 지운 버킷을 같은 이름으로 다시 만들기 | 권한 변경과 같은 시간이 걸립니다 |
| 버킷 설정 바꾸기 | 메타데이터는 바로 읽히지만 설정이 퍼지는 데 시간이 듭니다. 버전 관리를 켰으면 30초 이상 기다린 뒤 지우거나 덮어씁니다 |
| 공개 오브젝트의 캐시 | 캐시에 남은 옛 판이 읽힐 수 있습니다 |
공개 오브젝트에 Cache-Control 이 없으면 기본값 public, max-age=3600 이 붙습니다. 그러면 최대 60분 동안 캐시에 남을 수 있습니다. 고객 관리 암호화 키로 암호화했거나 VPC(Virtual Private Cloud, 가상 사설 클라우드) 서비스 경계 안에 둔 오브젝트에는 이 기본값이 붙지 않습니다.
캐시를 한꺼번에 비울 방법은 없습니다. 공개 접근을 거둬도 캐시에서는 계속 나갈 수 있습니다. GCS 의 내장 캐시는 파일 하나를 10 MiB 까지 담습니다. 캐시 무효화는 못 합니다. 구글의 Cloud CDN(Content Delivery Network, 콘텐츠 전송 네트워크)은 100 GiB 까지 담습니다. 무효화도 합니다.
세대 번호 없이 범위 읽기를 여러 번 나눠 하면 받은 데이터가 깨질 수 있습니다. 읽는 사이에 오브젝트가 덮어써지는 경우입니다. 맞는 판을 받도록 범위 읽기에도 프리컨디션을 겁니다. 여러 요청을 하나로 묶는 일괄 요청도 원자적이지 않습니다. 일부만 성공할 수 있습니다.
권한을 볼 때도 함정이 있습니다. 콘솔은 버킷에 걸리는 프로젝트 수준 권한까지 보여 줍니다. gcloud storage 와 클라이언트 라이브러리는 버킷 정책만 돌려줍니다. 누가 무엇을 할 수 있는지 따질 때는 프로젝트 정책과 버킷 정책을 둘 다 봅니다.
소프트 삭제
소프트 삭제는 지워지거나 덮어써진 오브젝트와 버킷을 정해진 기간 동안 되살릴 수 있게 남겨 둡니다. 지원하는 버킷에는 기본으로 켜져 있습니다. 기본 보존 기간은 7일입니다. 7일에서 90일 사이로 바꿀 수 있습니다. 0 으로 두면 꺼집니다. Rapid Bucket 을 쓰는 존 버킷처럼 소프트 삭제와 맞지 않는 버킷에는 기본 정책이 안 붙습니다.
남아 있는 동안에도 저장 요금이 붙습니다. 그래서 임시 데이터가 대부분인 버킷은 저장 요금이 크게 늘 수 있습니다. 최소 보관 기간 전에 소프트 삭제된 오브젝트에는 조기 삭제 요금도 붙습니다. Standard 등급에 둔 오브젝트는 예외입니다.
프로젝트를 지우면 그 안의 버킷과 오브젝트도 지워집니다. 소프트 삭제로 보호되는 것은 남습니다.
관련 항목
Google Cloud Storage 를 이루는 구성 요소
버킷 · 오브젝트 · 오브젝트 키 · 프리픽스 · 메타데이터 · 세대 번호 · 메타세대 번호 · 폴더 · 관리형 폴더 · 복합 오브젝트
Google Cloud Storage 의 주인이 되는 자원 계층
프로젝트 · 조직 · Google Cloud · 자원 계층
Google Cloud Storage 가 속하는 상위 분류
오브젝트 스토리지 · 클라우드 스토리지 · 클라우드 컴퓨팅 · 관리형 서비스
Google Cloud Storage 가 제공하는 관리 기능
객체 버전 관리 · 객체 수명 주기 · 스토리지 클래스 · Autoclass · 보존 정책 · 소프트 삭제 · 계층 네임스페이스 · 재개 가능 업로드 · 멀티파트 업로드 · 버킷 재배치 · 터보 복제 · Storage Intelligence · Rapid Bucket
Google Cloud Storage 에 접근을 허락하는 수단
Cloud IAM · ACL · 균일한 버킷 수준 액세스 · 서명된 URL · HMAC 키 · 서비스 계정 · Cloud KMS
Google Cloud Storage 를 호출하는 인터페이스
JSON API · XML API · REST API · gRPC · HTTP · gcloud storage
Google Cloud Storage 가 지키거나 놓는 성질
강한 일관성 · 최종 일관성 · 원자성 · 내구성 · 가용성 · 프리컨디션 · Last Write Wins
동시 쓰기를 가려내는 기법
낙관적 동시성 제어 · 조건부 요청 · ETag · 잃어버린 갱신 · 분산 잠금
Google Cloud Storage 에서 자주 받는 오류 응답
412 Precondition Failed · 429 Too Many Requests · 403 Forbidden · 지수 백오프
Google Cloud Storage 가 놓이는 지리 단위
리전 · 이중 리전 · 멀티 리전 · 가용 영역 · 존
Google Cloud Storage 를 대신할 수 있는 다른 저장소
Amazon S3 · S3 Glacier · Azure Blob Storage · MinIO · S3 호환 스토리지 · Persistent Disk · Filestore · 블록 스토리지 · 파일 시스템
Google Cloud Storage 에 데이터를 두는 시스템 구성
정적 웹사이트 · CDN · Cloud CDN · 데이터 레이크 · 백업 · 로그
Google Cloud Storage 를 저장소로 받는 제품
테라폼 · Grafana Loki · Grafana Mimir · Hadoop · HDFS · Apache Spark
Google Cloud Storage 위에서 데이터를 읽는 분석 도구
BigQuery · Dataflow · Dataproc · Apache Parquet
Google Cloud Storage 로 데이터를 옮기거나 붙이는 도구
Storage Transfer Service · Cloud Storage FUSE · Anywhere Cache
다른 이름: GCS · Google 클라우드 스토리지 · 구글 클라우드 스토리지 · Cloud Storage