全部產品
Search
文件中心

Object Storage Service:如何避免產生儲存不足規定時間長度容量費用?

更新時間:Nov 01, 2024

低頻訪問、歸檔類型、冷歸檔或者深度冷歸檔有最低儲存時間長度的要求。在儲存不足規定時間長度的情況下,轉換Object儲存類型或提前刪除Object會產生不足規定時間長度容量費用。為避免產生不足規定時間長度容量費用,您需要瞭解不同儲存類型Object的最低儲存時間長度計算方法,確保滿足其最低儲存時間長度後再進行轉儲或者刪除。

儲存類型與最低儲存時間長度

儲存類型

最低儲存時間長度

計算方法

標準

不涉及

低頻訪問

30

以Object的LastModified時間開始計算

歸檔

60

以Object的LastModified時間開始計算

冷歸檔

180

以Object轉儲為冷歸檔類型的時間開始計算

深度冷歸檔

180

以Object轉儲為深度冷歸檔類型的時間開始計算

範例程式碼

以常用SDK範例程式碼為例擷取對象中繼資料,並根據對象的LastModified、TransitionTime與目前時間進行比較,以判斷是否滿足最低儲存時間長度的要求。

Java

import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.common.auth.CredentialsProviderFactory;
import com.aliyun.oss.common.auth.EnvironmentVariableCredentialsProvider;
import com.aliyun.oss.common.utils.DateUtil;
import com.aliyun.oss.model.ObjectMetadata;
import com.aliyun.oss.model.HeadObjectRequest;
import com.aliyuncs.exceptions.ClientException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

public class Demo {

    public static void main(String[] args) throws ClientException {
        // yourEndpoint填寫Bucket所在地區對應的Endpoint。
        String endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
        // 從環境變數中擷取訪問憑證。運行本程式碼範例之前,請確保已設定環境變數OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
        EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();
        // 填寫Bucket名稱。
        String bucketName = "examplebucket";

        // 建立OSSClient執行個體。
        OSS ossClient = new OSSClientBuilder().build(endpoint, credentialsProvider);

        // 指定要檢查的單個對象的完整路徑。
        String[] objectNames = {"example.txt"};

        // 儲存類型與最低儲存時間長度映射(單位:天)。
        Map<String, Integer> minimumRetentionPeriod = new HashMap<>();
        minimumRetentionPeriod.put("Standard", 0);
        minimumRetentionPeriod.put("IA", 30);
        minimumRetentionPeriod.put("Archive", 60);
        minimumRetentionPeriod.put("ColdArchive", 180);
        minimumRetentionPeriod.put("DeepColdArchive", 180);

        for (String objectName : objectNames) {
            objectName = objectName.trim();
            try {
                // 擷取對象中繼資料。
                HeadObjectRequest headObjectRequest = new HeadObjectRequest(bucketName, objectName);
                ObjectMetadata objectMetadata = ossClient.headObject(headObjectRequest);

                // 擷取儲存類型和最後修改時間。
                String storageClass = String.valueOf(objectMetadata.getObjectStorageClass());
                String lastModifiedStr = objectMetadata.getLastModified().toString();
                Date lastModified = objectMetadata.getLastModified();

                if ("ColdArchive".equals(storageClass) || "DeepColdArchive".equals(storageClass)) {
                    Object transitionTimeObj = objectMetadata.getRawMetadata().get("x-oss-transition-time");
                    String transitionTimeStr = String.valueOf(transitionTimeObj);
                    Date transitionTime = DateUtil.parseRfc822Date(transitionTimeStr);

                    if (transitionTime != null) {
                        lastModified = transitionTime;
                    } else {
                        throw new Exception("對象 '" + objectName + "' 的儲存類型為:" + storageClass
                                + ", x-oss-transition-time時間為" + transitionTimeStr + "。");
                    }
                }

                // 擷取目前時間。
                Date currentTime = new Date();

                // 計算已儲存時間長度(天)。
                long storageDuration = (currentTime.getTime() - lastModified.getTime()) / (1000 * 60 * 60 * 24);

                // 列印資訊。
                System.out.println("對象名稱: " + objectName);
                System.out.println("儲存類型: " + storageClass);
                System.out.println("建立時間: " + lastModifiedStr);
                System.out.println("已儲存時間長度: " + storageDuration + " 天");

                // 判斷是否達到最低儲存時間長度。
                if (minimumRetentionPeriod.containsKey(storageClass)) {
                    int minRetention = minimumRetentionPeriod.get(storageClass);
                    if (storageDuration < minRetention) {
                        int daysRemaining = minRetention - (int) storageDuration;
                        System.out.println(objectName + " 尚未達到最低儲存時間長度,應再儲存 " + daysRemaining + " 天,提前刪除會產生"
                                + daysRemaining + "天的不足規定時間長度的容量費用。");
                    } else {
                        int daysExceeded = (int) storageDuration - minRetention;
                        System.out.println(objectName + " 已達到最低儲存時間長度,超出部分為 " + daysExceeded + " 天,刪除不會產生不足規定時間長度的容量費用。");
                    }
                } else {
                    System.out.println(objectName + " 的儲存類型未被識別。");
                }
                System.out.println("----------------------------------------");  // 分隔字元
            } catch (Exception e) {
                e.printStackTrace();
                System.out.println("擷取 " + objectName + " 中繼資料時出現錯誤: " + e.getMessage());
                System.out.println("----------------------------------------");  // 分隔字元
            }
        }

        // 關閉OSSClient。
        ossClient.shutdown();
    }
}

