用Amazon Simple Storage Service(S3)在云中存储数据

日期: 2009-05-25 来源:TechTarget中国 英文

  学习基本的Amazon SimpleDB(SDB)概念,研究boto(一个用于与SDB交互的开放源码Python库)提供的一些功能。在这个“用Amazon Web Services进行云计算”系列中,学习如何使用Amazon Web Services进行云计算。了解这些服务如何为设计和构建可伸缩、可靠的应用程序提供一种可选方案。本文讨论Amazon Simple Storage Service(S3)提供的可伸缩、高响应性的服务。了解用于与S3交互的工具,使用代码示例构建一个简单的shell。

  Amazon Simple Storage Service

  本系列的第1部分介绍了Amazon Web Services的构建块,解释了如何使用这个虚拟基础设施构建Web范围的系统。

  在本文中,学习关于Amazon Simple Storage Service(S3)的更多知识。S3是一个高度可伸缩的快速的Internet数据存储系统,用户可以从任何地方在任何时候轻松地存储和获取任意数量的数据。只需根据实际使用的存储和带宽付费。没有安装成本、最低成本或其他间接费用。

  Amazon负责对存储基础设施进行管理和维护,这使您能够把注意力集中在系统和应用程序的核心功能上。S3是一个具有工业强度的平台,能够轻松地满足您的数据存储需求。它能够:

  ·存储应用程序的数据。
  ·执行个人或企业备份。
  ·把媒体和需要很大带宽的其他内容快速且低成本地分发给您的客户。

  S3的特性包括:

  可靠性

  它具有容错能力,能够非常快速地恢复系统,停机时间非常短。Amazon提供的服务水平协议(SLA)保证99.99%的可用性。

  简单性

  S3基于简单的概念,为开发应用程序提供很强的灵活性。如果需要,可以在S3组件之上构建更多功能,从而构建更复杂的存储方案。

  可伸缩性

  S3提供很强的可伸缩性,可以在出现需求高峰时轻松快速地扩展。

  廉价

  与市场上的其他企业和个人数据存储解决方案相比,S3的费率非常有竞争优势。
