マルチパートアップロードを使用すると、ラージオブジェクトをパートに分割して OSS にアップロードできます。パートを並行してアップロードすることでスループットを向上させ、中断されたアップロードを最初からやり直すことなく再開し、最終的なオブジェクトサイズが不明な場合でもアップロードを開始できます。
前提条件
開始する前に、以下が準備できていることを確認してください。
Go SDK V2.2.5 以降がインストールされていること
oss:PutObject権限(お使いのバケット用)。詳細については、「RAM ユーザーにカスタムポリシーをアタッチする」をご参照ください。OSS_ACCESS_KEY_IDおよびOSS_ACCESS_KEY_SECRET環境変数が設定されています。詳細については、「アクセス認証情報の設定」をご参照ください。OSSClient インスタンス。詳細については、「OSSClient インスタンスの設定」をご参照ください。
このトピックの例では、中国 (杭州) リージョンのパブリックエンドポイントを使用します。アプリケーションと OSS バケットが同じリージョンにある場合は、データ転送コストを回避するために内部エンドポイントを使用してください。「リージョンとエンドポイント」を参照してください。
仕組み
マルチパートアップロードには 3 つのステップが必要です。
初期化 —
Bucket.InitiateMultipartUploadを呼び出します。OSS はグローバルに一意なアップロード ID を返します。パートのアップロード — 各パートに対して
Bucket.UploadPartを呼び出します。パートは、最終的なオブジェクト内での位置を決定するパート番号によって識別されます。同じパート番号で新しいパートをアップロードすると、既存のパートが上書きされます。OSS は、受信した各パートの MD5 ハッシュをETagヘッダーで返し、SDK が計算したハッシュと照合して検証します。これらが一致しない場合、OSS はInvalidDigestエラーを返します。完了 —
Bucket.CompleteMultipartUploadを呼び出して、アップロードされたすべてのパートを 1 つのオブジェクトにマージします。
オブジェクトのパート単位でのアップロード
次の例では、パートサイズを 5 MiB として、マルチパートアップロードを使用してローカルファイルをアップロードします。
package main
import (
"fmt"
"log"
"os"
"github.com/aliyun/aliyun-oss-go-sdk/oss"
)
func main() {
// 環境変数からアクセス認証情報を取得します。サンプルコードを実行する前に、
// OSS_ACCESS_KEY_ID と OSS_ACCESS_KEY_SECRET 環境変数が設定されていることを確認してください。
provider, err := oss.NewEnvironmentVariableCredentialsProvider()
if err != nil {
log.Fatalf("Error: %v", err)
}
// OSSClient インスタンスを作成します。
// yourEndpoint をバケットのエンドポイントに設定します。たとえば、
// 中国 (杭州) リージョン内のバケットの場合、エンドポイントを https://oss-cn-hangzhou.aliyuncs.com に設定します。
// yourRegion をバケットが配置されているリージョンに設定します。たとえば、cn-hangzhou です。
clientOptions := []oss.ClientOption{oss.SetCredentialsProvider(&provider)}
clientOptions = append(clientOptions, oss.Region("yourRegion"))
clientOptions = append(clientOptions, oss.AuthVersion(oss.AuthV4))
client, err := oss.New("yourEndpoint", "", "", clientOptions...)
if err != nil {
log.Fatalf("Error: %v", err)
}
bucketName := "examplebucket"
objectName := "exampleobject.txt"
// ローカルパスが指定されていない場合、ファイルはサンプルプログラムのディレクトリから読み取られます。
localFilename := "/localpath/exampleobject.txt"
bucket, err := client.Bucket(bucketName)
if err != nil {
log.Fatalf("Error: %v", err)
}
// パートサイズを 5 MiB に設定します。
partSize := int64(5 * 1024 * 1024)
if err := uploadMultipart(bucket, objectName, localFilename, partSize); err != nil {
log.Fatalf("Failed to upload multipart: %v", err)
}
}
func uploadMultipart(bucket *oss.Bucket, objectName, localFilename string, partSize int64) error {
// 指定されたパートサイズに基づいてローカルファイルをパートに分割します。
chunks, err := oss.SplitFileByPartSize(localFilename, partSize)
if err != nil {
return fmt.Errorf("failed to split file into chunks: %w", err)
}
file, err := os.Open(localFilename)
if err != nil {
return fmt.Errorf("failed to open file: %w", err)
}
defer file.Close()
// ステップ 1: マルチパートアップロードを初期化します。OSS は一意のアップロード ID を返します。
imur, err := bucket.InitiateMultipartUpload(objectName)
if err != nil {
return fmt.Errorf("failed to initiate multipart upload: %w", err)
}
// ステップ 2: 各パートをアップロードします。チャンク番号によって、最終的なオブジェクト内でのパートの位置が決まります。
var parts []oss.UploadPart
for _, chunk := range chunks {
part, err := bucket.UploadPart(imur, file, chunk.Size, chunk.Number)
if err != nil {
// アップロードを中止して、すでにアップロードされたパートのストレージを解放します。
if abortErr := bucket.AbortMultipartUpload(imur); abortErr != nil {
log.Printf("Failed to abort multipart upload: %v", abortErr)
}
return fmt.Errorf("failed to upload part: %w", err)
}
parts = append(parts, part)
}
// オブジェクト ACL を非公開に設定します。デフォルトでは、オブジェクトはバケット ACL を継承します。
objectAcl := oss.ObjectACL(oss.ACLPrivate)
// ステップ 3: アップロードされたすべてのパートをマージして、マルチパートアップロードを完了します。
_, err = bucket.CompleteMultipartUpload(imur, parts, objectAcl)
if err != nil {
if abortErr := bucket.AbortMultipartUpload(imur); abortErr != nil {
log.Printf("Failed to abort multipart upload: %v", abortErr)
}
return fmt.Errorf("failed to complete multipart upload: %w", err)
}
log.Printf("Multipart upload completed successfully.")
return nil
}よくある質問
マルチパートアップロードを中止する方法
Bucket.AbortMultipartUpload を呼び出してマルチパートアップロードを停止し、それまでにアップロードされたすべてのパートのストレージを解放します。ファイルが破損している、ネットワークが不安定、ストレージ容量が限られている、または誤ってアップロードが開始された場合に、アップロードを中止します。
...
if err = bucket.AbortMultipartUpload(imur); err != nil {
log.Fatalf("failed to abort multipart upload: %v", err)
}
log.Printf("Multipart upload aborted successfully.")アップロード済みパートをリスト表示する方法
バケット内の進行中のすべてのマルチパートアップロードをリスト表示する方法
Bucket.ListMultipartUploads を呼び出して、開始されたがまだ完了または中止されていないすべてのマルチパートアップロードをリスト表示します。これを使用して、バッチアップロードのモニター、停滞したアップロードの検出、またはクリーンアップ対象のアップロードの特定を行います。
以下のパラメーターで、結果をフィルターしたりページ分割したりできます。
| パラメーター | 説明 | デフォルト |
|---|---|---|
Delimiter | デリミタの最初の出現箇所までの共通プレフィックスを共有するオブジェクト名をグループ化します | — |
MaxUploads | 返すアップロードの最大数 | 1000 (最大値も同じ) |
KeyMarker | この値より辞書順で大きいオブジェクト名を持つアップロードを返します | — |
Prefix | オブジェクト名がこのプレフィックスで始まるアップロードのみを返します | — |
UploadIDMarker | KeyMarker と一緒に使用します。同じオブジェクト名で、この値より大きいアップロード ID を持つアップロードを返します。KeyMarker が設定されていない場合は無視されます | — |
デフォルトのパラメーターを使用:
...
lsRes, err := bucket.ListMultipartUploads(oss.KeyMarker(keyMarker), oss.UploadIDMarker(uploadIdMarker))
if err != nil {
log.Fatalf("failed to list multipart uploads: %v", err)
}
for _, upload := range lsRes.Uploads {
log.Printf("Key: %s, UploadID: %s\n", upload.Key, upload.UploadID)
}プレフィックスでフィルター:
...
lsRes, err := bucket.ListMultipartUploads(oss.Prefix("file"))
if err != nil {
log.Fatalf("failed to list multipart uploads with prefix: %v", err)
}
log.Printf("Uploads: %v", lsRes.Uploads)結果の数を制限:
...
lsRes, err := bucket.ListMultipartUploads(oss.MaxUploads(100))
if err != nil {
log.Fatalf("failed to list multipart uploads with limit: %v", err)
}
log.Printf("Uploads: %v", lsRes.Uploads)プレフィックスと制限を組み合わせる:
...
lsRes, err := bucket.ListMultipartUploads(oss.Prefix("file"), oss.MaxUploads(100))
if err != nil {
log.Fatalf("failed to list multipart uploads with prefix and limit: %v", err)
}
log.Printf("Uploads: %v", lsRes.Uploads)