Python

import datetime
import oss2
from oss2.credentials import EnvironmentVariableCredentialsProvider

# 從環境變數中擷取訪問憑證。運行本程式碼範例之前,請確保已設定環境變數OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
auth = oss2.ProviderAuth(EnvironmentVariableCredentialsProvider())
# 填寫Bucket所在地區對應的Endpoint。以華東1(杭州)為例,Endpoint填寫為https://oss-cn-hangzhou.aliyuncs.com。
# yourBucketName填寫儲存空間名稱。
bucket = oss2.Bucket(auth, 'https://oss-cn-hangzhou.aliyuncs.com', 'examplebucket')
# 指定要檢查的單個對象的完整路徑。
object_names = ['example.txt']

# 儲存類型與最低儲存時間長度映射(單位:天)。
minimum_retention_period = {
    'Standard': 0,
    'IA': 30,
    'Archive': 60,
    'ColdArchive': 180,
    'DeepColdArchive': 180
}

for object_name in object_names:
    object_name = object_name.strip()

    try:
        # 通過head_object方法擷取對象的全部中繼資料。
        object_info = bucket.head_object(object_name)

        # 擷取儲存類型和最後修改時間。
        storage_class = object_info.headers['x-oss-storage-class']
        last_modified = object_info.headers['Last-Modified']

        # 將最後修改時間轉換為datetime對象。
        last_modified_time = datetime.datetime.strptime(last_modified, '%a, %d %b %Y %H:%M:%S GMT')

        transition_time_str = object_info.headers.get('x-oss-transition-time')
        transition_time = None
        if storage_class == 'ColdArchive' or storage_class == 'DeepColdArchive':
            if transition_time_str:
                last_modified_time = datetime.datetime.strptime(transition_time_str, "%a, %d %b %Y %H:%M:%S %Z")
            else:
                raise Exception(f"對象 '{object_name}' 的儲存類型為:{storage_class}, x-oss-transition-time時間為{transition_time_str}。")


        # 擷取目前時間。
        current_time = datetime.datetime.now()

        # 計算已儲存時間長度(天)。
        storage_duration = (current_time - last_modified_time).days

        # 列印資訊。
        print(f"對象名稱: {object_name}")
        print(f"儲存類型: {storage_class}")
        print(f"建立時間: {last_modified}")
        print(f"已儲存時間長度: {storage_duration} 天")

        # 判斷是否達到最低儲存時間長度。
        if storage_class in minimum_retention_period:
            min_retention = minimum_retention_period[storage_class]
            if storage_duration < min_retention:
                days_remaining = min_retention - storage_duration
                print(f"{object_name} 尚未達到最低儲存時間長度,應再儲存 {days_remaining} 天,提前刪除會產生{days_remaining}天的不足規定時間長度的容量費用。")
            else:
                days_exceeded = storage_duration - min_retention
                print(f"{object_name} 已達到最低儲存時間長度,超出部分為 {days_exceeded} 天,刪除不會產生不足規定時間長度的容量費用。")
        else:
            print(f"{object_name} 的儲存類型未被識別。")

        print("-" * 40)  # 分隔字元

    except Exception as e:
        print(f"擷取 {object_name} 中繼資料時出現錯誤: {str(e)}")
        print("-" * 40)  # 分隔字元