支撑S3框架的三个基本概念是bucket、对象和键。

  bucket

  bucket是基本构建块。存储在Amazon S3中的每个对象都包含在一个bucket中。可以认为bucket相当于文件系统上的文件夹(即目录)。文件夹和bucket之间的主要差异之一是,每个bucket及其内容都可以通过URL访问。例如,如果有一个名为“prabhakar”的bucket,就可以使用URL http://prabhakar.s3.amazonaws.com访问它。

  Each S3账户可以包含最多100个bucket。bucket不能相互嵌套,所以不能在bucket中创建bucket。在创建bucket时,可以指定位置限制,从而影响bucket的地理位置。这会自动地确保在这个bucket中存储的所有对象都存储在指定的地理位置。目前,可以把bucket放在美国或欧盟。如果在创建bucket时没有指定位置,那么bucket及其内容会存储在最接近您帐户的账单地址的地方。

  bucket名称必须符合下面的S3规定:

  ·名称必须以数字或字母开头。
  ·名称的长度必须在3到255个字符之间。
  ·有效的名称只能包含小写字母、数字、点号、下划线和连字符。
  ·尽管名称可以包含数字和点号,但是不能采用IP地址格式。例如,不能把bucket命名为192.168.1.254。
  ·bucket名称空间在S3中的所有账户的所有bucket之间共享。bucket名称必须在整个S3中是惟一的。

  如果要通过URL访问bucket包含的对象,bucket名称还必须符合以下规定:

  ·bucket名称必须不包含下划线。
  ·名称的长度必须在3到63个字符之间。
  ·名称不能以连字符结尾。例如,myfavorite-.bucket.com是无效的。
  ·在名称中点号的旁边不能有连字符。所以my-.bucket.com是无效的。

  可以对bucket使用域名约定,比如media.yourdomain.com,从而把现有的Web域或子域映射到Amazon S3。通过添加指向S3的DNS CNAME条目进行实际的映射。这种方案的主要优点是,可以在下载文件的URL中使用自己的域名。CNAME映射负责转换bucket的S3地址。例如,http://media.yourdomain.com.s3.amazonaws.com会转换成更友好的http://media.yourdomain.com。

  对象
 
  对象包含存储在S3中bucket中的数据。可以把对象看作要存储的文件。存储的每个对象由两个实体组成:数据和元数据。数据是要实际存储的东西,比如PDF文件、Word文档、视频文件等。存储的数据还有相关联的元数据,元数据用于描述对象。例如,存储的对象的内容类型、最后一次修改对象的日期以及应用程序特有的其他元数据。在把对象发送给S3时,由开发人员以键-值对的形式指定对象的元数据。

  S3对于bucket的数量有限制,但是对于对象的数量没有限制。可以在bucket中存储任意数量的对象,每个对象可以包含最多5 GB数据。

  对于可公共访问的S3对象,可以使用HTTP、HTTPS或BitTorrent获取其中的数据。通过使用BitTorrent,可以非常简便地从S3账户分发大型媒体文件;Amazon不仅会创建对象的torrent文件,还会作为它的种子。

  

  在S3 bucket中存储的每个对象由一个惟一的键标识。这在概念上与文件系统文件夹中的文件名相似。在硬盘上的文件夹中,文件名必须在文件夹中是惟一的。bucket中的每个对象必须有且只有一个键。bucket名称和对象的键共同组成S3中存储的对象的惟一标识。

  可以使用URL访问S3中的每个对象,这个URL由S3服务URL、bucket名称和惟一的键组成。如果在名为prabhakar的bucket中存储一个键为my_favorite_video.mov的对象,那么可以使用URL http://prabhakar.s3.amazonaws.com/my_favorite_video.mov访问这个对象。

  尽管概念很简单(如图1所示),但是bucket、对象和键共同为构建数据存储解决方案提供很强的灵活性。可以使用这些构建块简便地在S3中存储数据,也可以利用其灵活性,在S3之上构建更复杂的存储和应用程序,提供更多功能。

                            

  图1. S3的概念视图
 
  访问日志记录

  每个S3 bucket可以有访问日志记录,其中包含每个对象请求的详细信息。在默认情况下,日志记录是关闭的;对于希望跟踪的每个Amazon S3 bucket,必须显式地启用日志记录。访问日志记录包含关于请求的大量详细信息,包括请求类型、请求的资源和处理请求的日期和时间。

  日志采用S3 Server Access Log Format,但是很容易转换为Apache Combined Log Format。然后,可以使用任何开放源码或商业日志分析工具(比如Webalizer)轻松地解析它们,从而提供适合人阅读的报告和漂亮的图表。可以通过报告了解访问文件的客户群。关于可以处理S3日志记录的工具的信息见 参考资料。

  安全性

  在S3中创建的每个bucket和对象都是创建它们的用户账户私有的。必须显式地把权限授予其他用户和客户,这样他们才能看到S3 bucket中的对象列表和下载其中的数据。Amazon S3提供下面的安全特性,从而保护bucket和其中的对象。

  身份验证

  确保请求是由拥有bucket或对象的用户发出的。每个S3请求必须包含惟一地标识用户的Amazon Web Services访问键。

  授权

  确保试图访问资源的用户具有所需的权限。每个S3对象有一个相关联的访问控制列表(ACL),ACL显式地指定此资源的授权。可以把访问权授予所有Amazon Web Services用户,或根据电子邮件地址授予某个用户,还可以把匿名访问权授予任何用户。
 
  完整性

  每个S3请求必须由发出请求的用户用Amazon Web Services密钥进行数字签名。在收到请求时,S3会检查签名以确保请求没有在传输过程中被篡改。

  加密

  可以通过HTTPS协议访问S3,从而确保通过加密的连接传输数据。

  不可否认

  每个S3请求都包含时间戳,以此作为事务的证据。

  对S3的每个REST请求必须经历下面的标准步骤以确保安全性:

  ·必须把请求和所需的所有参数组合为一个字符串。
  ·必须使用Amazon Web Services密钥创建请求字符串的Hash Message Authentication Code(HMAC)签名散列值。
  ·把这个计算出的签名本身作为参数添加到请求中。
  ·然后把请求发给Amazon S3。
  ·Amazon S3检查提供的签名是否是请求的有效HMAC散列值。
  ·只有在签名有效时,Amazon S3才会处理这个请求。

  Amazon Web Services和S3入门

  要想开始使用S3,需要注册一个Amazon Web Services账户。您会得到一个Amazon Web Services账号、安全访问密钥以及x.509安全证书,在开始使用各种库和工具与S3通信时需要这些密钥和安全证书。

  与任何Amazon Web Services的所有通信都要通过SOAP接口或查询/REST接口。通过这两个接口发送的请求消息必须由发送请求的用户进行数字签名,从而确保消息没有在传输过程中被篡改,并确保它们确实来自发送请求的用户。这是Amazon Web Services API使用过程的最基本部分。每个请求必须 进行数字签名并把签名附加到请求上。

  每个Amazon Web Services用户账户与下面的安全凭证相关联:

  ·访问键ID,用于识别通过查询/REST接口发出请求的用户。
  ·安全访问密钥,用于在通过查询接口发出请求时计算数字签名。
  ·公共和私有x.509安全证书,用于在使用SOAP时进行签名和身份验证。

  在Web Services Account information页面上,可以管理密钥和证书、重新生成它们、查看账户活动和使用情况报告以及修改个人信息。

  在成功地注册Amazon Web Services账户之后,需要按照以下步骤为账户启用Amazon S3服务:

  ·登录Amazon Web Services账户。
  ·导航到S3主页。
  ·单击页面右边的Sign Up For This Web Service。
  ·提供必需的信息并完成注册过程。

  本文中的示例使用查询/REST接口与S3通信。需要获得自己的访问键。可以通过在Web Services Account information页面上选择View Access Key Identifiers获得访问键。现在设置Amazon Web Services并为账户启用S3服务。

  与S3交互

  为了学习与S3交互,可以使用Amazon、第三方或独立开发人员提供的库。本文并不深入讨论与S3的通信的细节,比如如何对请求进行签名、如何构建用来封装数据的XML文档以及对S3发送和接收的参数。我们使用库提供的高层接口,让库处理所有细节。更多信息请查阅S3开发人员指南。

  我们将使用开放源码的Java库JetS3t与S3交互,通过一些代码片段了解它的API。在本文末尾,将把这些片段组合起来,实现一些有意义的功能:一个简单方便的S3 shell,可以随时使用它与S3交互。

  JetS3t

  JetS3t是一个用于与S3交互的开放源码Java工具箱。它不仅仅是一个库。它的发行版包含几个非常有用的与S3相关的工具,一般S3用户和在S3之上构建应用程序的服务提供商都可以使用它们。JetS3t包含:

  Cockpit

  用于管理Amazon S3账户内容的GUI。

  Synchronize

  用于同步用户计算机上的目录和Amazon S3帐户的命令行工具。

  Gatekeeper

  一个servlet,可以作为访问Amazon S3帐户的中介。

  CockpitLite

  Cockpit的轻量版本,它通过中介gatekeeper服务路由它的所有操作。

  Uploader

  一个GUI,它通过中介gatekeeper服务路由它的所有操作。服务提供商可以使用它允许客户访问他们的S3帐户。

  下载JetS3t的最新版本。
 
  当然,可以使用这些GUI应用程序之一与S3交互,但是这对于开发与S3交互的应用程序没什么帮助。可以下载本文的完整源代码,这是一个压缩的存档文件,其中包含一个准备就绪的Netbeans项目,可以把它导入自己的工作空间。

  连接S3

  JetS3t提供一个名为org.jets3t.service.S3Service的抽象类,实现特定接口(比如REST或SOAP)的类必须扩展它。JetS3t提供两个用于连接S3和与S3交互的实现:

  ·org.jets3t.service.impl.rest.httpclient.RestS3Service通过REST接口与S3通信。
  ·org.jets3t.service.impl.soap.axis.SoapS3Service通过SOAP接口使用Apache Axis 1.4与S3通信。

  JetS3t使用名为jets3t.properties的文件配置在与S3通信时使用的各种参数。本文中的示例使用发行版附带的默认jets3t.properties。JetS3t configuration guide详细解释了这些参数。

  在本文中,将使用RestS3Service连接S3。通过以AWSCredentials对象的形式提供Amazon Web Services访问键,可以创建一个新的RestS3Service对象。请记住,本文中的代码片段只用于演示API的使用方法。要想运行这些片段,必须导入所需的所有类。正确的导入语句请参考 下载 包中的源代码。更简单的方法是,把提供的Netbeans项目导入自己的工作空间,这样就能够轻松地访问所有源代码。

  清单1. 创建一个新的RestS3Service
