当存储空间(Bucket)中的文件(Object)数量达到数百万甚至上百亿时,通过 ListObjects 接口逐一列举效率低且成本高。存储空间清单功能通过异步、定期扫描 Bucket,生成包含指定对象元数据(如大小、存储类型等)的清单文件,适用于海量对象的管理场景。
适用范围
仅有地域属性的Bucket支持开启存储空间清单功能。
如需使用增量清单功能,请联系技术支持申请,当前仅支持墨西哥地域。
使用场景
OSS 提供全量清单和增量清单。其中,全量清单是指对某一时间点 Bucket 内所有存量文件的快照,增量清单则记录了指定时间段内新增或变动的文件元数据。全量清单和增量清单均可以按照一定周期生成清单文件,并投递到指定的 Bucket 进行转存。可配置按周期生成一次全量清单,并且通常每 10 分钟生成一次增量清单文件。使用全量清单文件和增量清单文件的场景如下:
一次性的数据分析和统计场景:若仅需要对历史文件进行统计,可以配置全量清单生成规则,定期生成一次全量文件元数据清单,用以离线的数据统计、数据分析。
持续性的数据分析和统计场景:不仅需要对历史文件进行统计分析,也需要对后续的增量文件进行统计和分析,可以基于全量元数据清单和增量元数据清单构建统一的元数据表,如将存量和增量元数据均写入到自建的 table 中,通过自己的 spark 集群进行元数据检索、查询、统计和分析。
工作原理
全量清单:定期(每天或每周)为存储空间中的对象生成一份完整的快照,其工作流程如下:
获取权限:OSS 通过扮演一个预先授权的 RAM 角色,来获得扫描源Bucket和向目标 Bucket 写入清单报告的权限。
扫描对象:OSS 根据清单规则中定义的筛选条件(如对象前缀、版本状态、创建时间或大小),扫描源 Bucket 中的所有匹配对象。
生成清单报告:OSS 将扫描结果聚合生成清单报告,并以 Gzip 压缩的 CSV 文件格式,写入目标的 Bucket 中。
增量清单:通常以10分钟为周期,捕获并报告该时间窗口内发生的所有对象变更事件(包括创建、元数据更新、删除),其工作流程如下:
获取权限:OSS 通过扮演一个预先授权的 RAM 角色,来获得扫描源Bucket日志和向目标 Bucket 写入清单报告的权限。
扫描对象:OSS 根据规则中定义的筛选条件(如对象前缀),扫描增量日志中所有匹配的记录。
生成清单报告:OSS 将扫描结果,以后端分区聚合的方式,生成清单报告,以CSV格式写入指定的目标Bucket 中。
创建清单规则后,OSS 会周期自动执行清单任务,该任务在后台异步运行,不影响对 Bucket 的正常访问。
创建并授权服务角色
OSS 清单服务需要通过扮演 RAM 角色来获得读取源 Bucket和写入目标 Bucket的权限。为确保账户安全,建议遵循最小权限原则,为清单功能创建专用的服务角色。
通过控制台快速配置清单时,系统会引导自动创建名为AliyunOSSRole的角色,可直接使用默认角色,无需自行创建服务角色。但此角色拥有对账户下所有 Bucket 的完全管理权限,不建议在生产环境中使用AliyunOSSRole。
以下是手动创建最小权限角色的步骤:
创建RAM角色:进入创建RAM角色页面。信任主体类型选择云服务,信任主体名称选择对象存储。
为RAM角色授予写入目标 Bucket 的权限:
在创建权限策略页面,单击脚本编辑页签。将以下策略内容粘贴到策略编辑器中,并将
dest-bucket替换为实际的源Bucket名称。{ "Version": "1", "Statement": [ { "Effect": "Allow", "Action": "oss:PutObject", "Resource": [ "acs:oss:*:*:dest-bucket/*" ] } ] }(可选)配置 KMS 加密权限:如果清单报告需要使用 KMS 密钥加密,还需为该 RAM 角色授予
AliyunKMSCryptoUserAccess权限或更精细的 KMS 相关权限。在授权页面,单击新增授权,授权主体选择创建的RAM角色,权限策略选择刚创建的策略,然后单击确认新增授权。
记录角色ARN:在角色页面找到创建RAM角色,进入基本信息页面,复制角色的ARN用于创建清单规则。格式为
acs:ram::{源账号UID}:role/{角色名}。
全量清单
全量清单会定期扫描并导出Bucket中所有(或指定前缀下所有)对象的完整列表。请注意:
报告快照:清单报告反映的是扫描任务启动时的对象状态。扫描过程需要时间,此期间的对象变更(如新增、删除)不保证会包含在本次报告中。
首份清单会在配置后立即执行,后续按设置的每日或每周的周期在北京时间凌晨批量执行,导出延迟受对象数量与任务队列影响。
配置清单规则
控制台
登录 OSS 管理控制台。
进入需要生成清单的源 Bucket,在左侧导航栏选择 数据管理 > Bucket 清单。
在Bucket 清单页面,单击创建清单。
在设置清单报告规则面板,配置以下参数:
参数
说明
状态
设置清单任务的状态,选择启动。
规则名称
设置清单任务的名称。只能包含小写字母、数字、短划线(-),且不能以短划线(-)开头或结尾。
清单报告存储至
设置清单报告的存储路径。配置清单的 Bucket 与存放清单 Bucket 必须同账号、同地域。
若需将报告保存到存储空间 examplebucket 的 exampledir1 路径,请填写
exampledir1/,指定路径在 Bucket 中不存在时,OSS 会自动创建该路径。若留空,报告将保存在根目录。
重要为避免影响OSS-HDFS服务的正常使用或者引发数据污染的风险,在开通了OSS-HDFS服务的Bucket设置清单报告规则时,禁止将清单报告目录填写为
.dlsdata/。清单文件扫描范围
扫描整个Bucket:扫描整个 Bucket的所有文件。
按前缀匹配:用于仅扫描指定前缀下的文件,例如 exampledir1/。
清单报告加密选项
选择是否加密清单文件。
无:不加密。
AES256:使用AES256加密算法加密清单文件。
KMS:使用KMS密钥加密清单文件,可以选择使用OSS托管的KMS密钥或在KMS平台创建一个与目标Bucket相同地域的KMS密钥。
说明使用KMS密钥功能时会产生少量的KMS密钥API调用费用,费用详情请参考KMS 1.0计费说明。
清单报告导出周期
设置清单报告的生成周期。可选择可选择每周、每天、单次导出。文件数超百亿时,建议选择每周以降低成本和扫描压力。
清单内容
选择希望导出的文件信息:
系统元数据:Object大小、存储类型、最后更新日期、ETag、TransitionTime、分片上传状态、加密状态、Object ACL、文件类型、Crc64。
自定义元数据:标签个数
配置高级筛选功能
重要仅华北1(青岛)、华北5(呼和浩特)和德国(法兰克福)地域支持配置以下过滤选项。
如果需要根据文件大小、存储类型等条件过滤导出的文件,需要打开配置高级筛选功能开关。
支持的过滤选项说明如下:
时间范围:设置待导出文件最后一次修改的起始日期和结束日期,时间精确到秒。
文件大小范围:设置待导出文件的文件大小最小值和最大值。
重要设置文件大小范围时,确保文件大小的最小值以及最大值均大于0 B,且最大值不能超过48.8 TB。
存储类型:设置待导出哪些存储类型的文件。可以选择导出标准存储、低频访问、归档存储、冷归档存储以及深度冷归档存储的文件。
对象版本
若 Bucket 开启了版本控制,可选择导出当前版本或所有版本。
选中我知晓并同意授予阿里云 OSS 服务访问 Bucket 资源的权限,然后单击确定。
涉及Object较多时,生成清单文件需要一定的时间。可以通过两种方式判断是否已生成清单文件,详情请参见如何判断是否已生成清单文件?。
SDK
import com.aliyun.oss.*;
import com.aliyun.oss.common.auth.*;
import com.aliyun.oss.common.comm.SignVersion;
import com.aliyun.oss.model.*;
import java.util.ArrayList;
import java.util.List;
public class Demo {
public static void main(String[] args) throws Exception {
// Endpoint以华东1(杭州)为例,其它Region请按实际情况填写。
String endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
// 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();
// 填写Bucket名称,例如examplebucket。
String bucketName = "examplebucket";
// 填写存放清单结果的Bucket名称。
String destBucketName ="yourDestinationBucketName";
// 填写Bucket所有者授予的账户ID。
String accountId ="yourDestinationBucketAccountId";
// 填写具有读取源Bucket所有文件和向目标Bucket写入文件权限的角色名称。
String roleArn ="yourDestinationBucketRoleArn";
// 填写Bucket所在地域。以华东1(杭州)为例,Region填写为cn-hangzhou。
String region = "cn-hangzhou";
// 创建OSSClient实例。
// 当OSSClient实例不再使用时,调用shutdown方法以释放资源。
ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration();
clientBuilderConfiguration.setSignatureVersion(SignVersion.V4);
OSS ossClient = OSSClientBuilder.create()
.endpoint(endpoint)
.credentialsProvider(credentialsProvider)
.clientConfiguration(clientBuilderConfiguration)
.region(region)
.build();
try {
// 创建清单配置。
InventoryConfiguration inventoryConfiguration = new InventoryConfiguration();
// 设置清单规则名称。
String inventoryId = "testid";
inventoryConfiguration.setInventoryId(inventoryId);
// 设置清单中包含的Object属性。
List<String> fields = new ArrayList<String>();
fields.add(InventoryOptionalFields.Size);
fields.add(InventoryOptionalFields.LastModifiedDate);
fields.add(InventoryOptionalFields.IsMultipartUploaded);
fields.add(InventoryOptionalFields.StorageClass);
fields.add(InventoryOptionalFields.ETag);
fields.add(InventoryOptionalFields.EncryptionStatus);
inventoryConfiguration.setOptionalFields(fields);
// 设置清单的生成计划,以下示例为每周一次。其中,Weekly表示每周一次,Daily表示每天一次。
inventoryConfiguration.setSchedule(new InventorySchedule().withFrequency(InventoryFrequency.Weekly));
// 设置清单中包含的Object的版本为当前版本。如果设置为InventoryIncludedObjectVersions.All则表示Object的所有版本在版本控制状态下生效。
inventoryConfiguration.setIncludedObjectVersions(InventoryIncludedObjectVersions.Current);
// 清单配置是否启用的标识,取值为true或者false,设置为true表示启用清单配置,设置为false表示关闭清单配置。
inventoryConfiguration.setEnabled(true);
// 设置清单筛选规则,指定筛选Object的前缀。
InventoryFilter inventoryFilter = new InventoryFilter().withPrefix("obj-prefix");
inventoryConfiguration.setInventoryFilter(inventoryFilter);
// 创建存放清单结果的目标Bucket配置。
InventoryOSSBucketDestination ossInvDest = new InventoryOSSBucketDestination();
// 设置存放清单结果的存储路径前缀。
ossInvDest.setPrefix("destination-prefix");
// 设置清单格式。
ossInvDest.setFormat(InventoryFormat.CSV);
// 设置目标Bucket的用户accountId。
ossInvDest.setAccountId(accountId);
// 设置目标Bucket的roleArn。
ossInvDest.setRoleArn(roleArn);
// 设置目标Bucket的名称。
ossInvDest.setBucket(destBucketName);
// 如果需要使用KMS加密清单,请参考如下设置。
// InventoryEncryption inventoryEncryption = new InventoryEncryption();
// InventoryServerSideEncryptionKMS serverSideKmsEncryption = new InventoryServerSideEncryptionKMS().withKeyId("test-kms-id");
// inventoryEncryption.setServerSideKmsEncryption(serverSideKmsEncryption);
// ossInvDest.setEncryption(inventoryEncryption);
// 如果需要使用OSS服务端加密清单,请参考如下设置。
// InventoryEncryption inventoryEncryption = new InventoryEncryption();
// inventoryEncryption.setServerSideOssEncryption(new InventoryServerSideEncryptionOSS());
// ossInvDest.setEncryption(inventoryEncryption);
// 设置清单的目的地。
InventoryDestination destination = new InventoryDestination();
destination.setOssBucketDestination(ossInvDest);
inventoryConfiguration.setDestination(destination);
// 上传清单配置。
ossClient.setBucketInventoryConfiguration(bucketName, inventoryConfiguration);
} catch (OSSException oe) {
System.out.println("Caught an OSSException, which means your request made it to OSS, "
+ "but was rejected with an error response for some reason.");
System.out.println("Error Message:" + oe.getErrorMessage());
System.out.println("Error Code:" + oe.getErrorCode());
System.out.println("Request ID:" + oe.getRequestId());
System.out.println("Host ID:" + oe.getHostId());
} catch (ClientException ce) {
System.out.println("Caught an ClientException, which means the client encountered "
+ "a serious internal problem while trying to communicate with OSS, "
+ "such as not being able to access the network.");
System.out.println("Error Message:" + ce.getMessage());
} finally {
if (ossClient != null) {
ossClient.shutdown();
}
}
}
}const OSS = require('ali-oss');
const client = new OSS({
// yourregion填写Bucket所在地域。以华东1(杭州)为例,Region填写为oss-cn-hangzhou。
region: 'yourregion',
// 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
accessKeyId: process.env.OSS_ACCESS_KEY_ID,
accessKeySecret: process.env.OSS_ACCESS_KEY_SECRET,
// 填写存储空间名称。
bucket: 'yourbucketname'
});
const inventory = {
// 设置清单配置ID。
id: 'default',
// 清单配置是否启用的标识,取值为true或false。
isEnabled: false,
//(可选)设置清单筛选规则,指定筛选object的前缀。
prefix: 'ttt',
OSSBucketDestination: {
// 设置清单格式。
format: 'CSV',
// 目标Bucket拥有者的账号ID。
accountId: '<Your AccountId>',
// 目标Bucket的角色名称。
rolename: 'AliyunOSSRole',
// 目标Bucket的名称。
bucket: '<Your BucketName>',
//(可选)清单结果的存储路径前缀。
prefix: '<Your Prefix>',
// 如果需要使用SSE-OSS加密清单,请参考以下代码。
//encryption: {'SSE-OSS': ''},
// 如果需要使用SSE-KMS加密清单,请参考以下代码。
/*
encryption: {
'SSE-KMS': {
keyId: 'test-kms-id',
};,
*/
},
// 设置清单的生成计划,WEEKLY对应每周一次,DAILY对应每天一次。
frequency: 'Daily',
// 设置清单结果中包含了Object的所有版本, 如果设置为Current,则表示仅包含Object的当前版本。
includedObjectVersions: 'All',
optionalFields: {
//(可选)设置清单中包含的Object属性。
field: ["Size", "LastModifiedDate", "ETag", "StorageClass", "IsMultipartUploaded", "EncryptionStatus"]
},
}
async function putInventory(){
// 需要添加清单配置的Bucket名称。
const bucket = '<Your BucketName>';
try {
await client.putBucketInventory(bucket, inventory);
console.log('清单配置添加成功')
} catch(err) {
console.log('清单配置添加失败: ', err);
}
}
putInventory()import argparse
import alibabacloud_oss_v2 as oss
# 创建命令行参数解析器,并描述脚本用途:设置存储空间清单(Inventory)
parser = argparse.ArgumentParser(description="put bucket inventory sample")
# 定义命令行参数,包括必需的区域、存储空间名称、endpoint、用户ID、角色ARN以及清单名称
parser.add_argument('--region', help='The region in which the bucket is located.', required=True)
parser.add_argument('--bucket', help='The name of the bucket.', required=True)
parser.add_argument('--endpoint', help='The domain names that other services can use to access OSS')
parser.add_argument('--user_id', help='User account ID.', required=True)
parser.add_argument('--arn', help='The Alibaba Cloud Resource Name (ARN) of the role that has the permissions to read all objects from the source bucket and write objects to the destination bucket. Format: `acs:ram::uid:role/rolename`.', required=True)
parser.add_argument('--inventory_id', help='The name of the inventory.', required=True)
def main():
# 解析命令行参数,获取用户输入的值
args = parser.parse_args()
# 从环境变量中加载访问凭证信息,用于身份验证
credentials_provider = oss.credentials.EnvironmentVariableCredentialsProvider()
# 使用SDK默认配置创建配置对象,并设置认证提供者
cfg = oss.config.load_default()
cfg.credentials_provider = credentials_provider
# 设置配置对象的区域属性,根据用户提供的命令行参数
cfg.region = args.region
# 如果提供了自定义endpoint,则更新配置对象中的endpoint属性
if args.endpoint is not None:
cfg.endpoint = args.endpoint
# 使用上述配置初始化OSS客户端,准备与OSS交互
client = oss.Client(cfg)
# 发送请求以配置指定存储空间的清单设置
result = client.put_bucket_inventory(oss.PutBucketInventoryRequest(
bucket=args.bucket, # 存储空间名
inventory_id=args.inventory_id, # 存储空间清单ID
inventory_configuration=oss.InventoryConfiguration(
included_object_versions='All', # 包含所有版本的对象
optional_fields=oss.OptionalFields(
fields=[ # 可选字段,如大小和最后修改日期
oss.InventoryOptionalFieldType.SIZE,
oss.InventoryOptionalFieldType.LAST_MODIFIED_DATE,
],
),
id=args.inventory_id, # 存储空间清单ID
is_enabled=True, # 启用存储空间清单
destination=oss.InventoryDestination(
oss_bucket_destination=oss.InventoryOSSBucketDestination(
format=oss.InventoryFormatType.CSV, # 输出格式为CSV
account_id=args.user_id, # 用户账户ID
role_arn=args.arn, # 角色ARN,具有读取源存储空间和写入目标存储空间的权限
bucket=f'acs:oss:::{args.bucket}', # 目标存储空间
prefix='aaa', # 清单文件前缀
),
),
schedule=oss.InventorySchedule(
frequency=oss.InventoryFrequencyType.DAILY, # 清单频率,这里设置为每天
),
filter=oss.InventoryFilter(
lower_size_bound=1024, # 对象大小下限(字节)
upper_size_bound=1048576, # 对象大小上限(字节)
storage_class='ColdArchive', # 存储类别筛选条件
prefix='aaa', # 对象前缀筛选条件
last_modify_begin_time_stamp=1637883649, # 最后修改时间戳开始范围
last_modify_end_time_stamp=1638347592, # 最后修改时间戳结束范围
),
),
))
# 打印操作结果的状态码和请求ID,以便确认请求状态
print(f'status code: {result.status_code},'
f' request id: {result.request_id},'
)
# 当此脚本被直接执行时,调用main函数开始处理逻辑
if __name__ == "__main__":
main() # 脚本入口点,控制程序流程从这里开始using Aliyun.OSS;
using Aliyun.OSS.Common;
// yourEndpoint填写Bucket所在地域对应的Endpoint。以华东1(杭州)为例,Endpoint填写为https://oss-cn-hangzhou.aliyuncs.com。
var endpoint = "yourEndpoint";
// 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
var accessKeyId = Environment.GetEnvironmentVariable("OSS_ACCESS_KEY_ID");
var accessKeySecret = Environment.GetEnvironmentVariable("OSS_ACCESS_KEY_SECRET");
// 填写Bucket名称。
var bucketName = "examplebucket";
// 填写Bucket所有者授予的账户ID。
var accountId ="yourDestinationBucketAccountId";
// 填写具有读取源Bucket所有文件和向目标Bucket写入文件权限的角色名称。
var roleArn ="yourDestinationBucketRoleArn";
// 填写存放清单结果的Bucket名称。
var destBucketName ="yourDestinationBucketName";
// 填写Bucket所在地域对应的Region。以华东1(杭州)为例,Region填写为cn-hangzhou。
const string region = "cn-hangzhou";
// 创建ClientConfiguration实例,按照您的需要修改默认参数。
var conf = new ClientConfiguration();
// 设置v4签名。
conf.SignatureVersion = SignatureVersion.V4;
// 创建OssClient实例。
var client = new OssClient(endpoint, accessKeyId, accessKeySecret, conf);
client.SetRegion(region);
try
{
// 添加Bucket清单。
var config = new InventoryConfiguration();
// 设置清单规则名称。
config.Id = "report1";
// 清单配置是否启用的标识,取值为true或false。设置为true,表示启用清单配置。
config.IsEnabled = true;
// 设置清单筛选规则,指定筛选Object的前缀。
config.Filter = new InventoryFilter("filterPrefix");
// 创建清单的bucket目的地配置。
config.Destination = new InventoryDestination();
config.Destination.OSSBucketDestination = new InventoryOSSBucketDestination();
// 设置清单格式。
config.Destination.OSSBucketDestination.Format = InventoryFormat.CSV;
// 存放清单结果的目标Bucket的用户accountId。
config.Destination.OSSBucketDestination.AccountId = accountId;
// 存放清单结果的目标Bucket的roleArn。
config.Destination.OSSBucketDestination.RoleArn = roleArn;
// 存放清单结果的目标Bucket名称。
config.Destination.OSSBucketDestination.Bucket = destBucketName;
// 设置存放清单结果的存储路径前缀。
config.Destination.OSSBucketDestination.Prefix = "prefix1";
// 设置清单的生成计划,以下示例为每周一次。其中,Weekly对应每周一次,Daily对应每天一次。
config.Schedule = new InventorySchedule(InventoryFrequency.Daily);
// 设置清单中包含的object的版本为当前版本。如果设置为InventoryIncludedObjectVersions.All则表示object的所有版本,在版本控制状态下生效。
config.IncludedObjectVersions = InventoryIncludedObjectVersions.All;
// 设置清单中包含的Object属性。
config.OptionalFields.Add(InventoryOptionalField.Size);
config.OptionalFields.Add(InventoryOptionalField.LastModifiedDate);
config.OptionalFields.Add(InventoryOptionalField.StorageClass);
config.OptionalFields.Add(InventoryOptionalField.IsMultipartUploaded);
config.OptionalFields.Add(InventoryOptionalField.EncryptionStatus);
config.OptionalFields.Add(InventoryOptionalField.ETag);
var req = new SetBucketInventoryConfigurationRequest(bucketName, config);
client.SetBucketInventoryConfiguration(req);
Console.WriteLine("Set bucket:{0} InventoryConfiguration succeeded", bucketName);
}
catch (OssException ex)
{
Console.WriteLine("Failed with error code: {0}; Error info: {1}. \nRequestID:{2}\tHostID:{3}",
ex.ErrorCode, ex.Message, ex.RequestId, ex.HostId);
}#include <alibabacloud/oss/OssClient.h>
using namespace AlibabaCloud::OSS;
int main(void)
{
/* 初始化OSS账号信息。*/
/* yourEndpoint填写Bucket所在地域对应的Endpoint。以华东1(杭州)为例,Endpoint填写为https://oss-cn-hangzhou.aliyuncs.com。*/
std::string Endpoint = "yourEndpoint";
/* yourRegion填写Bucket所在地域对应的Region。以华东1(杭州)为例,Region填写为cn-hangzhou。*/
std::string Region = "yourRegion";
/* 填写Bucket名称,例如examplebucket。*/
std::string BucketName = "examplebucket";
/* 初始化网络等资源。*/
InitializeSdk();
ClientConfiguration conf;
conf.signatureVersion = SignatureVersionType::V4;
/* 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。*/
auto credentialsProvider = std::make_shared<EnvironmentVariableCredentialsProvider>();
OssClient client(Endpoint, credentialsProvider, conf);
client.SetRegion(Region);
InventoryConfiguration inventoryConf;
/* 指定清单规则名称,该名称在当前Bucket下必须全局唯一。*/
inventoryConf.setId("inventoryId");
/* 清单配置是否启用的标识,可选值为true或false。*/
inventoryConf.setIsEnabled(true);
/* (可选)清单筛选的前缀。指定前缀后,清单将筛选出符合前缀的Object。*/
inventoryConf.setFilter(InventoryFilter("objectPrefix"));
InventoryOSSBucketDestination dest;
/* 导出清单文件的文件格式。*/
dest.setFormat(InventoryFormat::CSV);
/* 存储空间拥有者的账户UID。*/
dest.setAccountId("10988548********");
/* 指定角色名称,该角色需要拥有读取源存储空间所有文件以及向目标存储空间写入文件的权限,格式为acs:ram::uid:role/rolename。*/
dest.setRoleArn("acs:ram::10988548********:role/inventory-test");
/* 存放导出的清单文件的存储空间。*/
dest.setBucket("yourDstBucketName");
/* 清单文件的存储路径前缀。*/
dest.setPrefix("yourPrefix");
/* (可选)清单文件的加密方式, 可选SSEOSS或者SSEKMS方式加密。*/
//dest.setEncryption(InventoryEncryption(InventorySSEOSS()));
//dest.setEncryption(InventoryEncryption(InventorySSEKMS("yourKmskeyId")));
inventoryConf.setDestination(dest);
/* 清单文件导出的周期, 可选为Daily或者Weekly。*/
inventoryConf.setSchedule(InventoryFrequency::Daily);
/* 是否在清单中包含Object版本信息, 可选为All或者Current。*/
inventoryConf.setIncludedObjectVersions(InventoryIncludedObjectVersions::All);
/* (可选)设置清单结果中应包含的配置项, 请按需配置。*/
InventoryOptionalFields field {
InventoryOptionalField::Size, InventoryOptionalField::LastModifiedDate,
InventoryOptionalField::ETag, InventoryOptionalField::StorageClass,
InventoryOptionalField::IsMultipartUploaded, InventoryOptionalField::EncryptionStatus
};
inventoryConf.setOptionalFields(field);
/* 设置清单配置。*/
auto outcome = client.SetBucketInventoryConfiguration(
SetBucketInventoryConfigurationRequest(BucketName, inventoryConf));
if (!outcome.isSuccess()) {
/* 异常处理。*/
std::cout << "Set Bucket Inventory fail" <<
",code:" << outcome.error().Code() <<
",message:" << outcome.error().Message() <<
",requestId:" << outcome.error().RequestId() << std::endl;
return -1;
}
/* 释放网络等资源。*/
ShutdownSdk();
return 0;
}package main
import (
"context"
"flag"
"log"
"github.com/aliyun/alibabacloud-oss-go-sdk-v2/oss"
"github.com/aliyun/alibabacloud-oss-go-sdk-v2/oss/credentials"
)
// 定义全局变量
var (
region string // 存储区域
bucketName string // 存储空间名称
)
// init函数用于初始化命令行参数
func init() {
flag.StringVar(®ion, "region", "", "The region in which the bucket is located.")
flag.StringVar(&bucketName, "bucket", "", "The name of the bucket.")
}
func main() {
// 解析命令行参数
flag.Parse()
var (
accountId = "account id of the bucket" // 存储空间所有者授予的账户ID,例如109885487000****
inventoryId = "inventory id" // 由用户指定的清单名称,清单名称在当前Bucket下必须全局唯一
)
// 检查bucket名称是否为空
if len(bucketName) == 0 {
flag.PrintDefaults()
log.Fatalf("invalid parameters, bucket name required")
}
// 检查region是否为空
if len(region) == 0 {
flag.PrintDefaults()
log.Fatalf("invalid parameters, region required")
}
// 加载默认配置并设置凭证提供者和区域
cfg := oss.LoadDefaultConfig().
WithCredentialsProvider(credentials.NewEnvironmentVariableCredentialsProvider()).
WithRegion(region)
// 创建OSS客户端
client := oss.NewClient(cfg)
// 创建设置存储空间清单的请求
putRequest := &oss.PutBucketInventoryRequest{
Bucket: oss.Ptr(bucketName), // 存储空间名称
InventoryId: oss.Ptr(inventoryId), // 由用户指定的清单名称
InventoryConfiguration: &oss.InventoryConfiguration{
Id: oss.Ptr(inventoryId), // 由用户指定的清单名称
IsEnabled: oss.Ptr(true), // 启用清单配置
Filter: &oss.InventoryFilter{
Prefix: oss.Ptr("filterPrefix"), // 设置清单筛选规则,指定筛选Object的前缀
LastModifyBeginTimeStamp: oss.Ptr(int64(1637883649)), // 最后修改开始时间戳
LastModifyEndTimeStamp: oss.Ptr(int64(1638347592)), // 最后修改结束时间戳
LowerSizeBound: oss.Ptr(int64(1024)), // 文件大小下限(字节)
UpperSizeBound: oss.Ptr(int64(1048576)), // 文件大小上限(字节)
StorageClass: oss.Ptr("Standard,IA"), // 存储类型
},
Destination: &oss.InventoryDestination{
OSSBucketDestination: &oss.InventoryOSSBucketDestination{
Format: oss.InventoryFormatCSV, // 导出清单文件的文件格式
AccountId: oss.Ptr(accountId), // 存储空间所有者授予的账户ID,例如109885487000****
RoleArn: oss.Ptr("acs:ram::" + accountId + ":role/AliyunOSSRole"), // 存储空间所有者授予操作权限的角色名,比如acs:ram::109885487000****:role/ram-test
Bucket: oss.Ptr("acs:oss:::" + bucketName), // 存放导出的清单结果的Bucket名称
Prefix: oss.Ptr("export/"), // 存放清单结果的存储路径前缀
},
},
Schedule: &oss.InventorySchedule{
Frequency: oss.InventoryFrequencyDaily, // 清单文件导出的周期(每天)
},
IncludedObjectVersions: oss.Ptr("All"), // 是否在清单中包含Object的所有版本信息
},
}
// 执行设置存储空间清单的请求
putResult, err := client.PutBucketInventory(context.TODO(), putRequest)
if err != nil {
log.Fatalf("failed to put bucket inventory %v", err)
}
// 打印设置存储空间清单的结果
log.Printf("put bucket inventory result:%#v\n", putResult)
}
ossutil
创建一个名为 inventory-configuration.xml 的文件,内容如下:
<?xml version="1.0" encoding="UTF-8"?>
<InventoryConfiguration>
<Id>report1</Id>
<IsEnabled>true</IsEnabled>
<Destination>
<OSSBucketDestination>
<Format>CSV</Format>
<AccountId>100000000000000</AccountId>
<RoleArn>acs:ram::100000000000000:role/AliyunOSSRole</RoleArn>
<Bucket>acs:oss:::destbucket</Bucket>
<Prefix>prefix1/</Prefix>
<Encryption>
<SSE-KMS>
<KeyId>keyId</KeyId>
</SSE-KMS>
</Encryption>
</OSSBucketDestination>
</Destination>
<Schedule>
<Frequency>Daily</Frequency>
</Schedule>
<IncludedObjectVersions>All</IncludedObjectVersions>
<OptionalFields>
<Field>Size</Field>
<Field>LastModifiedDate</Field>
<Field>ETag</Field>
<Field>StorageClass</Field>
<Field>IsMultipartUploaded</Field>
<Field>EncryptionStatus</Field>
</OptionalFields>
</InventoryConfiguration>执行以下命令:
ossutil api put-bucket-inventory --bucket examplebucket --inventory-id report1 --inventory-configuration file://inventory-configuration.xml注意:关于 put-bucket-inventory 命令的详细用法,请参考 put-bucket-inventory。
API
可直接调用 PutBucketInventory来配置或修改清单规则。需要手动构造 HTTP 请求并计算签名,适用于对流程有高度自定义需求的场景。
解析清单报告
清单任务以异步方式执行。清单报告的所有文件都存储在一个以扫描启动时间命名的文件夹中。核心文件包括 manifest.json 和 data/ 目录下的 .csv.gz 数据文件。要确认任务是否完成,可以检查目标是否已生成 manifest.json 文件。
读取
manifest.json文件:解析manifest.json文件以获取正确的列顺序和数据文件信息,重点关注以下两个字段:fileSchema:字符串类型,定义了 CSV 文件中各列的名称和确切顺序。
files:数组类型,列出了本次报告生成的所有
.csv.gz数据文件的详细信息,包括:key:文件路径size:文件大小MD5checksum:MD5 校验值
根据
fileSchema解析 CSV 数据文件获取并解压数据文件:从
manifest.json的files数组中获取每个数据文件的key(即文件路径)。根据该路径下载对应的.csv.gz压缩包。解压文件,得到 CSV 格式的数据。按序解析数据:
以
fileSchema字段中定义的顺序作为 CSV 文件的列标题。逐行读取解压后的 CSV 文件。每一行代表一个对象(文件)的完整记录,每一列则对应fileSchema中指定的一个字段。CSV 内容示例:如果
fileSchema为"Bucket,Key,Size,StorageClass,LastModifiedDate",解压后的 CSV 内容格式如下:source-bucket,"dir%2Fbody.xml","102400","Standard","2025-04-14T07-06-00Z" source-bucket,"dest.png","312049","Standard","2025-04-14T07-05-59Z"Key 使用URL编码,可按需解码。
全量清单文件
清单任务配置完成后,OSS会按清单规则指定的导出周期生成清单文件。清单文件的目录结构如下:
<dest-bucket-name>/
└── <dest-prefix>/
└── <source-bucket-name>/
└── <inventory-id>/
├── YYYY-MM-DDTHH-MMZ/ (扫描开始的UTC时间)
│ ├── manifest.json (清单任务的元数据文件)
│ └── manifest.checksum (manifest.json 文件的 MD5 校验和)
└── data/
└── <uuid>.csv.gz (多份GZIP 压缩的清单数据文件)目录结构 | 说明 |
dest-prefix | 该目录根据设置的清单报告名前缀生成,如果清单报告名前缀设置为空,将省略该目录。 |
source-bucket-name | 该目录根据配置清单报告的源Bucket名生成。 |
inventory_id | 该目录根据清单任务的规则名称生成。 |
YYYY-MM-DDTHH-MMZ | 该目录是标准的格林威治时间戳,表示开始扫描Bucket的时间,例如2025-05-17T16-00Z。该目录下包含了manifest.json和manifest.checksum文件。 |
data | 该目录下存放了包含源Bucket中的对象列表以及每个对象的元数据的清单文件,清单文件格式为使用GZIP压缩的CSV文件。 重要
|
manifest文件
manifest文件包含manifest.json和manifest.checksum,详细说明如下:
manifest.json:提供了有关清单的元数据和其他基本信息。
{ "creationTimestamp": "1642994594", "destinationBucket": "dest-bucket-name", "fileFormat": "CSV", "fileSchema": "Bucket, Key, VersionId, IsLatest, IsDeleteMarker, Size, StorageClass, LastModifiedDate, ETag, IsMultipartUploaded, EncryptionStatus, ObjectAcl, TaggingCount, ObjectType, Crc64", "files": [{ "MD5checksum": "F77449179760C3B13F1E76110F07****", "key": "dest-prefix/source-bucket-name/inventory-id/data/a1574226-b5e5-40ee-91df-356845777c04.csv.gz", "size": 2046}], "sourceBucket": "source-bucket-name", "version": "2019-09-01" }各字段详细说明如下:
字段名称
说明
creationTimestamp
时间戳,显示开始扫描源Bucket的时间。
destinationBucket
存放清单文件的目标Bucket。
fileFormat
清单文件的格式。
fileSchema
清单文件包含的字段,分为固定字段和可选字段。其中,固定字段的顺序是固定的,可选字段的排列顺序取决于配置清单规则时清单内容字段的排列顺序(控制台配置时以字段的勾选先后顺序为准)。 因此,建议以fileSchema中的字段顺序去解析csv.gz中的数据列,避免出现列和属性对应错误的情况。
配置清单规则时如果对象版本选择了当前版本,则fileSchema中,先排列固定字段
Bucket, Key,后续为可选字段。配置清单规则时如果对象版本选择了所有版本,则fileSchema中,先排列固定字段
Bucket, Key, VersionId, IsLatest, IsDeleteMarker,后续为可选字段。
files
包含清单文件的MD5值、文件名完整路径及文件大小。
sourceBucket
配置清单规则的源Bucket。
version
清单版本号。
manifest.checksum:
manifest.checksum文件包含了manifest.json文件的 MD5 哈希值,可用于校验manifest.json文件的完整性,例如F77449179760C3B13F1E76110F07****。
全量清单报告
清单报告存储在data/目录中,包含清单功能导出的文件信息。清单报告示例如下:

字段名称 | 说明 |
Bucket | 执行清单任务的源Bucket名称。 |
Key | Bucket中Object的名称。 Object名称使用URL编码,可按需解码。 |
VersionId | Object的版本ID。仅当配置的清单规则为导出所有版本时出现此字段。
|
IsLatest | Object版本是否为最新版本。仅当配置的清单规则为导出所有版本时出现此字段。
|
IsDeleteMarker | Object版本是否为删除标记。仅当配置的清单规则为导出所有版本时出现此字段。
|
Size | Object大小。 |
StorageClass | Object的存储类型。 |
LastModifiedDate | Object的最后修改时间,格式是格林威治时间,与北京时间相差8小时。 |
TransistionTime | Object通过生命周期规则转储为冷归档或者深度冷归档存储类型的时间。 |
ETag | Object的ETag。 Object生成时会创建相应的ETag,用于标识一个Object的内容。
|
IsMultipartUploaded | Object是否通过分片上传生成。如果是,则该字段值为true,否则为false。 |
EncryptionStatus | Object是否已加密。若Object已加密,则该字段值为true,否则为false。 |
ObjectAcl | Object的读写权限。更多信息,请参见Object ACL。 |
TaggingCount | Object的标签个数。 |
ObjectType | Object类型。更多信息,请参见Object类型。 |
Crc64 | Object的CRC64。 |
增量清单
增量清单通常以10分钟为周期,捕获并报告该时间窗口内发生的所有对象变更事件(包括创建、元数据更新、删除)。
配置清单规则
控制台
登录 OSS 管理控制台。
进入需要生成清单的源 Bucket,在左侧导航栏选择 数据管理 > Bucket 清单。
在Bucket 清单页面,单击创建清单。
在设置清单报告规则面板。
配置基础设置参数:
参数
说明
状态
设置增量清单任务的状态,选择启动。
规则名称
设置清单任务的名称。只能包含小写字母、数字、短划线(-),且不能以短划线(-)开头或结尾。
清单报告存储至
设置清单报告的存储路径。配置清单的 Bucket 与存放清单 Bucket 必须同账号、同地域。
若需将报告保存到存储空间 examplebucket 的 exampledir1 路径,请填写
exampledir1/,指定路径在 Bucket 中不存在时,OSS 会自动创建该路径。目标路径前缀的长度不能超过 128 个字符。若留空,报告将保存在根目录。
重要为避免影响OSS-HDFS服务的正常使用或者引发数据污染的风险,在开通了OSS-HDFS服务的Bucket设置清单报告规则时,禁止将清单报告目录填写为
.dlsdata/。清单文件扫描范围
扫描整个Bucket:扫描整个 Bucket的所有文件。
按前缀匹配:用于仅扫描指定前缀下的文件,例如 exampledir1/。
在追踪并生成增量元数据更新区域,开启获取增量元数据更新,并根据需要选择希望导出的元数据字段。
参数
说明
元数据字段
选择希望导出的文件信息。
事件元数据:序列号、事件类型、时间戳、用户ID、请求ID、请求源IP。
系统元数据:Object大小、存储类型、最后更新日期、ETag、分片上传状态、文件类型、Object ACL、Crc64、加密状态。
选中我知晓并同意授予阿里云 OSS 服务访问 Bucket 资源的权限,然后单击确定。
ossutil
创建一个名为 incremental-inventory.xml 的文件。与全量清单配置相比,关键在于增加了 <IncrementalInventory> 节。
<?xml version="1.0" encoding="UTF-8"?>
<InventoryConfiguration>
<Id>Report-1</Id>
<IsEnabled>true</IsEnabled>
<Filter>
<Prefix>test</Prefix>
</Filter>
<Destination>
<OSSBucketDestination>
<Format>CSV</Format>
<AccountId>12xxxxxx29</AccountId>
<RoleArn>acs:ram::12xxxxxx29:role/AliyunOSSRole</RoleArn>
<Bucket>acs:oss:::test-inc-bi-bj</Bucket>
<Prefix>Report-1</Prefix>
</OSSBucketDestination>
</Destination>
<Schedule>
<Frequency>Weekly</Frequency>
</Schedule>
<IncludedObjectVersions>All</IncludedObjectVersions>
<OptionalFields>
<Field>Size</Field>
<Field>LastModifiedDate</Field>
<Field>ETag</Field>
<Field>StorageClass</Field>
</OptionalFields>
<IncrementalInventory>
<IsEnabled>true</IsEnabled>
<Schedule>
<Frequency>600</Frequency>
</Schedule>
<OptionalFields>
<Field>SequenceNumber</Field>
<Field>RecordType</Field>
<Field>RecordTimestamp</Field>
<Field>Requester</Field>
<Field>RequestId</Field>
<Field>SourceIp</Field>
<Field>Size</Field>
<Field>StorageClass</Field>
<Field>LastModifiedDate</Field>
<Field>ETag</Field>
<Field>IsMultipartUploaded</Field>
<Field>ObjectType</Field>
<Field>ObjectAcl</Field>
<Field>Crc64</Field>
<Field>EncryptionStatus</Field>
</OptionalFields>
</IncrementalInventory>
</InventoryConfiguration>执行以下命令:
ossutil api put-bucket-inventory --bucket examplebucket --inventory-id report1 --inventory-configuration file://inventory-configuration.xml注意:关于 put-bucket-inventory 命令的详细用法,请参考 put-bucket-inventory。API
可直接调用 PutBucketInventory来配置或修改清单规则。这需要手动构造 HTTP 请求并计算签名,适用于对流程有高度自定义需求的场景。
解析清单报告
清单任务完成后,会在目标 Bucket 的指定路径下生成报告文件,核心包括:
manifest.json文件data/目录下的.csv数据文件
判断任务是否已完成,可以检查目标 Bucket 中是否生成了 manifest.json 文件。
解析步骤如下:
读取
manifest.json文件:清单报告的列顺序是动态的,取决于配置清单规则时所勾选的字段。需要先解析manifest.json中的fileSchema字段,该字段定义了 CSV 文件中各列的名称及其顺序。根据
fileSchema解析 CSV 数据文件以
fileSchema中定义的顺序作为 CSV 文件的列标题。按行读取 CSV 文件:每一行代表一个对象(文件)的完整记录,每一列对应
fileSchema中声明的一个字段。
增量清单文件
清单任务配置完成后,OSS会按清单规则指定的导出周期生成清单文件。清单文件的目录结构如下:
<dest-bucket-name>/
└── <dest-prefix>/
└── <source-bucket-name>/
└── <inventory-id>/
└── incremental_inventory/
└── YYYY-MM-DDTHH-MMSSZ/
├── manifest.json
└── data/
├── uuid1_0.csv
└── ......目录结构 | 说明 |
dest-prefix | 该目录根据设置的清单报告名前缀生成,如果清单报告名前缀设置为空,将省略该目录。 |
source-bucket-name | 该目录根据配置清单报告的源Bucket名生成。 |
inventory_id | 该目录根据清单任务的规则名称生成。 |
incremental_inventory | 增量清单的固定前缀(区分全量导出结果)。 |
YYYY-MM-DDTHH-MMSSZ | 该目录是标准的格林威治时间戳,表示开始扫描Bucket的时间,例如2020-05-17T16-0000Z。 |
data | 该目录下存放的是在指定时间周期内,源 Bucket 中发生修改的对象及其元数据的清单文件,清单文件格式为CSV文件。 |
manifest文件
{
"creationTimestamp": "1642994594",
"destinationBucket": "destbucket",
"fileFormat": "CSV",
"fileSchema": "Bucket, Key, VersionId, IsDeleteMarker, SequenceNumber, RecordType, RecordTimestamp, Requester, RequestId, SourceIp, Size, StorageClass, LastModifiedDate, ETag, IsMultipartUploaded, ObjectType, ObjectAcl, Crc64, EncryptionStatus",
"files": [{
"MD5checksum": "60463A9A34019CF448A730EB2CB3****",
"key": "dest-prefix/source-bucket-name/inventory-id/incremental_inventory/2025-09-28T07-4000Z/data/a1574226-b5e5-40ee-91df-356845777c04.csv",
"size": 2046}],
"sourceBucket": "srcbucket",
"version": "2025-09-30"
}各字段详细说明如下:
字段名称 | 说明 |
creationTimestamp | 时间戳,显示开始扫描源Bucket的时间。 |
destinationBucket | 存放清单文件的目标Bucket。 |
fileFormat | 清单文件的格式。 |
fileSchema | 清单文件包含的字段,分为固定字段和可选字段。其中,固定字段的顺序是固定的,可选字段的排列顺序取决于配置清单规则时清单内容字段的排列顺序(控制台配置时以字段的勾选先后顺序为准)。 因此,建议以fileSchema中的字段顺序去解析csv.gz中的数据列,避免出现列和属性对应错误的情况。
|
files | 包含清单文件的MD5值、文件名完整路径及文件大小。 |
sourceBucket | 配置清单规则的源Bucket。 |
version | 清单版本号。 |
增量清单报告字段
元数据类型 | 字段名称 | 说明 |
System Metadata | Bucket | 执行清单任务的源Bucket名称。 |
Event Metadata | SequenceNumber | 序列号,每条记录的SequenceNumber唯一,同Bucket同Object下的记录,可按照SequenceNumber排序,通常保证排序后的记录遵循时间逻辑顺序。 |
RecordType | 事件类型:CREATE、UPDATE_METADATA、DELETE
| |
RecordTimestamp | 时间戳 ( 示例:"2024-08-25 18:08:01.024"),采用格林威治时区,精度到毫秒。 | |
Requester | 请求者的阿里云 ID 或者 Principal ID。 | |
RequestId | 请求的唯一标识。 | |
SourceIp | 请求者源 IP。 | |
System Metadata | Key | Bucket 中 Object 的名称,采用URL编码。 |
VersionId | Object的版本ID。仅当配置的清单规则为导出所有版本时出现此字段。
| |
IsDeleteMarker | Object版本是否为删除标记。仅当配置的清单规则为导出所有版本时出现此字段。
| |
Size | Object大小。 | |
StorageClass | Object的存储类型。 | |
LastModifiedDate | Object的最后修改时间,格式是格林威治时间,与北京时间相差8小时。 | |
ETag | Object的ETag。Object生成时会创建相应的ETag,用于标识一个Object的内容。
| |
IsMultipartUploaded | Object是否通过分片上传生成。如果是,则该字段值为true,否则为false。 | |
EncryptionStatus | Object是否已加密。若Object已加密,则该字段值为true,否则为false。 | |
ObjectAcl | Object的读写权限。更多信息,请参见Object ACL。 | |
ObjectType | Object类型。更多信息,请参见Object类型。 | |
Crc64 | Object的CRC64。 |
配额与限制
单个 Bucket 最多支持 1000 条清单规则(通过 API/SDK)或 10 条(通过控制台)。
计费说明
存储空间清单暂不收取功能使用费,但会产生以下关联费用:
API 请求费:配置和获取清单规则时产生
Put请求费用和Get请求费用。OSS 写入清单报告到目标 Bucket 时会产生 PUT 请求费用。下载和读取清单报告时,会产生 GET 请求费用。存储费用:生成的清单报告(
manifest文件和csv.gz、csv文件)会占用目标 Bucket 的存储空间,按标准存储费用计费。外网流出费用:使用外网 Endpoint 下载和读取清单报告时,会产生外网流出流量费用。
为避免不必要的开销,请及时删除不再需要的清单规则,并使用生命周期规则自动清理过期的清单报告文件。
应用于生产环境
最佳实践
最小权限:始终使用专用的、具备最小权限的 RAM 角色,切勿在生产环境中使用
AliyunOSSRole。性能建议:对于高流量的源 Bucket,应将清单报告存储到另一个专用的 Bucket,避免因写入报告而产生的带宽竞争影响线上业务。
成本优化:存储空间清单支持按天或按周导出清单文件。对于超过百亿文件的 Bucket,建议使用每周清单。同时,在目标 Bucket 上配置生命周期规则,自动删除超过 N 天(例如 30 天)的清单报告以节省存储成本。
Bucket内的文件数量
导出建议
<100亿
按需配置按天或按周导出
100亿~500亿
按周导出
≥500亿
按前缀匹配分批导出
通过提交工单提升导出限制
前缀分区:对于超大规模(如千亿级)的 Bucket,可按业务前缀创建多条清单规则,分而治之地生成报告,便于管理和处理。
风险防范
数据审计:导出清单文件的过程中,由于Object的创建、删除或覆盖等操作,可能会导致最终输出的清单列表中不一定包含所有的Object。最后修改时间早于manifest.json文件中createTimeStamp字段显示时间的Object会出现在清单文件中;最后修改时间晚于createTimeStamp字段显示时间的Object可能不会出现在清单文件中。建议在对清单列表中的Object进行操作之前,先使用HeadObject接口检查Object的属性。
监控告警:监控目标 Bucket 的存储用量,防止清单文件无限制增长导致成本失控。监控
PutBucketInventory等 API 的调用,以便追踪配置变更。变更管理:清单规则的变更(如修改前缀、频率)会影响下游的数据分析流程。所有变更应纳入版本控制和评审流程。