Node.js

const OSS = require("ali-oss");

// 從環境變數中擷取訪問憑證。運行本程式碼範例之前,請確保已設定環境變數OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
const config = {
  accessKeyId: process.env.OSS_ACCESS_KEY_ID,
  accessKeySecret: process.env.OSS_ACCESS_KEY_SECRET,
  // region填寫Bucket所在地區。以華東1(杭州)為例,Region填寫為oss-cn-hangzhou。
  region: "oss-cn-hangzhou",
  // 填寫Bucket名稱。
  bucket: "examplebucket",
};
const client = new OSS(config);

// 儲存類型與最低儲存時間長度映射(單位:天)。
const minimum_retention_period = {
  Standard: 0,
  IA: 30,
  Archive: 60,
  ColdArchive: 180,
  DeepColdArchive: 180,
};

// 計算時間相差天數。
function getDays(date1, date2) {
  if (!(date1 instanceof Date) || !(date2 instanceof Date)) {
    throw new Error("需要傳遞有效Date對象");
  }
  const timestamp1 = date1.getTime();
  const timestamp2 = date2.getTime();
  const diffInMilliseconds = Math.abs(timestamp2 - timestamp1);
  const diffInDays = diffInMilliseconds / (1000 * 60 * 60 * 24);

  return Math.round(diffInDays);
}

// 指定要檢查的單個對象的完整路徑。
const object_names = ["example.jpg"];

(async () => {
  for (const object_name of object_names) {
    try {
      // 通過head方法擷取對象的全部中繼資料。
      const object_info = await client.head(object_name);
      const { headers } = object_info.res;

      // 擷取儲存類型和最後修改時間。
      const storage_class = headers["x-oss-storage-class"];
      const last_modified = headers["last-modified"];

      let last_modified_time = new Date(last_modified);
      const transition_time_str = headers["x-oss-transition-time"];
      if (["ColdArchive", "DeepColdArchive"].includes(storage_class)) {
        if (transition_time_str)
          last_modified_time = new Date(transition_time_str);
        else {
          const errorStr = `對象 '${object_name}' 的儲存類型為:${storage_class}, x-oss-transition-time時間為${transition_time_str}。通過生命週期轉到冷歸檔和深度冷歸檔的檔案,才會有x-oss-transition-time`;
          throw new Error(errorStr);
        }
      }

      const current_time = new Date(); // 擷取目前時間。
      const storage_duration = getDays(current_time, last_modified_time); // 計算已儲存時間長度(天)。
      // 列印資訊。
      console.log(`對象名稱: ${object_name}`);
      console.log(`儲存類型: ${storage_class}`);
      console.log(`建立時間: ${last_modified}`);
      console.log(`已儲存時間長度: ${storage_duration} 天`);

      // 判斷是否達到最低儲存時間長度。
      if (Object.keys(minimum_retention_period).includes(storage_class)) {
        min_retention = minimum_retention_period[storage_class];
        if (storage_duration < min_retention) {
          const days_remaining = min_retention - storage_duration;
          console.log(
            `${object_name} 尚未達到最低儲存時間長度,應再儲存 ${days_remaining} 天,提前刪除會產生${days_remaining}天的不足規定時間長度的容量費用。`
          );
        } else {
          const days_exceeded = storage_duration - min_retention;
          console.log(
            `${object_name} 已達到最低儲存時間長度,超出部分為 ${days_exceeded} 天,刪除不會產生不足規定時間長度的容量費用。`
          );
        }
      } else console.log(`${object_name} 的儲存類型未被識別。`);
    } catch (e) {
      console.log(`擷取 ${object_name} 中繼資料時出現錯誤:`, e);
    }
  }
})();