String awsAccessKey = ”Your AWS access key”;
String awsSecretKey = “Your AWS Secret key”;

// use your AWS keys to create a credentials object
AWSCredentials awsCredentials = new AWSCredentials(awsAccessKey, awsSecretKey);

// create the service object with our AWS credentials
S3Service s3Service = new RestS3Service(awsCredentials);
 
  管理bucket

  bucket的概念由org.jets3t.service.model.S3Bucket封装,这个类扩展org.jets3t.service.model.BaseS3Object类。这个类是JetS3t模型中bucket和对象的父类。除了各种访问器方法之外,每个S3Bucket对象还提供一个toString()方法,可以使用它输出 bucket 的重要信息(bucket 的名称和地理位置,创建 bucket的日期,所有者的姓名,与这个bucket相关联的所有元数据)。

  清单2. 列出bucket
// list all buckets in the AWS account and print info for each bucket.
S3Bucket[] buckets = s3Service.listAllBuckets();
for (S3Bucket b : buckets) {
   System.out.println(b);
}
 
  可以通过提供惟一的bucket名称创建新的bucket。bucket的名称空间由所有用户账户共享,所以有时候找到惟一的名称可能有困难。还可以指定希望把bucket及其包含的对象放在哪里。

  清单3. 创建bucket
// create a US bucket and print its info
S3Bucket bucket = s3Service.createBucket(bucketName);
System.out.println(“Created bucket – ” + bucketName + ” – ” + bucket);

// create a EU bucket and print its info
S3Bucket bucket = s3Service.createBucket(bucketName, S3Bucket.LOCATION_EUROPE);
System.out.println(“Created bucket – ” + bucketName + ” – ” + bucket);
 
  在删除bucket之前,必须删除其中包含的所有对象,否则会引发异常。RestS3Service类适合处理单一对象。如果需要处理多个对象,最好考虑使用多线程方式以提高速度。JetS3t提供用于此目的的org.jets3t.service.multithread.S3ServiceSimpleMulti类。可以使用这个类包装现有的s3Service对象,就可以充分利用多处理器的能力。这对于删除bucket中的所有对象很方便。

  清单4. 删除bucket
// get the bucket
S3Bucket bucket = getBucketFromName(s3Service, “my bucket”);

// delete a bucket – it must be empty first
s3Service.deleteBucket(bucket);

// create a multi threaded version of the RestService
S3ServiceSimpleMulti s3ServiceMulti = new S3ServiceSimpleMulti(s3Service);

// get all the objects from bucket
S3Object[] objects = s3Service.listObjects(bucket);

// clear the bucket by deleting all its objects
s3ServiceMulti.deleteObjects(bucket, objects);
 
  每个bucket与一个ACL相关联,ACL决定bucket的授权和提供给其他用户的访问级别。可以获取ACL并输出它提供的授权。

  清单5. 获取bucket的ACL
// get the bucket
S3Bucket bucket = getBucketFromName(s3Service, “my bucket”);

// get the ACL and print it
AccessControlList acl = s3Service.getBucketAcl(bucket);
System.out.println(acl);
 
  在新创建的bucket和对象上,默认权限指定它们是所有者私有的。可以修改bucket的ACL,向一组用户授予读和写权限,或者对bucket的完全控制权。

  清单6. 公开bucket及其内容