PHP

<?php
if (is_file(__DIR__ . '/../autoload.php')) {
    require_once __DIR__ . '/../autoload.php';
}
if (is_file(__DIR__ . '/../vendor/autoload.php')) {
    require_once __DIR__ . '/../vendor/autoload.php';
}

use OSS\Credentials\EnvironmentVariableCredentialsProvider;
use OSS\OssClient;
use OSS\Core\OssException;

// 填寫Bucket所在地區對應的Endpoint。以華東1(杭州)為例,Endpoint填寫為https://oss-cn-hangzhou.aliyuncs.com。
$endpoint = 'http://oss-cn-hangzhou.aliyuncs.com';
// 填寫儲存空間名稱。
$bucketName = 'examplebucket';

// 建立OssClient執行個體。
try {
    // 從環境變數中擷取訪問憑證。運行本程式碼範例之前,請確保已設定環境變數OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
    $provider = new EnvironmentVariableCredentialsProvider();
    $config = array(
        "provider" => $provider,
        "endpoint" => $endpoint,
    );
    $ossClient = new OssClient($config);
	// 指定要檢查的單個對象的完整路徑。
    $objectNames = ['example.txt'];
    $minimumRetentionPeriod = [
        'Standard' => 0,
        'IA' => 30,
        'Archive' => 60,
        'ColdArchive' => 180,
        'DeepColdArchive' => 180,
    ];

    foreach ($objectNames as $objectName) {
        $objectName = trim($objectName);
        try {
            // 通過headObject方法擷取對象的全部中繼資料。
            $objectInfo = $ossClient->getObjectMeta($bucketName, $objectName);

            // 擷取儲存類型和最後修改時間。
            $storageClass = $objectInfo['x-oss-storage-class'];
            $lastModified = $objectInfo['last-modified'];

            // 將最後修改時間轉換為時間戳記。
            $lastModifiedTime = strtotime($lastModified);

            if (in_array($storageClass, array("ColdArchive", "DeepColdArchive")) && isset($objectInfo["x-oss-transition-time"])) {
                $lastModifiedTime = strtotime($objectInfo["x-oss-transition-time"]);
            }

            // 擷取目前時間。
            $currentTime = time();

            // 計算已儲存時間長度(天)。
            $storageDuration = floor(($currentTime - $lastModifiedTime) / (60 * 60 * 24));

            // 列印資訊。
            echo "對象名稱: $objectName\n";
            echo "儲存類型: $storageClass\n";
            echo "建立時間: $lastModified\n";
            echo "已儲存時間長度: $storageDuration 天\n";

            // 判斷是否達到最低儲存時間長度。
            if (isset($minimumRetentionPeriod[$storageClass])) {
                $minRetention = $minimumRetentionPeriod[$storageClass];
                if ($storageDuration < $minRetention) {
                    $daysRemaining = $minRetention - $storageDuration;
                    echo "$objectName 尚未達到最低儲存時間長度,應再儲存 $daysRemaining 天,提前刪除會產生 $daysRemaining 天的不足規定時間長度的容量費用。\n";
                } else {
                    $daysExceeded = $storageDuration - $minRetention;
                    echo "$objectName 已達到最低儲存時間長度,超出部分為 $daysExceeded 天,刪除不會產生不足規定時間長度的容量費用。\n";
                }
            } else {
                echo "$objectName 的儲存類型未被識別。\n";
            }
            echo str_repeat("-", 40) . "\n"; // 分隔字元
        } catch (OssException $e) {
            echo "擷取 $objectName 中繼資料時出現錯誤: " . $e->getMessage() . "\n";
            echo str_repeat("-", 40) . "\n"; // 分隔字元
        }
    }
} catch (OssException $e) {
    printf(__FUNCTION__ . ": FAILED\n");
    printf($e->getMessage() . "\n");
    return;
}

Go

package main

import (
	"context"
	"fmt"
	"log"
	"net/http"
	"strings"
	"time"

	"github.com/aliyun/alibabacloud-oss-go-sdk-v2/oss"
	"github.com/aliyun/alibabacloud-oss-go-sdk-v2/oss/credentials"
)

func main() {
	cfg := oss.LoadDefaultConfig().
		WithCredentialsProvider(credentials.NewEnvironmentVariableCredentialsProvider()).
		WithRegion("cn-hangzhou").
		WithEndpoint("https://oss-cn-hangzhou.aliyuncs.com")
	client := oss.NewClient(cfg)
	// 指定要檢查的單個對象的完整路徑。
	objectNames := []string{"example.txt"}
	minimumRetentionPeriod := map[string]int{
		"Standard":        0,
		"IA":              30,
		"Archive":         60,
		"ColdArchive":     180,
		"DeepColdArchive": 180,
	}
        // 填寫Bucket名稱。
	bucketName := "examplebucket"
	for _, objectName := range objectNames {
		objectName = strings.Trim(objectName, " ")
		objectInfo, err := client.HeadObject(context.TODO(), &oss.HeadObjectRequest{
			Bucket: oss.Ptr(bucketName),
			Key:    oss.Ptr(objectName),
		})
		if err != nil {
			log.Printf("擷取 %s 中繼資料時出現錯誤: %v\n", objectName, err)
			continue
		}

		storageClass := objectInfo.StorageClass
		currentTime := time.Now().Unix()
		storageDuration := (currentTime - objectInfo.LastModified.Unix()) / 60 / 60 / 24
		if *storageClass == "ColdArchive" || *storageClass == "DeepColdArchive" {
			if objectInfo.Headers.Get("x-oss-transition-time") != "" {
				transitionTime, err := time.Parse(http.TimeFormat, objectInfo.Headers.Get("x-oss-transition-time"))
				if err != nil {
					fmt.Printf("Failed to parse %s x-oss-transition-time: %v\n", objectName, err)
					continue
				}
				storageDuration = (currentTime - transitionTime.Unix()) / 60 / 60 / 24
			}
		}

		fmt.Printf("對象名稱: %s\n", objectName)
		fmt.Printf("儲存類型: %s\n", *storageClass)
		fmt.Printf("建立時間: %s\n", *objectInfo.LastModified)
		fmt.Printf("已儲存時間長度: %d 天\n", storageDuration)

		if minimumRetentionPeriod[*storageClass] != 0 {
			minRetention := minimumRetentionPeriod[*storageClass]
			daysRemaining := minRetention - int(storageDuration)
			fmt.Printf("%s 尚未達到最低儲存時間長度,應再儲存 %d 天,提前刪除會產生 %d 天的不足規定時間長度的容量費用。\n", objectName, daysRemaining, daysRemaining)
		} else {
			fmt.Printf("%s 的儲存類型未被識別。\n", objectName)
		}
	}
}

更多參考

以上範例程式碼示範通過head_object方法擷取單個對象的儲存類型,並根據對象的LastModified、TransitionTime與目前時間進行比較,以判斷是否滿足最低儲存時間長度的要求。如果涉及擷取多個對象,可以使用GetBucket (ListObjects)ListObjectVersions(GetBucketVersions)ListBucketInventory介面。