// get the bucket
S3Bucket bucket = getBucketFromName(s3Service, “my bucket”);

// get the ACL
AccessControlList acl = s3Service.getBucketAcl(bucket);

// give everyone read access
acl.grantPermission(GroupGrantee.ALL_USERS, Permission.PERMISSION_READ);

// save changes back to S3
bucket.setAcl(acl);
s3Service.putBucketAcl(bucket);
 
  很容易为bucket启用日志记录和获取当前的日志记录状态。启用日志记录之后,会在S3中存储这个bucket中每个文件的详细访问日志。您的S3账户要为日志占用的存储空间付费。

  清单7. S3 bucket的日志记录
// get the bucket
S3Bucket bucket = getBucketFromName(s3Service, “my bucket”);

// is logging enabled?
S3BucketLoggingStatus loggingStatus = s3Service.getBucketLoggingStatus(bucketName);
System.out.println(loggingStatus);

// enable logging
S3BucketLoggingStatus newLoggingStatus = new S3BucketLoggingStatus();

// set a prefix for your log files
newLoggingStatus.setLogfilePrefix(logFilePrefix);

// set the target bucket name
newLoggingStatus.setTargetBucketName(bucketName);

// give the log_delivery group permissions to read and write from the bucket
AccessControlList acl = s3Service.getBucketAcl(bucket);
acl.grantPermission(GroupGrantee.LOG_DELIVERY, Permission.PERMISSION_WRITE);
acl.grantPermission(GroupGrantee.LOG_DELIVERY, Permission.PERMISSION_READ_ACP);
bucket.setAcl(acl);

// save the changed ACL for the bucket to S3
s3Service.putBucketAcl(bucket);

// save the changes to the bucket logging
s3Service.setBucketLoggingStatus(bucketName, newLoggingStatus, true);
System.out.println(“The bucket logging status is now enabled.”);
 
  管理对象

  bucket中的每个对象由org.jets3t.service.model.S3Object表示。每个S3Object对象提供一个toString()方法,可以使用它输出对象的重要信息:

  ·键的名称
  ·包含它的bucket的名称
  ·最后一次修改对象的日期
  ·与对象相关联的所有元数据

  它还提供用来访问对象的各个属性和元数据的方法。

  清单8. 列出对象
// list objects in a bucket.
S3Object[] objects = s3Service.listObjects(bucket);

// print out the object details
if (objects.length == 0) {
   System.out.println(“No objects found”);
} else {
   for (S3Object o : objects) {
      System.out.println(o);
   }
}
 
  可以通过提供要匹配的前缀来筛选获取的对象列表。

  清单9. 筛选对象列表
// list objects matching a prefix.
S3Object[] filteredObjects = s3Service.listObjects(bucket, “myprefix”, null);

// print out the object details
if (filteredObjects.length == 0) {
   System.out.println(“No objects found”);
} else {
   for (S3Object o : filteredObjects) {
      System.out.println(o);
   }
}
 
  每个对象可以有相关联的元数据,比如内容类型、修改的日期等等。还可以把应用程序特有的定制元数据与对象关联起来。

  清单10. 获取对象的元数据
// get the bucket
S3Bucket bucket = getBucketFromName(s3Service, bucketName);

// getobjects matching a prefix
S3Object[] filteredObjects = s3Service.listObjects(bucket, “myprefix”, null);

if (filteredObjects.length == 0) {
   System.out.println(“No matching objects found”);
}else {
  
   // get the metadata for multiple objects.
   S3Object[] objectsWithHeadDetails = s3ServiceMulti.getObjectsHeads(bucket,
      filteredObjects);

   // print out the metadata
   for (S3Object o : objectsWithHeadDetails) {
      System.out.println(o);
   }
}
 
  在默认情况下,每个新创建的对象都是私有的。可以使用JetS3t生成一个带签名的URL,其他用户可以使用它下载对象数据。这个URL只在特定的时间段内有效,在此之后它自动地过期。对象仍然是私有的,但是可以把URL提供给任何人,让他们能够在一段时间内下载对象。

  清单11. 生成用于下载对象的带签名的URL
// get the bucket
S3Bucket bucket = getBucketFromName(s3Service, bucketName);

// how long should this URL be valid?
int duration = Integer.parseInt(tokens.nextToken());
Calendar cal = Calendar.getInstance();
cal.add(Calendar.MINUTE, duration);
Date expiryDate = cal.getTime();

// create the signed url
String url = S3Service.createSignedGetUrl(bucketName, objectKey,
        awsCredentials, expiryDate);
System.out.println(“You can use this public URL to access this file for the next ”
   + duration + ” min – ” + url);
 
  S3允许bucket中的每个对象最多包含5 GB数据。如果对象超过这个限制,就需要把对象分割为多个不超过5 GB的文件,然后把所有部分上传给S3。

  清单12. 上传到S3
// get the bucket
S3Bucket bucket = getBucketFromName(s3Service, bucketName);

// create an object with the file data
File fileData = new File(“/my_file_to_upload”);
S3Object fileObject = new S3Object(bucket, fileData);

// put the data on S3
s3Service.putObject(bucket, fileObject);
System.out.println(“Successfully uploaded object – ” + fileObject);
 
  JetS3t提供一个DownloadPackage类,它可以方便地把S3对象中的数据与本地文件关联起来,自动地把数据保存到文件中。可以使用这个特性轻松地从S3下载对象。

  清单13. 从S3下载
// get the bucket
S3Bucket bucket = getBucketFromName(s3Service, bucketName);

// get the object
S3Object fileObject = s3Service.getObject(bucket, fileName);

// associate a file with the object data
DownloadPackage[] downloadPackages = new DownloadPackage[1];
downloadPackages[0] = new DownloadPackage(fileObject,
                            new File(fileObject.getKey()));

// download objects to the associated files
s3ServiceMulti.downloadObjects(bucket, downloadPackages);
System.out.println(“Successfully retrieved object to current directory”);
 
  本节讨论了JetS3t工具箱提供的一些基本功能,以及如何使用它们与S3交互。关于S3服务和JetS3t工具箱的更多信息请参见参考资料。

  S3 shell

  目前为止,我们通过代码片段了解了与S3的交互。可以把这些片段组合起来,创建一个可以从命令行运行的简单的S3 shell程序。我们将创建一个简单的Java程序,它通过参数接收Amazon Web Services访问键和密钥,返回一个控制台提示。然后,可以输入一个或几个字母,比如b(列出bucket)或om(列出与特定前缀匹配的对象)。使用这个程序体验S3服务。

  这个shell程序包含一个main()方法,它的实现由本文中的代码片段组成。为了节省篇幅,这里没有给出S3 shell的代码清单。完整的S3 shell源代码和它依赖的文件可以在下载中找到。只需执行devworks-s3.jar文件,即可运行这个shell。

  清单14. 运行S3 shell
java -jar devworks-s3.jar my_aws_access_key my_aws_secret_key
 
  在任何时候在S3 shell中输入h,就会列出支持的命令。

                

  图2. S3 shell中的帮助
 
  这个S3 shell中已经添加了一些有用的方法。可以在其中添加其他功能,让shell更适合您的需求。

  结束语

  在本文中,了解了Amazon S3服务的一些基本概念。学习了用于与S3交互的开放源码库JetS3t。还学习了如何使用示例代码片段创建一个简单的S3 shell,让您可以使用命令行轻松地体验S3服务。

  这个“用Amazon Web Services进行云计算”系列的第3部分解释如何使用Amazon Elastic Compute Cloud(EC2)在云中运行虚拟服务器。

我们一直都在努力坚持原创.......请不要一声不吭,就悄悄拿走。

我原创,你原创,我们的内容世界才会更加精彩!

【所有原创内容版权均属TechTarget,欢迎大家转发分享。但未经授权,严禁任何媒体(平面媒体、网络媒体、自媒体等)以及微信公众号复制、转载、摘编或以其他方式进行使用。】

微信公众号

TechTarget微信公众号二维码

TechTarget

官方微博

TechTarget中国官方微博二维码

TechTarget中国

相关推荐